Android NDK: read JPG from assets and sdcard
Some parts of the code are borrowed from Independent JPEG Group and
Android NDKでlibjpegをビルドして利用する(UsefullCode.net)
Resulted texture will have dummy alpha components (0xff) for compatibility with PNG.
static uint32_t make8888(int red, int green, int blue, int alpha){ return (uint32_t)( ((alpha << 24) & 0xff000000) | ((blue << 16) & 0x00ff0000) | ((green << 8) & 0x0000ff00) | ( red & 0x000000ff) ); } static void _JpegError(j_common_ptr cInfo){ char pszMessage[JMSG_LENGTH_MAX]; (*cInfo->err->format_message)(cInfo, pszMessage); LOGE("Jpeg Lib","error! %s", pszMessage); } // media: 0=asset, 1=sdcard unsigned char* loadJPG(int medium, AAssetManager* mgr, const char* pImgFileName){ AAsset* pAsset = NULL; FILE* fp = NULL; if (isJpgRead) return NULL; // already read. struct jpeg_decompress_struct cInfo; struct jpeg_error_mgr jError; cInfo.err = jpeg_std_error(&jError); // register error handler 1 jError.error_exit = _JpegError; // register error handler 2 jpeg_create_decompress(&cInfo); // create a decompresser // init the ptr to the source medium ////////////////////////// if (medium == 0){ /// load from asset //////////////////////////////////////// pAsset = AAssetManager_open(mgr, pImgFileName, AASSET_MODE_UNKNOWN); if (!pAsset) return NULL; unsigned char* ucharRawData = (unsigned char*)AAsset_getBuffer(pAsset); long myAssetLength = (long)AAsset_getLength(pAsset); // the jpeg_stdio_src alternative func, which is also included in IJG's lib. jpeg_mem_src(&cInfo, ucharRawData, myAssetLength); }else if(medium == 1){ /// load from FILE ///////////////////////////////////////// fp = fopen(pImgFileName,"r+"); if(fp == NULL) return NULL; jpeg_stdio_src(&cInfo, fp); // notify the decomp the ptr to src }else { LOGE("The medium is not supported."); return NULL; } /////////////////////////////////////////////// uint32_t* pTexUint; int yy; int width, height, pixelSize, lineSize; char* lpbtBits; JSAMPLE tmp; int rectHeight, rectWidth; /////////////////////////////////////////////// jpeg_read_header(&cInfo, TRUE); // read header jpeg_start_decompress(&cInfo); // start decompression width = cInfo.output_width; height = height = cInfo.output_height; pixelSize = cInfo.output_components; lineSize = width * pixelSize; pTexUint = (uint32_t*)calloc(sizeof(uint32_t), width * height); if (pTexUint == NULL){ switch (medium){ case 0: AAsset_close(pAsset); break; case 1: fclose(fp); break; } return NULL; } JSAMPLE* pSample = (JSAMPLE*)calloc(sizeof(JSAMPLE), lineSize + 10); if (!pSample){ __android_log_print(ANDROID_LOG_ERROR,"Jpeg Lib","cannot alloc pSample"); if (pTexUint) free(pTexUint); switch (medium){ case 0: AAsset_close(pAsset); break; case 1: fclose(fp); break; } return NULL; //error } JSAMPROW buffer[1]; buffer[0] = pSample; uint32_t* pPixelsUint = pTexUint; yy = 0; while(cInfo.output_scanline < cInfo.output_height){ if(yy >= cInfo.output_height) break; jpeg_read_scanlines(&cInfo, buffer, 1); int xx; int x3; for(xx = 0, x3 = 0; xx < width; xx++, x3 += 3) pPixelsUint[xx] = make8888(buffer[0][x3], buffer[0][x3 + 1], buffer[0][x3 + 2], 0xff); pPixelsUint = (uint32_t*)pPixelsUint + width; yy++; } jpeg_finish_decompress(&cInfo); jpeg_destroy_decompress(&cInfo); if (pSample) free(pSample); switch (medium){ case 0: AAsset_close(pAsset); break; case 1: fclose(fp); break; } return (unsigned char*)pTexUint; }