说明:libjpeg下载http://www.ijg.org/,jpegsrc.v8c.tar.gz。(下面是用的是Linux环境NDKr7版本)
(1)使用NDK的GCC编译
1. 解压jpeg包
2. 建立两个文件夹,用于存储编译后的头文件和库文件等(下面的configure用到)。
3. 在终端设置NDK的GCC路径如下:
export SYSROOT=$NDK/platforms/android-14/arch-arm
export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
4. configure
./configure --prefix=/home/sgeng2/Desktop/ndk_lab/libjpeg/prefix/ --exec-prefix=/home/sgeng2/Desktop/ndk_lab/libjpeg/exec_prefix/ --host=arm
注意:要指定--host,否则configure会有错误。
5. make和make install
make
make install
完成后,在configure中指定的prefix和exec-prefix的文件夹中可以找到编译后得到的头文件和库文件。
总结:jpeg的编译过程很顺利,configure的时候没遇到什么错误,make的时候也不需要修改代码,比较容易的了。
(2)测试
为了测试如何使用编译后的jpeg,写了一个简单的测试代码。建立一个test_prj的文件夹,在其下新建一个jni文件夹,将上面生成的prefix下的include文件夹中的头文件和exec-prefix下的libs文件夹中的libjpeg.a复制到jni文件夹中,在jni中新建Android.mk和test.c文件,最终目录树如下:
NDK#tree
.
└── jni
├── Android.mk
├── jconfig.h
├── jerror.h
├── jmorecfg.h
├── jpeglib.h
├── libjpeg.a
└── test.c
1 directory, 7 files
NDK#
其中,Android.mk的写法如下:
LOCAL_PATH := $(call my-dir)
## prebuilt the static libs
include $(CLEAR_VARS)
LOCAL_MODULE := jpeg
LOCAL_SRC_FILES := libjpeg.a
include $(PREBUILT_STATIC_LIBRARY)
## to call the static libs
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.c
LOCAL_STATIC_LIBRARIES += jpeg
include $(BUILD_SHARED_LIBRARY)
(注意:关于如何调用第三方静态库动态库等的Android.mk的写法,可以参考 http://hi.baidu.com/joec3/blog/item/687cf98913065dae0e244442.html的文章)
其中,test.c的内容如下:
#include
#include
#include
#include
#include
typedef uint8_t BYTE;
#define true 1
#define false 0
#include "jpeglib.h"
int generateJPEG(BYTE* data,int w, int h, const char* outfilename)
{
int nComponent = 3;
struct jpeg_compress_struct jcs;
// ÉùÃ÷ŽíÎóŽŠÀíÆ÷£¬²¢ž³Öµžøjcs.errÓò
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
FILE* f=fopen(outfilename,"wb");
if (f==NULL)
{
free(data);
return 0;
}
jpeg_stdio_dest(&jcs, f);
jcs.image_width = w; // Ϊ͌µÄ¿íºÍžß£¬µ¥Î»ÎªÏñËØ
jcs.image_height = h;
jcs.input_components = nComponent; // 1,±íÊŸ»Ò¶ÈÍŒ£¬ Èç¹ûÊDzÊɫλ͌£¬ÔòΪ3
if (nComponent==1)
jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE±íÊŸ»Ò¶ÈÍŒ£¬JCS_RGB±íÊŸ²ÊÉ«ÍŒÏñ
else
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);
jpeg_set_quality (&jcs, 60, true);
jpeg_start_compress(&jcs, TRUE);
JSAMPROW row_pointer[1]; // Ò»ÐÐλ͌
int row_stride; // ÿһÐеÄ×ÖœÚÊý
row_stride = jcs.image_width*nComponent; // Èç¹û²»ÊÇË÷ÒýÍŒ,ŽËŽŠÐèÒª³ËÒÔ3
// ¶ÔÿһÐÐœøÐÐѹËõ
while (jcs.next_scanline < jcs.image_height) {
row_pointer[0] = & data[jcs.next_scanline*row_stride]; //×¢Ò⣺row_pointer[0]±íÃ÷ÿһžöÉšÃèÐеÄÖžÕ룬עÒâ¶ÔdataœøÐзÖÎö¡£
//Èç¹ûdataÊÇÖ±œÓŽÓ24λλ͌¶ÁÈ¡£¬ÒªœøÐÐ×֜ڶÔÆ뎊Àí£¬
// ÕâÀïÓÉÓÚÉÏÃæµÄread24BMP±ŸÉíŸÍŽŠÀíÁËÕâЩÎÊÌ⣬ËùÒÔÖ±œÓŸÍÊÇÕý³£µÄÍ·Ïñ×ø±êϵºÍÐеij€¶È¡£
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
fclose(f);
return 1;
}
/*
Éú³ÉRGB24ÊýŸÝ£¬žùŸÝÐèÒªœøÐÐÐÞžÄ
*/
BYTE* generateRGB24Data()
{
struct {
BYTE r;
BYTE g;
BYTE b;
} pRGB[100][199]; // ÐÞžÄ˳Ðò£¬ŽÓ¶ø±íÊŸ²»Í¬µÄžñÊœ£¬RGB¡¢BGRµÈµÈ¡£
memset( pRGB, 0, sizeof(pRGB) ); // ÉèÖñ³Ÿ°ÎªºÚÉ«
int i=0, j=0;
// ÔÚÖÐŒä»À¶É«ÇøÓò
for( i=50;i<70;i++ ){
for( j=70;j<140;j++ ){
pRGB[i][j].b = 0xff;
}
}
// ÔÚÖЌ仺ìÉ«ÇøÓò
for( i=0;i<10;i++ ){
for( j=0;j<199;j++ ){
pRGB[i][j].r = 0xff;
}
}
BYTE* ret = (BYTE*)malloc(sizeof(BYTE)*100*199*3);
memcpy(ret, (BYTE*)pRGB, sizeof(pRGB));
return ret;
}
void Java_com_example_TestjpegActivity_generateJPG(JNIEnv* env, jobject thiz )
{
BYTE* data = generateRGB24Data();
generateJPEG(data,199, 100, "/sdcard/test.jpg");
free(data);
}
注意:这里的代码是我以前写的,里面的乱码是中文注释,弄到虚拟机里面变成了乱码,也不管了,libjpeg的用法也不属于这里要讨论的内容。这里只关注最后一个JNI封装的函数,generateJPG,最后要在Android的Java中调用的就是这个函数,这里实现的功能是,在sdcard下生成一张JPG图片test.jpg,生成的数据也是generateRGB24Data来生成的RGB数据。
最后,在test_prj下编译:
NDK#$NDK/ndk-build
Compile thumb : test <= test.c
Prebuilt : libjpeg.a <= jni/
SharedLibrary : libtest.so
Install : libtest.so => libs/armeabi/libtest.so
NDK#
得到libtest.so,然后将此.so文件放到Eclipse中Android工程中去(package com.example;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class TestjpegActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("MyLog", "Generating JPG file to /sdardc/test.jpg");
generateJPG();
Log.d("MyLog", "Done");
}
public native void generateJPG();
static {
System.loadLibrary("test");
}
}
注意:给工程添加如下权限:
然后就可以运行Android程序了,最后的结果是运行后会在sdcard下生成一张JPG图片,用DDMS中的File Explorer可以看到,导出文件后可以打开JPG图片。
如果没有意外,最后生成的JPG图片如下:
更新:
下载Linux:http://dl.dbank.com/c0pp14j2ei (dbank,用QQ号就可以登录)
下载Cywin:http://dl.dbank.com/c0a1d42ujk
说明:这里的编译的方式是利用NDK中的gcc进行交叉编译,NDK for windows里面的工具链可能不太规范,所以容易出错。更好的一种方式是,NDK的build/tools下面提供了一个脚本make-standalone-toolchain.sh,其用于从NDK中提取出一个独立的交叉工具链,使用这个提取出来的工具链是更好的方法。这里的Cygwin的测试,就是先提取交叉工具链然后使用的(因为按照前面Linux的方法,发现有很多问题,最终也没有完全解决,用提取的工具链很容易就解决了)。
另外,使用NDK进行交叉编译,个人还是推荐使用Linux上编译,使用Cygwin麻烦而且有可能有一些问题。反正,Linux和windows上编译,都是一样的。