Handling Large Bitmaps

Handling large Bitmaps

There is an option in BitmapFactory.Options class (one I overlooked) named inJustDecodeBounds, javadoc of which reads:

If set to true, the decoder will
return null (no bitmap), but the
out... fields will still be set,
allowing the caller to query the
bitmap without having to allocate the
memory for its pixels.

I used it to find out the actual size of the Bitmap and then chose to down sample it using inSampleSize option. This at least avoids any OOM errors while decoding the file.

Reference:

1. Handling larger Bitmaps

2. How do I get Bitmap info before I decode

Handling Large Bitmaps in Image Editor

Have a look at this video from Google I/O where they develop an Advanced gallery app with image editing.

You can download source code for the application here. This is how it opens the activity for image editing:

private OnItemClickListener mPhotoClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// User clicked on photo, open our viewer
final Intent intent = new Intent(AlbumActivity.this, PhotoActivity.class);
final Uri data = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
intent.setData(data);
startActivity(intent);
}
};

The gallery also implements image editing functionality. The code might be helpful.

Handling large images

As you say:

I can't go for bitmap sampling as I can't change the size of images.

so, reduce image size or sample it before show, is not ok. I think below my be a solution.

Because Android's dalvik limit, there is a max heap size you can use. When exceed it, crash happen.

In order to bypass dalvik limit, you can use jni to apply for memory from native heap. You must use libjpeg in jni. You can choose show image on SurfaceView, then by holder.getSurface() to get a Surface Object, pass it to jni, then use libjpeg lib to decode image and show it. Next is some example code, call showJPG() function to display large image.

JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_SurfaceProcessingActivity_showJPG(
JNIEnv * env, jobject activity, jobject surface, jstring img) {
const char * imgChar;
jboolean * isCopy;
imgChar = env->GetStringUTFChars(img, 0);
ANativeWindow_Buffer nwBuffer;

LOGI("img path : %s ",imgChar);

LOGI("ANativeWindow_fromSurface ");
ANativeWindow * mANativeWindow = ANativeWindow_fromSurface(env, surface);

if (mANativeWindow == NULL) {
LOGE("ANativeWindow_fromSurface error");
return;
}

LOGI("ANativeWindow_lock ");
if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, 0)) {
LOGE("ANativeWindow_lock error");
return;
}

read_jpeg_file_show(imgChar, nwBuffer);

if (nwBuffer.format == WINDOW_FORMAT_RGBA_8888) {
LOGI("nwBuffer->format == WINDOW_FORMAT_RGBA_8888 ");
}

LOGI("ANativeWindow_unlockAndPost ");
if (0 != ANativeWindow_unlockAndPost(mANativeWindow)) {
LOGE("ANativeWindow_unlockAndPost error");
return;
}

env->ReleaseStringUTFChars(img,imgChar);
ANativeWindow_release(mANativeWindow);
LOGI("ANativeWindow_release ");
return;
}

int read_jpeg_file_show(const char *input_filename,
ANativeWindow_Buffer& nwBuffer) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *input_file;
JSAMPARRAY buffer;
int row_width;

unsigned char *buffertmp;

cinfo.err = jpeg_std_error(&jerr);

if ((input_file = fopen(input_filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", input_filename);
LOGI("can't open jpg1");
return -1;
}
jpeg_create_decompress(&cinfo);

/* Specify data source for decompression */
jpeg_stdio_src(&cinfo, input_file);

/* Read file header, set default decompression parameters */
(void) jpeg_read_header(&cinfo, TRUE);

/* Start decompressor */
(void) jpeg_start_decompress(&cinfo);

row_width = cinfo.output_width * cinfo.output_components;

buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE,
row_width, 1);

buffertmp = (unsigned char *) malloc(row_width);
memset(buffertmp, 0, row_width);
LOGI("malloc and memset");

/* Process data */
int get8h5 = 248, get8h6 = 252;
__uint16_t * line = (__uint16_t *) nwBuffer.bits;
int wheight = 0;

int scalew = 1, scaleh = 1;

if (cinfo.output_width > nwBuffer.width) {
scalew = cinfo.output_width / nwBuffer.width;
}

LOGI(" scale of img = %d", scalew);

for (int i = 0, choosehNum = 0; i < cinfo.output_height; i++) {

jpeg_read_scanlines(&cinfo, buffer, 1);
buffertmp = *buffer;

if (i % scalew == 0 && choosehNum++ < nwBuffer.height) {

//LOGI("nwBuffer->format == WINDOW_FORMAT_RGB_565");
for (int j = 0, choosewNum = 0; j < cinfo.output_width; j++) {
if (j % scalew == 0) {
if (nwBuffer.format == WINDOW_FORMAT_RGB_565) {
line[choosewNum] = ((__uint16_t ) buffertmp[3 * j + 0]
& get8h5) << 8
| ((__uint16_t ) (buffertmp[3 * j + 1] & get8h6)
<< 3)
| ((__uint16_t ) (buffertmp[3 * j + 2] & get8h6)
>> 3);
choosewNum++;
}
}

}
line = line + nwBuffer.stride;
}
}

(void) jpeg_finish_decompress(&cinfo);
LOGI("jpeg_finish_decompress !!");

jpeg_destroy_decompress(&cinfo);
LOGI("jpeg_destroy_decompress !!");

/* Close files, if we opened them */
fclose(input_file);

return 0;
}

Hope to help you!



Related Topics



Leave a reply



Submit