Android NDKでlibjpegをビルドして利用する

test118_01.png
今回はIJGのJPEGライブラリ(libjpeg、jpeglib)をAndroid NDKから利用してJpgファイルを表示する。

まずIndependent JPEG GroupからJPEGライブラリのソースファイルをダウンロードする。「jpegsr8c.zip」というファイルだった。

test118_02.png
EasyProjectGenerator for Androidで雛形となるAndroidプロジェクトを作成する。今回はC++でNativeViewを利用する。

test118_03.png
ダウンロードしたJPEGライブラリのソースファイル一式をAndroidプロジェクトのjniフォルダへ解凍する。

test118_04.png
さらにjniフォルダにあったソースファイルやmakefileを「Test118」というフォルダを作成してその中へ移動する。

test118_05.png
プロジェクトをEclipseへ取り込む。

jniフォルダ直下に「Android.mk」ファイルを作成する。そしてjniフォルダの下のフォルダをビルド対象に指定する。
include $(call all-subdir-makefiles)

test118_06.png 次にlibjpegの「jpeg-8c」フォルダの中に「Android.mk」ファイルを作成して、JPEGライブラリのビルド指定をする。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libjpeg

LOCAL_SRC_FILES := jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemname.c

include $(BUILD_STATIC_LIBRARY)

test118_07.png
次にlibjpegの「jpeg-8c」フォルダの中にある「jconfig.txt」ファイルを選択した状態で[F2]キーを押して、ファイル名を「jconfig.h」に変更する。これでJPEGライブラリのビルド準備が整った。

test118_08.png 次にcppファイルを開き、実際にlibjpegを利用してjpgファイルを読み込み表示する処理を実装する。
#if(true)
#define LOCAL_LOG
#define LOCAL_LOGD
#endif

#include <jni.h>
#include <android/bitmap.h>

#ifdef LOCAL_LOG
#include <android/log.h>
#endif


/* this function is from Android NDK bitmap-plasma , and modify for green color bug */
static uint16_t  make565(int red, int green, int blue)
{
	return (uint16_t)( ((red   << 8) & 0xf800) |
					   ((green << 3) & 0x07e0) |
					   ((blue  >> 3) & 0x001f) );
}


#include <stdio.h>

extern "C"
{
#define XMD_H
#include "../jpeg-8c/jpeglib.h"
#include "../jpeg-8c/jerror.h"
}


static	void	_JpegError(j_common_ptr cinfo)
{
	char	pszMessage[JMSG_LENGTH_MAX];

	(*cinfo->err->format_message)(cinfo,pszMessage);

	__android_log_print(ANDROID_LOG_INFO,"Test118","error!  %s",pszMessage);
}

static int DrawBitmap(AndroidBitmapInfo* pBitmapInfo, void* pPixels,const char* pszJpegFile)
{
	int			yy;
	int			nJpegLineBytes;			//JPEG1ラインのバイト数

	char*		lpbtBits;
	JSAMPLE*	pSample;
	FILE*		fp;
	JSAMPROW	buffer[1];
	JSAMPLE		tmp;

	jpeg_decompress_struct		cInfo;
	jpeg_error_mgr				jError;

	fp = fopen(pszJpegFile,"rb");
	if(fp == NULL)
		return	0;

	cInfo.err = jpeg_std_error(&jError);			//エラーハンドラ設定
	jError.error_exit = _JpegError;					//エラーハンドラ設定

	jpeg_create_decompress(&cInfo);					//
	jpeg_stdio_src(&cInfo,fp);						//読込ファイル設定
	jpeg_read_header(&cInfo,TRUE);					//ヘッダー読込
	jpeg_start_decompress(&cInfo);					//デコードスタート

	nJpegLineBytes = cInfo.output_width * cInfo.output_components;		//JPEG 1ラインのバイト数

	pSample = new JSAMPLE[nJpegLineBytes + 10];		// ラインバッファ確保
	buffer[0] = pSample;

	yy = 0;
	while(cInfo.output_scanline < cInfo.output_height)
	{
		if(yy >= pBitmapInfo->height)
			break;

		jpeg_read_scanlines(&cInfo,buffer,1);		//Jpegを1ライン読み込む

		int		xx;
		int		x3;

		uint16_t*  pLine = (uint16_t*)pPixels;
		for(xx = 0, x3 = 0; xx < pBitmapInfo->width && x3 < nJpegLineBytes; xx++, x3 += 3)
		{
			//JPEGはBGRの順
			pLine[xx] = make565(buffer[0][x3 + 0],buffer[0][x3 + 1],buffer[0][x3 + 2]);
		}

		// go to next line
		pPixels = (char*)pPixels + pBitmapInfo->stride;
		yy++;
	}
	delete	pSample;

	jpeg_finish_decompress(&cInfo);		// 読み込み終了処理
	jpeg_destroy_decompress(&cInfo);
	fclose(fp);

	return	1;
}




extern "C"
JNIEXPORT void JNICALL Java_com_Test118_NativeView_RenderBitmap(JNIEnv * env, jobject  obj, jobject bitmap)
{
	AndroidBitmapInfo  info;
	void*			  pixels;
	int				ret;

	if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
		return;

	if (info.format != ANDROID_BITMAP_FORMAT_RGB_565)
		return;

	if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
		return;

	DrawBitmap(&info,pixels,"/sdcard/test.jpg");

	AndroidBitmap_unlockPixels(env, bitmap);
}

test118_09.png 最後にcppファイルをビルドするための「Android.mk」ファイルにビルドしたlibjpegを利用する指定をする。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test118
LOCAL_SRC_FILES := Test118.cpp
LOCAL_LDLIBS    := -lz -ljnigraphics

LOCAL_STATIC_LIBRARIES += libjpeg

LOCAL_IS_SUPPORT_LOG := true
ifeq ($(LOCAL_IS_SUPPORT_LOG),true)
	LOCAL_LDLIBS += -llog
endif

include $(BUILD_SHARED_LIBRARY)

test118_10.png
これでビルドをかけると、libjpeg.aとそれを利用したバイナリが生成される。

test118_11.png
テスト表示用のjpgファイル「test.jpg」をAndroidエミュレーターのSDカードへと転送する。

test118_12.png
そしてプロジェクトを実行すると、jpgファイルが表示された。




プロジェクトファイルをダウンロード


カテゴリー「android」 のエントリー