说明: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 <string.h> #include <jni.h> #include <math.h> #include <stdio.h> #include <stdint.h> 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工程中去(<prj>/libs/armeabi/libtest.so),java代码如下:
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"); } }注意:给工程添加如下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>然后就可以运行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上编译,都是一样的。