基本的にAndroid

Android初心者の備忘録のようなもの. 公開しているソースコードは主にgccでコンパイルされると想定されています.

libpng for Android

swfファイルから画像ファイルを抽出する際に, タグの内部にJPEGで内蔵されて透明チャンネルをzlibで圧縮したものが付属されている.
透明色を表現することはJPEGでも可能ですが, JPEGのライブラリは扱いが少し厄介なのでPNGで保存されるようにするため今回はlibpngについてです.
Android NDKには, libpngがないため, github
julienr/libpng-android · GitHub
とかlibpng
libpng Home Page
本家からダウンロードして, NDKにライブラリを追加します.

NDKのAndroid.mkに追加した状態を記述すると

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := libpng
LOCAL_SRC_FILES :=\
	libpng/png.c \
	libpng/pngerror.c \
	libpng/pngget.c \
	libpng/pngmem.c \
	libpng/pngpread.c \
	libpng/pngread.c \
	libpng/pngrio.c \
	libpng/pngrtran.c \
	libpng/pngrutil.c \
	libpng/pngset.c \
	libpng/pngtest.c \
	libpng/pngtrans.c \
	libpng/pngwio.c \
	libpng/pngwrite.c \
	libpng/pngwtran.c \
	libpng/pngwutil.c

#LOCAL_LDLIBS := -lz
#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := buildpng
LOCAL_SRC_FILES := buildpng.c
LOCAL_LDLIBS	:= -llog -lz
LOCAL_C_INCLUDES += $(LOCAL_PATH)/libpng
LOCAL_STATIC_LIBRARIES := libpng

include $(BUILD_SHARED_LIBRARY)

必要なファイルをコピーしてコンパイルをしています.

ちなみにC言語のコードは,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>

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

#define TAG "buildpng"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define PATH_LENGTH (1024)

/* jni/build_png.c */
int build_png(const char *path);

int
Java_com_archmint_pngbuild_PNGActiv_createpng(
    JNIEnv *env,
    jobject thiz,
    jstring path) {
  const char *external_path = (*env)->GetStringUTFChars(
      env, path, NULL);

  if(build_png(external_path) == (-1)) {
    return (-1);
  }

  (*env)->ReleaseStringUTFChars(
      env, path, external_path);
  return 1;
}

int build_png(const char *path) {
  png_structp png_ptr;
  png_infop info_ptr;
  int i, j;
  const int width = 256, height = 256;

  unsigned char **src;
  FILE *fp;

  char png_path[PATH_LENGTH];
  memset(png_path, '\0', PATH_LENGTH);
  sprintf(png_path, "%s/%s", path, "png_path.png");

  if((fp = fopen(png_path, "wb")) == NULL) {
    LOGD("fopen(3)");
    return (-1);
  }

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
      NULL, NULL, NULL);
  info_ptr = png_create_info_struct(png_ptr);

  png_init_io(png_ptr, fp);

  png_set_IHDR(png_ptr, info_ptr,
      width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
      PNG_FILTER_TYPE_BASE);

  src = (unsigned char **)calloc(height, sizeof(unsigned char **));
  for(i = 0; i < height; i++) {
    src[i] = (unsigned char *)calloc(width, sizeof(unsigned char *));

    for(j = 0; j < width; j++) {
      src[i][j * 4 + 0] = 200;
      src[i][j * 4 + 1] = j;
      src[i][j * 4 + 2] = i;
      src[i][j * 4 + 3] = 0xFF;
    }
  }


  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, src);

  png_write_end(png_ptr, info_ptr);
  png_destroy_write_struct(&png_ptr, &info_ptr);

  for(i = 0; i < height; i++) {
    free(src[i]);
  }
  free(src);
  fclose(fp);
  return 1;
}

エラー処理がまともにされていない, 危険なコードです.
が, 今回はこのまま使用しました.

そして,
パッケージ名:com.archmint.pngbuild
アクティビティ名: PNGActiv
ソースコード内に,

static {
System.loadLibrary("buildpng");
}
static native createpng(String path);

圧縮したファイルをGoogle Driveに保存をさせました.
https://drive.google.com/folderview?id=0B4z92cYyh2opV1h6cTFtV1JDX0E&usp=sharing


Androidで実行した結果は,
f:id:calloc:20140824234256p:plain
f:id:calloc:20140824234259p:plain
こうなりました.