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
Android Emulator: How to Monitor Network Traffic
Android, Make an Image at a Url Equal to Imageview's Image
Edittext Maxlines Not Working - User Can Still Input More Lines Than Set
How to Resolve "Waiting for Debugger" Message
Gradle Failed to Resolve Library in Android Studio
Can't Get Values Out of Ondatachange Method
Android: When Should I Use a Handler() and When Should I Use a Thread
How to View the Shared Preferences File Using Android Studio
Wrap_Content View Inside a Constraintlayout Stretches Outside the Screen
How to Get Hosting Activity from a View
Eclipse/Android:"Errors Running Builder 'Android Pre Compiler' on Project..."
Android - R Cannot Be Resolved to a Variable
Error Message:This Android Sdk Requires Android Developer Toolkit Version 22.6.1 or Above
Volley JSONobjectrequest Post Parameters No Longer Work
Clicking Hamburger Icon on Toolbar Does Not Open Navigation Drawer