2

I am well aware of the OutOfMemoryError hell that working with bitmaps can land image-heavy apps in. Normally, I always work around this by adaptively scaling the images, using caching, etc.

However, currently I work on an app where one use case is the ability to take an image and have it automatically watermarked by (i.e. merged with) another, smaller image. The specification unambiguously states that the branded image must be of the same size and quality as the original one, so I am not able to scale.

I have already found this impossible to implement: attempting to create a bitmap with the same dimensions as the original image always throws OOME on the Galaxy S3 I use for testing, even if android:largeHeap="true" is set.

Is there any possibility at all to get around this?

The relevant code is:

private Bitmap mergeImages(Bitmap firstImage, Bitmap secondImage) {

    Bitmap.Config config = (firstImage.getConfig() != null) ? firstImage.getConfig() : Bitmap.Config.ARGB_8888;
    Bitmap resultImage = Bitmap.createBitmap(
            Math.max(firstImage.getWidth(), secondImage.getWidth()),
            Math.max(firstImage.getHeight(), secondImage.getHeight()),
            config);

    Canvas mergeCanvas = new Canvas(resultImage);
    Paint paint = new Paint();
    mergeCanvas.drawBitmap(firstImage, 0, 0, paint);
    mergeCanvas.drawBitmap(secondImage, 0, 0, paint);

    return resultImage;
}
csvan
  • 8,782
  • 12
  • 48
  • 91

1 Answers1

1

We do a similar merge-effect in my app with two bitmaps, and the way that we've done it is to use a RelativeLayout container for both of them so that they appear in the same place, one overlayed onto the other:

<RelativeLayout 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp"
     >

<ImageView
    android:id="@+id/discovery_row_photo"
    android:layout_width="130dp"
    android:layout_height="130dp" />

<ImageView
    android:id="@+id/discovery_row_photo_corner"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@id/discovery_row_photo"
    android:layout_alignTop="@id/discovery_row_photo"
    android:contentDescription="@null"
    android:src="@drawable/discovery_corner_badge" />
</RelativeLayout>

The second ImageView is the "watermark" that I think you're going for. This way we scale the original image, discovery_row_photo, and the discovery_row_photo_corner gets placed on top of it. Since the second one is mostly transparent it works well. Not sure if that can apply to your use case or not, but it's a useful trick.

Carl Anderson
  • 3,446
  • 1
  • 25
  • 45
  • Thanks, I am actually doing something very similar in the layout of the fragment in question, in order to show the user the final output. It works fine - the problem is actually merging the two images in order to save the final image to memory. To do this, as far as I know, I have no option but to merge them on a canvas to create a final bitmap. It is the latter I would like to avoid if possible, if it will solve the memory issue. – csvan Apr 28 '14 at 21:13
  • Looks like you're doing it the recommended way then: http://stackoverflow.com/a/10616868/2171147 They must be extremely large images to be overflowing the memory and causing exceptions. The only other idea I have at that point is to try to clear any of the app's memory you can. Maybe launch the tool in a cleared-stack activity or something, so nothing else is in memory other than the current Activity and the Bitmaps you're modifying. – Carl Anderson Apr 28 '14 at 21:17
  • They are rather large, I ran some basics maths on it, and a max-res S3 image (3264x2448) should take approximately 16-18MB on the heap. I cannot for the life of me understand how having only two of them (the original and the copy) in memory manages to bring the entire app down. – csvan Apr 28 '14 at 21:31
  • 1
    I suspect it might not be able to allocate a contiguous block that large. You can see a similar issue here: http://stackoverflow.com/questions/20472094/outofmemoryerror-although-vm-has-enough-free-memory – Carl Anderson Apr 29 '14 at 15:53