Android OutOfMemoryError when trying to rotate an image - java

I want to display an image on screen (I have an activity that displays an image):
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
ExifInterface exif = new ExifInterface(imagePath);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
Matrix matrix = new Matrix();
matrix.preRotate(rotationInDegrees);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
The last line throws java.lang.OutOfMemoryError
I don't understand how to do this... I have to create the bitmap at first (BitmapFactory.decodeFile) but when I want to rotate it I have to provide the source bitmap already - how can I avoid it?
Thanks

You can try downsizing the image first before decoding it by adding inSampleSize in the bitmap options. as stated at the document: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
Hope that helps.

If you aren't doing any crazy things elsewhere then your image is probably just too big.
You just need to increase your heap. Add this to your manifest file:
android:largeHeap="true"

You cannot rotate the bitmap in place, because the dimensions can be different. I don't know, why it's impossible to load already rotated bitmap.
You can rotate the bitmap in the place of use. When drawing the bitmap, use the rotation matrix to have it drawn with rotation.
Other thing is that you probably should review your app and try to minimize the memory usage. Maybe the bitmaps you use are too big and you should use Options with inSampleSize set to 2 or more.

Related

Is there a way to not stretch the Bitmap when using Matrix.polyToPoly() on a bitmap?

I'm trying to do perspective transformation on my bitmap with a given quadrilateral. However, the Matrix.polyToPoly function stretches not only the part of the image I want but also the pixels outside the given area, so that a huge image is formed in some edge cases which crashes my app because of OOM.
Is there any way to sort of drop the pixels outside of the said area to not be stretched?
Or are there any other possibilities to do a perspective transform which is more memory friendly?
I`m currenty doing it like this:
// Perspective Transformation
float[] destination = {0, 0,
width, 0,
width, height,
0, height};
Matrix post = new Matrix();
post.setPolyToPoly(boundingBox.toArray(), 0, destination, 0, 4);
Bitmap transformed = Bitmap.createBitmap(temp, 0, 0, cropWidth, cropHeight, post, true);
where cropWidth and cropHeight are the size of the bitmap (I cropped it to the edges of the quadrilateral to save memory) and temp is said cropped bitmap.
Thanks to pskink I got it working, here is a post with the code in it:
Distorting an image to a quadrangle fails in some cases on Android

How to center and scale an overlayed drawable icon on a bitmap

I have a bitmap thumbnail for a map and I want to add the a map marker in the center but am struggling to do so. I was able to overlay the two bitmaps but the the one in front is significantly smaller and not centered. Is there a way to center the bitmap and scale it up? This is what it looks like:
I looked at this Android: How to overlay-a-bitmap/draw-over a bitmap? and it helped but the map marker is very small and off centered. Thanks
Update:
I ended up solving it this way. I'll leave my solution for anyone who needs it in the future. Here it goes:
public static Bitmap overlay(Bitmap bmp1, Bitmap bmp2) {
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bmp2, 500, 500, false);
Bitmap bitmapWithOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas = new Canvas(bitmapWithOverlay);
canvas.drawBitmap(bmp1, new Matrix(), null);
canvas.drawBitmap(resizedBitmap, ((bmp1.getWidth()/2)-250), ((bmp1.getHeight()/2)-450), null);
return bitmapWithOverlay;
}
and here is the process of getting the bitmap from a drawable
Bitmap icon = BitmapFactory.decodeResource(getActivity().getBaseContext().getResources(),
R.drawable.your_icon);
You can put both in the same FrameLayout. FrameLayout is build to only have one child, if you put more childs into it they will overlap. Ty this.
And also putting more childs into FrameLayout isn't bad practice.

Android add a watermark logo to very large jpg file (say 10000 x 150000) [duplicate]

This question already has an answer here:
Load large picture from file and add watermark
(1 answer)
Closed 8 years ago.
I have a large jpeg file say 10000 x 150000 px. I want to add a small logo to the bottom of the image without re sizing.
I am able to do this If i down sample the original image and draw the logo using canvas.But when i finally save it to file, the image original size will be reduced as I am sampling it.
If i load the original image into bitmap without down sampling, it exceeds the VM.
Below code work for me :-
public static Bitmap mark(Bitmap src, String watermark, Point location, Color color, int alpha, int size, boolean underline) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(color);
paint.setAlpha(alpha);
paint.setTextSize(size);
paint.setAntiAlias(true);
paint.setUnderlineText(underline);
canvas.drawText(watermark, location.x, location.y, paint);
return result;
}
For large image editing you'll need to use native tools like imagemagick. Because there seem to be a lack of advanced image processing libraries in android supported Java.
If you can compile Composite tool's binaries for android. Then you can use them with --limit option to work with limited memory.
Also, you can try OpenCV as an alternative.
You can use BitmapRegionDecoder when deal with large image file. From the official document.
BitmapRegionDecoder can be used to decode a rectangle region from an image. BitmapRegionDecoder is particularly useful when an original image is large and you only need parts of the image.
To create a BitmapRegionDecoder, call newInstance(...). Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly to get a decoded Bitmap of the specified region.
Just decode the part of your image that you need to add watermark, then use Canva to draw text on it.
try {
BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance("/sdcard/test.png", true);
Bitmap bitmap = regionDecoder.decodeRegion(rect, options);
} catch (IOException e) {
e.printStackTrace();
}

Android Java create bitmap from hex value

Can anyone suggest a way to create a small solid colored bitmap image from a hex value?
Alternatively, you can use Bitmap.eraseColor() to set a solid color for your bitmap.
Example:
import android.graphics.Bitmap;
...
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
image.eraseColor(android.graphics.Color.GREEN);
I think I may have the answer. Technically I believe it is much easier on Android than on a "pc". The last time I searched to create a bitmap (.bmp), I only found some Android functions and the BitmapFactory for non-android, which didn't work for me.
Please look at this site: http://developer.android.com/reference/android/graphics/Bitmap.html
This point could fit for you:
static Bitmap createBitmap(int[] colors, int offset, int stride, int width, int height, Bitmap.Config config)
Returns a immutable bitmap
with the specified width and height, with each pixel value set to the
corresponding value in the colors array.
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas (image);
int HEX=0xFF888888;
canvas.drawColor (HEX);
Use the createBitmap().
Here is a link that will show you how: http://developer.android.com/reference/android/graphics/Bitmap.html

Rotated image in ImageView

I want to show an arrow that indicates the direction towards a goal, using the orientation sensor and current GPS position. Everything works well, except that I want to rotate the arrow image in my ImageView.
The current code, which shows the arrow pointing upwards, is this:
ImageViewArrow.setImageResource(R.drawable.arrow);
What is the best solution for showing the arrow, rotated by N degrees?
I tried this, but it gave messed up graphics:
Matrix matrix = new Matrix();
matrix.postRotate(Rotation);
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.arrow);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
bitmapOrg.getWidth(),bitmapOrg.getHeight(), matrix, true);
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
InfoArrow.setScaleType(ScaleType.CENTER);
InfoArrow.setImageDrawable(bmd);
here you can find a tutorial
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html
There is a matrix parameter in the createBitmap method that can be used for resizing and rotating the image. You could try something like the following:
Matrix matrix = new Matrix();
// to rotate the image bitmap use post Rotate
matrix.postRotate(45);
Bitmap rotatedImage = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true); `

Categories

Resources