I´m trying to merge 2 images, one is bitmap from camera, second one is .png file stored in drawables. What I did was that I used both images as bitmaps and I tried to merge them by using canvas, something like this:
Bitmap topImage = BitmapFactory.decodeFile("gui.png");
Bitmap bottomImage = BitmapFactory.decodeByteArray(arg0, 0, arg0.length);
Canvas canvas = new Canvas(bottomImage);
canvas.drawBitmap(topImage, 0, 0, null);
But I keep getting "Bitmap size exceeds VM budget" error all the time. I tried nearly everything, but still, it keeps throwing this error. Is there another way of merging 2 images? What i need to do is simple - I need to take photo and save it merged with that .PNG image stored in drawables. For example this app is very close to what i need - https://play.google.com/store/apps/details?id=com.hl2.hud&feature=search_result#?t=W251bGwsMSwyLDEsImNvbS5obDIuaHVkIl0.
Thanks :)
See the below code for combining two images.
This method returns combined bitmap
public Bitmap combineImages(Bitmap frame, Bitmap image) {
Bitmap cs = null;
Bitmap rs = null;
rs = Bitmap.createScaledBitmap(frame, image.getWidth() + 50,
image.getHeight() + 50, true);
cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
Bitmap.Config.RGB_565);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(image, 25, 25, null);
comboImage.drawBitmap(rs, 0, 0, null);
if (rs != null) {
rs.recycle();
rs = null;
}
Runtime.getRuntime().gc();
return cs;
}
You can change height and width as per your requirements
Hope this will help...
How large are the images? I've only encountered this problem when trying to load large images into memory.
Is the byte array your decoding actually an image?
From a quick look at the android docs you can capture an image using the default camera app which may work in this situation.
http://developer.android.com/training/camera/photobasics.html
Also see this question: Capture Image from Camera and Display in Activity
Edit: You may also need to scale the image from the camera down if it is very large. See the end of the android page I linked to for details on that.
Related
I have a Bitmap and i want to configure it. I also set my bitmap to Mutable one that's not a problem but when i want to configure, it comes with a error that my bitmap is not large enough.
Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.ic_cm);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888,true);
bitmap.setWidth(getWidth() / 2);
I'm using the Android Camera2 API to take still capture images and displaying them on a TextureView (for later image editing).
I have been scouring the web for a faster method to:
Decode Camera Image buffer into bitmap
Scale bitmap to size of screen and rotate it (since it comes in rotated 90 degrees)
Display it on a texture view
Currently I've managed an execution time of around 0.8s for the above, but this is too long for my particular application.
A few solutions I've considered were:
Simply taking a single frame of the preview (timing-wise this was fast, except that I had no control over auto flash)
Trying to get instead a YUV_420_888 formatted image and then somehow turning that into a bitmap (there's a lot of stuff online that might help but my initial attempts bore no fruit as of yet)
Simply sending a reduced quality image from the camera itself, but from what I've read it looks like the JPEG_QUALITY parameter in CaptureRequests does nothing! I've also tried setting BitmapFactory options inSampleSize but without any noticeable improvement in speed.
Finding some way to directly manipulate the jpeg byte array from image buffer to transform it and then converting to bitmap, all in one shot
For your reference, the following code takes the image buffer, decodes and transforms it, and displays it on the textureview:
Canvas canvas = mTextureView.lockCanvas();
// obtain image bytes (jpeg) from image in camera fragment
// mFragment.getImage() returns Image object
ByteBuffer buffer = mFragment.getImage().getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
// decoding process takes several hundred milliseconds
Bitmap src = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mFragment.getImage().close();
// resize horizontally oriented images
if (src.getWidth() > src.getHeight()) {
// transformation matrix that scales and rotates
Matrix matrix = new Matrix();
if (CameraLayout.getFace() == CameraCharacteristics.LENS_FACING_FRONT) {
matrix.setScale(-1, 1);
}
matrix.postRotate(90);
matrix.postScale(((float) canvas.getWidth()) / src.getHeight(),
((float) canvas.getHeight()) / src.getWidth());
// bitmap creation process takes another several hundred millis!
Bitmap resizedBitmap = Bitmap.createBitmap(
src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
canvas.drawBitmap(resizedBitmap, 0, 0, null);
} else {
canvas.drawBitmap(src, 0, 0, null);
}
// post canvas to texture view
mTextureView.unlockCanvasAndPost(canvas);
This is my first question on stack overflow, so I apologize if I haven't quite followed common conventions.
Thanks in advance for any feedback.
If all you're doing with this is to draw it into a View, and won't be saving it, have you tried to simply request JPEGs that are lower resolution than maximum, and match the screen dimensions better?
Alternatively, if you need the full-size image, JPEG images typically contain a thumbnail - extracting that and displaying it is a lot faster than processing the full-resolution image.
In terms of your current code, if possible, you should avoid having to create a second Bitmap with the scaling. Could you instead place an ImageView on top of your TextureView when you want to display the image, and then rely on its built-in scaling?
Or use Canvas.concat(Matrix) instead of creating the intermediate Bitmap?
In Application i need to load a few Bitmaps on create.
To save Memory i'm loading one image, rescale it by creating a scaledBitmap out of it, recycle the unscaled Bitmap on so on:
bmpUnscaled = BitmapFactory.decodeResource(getResources(), R.drawable.cultivation_plant_resized_1);
plant1 = Bitmap.createScaledBitmap(bmpUnscaled,(int) plant[0].getWidth(), (int) plant[0].getHeight(), true);
bmpUnscaled.recycle();
System.gc();
bmpUnscaled = BitmapFactory.decodeResource(getResources(), R.drawable.cultivation_plant_resized_2);
plant2 = Bitmap.createScaledBitmap(bmpUnscaled,(int) plant[0].getWidth(), (int) plant[0].getHeight(), true);
bmpUnscaled.recycle();
System.gc();
and so on...
I am doing this 10 Images, wich are scaled relative to the screen resolution.
The orginal Image is a PNG (570x900 (max. 660KB))
Does anybody have some Ideas to save Memory simply?
I'm desperate right now...
Have you read: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html?
The article contain great information about working with BitMap.
In my app, the bitmap is drawn as if the color is some lower quality type. If i load up the background image using the gallery app, it loads just fine and does not look like it's super low quality. The code i am using to load and draw my images is simple:
//Code for initializing the Bitmap
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.none), (int) (canvas.getWidth() * compression), (int) (canvas.getHeight() * compression), true);
//...
//Code for drawing this Bitmap
canvas.drawBitmap(bitmap, null, new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), null);
If nothing in the code tells you what is wrong, i made an image comparing what the image actually looks like on a computer or other image viewer, and what it looks like in the app.
question is somewhat similar to Bad image quality after resizing/scaling bitmap
try disabling scaling, resize in an offscreen bitmap and make sure that Bitmap is 32 bits (ARGB888):
Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap source = BitmapFactory.decodeResource(a.getResources(), path, options);
another good and complete answer about image scaling/processing can be found at Quality problems when resizing an image at runtime
I like to use the assets folder instead of the drawable folder (if it's not a nine-patch) because I can use multiple folders there. However the method I use to get an drawable required the cpu to do quiet a lot. For example: after adding 10 ImageViews need 10% CPU (I am using Android Assistent and Samsung TouchWiz TaskManager). I haven't notice it while I was writing a game. And now this game needs 40-100% CPU even if it isn't in the foreground.
That's the method I use to create an drawable:
public BitmapDrawable readAsset(path){
try{
inputStream = assetManager.open(path);
//get the Bitmap
desiredImg = BitmapFactory.decodeStream(inputStream, null, opts);
//resize for other screen sizes (scale is calculated beforehand)
scaleX =(int)(desiredImg.getWidth()/scale);
scaleY = (int)(desiredImg.getHeight()/scale);
//Bitmap to get config ARGB_8888 (createScaledBitmap returns RGB_565 => bad quality especially in gradients)
//create empty bitmap with Config.ARGB_8888 with the needed size for drawable
Bitmap temp = Bitmap.createBitmap(scaleX, scaleY, Config.ARGB_8888);
//Canvas to draw desiredImg on temp
Canvas canvas = new Canvas(temp);
canvas.drawBitmap(convert, null, new Rect(0, 0, scaleX, scaleY), paint);
//Convert to BitmapDrawable
BitmapDrawable bitmapDrawable=new BitmapDrawable(temp);
bitmapDrawable.setTargetDensity(metrics);
inputStream.close();
return bitmapDrawable;
}catch (Exception e) {
Log.d(TAG, "InputStream failed: "+e.getMessage());
}
return null;
}
The only thing I do in the app is adding some ImageViews in a RelativeLayout with this method:
private void addImageToContainer(int paddingLeft, int paddingTop) {
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(assetReader.readAsset("test.jpg"));
imageView.setPadding(paddingLeft, paddingTop, 0, 0);
container.addView(imageView);
}
Probably the best thing for you to do would be to profile the execution with traceview, as this will give you a full understanding of where your app is spending most of its execution time. Then you can focus on optimizing that specific piece of code.
Just an educated guess, but I have a feeling that the majority of the wasted execution is not because you are pulling the images out of assets/ instead of resources, but all the scaling work being done afterwards (and from the looks of it, this is all being done on the main thread, so there's no concurrency to speak of).
I might recommend trying to leverage some of the BitmapFactory.Options (Docs link) available to you when you decode the asset. In particular, you should be able to do all the scaling you need with a combination of the inScaled, inDensity, and inTargetDensity options. If you pass these to your decodeStream() method, you could likely remove all the subsequent code used to resize the image before returning.