I tried to post an image on Facebook wall from my android application.For this I created a bitmap from layout.Here is my code
System.gc();
Bitmap bitmap = Bitmap.createBitmap(
view.getMeasuredWidth(),
view.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Drawable bgDrawable = newLinearLayout.getBackground();
if (bgDrawable != null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(1.0f, 1.0f);
// recreate the new Bitmap
Bitmap resizedBitmap = null;
resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//Canvas resizedCanvas = new Canvas(resizedBitmap);
if (bitmap != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
Bundle parameters = new Bundle();
byte[] data = baos.toByteArray();
parameters.putByteArray("picture", data);
DataKeeper.getInstance().setBundleToPost(parameters);
}
bitmap.recycle();
It shows OutOfMemory exception.I know that this is due to imagesize exceeds its available size.How can i resize image without lossing its quality? I tried to correct this using BitmapFactory.Options. But does not work.How can solve this exception?
Regards
Asha
use this :
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);
for more detail see this link
link
The idea of #Zaz Gmy is correct,
however I don't think the value of inSampleSize should be constant (8) for every image.
This of course will work, but scaling different images with different resolutions on the same scale factor = 8, will cause some of images to have a visible loss of quality.
Instead, the inSimpleSize should be generated based on the target width and height of image.
Android documentation provides a good article on how to deal with this issue.
Please check this tutorial and download the sample project.This will solve your problem
http://developer.sonymobile.com/wp/2011/06/27/how-to-scale-images-for-your-android%E2%84%A2-application/
Related
I am developing an Android application for image processing. In that, I first need to generate an ortho image by stitching 100+ images together. I have tried it in Android using Bitmap and Canvas. I first did it for 3 images. Is it the right way to generate an ortho or is there any better solution for this? Here is the code that I have used for stitching 3 images:
private void joinImages(File first, File second , File third) throws IOException
{
Bitmap bmp1, bmp2, bmp3;
bmp1 = BitmapFactory.decodeFile(first.getPath());
bmp2 = BitmapFactory.decodeFile(second.getPath());
bmp3 = BitmapFactory.decodeFile(third.getPath());
int height = bmp1.getHeight()+bmp2.getHeight()+bmp3.getHeight();
String height1 = height+"";
Log.d(height1,"heght");
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, 0, 0, null);
canvas.drawBitmap(bmp2, bmp1.getHeight(), 0, null);
canvas.drawBitmap(bmp3,bmp1.getHeight()+bmp2.getHeight() , 0, null);
FileOutputStream out = new FileOutputStream("/storage/emulated/0/DCIM/final.jpg");
bmOverlay.compress(Bitmap.CompressFormat.JPEG, 80, out);
out.close();
}
As I am new to Android as well as image processing, I also want to know the difference between image stitching and 2D-orthomosaic generation. Kindly help me with this issue.
I'm writing a custom printing app in Android and I'm looking for ways to save on memory. I have three basic rectangles I need to print on a full page. Currently I'm creating a base Bitmap the size of the page:
_baseBitmap = Bitmap.createBitmap(width/_scale, height/_scale, Bitmap.Config.ARGB_8888);
The print process requests a Rect portion of that page. I cannot predetermine the dimensions of this Rect.
newBitmap = Bitmap.createBitmap(fullPageBitmap, rect.left/_scale, rect.top/_scale, rect.width()/_scale, rect.height()/_scale);
return Bitmap.createScaledBitmap(newBitmap, rect.width(), rect.height(), true);
Using bitmap config ARGB_8888 _baseBitmap is about 28MB (8.5"x11" # 300dpi = 2250*3300*4bytes). Even at 50% scaling (used above), my image is over 7MB. Scaling any smaller than this and image quality is too poor.
I've attempted to create _baseBitmap using Bitmap.Config.RGB_565, which does greatly reduce the full image size, but then when I overlay an image (jpegs) I get funny results. The image is compressed in width, duplicated next to itself, and all the color is green.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap myBitmap = BitmapFactory.decodeStream(input, null, options);
input.close();
return myBitmap;
....
private static Bitmap overlay(Bitmap bmp1, Bitmap bmp2, float left, float top) {
Canvas canvas = new Canvas(bmp1);
canvas.drawBitmap(bmp2, left, top, null);
return bmp1;
}
I know I can compress an image of these dimensions down to a reasonable size. I've looked into Bitmap.compress, but for some reason beyond my understanding I'm getting the same size image back:
ByteArrayOutputStream os = new ByteArrayOutputStream();
_baseBitmap.compress(Bitmap.CompressFormat.JPEG, 3, os);
byte[] array = os.toByteArray();
Bitmap newBitmap = BitmapFactory.decodeByteArray(array, 0, array.length);
_baseBitmap.getAllocationByteCount() == newBitmap.getAllocationByteCount()
It would be better to create it compressed than to create a large one and then compress it. Is there any way to create a compressed Bitmap? Any advice is greatly appreciated.
note: Not an Android expert. I'm not necessarily familiar with the platform specific terms you may use to respond. Please be gentle.
Try something like this, if you have a target size in mind.
private static final int MAX_BYTES_IMAGE = 4194304; // 4MB
//...
ByteArrayOutputStream out;
int quality = 90;
do
{
out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out);
quality -= 10;
} while (out.size() > MAX_BYTES_IMAGE_FILESIZE);
out.close();
In onPictureTaken, I want to do the following:
Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length);
Matrix matrix = new Matrix();
matrix.preScale(-1.0f, 1.0f);
Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false);
View v1 = mainLayout.getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true);
Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(compos);
canvas.drawBitmap(scaledPicture, new Matrix(), null);
canvas.drawBitmap(screenshot, new Matrix(), null);
MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description");
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
My only requirement is that I'd like to save a high-quality photo... Seems I might have to sacrifice that.
On my Nexus 4 and newer devices, this code runs fine and as expected. But on older devices that have less memory, I'm running out of RAM! :(
How do I do the same image manipulation without running up against the memory limit?? I'm not trying to display these images on screen, so the solutions that have to do with a scaled down image don't really apply here...
you need to read the bitmap in with an increased sample size. the trick is finding the correct sample size that won't result in reduced resolution when you ultimately scale the image. i wrote a blog entry about it here that includes a nice utility class for scaling,
http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/
you could probably simplify that class quite a bit depending on your specific needs.
the jist is to read just the size of the bitmap. calculate the optimal sample size based on your desired scaled size, read the bitmap in using that sample size, then fine-scale it to exactly the size you want.
You have so many Bitmap object lying around. try recycling/reusing some of this.
Not exactly sure what is your requirement is but i can see you can save some memory by simply doing this.
Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length);
Matrix matrix = new Matrix();
matrix.preScale(-1.0f, 1.0f);
Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false);
decodedPicture.recycle();
decodedPicture=null;
View v1 = mainLayout.getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true);
picture.recycle();
picture=null;
Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(compos);
canvas.drawBitmap(scaledPicture, new Matrix(), null);
canvas.drawBitmap(screenshot, new Matrix(), null);
MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description");
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
Also look into your memory footprint, make sure device wise memory you are using are is not too big.
FYI, on post honycomb devices bitmap pixel image allocated on native layer. You need recycle() or finalizer() to restore memory
Considering you don't want to resize your bitmap and don't want to display it, I'd do something like this:
Load the Bitmap with inJustDecodeBounds to see its original height and width (code from here)
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
Depending on the size and memory you have, you can directly process it from there (i.e. load the Bitmap) or proceed to load a number of chunks of said Bitmap with the Bitmap.createBitmap method that allows you to only load a chunk of data. Optionally: consider converting it into a byte array (see code below) and null+ recycle() before you process the chunk.
code
ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream();
bitmapPicture.compress(Bitmap.CompressFormat.PNG, COMPRESSION_QUALITY, byteArrayBitmapStream);
byte[] b = byteArrayBitmapStream.toByteArray();
I use for work with Bitmap class WeakReference and after I always call recycle on the instance object WeakReference, the snippet code for rotate image:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
WeakReference<Bitmap> imageBitmapReference = new WeakReference<Bitmap>(BitmapFactory.decodeByteArray(params[0], 0, params[0].length, options));
Matrix mat = new Matrix();
mat.postRotate(90.0f);
imageBitmapReference = new WeakReference<Bitmap (Bitmap.createBitmap(imageBitmapReference.get(), 0, 0, resolution[0], resolution[1], mat, true));
FileOutputStream fos = new FileOutputStream(filename);
imageBitmapReference.get().compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
imageBitmapReference.get().recycle();
And second solution how work with Bitmap and don't get OutOfMemory Exception is use library Universal Image Loader
(Of course is so the third solution set in your AndroidManifest property android:largeHeap="true" and really DON'T USE THIS property).
The perfect material is on the http://developer.android.com/training/displaying-bitmaps/index.html and video https://www.youtube.com/watch?v=_CruQY55HOk
i am trying to edit images. but i am getting errors with setPixels.
picw = pic.getWidth();
pich = pic.getHeight();
picsize = picw*pich;
int[] pix = new int [picsize];
pic.getPixels(pix, 0, picw, 0, 0, picw, pich);
pic.setPixels(pix,0,pic.getWidth(),0,0,pic.getWidth(),pic.getHeight());
but i am getting illegal state exception with setPixels
Caused by: java.lang.IllegalStateException
at android.graphics.Bitmap.setPixels(Bitmap.java:878)
at com.sandyapps.testapp.testapp.onCreate(testapp.java:66)
I think your Bitmap is not mutable (see setPixel()'s documentation).
If so, create a mutable copy of this Bitmap (using Bitmap.copy(Bitmap.Config config, boolean isMutable) as an example) and work on this one.
It's simple, just use the following command to change it to a mutable Bitmap:
myBitmap = myBitmap.copy( Bitmap.Config.ARGB_8888 , true);
Now the Bitmap myBitmap is replaced by the same Bitmap but this time is mutable
You can also choose another way of storing Pixels (ARGB_8888 etc..):
https://developer.android.com/reference/android/graphics/Bitmap.Config.html
Most probably your pic is immutable. By default, any bitmap created from drawable would be immutable.
If you need to modify an existing bitmap, you should do following:
// Create a bitmap of the same size
Bitmap newBmp = Bitmap.createBitmap(pic.getWidth(), pic.getHeight(), Config.ARGB);
// Create a canvas for new bitmap
Canvas c = new Canvas(newBmp);
// Draw your old bitmap on it.
c.drawBitmap(pic, 0, 0, new Paint());
I had the same problem. Use to fix it:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource( getResources(), R.drawable.my_bitmap, opt );
I was facing this problem and finally fixed after long time.
public static void filterApply(Filter filter){
Bitmap bitmcopy = PhotoModel.getInstance().getPhotoCopyBitmap();
//custom scalling is important to apply filter otherwise it will not apply on image
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmcopy, bitmcopy.getWidth()-1, bitmcopy.getHeight()-1, false);
filter.processFilter(scaledBitmap);
filterImage.setImageBitmap(scaledBitmap);
}
I have some code where the user draws something on the screen and I want to store it as a PNG in a byte[]. However, the compress() method returns false. Any idea why that is? Is there a better way to get the byte[]?
Bitmap bm = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(bm);
c.drawPath(mSignaturePath, mSignaturePaint);
ByteArrayOutputStream out = new ByteArrayOutputStream();
if (bm.compress(Bitmap.CompressFormat.PNG, 100, out)) {
byte[] result = out.toByteArray(); // Never gets called
}
Thanks in advance.
The problem was in how I was creating the image:
Bitmap bm = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ALPHA_8);
When I changed that to Bitmap.Config.RGB_565 it worked fine.
Thanks to Mark Murphy (#commonsware) for the advice during his office hours!