libpngをAndroid NDKの標準ライブラリに登録する

test110_01.png
以前扱った「Android NDK用にlibpngをビルドして利用する」では、libpngをそのソースコードからビルドして利用した。毎回libpngをビルドするのは面倒なので、そのときにビルドしてできたバイナリファイルを、Android NDKの標準ライブラリとして登録してしまう。

まずはlibpngのソースコードに含まれていたpng.hとpngconf.hを"C:\android-ndk\platforms\android-xxx\arch-arm\usr\include\"へコピーする。

test110_02.png
次に「Android NDK用にlibpngをビルドして利用する」のプロジェクトをビルドして得られたlibpng.aを"C:\android-ndk\platforms\android-xxx\arch-arm\usr\lib\"へコピーする。これでAndroid NDK標準ライブラリへの登録作業は終りだ。

libpngでは内部でzlibを利用しているが、zlibはAndroid NDKの標準ライブラリとして組み込み済みなためコピーする必要はない。



test110_03.png 次に実際に使ってみる。標準ライブラリとして登録したlibpngを利用するときは、Android.mkのLOCAL_LDLIBSに「-lz -lpng」を指定する。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test110jni
LOCAL_SRC_FILES := Test110jni.c
LOCAL_LDLIBS    := -lz -lpng -llog -ljnigraphics

include $(BUILD_SHARED_LIBRARY)

test110_04.png 描画コードは「Android NDK用にlibpngをビルドして利用する」と同じものを利用した。
#include <jni.h>
#include <android/bitmap.h>
#include <stdlib.h>
#include <png.h>

/* 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) );
}


static int DrawBitmap(AndroidBitmapInfo* pBitmapInfo, void* pPixels, const char* pszImageFile)
{
	FILE	*fp;

	//画像ファイルの読み込み
	fp = fopen(pszImageFile,"r");
	if(fp == NULL)
		return	0;

	int		bSucceeded = 0;

	png_bytepp	ppRowImage = NULL;
	png_structp	pPng = NULL;
	png_infop	pInfo = NULL;

	while(1)
	{
		pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
		if(pPng == NULL)
			break;

		pInfo = png_create_info_struct(pPng);
		if(pInfo == NULL)
			break;

		//ファイルポインタの設定
		png_init_io(pPng,fp);

		png_uint_32	nWidth;
		png_uint_32	nHeight;
		int		nBitDepth;
		int		nColorType;
		int		nIntMethod;
		int		nCompMethod;
		int		nFilterMethod;
		png_uint_32	nImageBytes;
		png_uint_32	nRowBytes;

		//画像情報取得
		png_read_info(pPng,pInfo);
		png_get_IHDR(pPng,pInfo,&nWidth,&nHeight,&nBitDepth,&nColorType,&nIntMethod,&nCompMethod,&nFilterMethod);
		nRowBytes	= png_get_rowbytes(pPng,pInfo);
		nImageBytes	= nHeight * nRowBytes;

		//画像データ用バッファーの確保
		ppRowImage = (png_bytepp)malloc(sizeof(png_bytep) * nHeight + nImageBytes);
		if(ppRowImage == NULL)
			break;

		int		yy;

		//画像データ用バッファーの初期化
		{
			png_bytep	pRowImage;

			pRowImage = (png_bytep)&(ppRowImage[nHeight]);
			for(yy = 0; yy < nHeight; yy++)
			{
				ppRowImage[yy] = pRowImage;
				pRowImage += nRowBytes;
			}
		}


		//画像ファイル読み込み
		png_read_image(pPng,ppRowImage);


		//描画
		for(yy = 0; yy < pBitmapInfo->height && yy < nHeight; yy++)
		{
			int		xx;
			uint16_t*	pLine;
			char*		pImagePixel;

			pLine = (uint16_t*)pPixels;					//ビットマップの行データ
			pImagePixel = (char*)(ppRowImage[yy]);		//画像ファイルの行データ

			for(xx = 0; xx < pBitmapInfo->width && xx < nWidth; xx++)
			{
				//■■注意■■1ピクセル3バイト前提で処理している。しかも画像ファイルが1ピクセル3バイトかどうかはチェックしていない!
				pLine[xx] = make565(pImagePixel[0],pImagePixel[1],pImagePixel[2]);
				pImagePixel += 3;
			}

			pPixels = (char*)pPixels + pBitmapInfo->stride;
		}

		bSucceeded = 1;
		break;				//必須忘れないこと!
	}


	if(ppRowImage)
	{
		free(ppRowImage);
		ppRowImage = NULL;
	}

	if(pPng)
	{
		if(pInfo)
			png_destroy_read_struct(&pPng,&pInfo,NULL);
		else
			png_destroy_read_struct(&pPng,NULL,NULL);

		pPng = NULL;
		pInfo = NULL;
	}

	fclose(fp);

	return	bSucceeded;
}


JNIEXPORT void JNICALL Java_com_Test110_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.png");

	AndroidBitmap_unlockPixels(env, bitmap);
}

test110_05.png
これで仮想SDカードに保存したPNG画像を表示できた。

本当はAndroid NDKの標準ライブラリとしての登録は避けて、LOCAL_PREBUILT_LIBSを利用したmakefileで済ませたかったのですが、方法が分かりませんでした。今回の方法はかなり苦肉の策です。




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


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