使用NDK移植/编译开源库(4)libjpeg的编译

说明: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上编译,都是一样的。

你可能感兴趣的:(android,linux,struct,jni,工具,byte)