
सभी पाठकों को नमस्कार!
यह आलेख चर्चा करेगा कि एंड्रॉइड एनडीके में पीएनजी और जेपीईजी छवियों को एक फ़ाइल या मेमोरी से कैसे लोड किया जाए, साथ ही इन ओपन इमेज को खिलाने के लिए कुछ उपयोगी कोड।
डाउनलोड
छवियों को डाउनलोड करने के लिए, हम निम्नलिखित पुस्तकालयों का उपयोग करेंगे:
खोलना
हम सब कुछ फ़ोल्डरों में बड़े करीने से विघटित करते हैं, उदाहरण के लिए, प्रोजेक्ट रूट में
मॉड्यूल फ़ोल्डर बनाएं, जहां
जेनी फ़ोल्डर
स्थित है । खोल:
- मॉड्यूल / pn g फ़ोल्डर में pnglib
- मॉड्यूल / jpeg में libjpeg-टर्बो
- मॉड्यूल में zlib / zlib
इस प्रकार ऐसी संरचना प्राप्त करें
परियोजना / जानी
परियोजना / मॉड्यूल / पीएनजी
परियोजना / मॉड्यूल / जेपीईजी
परियोजना / मॉड्यूल / zlib
धुन
- PROJECT / मॉड्यूल / png / लिपियों / pnglibconf.h.prebuilt को PROJECT / मॉड्यूल / png / pnglibconf.h पर कॉपी करें
- LOCAL_MODULE के बाद फ़ाइल मॉड्यूल / jpeg / Android.mk और 70 वीं पंक्ति पर खोलें: = 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
- टर्मिनल में, मॉड्यूल / जेपीईजी फ़ोल्डर पर जाएं और 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) /../ मॉड्यूल / png / * C।)।
LOCAL_SRC_FILES: = $ (FILE_LIST: $ (LOCAL_PATH) /% =%)
LOCAL_EXPORT_C_INCLUDES: = $ (LOCAL_PATH) /../ मॉड्यूल / पीएनजी
हेडर्स + = $ (LOCAL_EXPORT_C_INCLUDES)
STATICLIBS + = $ (LOCAL_MODULE)
$ (BUILD_STATIC_LIBRARY) शामिल करें
$ (CLEAR_VARS) शामिल करें
LOCAL_MODULE: = zlib
FILE_LIST: = $ (वाइल्डकार्ड $ (LOCAL_PATH) /../ मॉड्यूल / zlib / *। C *)
LOCAL_SRC_FILES: = $ (FILE_LIST: $ (LOCAL_PATH) /% =%)
LOCAL_EXPORT_C_INCLUDES: = $ (LOCAL_PATH) /../ मॉड्यूल / ज़ीब
हेडर्स + = $ (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) /../ मॉड्यूल / एमपीईजी
STATICLIBS + = $ (LOCAL_MODULE)
हेडर्स + = $ (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 -fsign-char -Wno-write -Wno-psabi
LOCAL_LDLIBS: = -llog -lGLESv1_CM
LOCAL_STATIC_LIBRARIES: = $ (STATICLIBS)
LOCAL_C_INCLUDES = $ (HEADERS)
$ (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; }
परीक्षण
मेमोरी कार्ड से
पीएनजी छवियों का परीक्षण करना:
इसी तरह, हम
जेपीईजी के साथ करते हैं, यह देखते हुए कि जेपीईजी हमेशा पारदर्शिता के बिना होता है
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) {
- 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) ERREXIT(cinfo, JERR_INPUT_EMPTY); WARNMS(cinfo, JWRN_JPEG_EOF); src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } else {
स्मृति से चित्र पढ़ना
उदाहरण के लिए, एप्लिकेशन को नेटवर्क पर एक चित्र प्राप्त हुआ और चित्र पूरी तरह से मेमोरी में लटका हुआ है।
- PNG के लिए, हम एक फ़ाइल से पढ़ने की कार्यप्रणाली को किसी सरणी से कॉपी करने के कार्य से प्रतिस्थापित करते हैं:
- JPEG के लिए, jdatasrc.c फ़ाइल को निम्न के साथ बदलें और पुस्तकालयों को फिर से खोलें :
छिपा हुआ पाठ #include "jinclude.h" #include "jpeglib.h" #include "jerror.h" typedef struct { unsigned int pos; unsigned int length; const char* data; } pngrd; typedef struct { struct jpeg_source_mgr pub; pngrd* infile; JOCTET * buffer; boolean start_of_file; } my_source_mgr; typedef my_source_mgr * my_src_ptr; #define INPUT_BUF_SIZE 4096 METHODDEF(void) init_source (j_decompress_ptr cinfo) { } #if JPEG_LIB_VERSION >= 80 METHODDEF(void) init_mem_source (j_decompress_ptr cinfo) { } #endif METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static JOCTET mybuffer[4]; WARNMS(cinfo, JWRN_JPEG_EOF); 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]; WARNMS(cinfo, JWRN_JPEG_EOF); mybuffer[0] = (JOCTET) 0xFF; mybuffer[1] = (JOCTET) JPEG_EOI; cinfo->src->next_input_byte = mybuffer; cinfo->src->bytes_in_buffer = 2; return TRUE; } #endif METHODDEF(void) skip_input_data (j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr * src = cinfo->src; 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); } src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; } } METHODDEF(void) term_source (j_decompress_ptr cinfo) { } GLOBAL(void) jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) { struct jpeg_source_mgr * src; if (cinfo->src == NULL) { 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; 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 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) ERREXIT(cinfo, JERR_INPUT_EMPTY); if (cinfo->src == NULL) { 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; 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 बनावट बनाने के बाद हमें इसकी आवश्यकता नहीं होती है।
मुझे यकीन है कि किसी को ये घटनाक्रम उपयोगी लगेगा। किसी भी स्थिति में, इससे पहले मुझे जेएनआई जावा के माध्यम से डाउनलोड की गई फ़ाइलों को फेंकना था, वहां एक बिटमैप बनाएं, पिक्सल पढ़ें और उन्हें एनडीके को वापस भेजें, जो कि समय और मेमोरी दोनों में अधिक महंगा परिमाण का एक आदेश था। इसके अलावा, इन सभी कार्यों का उपयोग न केवल एंड्रॉइड एनडीके में, बल्कि आईओएस / मैकओएस में भी किया जा सकता है।
बस के मामले में, यहाँ libjpeg-टर्बो संकलित करने के आदेश हैं (libpng को बिना किसी समस्या के केवल Xcode में फ़ोल्डर जोड़कर संकलित किया जा सकता है):
छिपा हुआ पाठसीडी {source_directory}
autoreconf -fiv
mkdir का निर्माण
सीडी का निर्माण
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 -एप्पल-डार्विन 10-llvm-gcc-4.2 "LD =" / Applications / Xcode.app / Contents / Developer / Platforms / iPhoneOS.platform / Developer / usr / bin / arm-apple-darv10-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 = cortex-a8 -mfpu = नियॉन "LDFLAGS =" - mfloat-abi = softfp -isysroot /Applications/Xcode.app/Contents/Developer/dlatforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1s.sf -mcpu = cortex-a8 -mtune = cortex-a8 -mfpu = नियॉन "
अपडेट:Zlib लाइब्रेरी को NDK से देशी जोड़ा जा सकता है। ऐसा करने के लिए, Android.mk में आपको उस ब्लॉक को हटाने की जरूरत है जो zlib और रजिस्टर की चिंता करता है:
LOCAL_LDLIBS := -llog -lGLESv1_CM -lz