I am getting memory error in my android game and i think its caused by my image loading function. everything is working fine on my mobile but on tablet i get memory exceed error.
I am using a matrix because i need to resize the image to a float value. But in this case i have to load the image in full size first and then resize it with the matrix and i think this causes the memory error.
is this the correct way to handle image resize?
public class Sprite {
private Bitmap bitmap = null;
private float scaleX, scaleY;
public Sprite(String path, float targetWidth, float targetHeight, Context context) {
InputStream istr;
AssetManager assetManager = context.getAssets();
Matrix scalematrix = new Matrix();
try {
istr = assetManager.open(path);
bitmap = BitmapFactory.decodeStream(istr);
scaleX = targetWidth / bitmap.getWidth();
scaleY = targetHeight / bitmap.getHeight();
scalematrix.postScale(scaleX, scaleY);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), scalematrix, true);
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
BitmapFactory.Options has public int inSampleSize -- If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
You may try to use BitmapFactory.decodeXXX(..., BitmapFactory.Options opts) (decodeFile() etc.)
Related
I'm currently in the process of porting an existing iOS app over to Android and have run into a snag where I need to crop the contents of a view in my layout.
In iOS I was simply accessing the layer of the view and then setting layer.contentsRect accordingly.
In Android, I thought I had found an equivalent function of the GLSurfaceView class - setClipBounds, but this only works on devices with support for API level 18 and throws a NoSuchMethodError exception on my Galaxy S 3.
Does anyone have an alternative solution (or support library) for clipping or cropping the view contents for API level 9 (2.3)? Thanks.
here's some cropping code i wrote in xamarin (c#) it was ported from Java, you'll need to do the conversion on your own, the class names are roughly the same and the methods and properties are exposed as get/set in Java.
the code crops a bitmap to a circle, similar to facebook floating faces :)
public static class BitmapHelpers
{
public static Bitmap LoadAndResizeBitmap (this string fileName, int width, int height)
{
// First we get the the dimensions of the file on disk
BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
BitmapFactory.DecodeFile (fileName, options);
// Next we calculate the ratio that we need to resize the image by
// in order to fit the requested dimensions.
int outHeight = options.OutHeight;
int outWidth = options.OutWidth;
int inSampleSize = 1;
if (outHeight > height || outWidth > width) {
inSampleSize = outWidth > outHeight
? outHeight / height
: outWidth / width;
}
// Now we will load the image and have BitmapFactory resize it for us.
options.InSampleSize = inSampleSize;
options.InJustDecodeBounds = false;
Bitmap resizedBitmap = BitmapFactory.DecodeFile (fileName, options);
return resizedBitmap;
}
public static Bitmap GetCroppedBitmap (Bitmap bitmap)
{
Bitmap output = Bitmap.CreateBitmap (bitmap.Width,
bitmap.Height, global::Android.Graphics.Bitmap.Config.Argb8888);
Canvas canvas = new Canvas (output);
int color = -1;
Paint paint = new Paint ();
Rect rect = new Rect (0, 0, bitmap.Width, bitmap.Height);
paint.AntiAlias = true;
canvas.DrawARGB (0, 0, 0, 0);
paint.Color = Color.White;
canvas.DrawCircle (bitmap.Width / 2, bitmap.Height / 2,
bitmap.Width / 2, paint);
paint.SetXfermode (new PorterDuffXfermode (global::Android.Graphics.PorterDuff.Mode.SrcIn));
canvas.DrawBitmap (bitmap, rect, rect, paint);
return output;
}
}
I am creating an application and want to setup Image . I do not want the images in same size, but same image quality. how to resize that image but same image quality in android ?
i'm using this method to resize the image
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile
.getAbsolutePath());
int h = myBitmap.getHeight() / 20;
int w = myBitmap.getWidth() / 20;
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, w, h,
true);
imageTab.setImageBitmap(scaled);
Pass btimap you want to resize and size in which you want it to resize in following method
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
{
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
Your requirement makes no sense. Whenever you resize it the quality will be changed. Downscaling will make your image lose image data like thin lines etc, and upscaling will make your image blurred and lose clarity.
This is because you only have so much image data with you, and you cannot arbitrarily change the amount of data you have to produce good quality images.
That said, using a format like PNG over JPG can help you save some of the quality at least, as JPG compresses the data even more.
Here is code snippet ..
private static BufferedImage resizeImage(BufferedImage originalImage, int type){
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
return resizedImage;
}
BufferedImage resizeImagePng = resizeImage(originalImage, type);
ImageIO.write(resizeImagePng, "png", new File("Image PAth"));
I have a bitmap downloaded from internet and now i want to decrease the height and width of bitmap without losing the quality of bitmap. How to achieve this.
This is way for downloading bitmap from internet.
URL url_1 = null;
try {
url_1 = new URL(vmImageUrl);
bmp = BitmapFactory.decodeStream(url_1.openConnection().getInputStream());
} catch (Exception e) {
Log.v("Error while downloading bitmap from url", e.getMessage());
I have scaled like this.
Bitmap.createScaledBitmap(bmp, convertDpToPixel(140, context), convertDpToPixel(35, context), false);
This method convets dp unit to equivalent device specific value in pixels.
public static int convertDpToPixel(float dp,Context context)
{
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
int px = (int) (dp * (metrics.densityDpi/160f));
return px;
}
Use BitmapFactory.Options.inSampleSize to get a smaller bitmap.
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(YOUR_FILE, opts);
I set this.
Bitmap.createScaledBitmap(bmp, convertDpToPixel(140, context), VirtualMirrorActivity.convertDpToPixel(35, context), true);
instead of
Bitmap.createScaledBitmap(bmp, convertDpToPixel(140, context), VirtualMirrorActivity.convertDpToPixel(35, context), false);
Its give smoother edges & clear of bitmap. Now its working fine..
you need 2 Rect,
Rect src = new Rect();
Rect dst = new Rect();
then u can set the src for the current image,
src.set(0,0,imgWidth,imgHeigth);
then then the required size
dst.set(startX,startY,endX,endY);
Note: startX and startY will be the destination coordinates on the screen
and ur image will be drawn u to the endX endY coordinate.
and draw ur bit man with Canvas
Canvas.drawBitmap(bitmapFile, src, dst, null);
So I got this background image for my activity. Its a 480x800 png.
It has a gradient in it, so there is danger of banding, that's why I made it 99% opaque to force the best color mode.
On my device, and even on a HTC magic this is no problem.
However, on the default 1.6 emulator, I get out of memory errors. What to do?
The background is set in code with:
bgView.setImageResource(R.drawable.baby_pink_solid);
Setting the max VM heap to 192 and device ram size to 256 does not seem to be a solution.
Try accessing the Bitmap in code, and then set it via setImageBitmap(). If you get an OOM when you are decoding the Bitmap in code, then this is why you are getting it from setImageResource().
I have found that Bitmaps are a tricky thing to handle on Android, and you have to be careful when using them!
Also check out #Sadeshkumar Periyasamy's answer, this is useful for decoding Bitmaps or larger sizes for devices which do not have as much power as todays devices.
Try this code to scale any bitmap:
public class ImageScale
{
/**
* Decodes the path of the image to Bitmap Image.
* #param imagePath : path of the image.
* #return Bitmap image.
*/
public Bitmap decodeImage(String imagePath)
{
Bitmap bitmap=null;
try
{
File file=new File(imagePath);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file),null,o);
final int REQUIRED_SIZE=200;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true)
{
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=scale;
bitmap=BitmapFactory.decodeStream(new FileInputStream(file), null, options);
}
catch(Exception e)
{
bitmap = null;
}
return bitmap;
}
/**
* Resizes the given Bitmap to Given size.
* #param bm : Bitmap to resize.
* #param newHeight : Height to resize.
* #param newWidth : Width to resize.
* #return Resized Bitmap.
*/
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
{
Bitmap resizedBitmap = null;
try
{
if(bm!=null)
{
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
// resizedBitmap = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
}
}
catch(Exception e)
{
resizedBitmap = null;
}
return resizedBitmap;
}
}
I am using bitmap to get a image from a url using this
public void loadImage(String url){
try {
bitmap = BitmapFactory.decodeStream((InputStream)new URL(url).getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Is there anyway i can resize the image from here? setting the width and the height of it still keeping the resolution?
Use: Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
You can try this too.
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1; // 1 = 100% if you write 4 means 1/4 = 25%
bitmap = BitmapFactory.decodeStream((InputStream)new URL(url).getContent(),
null, bmOptions);
bmImage.setImageBitmap(bitmap);
Maybe this will help you:
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
You can just use Picasso(very simple!):
Picasso.with(context) .load(url) .resize(10, 10) .into(imageView)
http://square.github.io/picasso/
why don't you set the width and height property of imageView in XML?
I find out that the image from url is resized automatically so that it can fit in that imageView.
I needed similar capabilities in my app also. I found the best solution for me here.
https://github.com/coomar2841/image-chooser-library/blob/dev/src/com/kbeanie/imagechooser/threads/MediaProcessorThread.java
You might not need all that functionality, but at some point the guy is compressing /scaling bitmaps.