この記事では、PNGおよびJPEGイメージをファイルまたはメモリからAndroid NDKにロードする方法と、これらのOpenGLイメージをフィードするための便利なコードについて説明します。
ダウンロードする
画像をダウンロードするには、次のライブラリを使用します。
- zlib - http: //www.zlib.net
- pnglib - http://www.libpng.org/pub/png/libpng.html
- libjpeg-turbo -git clone git://git.linaro.org/people/tomgall/libjpeg-turbo/libjpeg-turbo.git -b linaro-android
開梱
すべてを適切にフォルダーに分解します。たとえば、プロジェクトルートにあるモジュールフォルダーを作成します 。 このフォルダーにはjniフォルダーがあります。 開梱:
- モジュール/ pn gフォルダーへのpnglib
- モジュール内のlibjpeg-turbo / jpeg
- モジュール内のzlib / zlib
プロジェクト/ jni
プロジェクト/モジュール/ png
プロジェクト/モジュール/ jpeg
プロジェクト/モジュール/ zlib
カスタマイズする
- PROJECT / modules / png / scripts / pnglibconf.h.prebuiltをPROJECT / modules / png / pnglibconf.hにコピーします
- ファイルモジュール/ jpeg / Android.mkを開き、70行目でLOCAL_MODULE:= libjpegの後に、以下を追加します。
ifeq ($(notdir $(MAKECMDGOALS)),libjpeg.a) LOCAL_SRC_FILES += $(libsimd_SOURCES_DIST) include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := dummy endif
- そして11行目で改行を修正します
ifeq ($(ARCH_ARM_HAVE_NEON),true) LOCAL_CFLAGS += -D__ARM_HAVE_NEON endif
- ターミナルで、 modules / jpegフォルダーに移動し、次のコマンドを実行してarmv6およびarmv7のライブラリをコンパイルします
/PATH_TO_NDK/android-ndk-r8/ndk-build NDK_PROJECT_PATH=. LOCAL_ARM_MODE=arm APP_BUILD_SCRIPT=./Android.mk obj/local/armeabi/libjpeg.a /PATH_TO_NDK/android-ndk-r8/ndk-build NDK_PROJECT_PATH=. LOCAL_ARM_MODE=arm APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi-v7a obj/local/armeabi-v7a/libjpeg.a
Android.mkを編集します
Android.mkで、すべてのライブラリを一緒に接続します
LOCAL_PATH:= $(my-dirを呼び出す)
ヘッダー:=
STATICLIBS:=
含む$(CLEAR_VARS)
LOCAL_MODULE:= png
FILE_LIST:= $(ワイルドカード$(LOCAL_PATH)/../ modules / png / *。C *)
LOCAL_SRC_FILES:= $(FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / png
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
STATICLIBS + = $(LOCAL_MODULE)
インクルード$(BUILD_STATIC_LIBRARY)
含む$(CLEAR_VARS)
LOCAL_MODULE:= zlib
FILE_LIST:= $(ワイルドカード$(LOCAL_PATH)/../ modules / zlib / *。C *)
LOCAL_SRC_FILES:= $(FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / zlib
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
STATICLIBS + = $(LOCAL_MODULE)
インクルード$(BUILD_STATIC_LIBRARY)
含む$(CLEAR_VARS)
LOCAL_MODULE:= jpeg
LOCAL_SRC_FILES:= ../modules/jpeg/obj/local/$(TARGET_ARCH_ABI)/libjpeg.a
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / jpeg
STATICLIBS + = $(LOCAL_MODULE)
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
インクルード$(PREBUILT_STATIC_LIBRARY)
#------------------------------------------------- ---------
含む$(CLEAR_VARS)
LOCAL_ARM_MODE:=アーム
LOCAL_MODULE:= LoadImage
LOCAL_SRC_FILES:= loadimage.cpp
LOCAL_CFLAGS:= -Werror -DGL_GLEXT_PROTOTYPES = 1 -fsigned-char -Wno-write-strings -Wno-psabi
LOCAL_LDLIBS:= -llog -lGLESv1_CM
LOCAL_STATIC_LIBRARIES:= $(STATICLIBS)
LOCAL_C_INCLUDES = $(ヘッダー)
インクルード$(BUILD_SHARED_LIBRARY)
ヘッダー:=
STATICLIBS:=
含む$(CLEAR_VARS)
LOCAL_MODULE:= png
FILE_LIST:= $(ワイルドカード$(LOCAL_PATH)/../ modules / png / *。C *)
LOCAL_SRC_FILES:= $(FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / png
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
STATICLIBS + = $(LOCAL_MODULE)
インクルード$(BUILD_STATIC_LIBRARY)
含む$(CLEAR_VARS)
LOCAL_MODULE:= zlib
FILE_LIST:= $(ワイルドカード$(LOCAL_PATH)/../ modules / zlib / *。C *)
LOCAL_SRC_FILES:= $(FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / zlib
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
STATICLIBS + = $(LOCAL_MODULE)
インクルード$(BUILD_STATIC_LIBRARY)
含む$(CLEAR_VARS)
LOCAL_MODULE:= jpeg
LOCAL_SRC_FILES:= ../modules/jpeg/obj/local/$(TARGET_ARCH_ABI)/libjpeg.a
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/../ modules / jpeg
STATICLIBS + = $(LOCAL_MODULE)
HEADERS + = $(LOCAL_EXPORT_C_INCLUDES)
インクルード$(PREBUILT_STATIC_LIBRARY)
#------------------------------------------------- ---------
含む$(CLEAR_VARS)
LOCAL_ARM_MODE:=アーム
LOCAL_MODULE:= LoadImage
LOCAL_SRC_FILES:= loadimage.cpp
LOCAL_CFLAGS:= -Werror -DGL_GLEXT_PROTOTYPES = 1 -fsigned-char -Wno-write-strings -Wno-psabi
LOCAL_LDLIBS:= -llog -lGLESv1_CM
LOCAL_STATIC_LIBRARIES:= $(STATICLIBS)
LOCAL_C_INCLUDES = $(ヘッダー)
インクルード$(BUILD_SHARED_LIBRARY)
写真を読む
C ++コード(このファイルloadimage.cppがあります)では、次のことを行います。
コメント付きのコード
#include <jni.h> #include <android/log.h> #include <GLES/gl.h> #include <GLES/glext.h> // extern "C" { #include "png.h" #include <setjmp.h> #include "jpeglib.h" } #define LOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "NDK",__VA_ARGS__) // struct image { png_uint_32 imWidth, imHeight; // png_uint_32 glWidth, glHeight; // OpenGL int bit_depth, color_type; char* data; // RGB/RGBA }; //- OpenGL static int reNpot(int w) { // OpenGL // //String s = gl.glGetString(GL10.GL_EXTENSIONS); //NON_POWER_OF_TWO_SUPPORTED = s.contains("texture_2D_limited_npot") || s.contains("texture_npot") || s.contains("texture_non_power_of_two"); bool NON_POWER_OF_TWO_SUPPORTED = false; if (NON_POWER_OF_TWO_SUPPORTED) { if (w % 2) w++; } else { if (w <= 4) w = 4; else if (w <= 8) w = 8; else if (w <= 16) w = 16; else if (w <= 32) w = 32; else if (w <= 64) w = 64; else if (w <= 128) w = 128; else if (w <= 256) w = 256; else if (w <= 512) w = 512; else if (w <= 1024) w = 1024; else if (w <= 2048) w = 2048; else if (w <= 4096) w = 4096; } return w; } //- PNG static image readPng(const char* fileName) { image im; FILE* file = fopen(fileName, "rb"); // , PNG JPEG, - fseek(file, 8, SEEK_CUR); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); // png_get_IHDR(png_ptr, info_ptr, &im.imWidth, &im.imHeight, &im.bit_depth, &im.color_type, NULL, NULL, NULL); // OpenGL im.glWidth = reNpot(im.imWidth); im.glHeight = reNpot(im.imHeight); // 4 (RGBA), 3 (RGB) int row = im.glWidth * (im.color_type == PNG_COLOR_TYPE_RGBA ? 4 : 3); im.data = new char[row * im.glHeight]; // png_bytep * row_pointers = new png_bytep[im.imHeight]; for(int i = 0; i < im.imHeight; ++i) row_pointers[i] = (png_bytep) (im.data + i * row); // png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, 0); delete[] row_pointers; return im; } // libjpeg-turbo struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct my_error_mgr * my_error_ptr; METHODDEF(void) my_error_exit(j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message)(cinfo); longjmp(myerr->setjmp_buffer, 1); } //- JPEG static image readJpeg(const char* fileName) { image im; FILE* file = fopen(fileName, "rb"); struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); return im; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, file); // jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); im.imWidth = cinfo.image_width; im.imHeight = cinfo.image_height; im.glWidth = reNpot(im.imWidth); im.glHeight = reNpot(im.imHeight); //JPEG 3- (RGB) int row = im.glWidth * 3; im.data = new char[row * im.glHeight]; // unsigned char* line = (unsigned char*) (im.data); while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, &line, 1); line += row; } // jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return im; }
テスト
メモリカードからのPNG画像の読み込みのテスト:
// OpenGL GLuint texture1; glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // PNG image im = readPng("/mnt/sdcard/scrrihs.png"); LOG("PNG: %dx%d (%dx%d) bit:%d type:%d", im.imWidth, im.imHeight, im.glWidth, im.glHeight, im.bit_depth, im.color_type); // OpenGL if (im.color_type == PNG_COLOR_TYPE_RGBA) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.glWidth, im.glHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, im.data); } else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, im.glWidth, im.glHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, im.data); } delete[] im.data;
同様に、JPEGは常に透過性がないため、 JPEGを使用します
GLuint texture2; glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); image imJpeg = readJpeg("/mnt/sdcard/test.jpg"); LOG("JPEG: %dx%d (%dx%d)", imJpeg.imWidth, imJpeg.imHeight, imJpeg.glWidth, imJpeg.glHeight); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imJpeg.glWidth, imJpeg.glHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imJpeg.data); delete[] imJpeg.data;
暗号化して写真を読む
単純な画像暗号化を適用する必要がある場合は、復号化機能を画像読み取りプロセスに直接挿入できます。
- PNGの場合、読み取り用に独自の関数を指定する必要があります。 非表示のテキスト
static void userReadData(png_structp png_ptr, png_bytep data, png_size_t length) { // png_init_io(png_ptr, file); FILE* file=(FILE*)png_get_io_ptr(png_ptr); // fread(data, 1, length, file); // , for(int i = 0; i < length; i++) data[i] ^= 73; } ... png_init_io(png_ptr, file); png_set_read_fn(png_ptr, png_get_io_ptr(png_ptr), userReadData); ...
- JPEGの場合、それはもう少し複雑です。 ライブラリを再コンパイルする必要があります。 jdatasrc.cを開き、次の関数を変更します。 非表示のテキスト
METHODDEF (boolean) fill_input_buffer (j_decompress_ptr cinfo) { my_src_ptr src = (my_src_ptr) cinfo->src; size_t nbytes; nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); if (nbytes <= 0) { if (src->start_of_file) /* Treat empty input file as fatal error */ ERREXIT(cinfo, JERR_INPUT_EMPTY); WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } else { // int i; for(i = 0; i < nbytes; i++) src->buffer[i] ^= 73; } src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; src->start_of_file = FALSE; return TRUE; }
メモリから画像を読み取る
たとえば、アプリケーションがネットワーク経由で画像を受信し、画像が完全にメモリにハングアップします。
- PNGの場合、ファイルから読み取る機能を配列からコピーする機能に置き換えます。 非表示のテキスト
// struct mypng { unsigned int pos;// unsigned int length;// const char* data;// }; static void userReadData(png_structp png_ptr, png_bytep data, png_size_t length) { // mypng* png = (mypng*) png_get_io_ptr(png_ptr); // if (png->pos + length > png->length) length += png->pos-png->length; if (length > 0) { // memcpy(data, png->data + png->pos, length); // png->pos += length; } } ... mypng png = { 8, pngLength, pngData }; png_init_io(png_ptr, (FILE*) &png); png_set_read_fn(png_ptr, png_get_io_ptr(png_ptr), userReadData); ...
- JPEGの場合、 jdatasrc.cファイルを次のものに置き換え、ライブラリを再コンパイルします。
非表示のテキスト次のように使用します。/* * jdatasrc.c * * Copyright (C) 1994-1996, Thomas G. Lane. * Modified 2009-2010 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains decompression data source routines for the case of * reading JPEG data from memory or from a file (or any stdio stream). * While these routines are sufficient for most applications, * some will want to use a different source manager. * IMPORTANT: we assume that fread() will correctly transcribe an array of * JOCTETs from 8-bit-wide elements on external storage. If char is wider * than 8 bits on your machine, you may need to do some tweaking. */ /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ #include "jinclude.h" #include "jpeglib.h" #include "jerror.h" /* Expanded data source object for stdio input */ typedef struct { unsigned int pos; unsigned int length; const char* data; } pngrd; typedef struct { struct jpeg_source_mgr pub; /* public fields */ pngrd* infile; /* source stream */ JOCTET * buffer; /* start of buffer */ boolean start_of_file; /* have we gotten any data yet? */ } my_source_mgr; typedef my_source_mgr * my_src_ptr; #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ /* * Initialize source --- called by jpeg_read_header * before any data is actually read. */ METHODDEF(void) init_source (j_decompress_ptr cinfo) { } #if JPEG_LIB_VERSION >= 80 METHODDEF(void) init_mem_source (j_decompress_ptr cinfo) { /* no work necessary here */ } #endif /* * Fill the input buffer --- called whenever buffer is emptied. * * In typical applications, this should read fresh data into the buffer * (ignoring the current state of next_input_byte & bytes_in_buffer), * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been reloaded. It is not necessary to * fill the buffer entirely, only to obtain at least one more byte. * * There is no such thing as an EOF return. If the end of the file has been * reached, the routine has a choice of ERREXIT() or inserting fake data into * the buffer. In most cases, generating a warning message and inserting a * fake EOI marker is the best course of action --- this will allow the * decompressor to output however much of the image is there. However, * the resulting error message is misleading if the real problem is an empty * input file, so we handle that case specially. * * In applications that need to be able to suspend compression due to input * not being available yet, a FALSE return indicates that no more data can be * obtained right now, but more may be forthcoming later. In this situation, * the decompressor will return to its caller (with an indication of the * number of scanlines it has read, if any). The application should resume * decompression after it has loaded more data into the input buffer. Note * that there are substantial restrictions on the use of suspension --- see * the documentation. * * When suspending, the decompressor will back up to a convenient restart point * (typically the start of the current MCU). next_input_byte & bytes_in_buffer * indicate where the restart point will be if the current call returns FALSE. * Data beyond this point must be rescanned after resumption, so move it to * the front of the buffer rather than discarding it. */ METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static JOCTET mybuffer[4]; /* The whole JPEG data is expected to reside in the supplied memory * buffer, so any request for more data beyond the given buffer size * is treated as an error. */ WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ mybuffer[0] = (JOCTET) 0xFF; mybuffer[1] = (JOCTET) JPEG_EOI; cinfo->src->next_input_byte = mybuffer; cinfo->src->bytes_in_buffer = 2; return TRUE; } #if JPEG_LIB_VERSION >= 80 METHODDEF(boolean) fill_mem_input_buffer (j_decompress_ptr cinfo) { static JOCTET mybuffer[4]; /* The whole JPEG data is expected to reside in the supplied memory * buffer, so any request for more data beyond the given buffer size * is treated as an error. */ WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ mybuffer[0] = (JOCTET) 0xFF; mybuffer[1] = (JOCTET) JPEG_EOI; cinfo->src->next_input_byte = mybuffer; cinfo->src->bytes_in_buffer = 2; return TRUE; } #endif /* * Skip data --- used to skip over a potentially large amount of * uninteresting data (such as an APPn marker). * * Writers of suspendable-input applications must note that skip_input_data * is not granted the right to give a suspension return. If the skip extends * beyond the data currently in the buffer, the buffer can be marked empty so * that the next read will cause a fill_input_buffer call that can suspend. * Arranging for additional bytes to be discarded before reloading the input * buffer is the application writer's problem. */ METHODDEF(void) skip_input_data (j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr * src = cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->bytes_in_buffer) { num_bytes -= (long) src->bytes_in_buffer; (void) (*src->fill_input_buffer) (cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; } } /* * An additional method that can be provided by data source modules is the * resync_to_restart method for error recovery in the presence of RST markers. * For the moment, this source module just uses the default resync method * provided by the JPEG library. That method assumes that no backtracking * is possible. */ /* * Terminate source --- called by jpeg_finish_decompress * after all data has been read. Often a no-op. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */ METHODDEF(void) term_source (j_decompress_ptr cinfo) { /* no work necessary here */ } /* * Prepare for input from a stdio stream. * The caller must have already opened the stream, and is responsible * for closing it after finishing decompression. */ GLOBAL(void) jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) { struct jpeg_source_mgr * src; /* The source object is made permanent so that a series of JPEG images * can be read from the same buffer by calling jpeg_mem_src only before * the first one. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(struct jpeg_source_mgr)); } src = cinfo->src; src->init_source = init_source; src->fill_input_buffer = fill_input_buffer; src->skip_input_data = skip_input_data; src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->term_source = term_source; src->bytes_in_buffer = (size_t) ((pngrd*)infile)->length; src->next_input_byte = (JOCTET *) ((pngrd*)infile)->data; } #if JPEG_LIB_VERSION >= 80 /* * Prepare for input from a supplied memory buffer. * The buffer must contain the whole JPEG data. */ GLOBAL(void) jpeg_mem_src (j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize) { struct jpeg_source_mgr * src; if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */ ERREXIT(cinfo, JERR_INPUT_EMPTY); /* The source object is made permanent so that a series of JPEG images * can be read from the same buffer by calling jpeg_mem_src only before * the first one. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(struct jpeg_source_mgr)); } src = cinfo->src; src->init_source = init_mem_source; src->fill_input_buffer = fill_mem_input_buffer; src->skip_input_data = skip_input_data; src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->term_source = term_source; src->bytes_in_buffer = (size_t) insize; src->next_input_byte = (JOCTET *) inbuffer; } #endif
... mypng jpeg = { 0, jpegLength, jpegData }; jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, (FILE*) &jpeg); ...
Openglパン
// RGBA RGBA4444 int len = im.glWidth * im.glHeight; unsigned short* tmp = (unsigned short*) im.data; for(int i = 0; i < len; i++) tmp[i] = ((im.data[i * 4] >> 4) << 12) | ((im.data[i * 4 + 1] >> 4) << 8) | ((im.data[i * 4 + 2] >> 4) << 4) | (im.data[i * 4 + 3] >> 4); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.glWidth, im.glHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, im.data); // RGB RGB565 int len = im.glWidth * im.glHeight; unsigned short* tmp = (unsigned short*) im.data; for(int i = 0; i < len; i++) tmp[i] = ((im.data[i * row] >> 3) << 11) | ((im.data[i * row + 1] >> 2) << 5) | (im.data[i * row + 2] >> 3); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, im.glWidth, im.glHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, im.data); // RGB/RGBA GL_LUMINANCE GL_ALPHA int row = HAS_ALPHA?4:3; int len = im.glWidth * im.glHeight * row; for(int i = 0, a = 0; i < len; i += row, a++) im.data[a] = im.data[i]; glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, im.glWidth, im.glHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, im.data);
ループ内で配列が自分自身に書き込むことは大丈夫です 最終的な配列は常に元の配列よりも小さく、OpenGLテクスチャを作成した後は不要になります。
私は誰かがこれらの開発が役立つと確信しています。 いずれにせよ、その前に、JNIを介してダウンロードしたファイルを投げ、そこにビットマップを作成し、ピクセルを読み取ってNDKに送り返さなければなりませんでした。 さらに、これらすべての機能は、Android NDKだけでなく、iOS / MacOSでも使用できます。
念のため、以下はlibjpeg-turboをコンパイルするためのコマンドです(libpngはXcodeにフォルダーを追加するだけで問題なくコンパイルできます)。
非表示のテキスト
cd {source_directory}
autoreconf -fiv
mkdirビルド
cdビルド
MacOS
sh ../configure --host i686-apple-darwin CFLAGS = '-O3 -m32' LDFLAGS = -m32
iOS ARM v7のみ
sh ../configure --host arm-apple-darwin10 --enable-static --disable-shared CC = "/ Applications / Xcode.app / Contents / Developer / Platforms / iPhoneOS.platform / Developer / usr / bin / arm -apple-darwin10-llvm-gcc-4.2 "LD =" / Applications / Xcode.app / Contents / Developer / Platforms / iPhoneOS.platform / Developer / usr / bin / arm-apple-darwin10-llvm-gcc-4.2 "CFLAGS = "-mfloat-abi = softfp -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk -O3 -march = armv7 -mcpu = cortex-a8 -mtune = cortex-a8 -mfpu = neon "LDFLAGS ="-mfloat-abi = softfp -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk -march = armv7 -mcpu = cortex-a8 -mtune = cortex-a8 -mfpu = neon "
autoreconf -fiv
mkdirビルド
cdビルド
MacOS
sh ../configure --host i686-apple-darwin CFLAGS = '-O3 -m32' LDFLAGS = -m32
iOS ARM v7のみ
sh ../configure --host arm-apple-darwin10 --enable-static --disable-shared CC = "/ Applications / Xcode.app / Contents / Developer / Platforms / iPhoneOS.platform / Developer / usr / bin / arm -apple-darwin10-llvm-gcc-4.2 "LD =" / Applications / Xcode.app / Contents / Developer / Platforms / iPhoneOS.platform / Developer / usr / bin / arm-apple-darwin10-llvm-gcc-4.2 "CFLAGS = "-mfloat-abi = softfp -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk -O3 -march = armv7 -mcpu = cortex-a8 -mtune = cortex-a8 -mfpu = neon "LDFLAGS ="-mfloat-abi = softfp -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk -march = armv7 -mcpu = cortex-a8 -mtune = cortex-a8 -mfpu = neon "
更新:
zlibライブラリは、NDKからネイティブに接続できます。 これを行うには、Android.mkで、zlibに関係するブロックを削除して登録する必要があります。
LOCAL_LDLIBS := -llog -lGLESv1_CM -lz