im trying to get imageview from drawable and resize it my current code is working on all devices except on oppo devices it crash inside crop() method
the crash im getting is on the first line in crop() method you can find below
Caused by: java.lang.NullPointerException:
my current code is:
public Bitmap getTileBitmap(int id, int size) {
String string = tileUrls.get(id);
if (string.contains(Themes.URI_DRAWABLE)) {
String drawableResourceName = string.substring(Themes.URI_DRAWABLE.length());
int drawableResourceId = Shared.context.getResources().getIdentifier(drawableResourceName, "drawable", Shared.context.getPackageName());
Bitmap bitmap = Utils.scaleDown(drawableResourceId, size, size);
return Utils.crop(bitmap, size, size);
}
return null;
}
public static Bitmap crop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
EDIT: added scale method which may cause the issue
public static Bitmap scaleDown(int resource, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(Shared.context.getResources(), resource);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(Shared.context.getResources(), resource, options);
}
and so far im not sure what is causing the crash only on oppo devices
Try this:
options.inJustDecodeBounds = true;
options.inScaled = false;
options.inDensity = 0;
options.inMutable = true; //API 11. Pass to canvas? Might crash without this.
//Load the image here... BitmapFactory.decodeResource()...
... //Some calculations.
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Related
I need scale my bitmap to screenSizeAverage / 3. When I do it like this, I have sometimes OutOfMemory error.
screenWidth = size.x;
screenHeight = size.y;
screenSizeAverage = (screenWidth + screenHeight) / 2;
Bitmap b2 = BitmapFactory.decodeResource(getResources(), R.drawable.logoqrtz);
logoqrtz = Bitmap.createScaledBitmap(b2, screenSizeAverage / 3,screenSizeAverage / 3, true);
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(logoqrtz, (int) (screenWidth / 2, (int) (screenHeight /2), p);
}
What is the best way to do this without OutOfMemory error?
From developer.android.com
private Bitmap setPic() {
// Get the dimensions of the View
int targetW = size.x;
int targetH = size.y;
int size = ((screenWidth + screenHeight) / 2) / 3;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/size, photoH/size);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
return BitmapFactory.decodeResource(getResources(), R.drawable.logoqrtz, bmOptions);
}
Modified for your case.
im having problems with high resolution images.
Im using nodpi-drawable folder for 1280x720 images, and using this code to scale it.
public static Drawable scaleDrawable(Drawable d, int width, Activity cxt)
{
BitmapDrawable bd = (BitmapDrawable)d;
double oldWidth = bd.getBitmap().getWidth();
double scaleFactor = width / oldWidth;
int newHeight = (int) (d.getIntrinsicHeight() * scaleFactor);
int newWidth = (int) (oldWidth * scaleFactor);
Drawable drawable = new BitmapDrawable(cxt.getResources(),MainScreen.getResizedBitmap(bd.getBitmap(),newHeight,newWidth));
BitmapDrawable bd2 = (BitmapDrawable)drawable;
return drawable;
}
public static 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;
}
I use that code to scale images to screen witdh so if the screen is 320x480 the image will scale to 320 and keep proportions, i dont care if image go out of screen from bottom.
All its working fine, but when trying in a xhdpi device specifically a Samsung Galaxy Note 2 with a screen of exactly 720x1280.
It crash with Out Of Memory Exception in the line:
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
I cant understand why, the image should be scaled from 720 to 720 but my code must be really bad optimized or something.
I havent tried on a 1080x1920 device but it seems it will crash too.
Someone can see something bad when looking at the code?
use this method to resize your bitmap-
Bitmap bm=decodeSampledBitmapFromPath(src, reqWidth, reqHeight);
use this Defination-
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}
}
public int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
If you are using resource then replace method with BitmapFactory's decodeResource method..
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
....
.....
return BitmapFactory.decodeResource(res, resId, options);
}
You should use the utility class BitmapFactory for image-processing-operations. Also use BitmapFactory.Options to adjust the input/output sizes of the bitmaps. After a bitmap is not needed anymore, you should free the related memory.
I am creating an application and want to setup a gallery view. I do not want the images in the gallery view to be full size. How do I resize images in Android?
Try:
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
or:
resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
public Bitmap resizeBitmap(String photoPath, int targetW, int targetH) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(photoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true; //Deprecated API 21
return BitmapFactory.decodeFile(photoPath, bmOptions);
}
Capture the image and resize it.
Bitmap image2 = (Bitmap) data.getExtras().get("data");
img.setImageBitmap(image2);
String incident_ID = IncidentFormActivity.incident_id;
imagepath="/sdcard/RDMS/"+incident_ID+ x + ".PNG";
File file = new File(imagepath);
try {
double xFactor = 0;
double width = Double.valueOf(image2.getWidth());
Log.v("WIDTH", String.valueOf(width));
double height = Double.valueOf(image2.getHeight());
Log.v("height", String.valueOf(height));
if(width>height){
xFactor = 841/width;
}
else{
xFactor = 595/width;
}
Log.v("Nheight", String.valueOf(width*xFactor));
Log.v("Nweight", String.valueOf(height*xFactor));
int Nheight = (int) ((xFactor*height));
int NWidth =(int) (xFactor * width) ;
bm = Bitmap.createScaledBitmap( image2,NWidth, Nheight, true);
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bm.compress(CompressFormat.PNG, 100, ostream);
ostream.close();
You can use Matrix to resize your camera image ....
BitmapFactory.Options options=new BitmapFactory.Options();
InputStream is = getContentResolver().openInputStream(currImageURI);
bm = BitmapFactory.decodeStream(is,null,options);
int Height = bm.getHeight();
int Width = bm.getWidth();
int newHeight = 300;
int newWidth = 300;
float scaleWidth = ((float) newWidth) / Width;
float scaleHeight = ((float) newHeight) / Height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0,Width, Height, matrix, true);
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
//photo is bitmap image
Bitmap btm00 = Utils.getResizedBitmap(photo, 200, 200);
setimage.setImageBitmap(btm00);
And in Utils class :
public static 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;
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;
}
bm = Bitmap.createScaledBitmap(bitmapSource, width, height, true);
:)
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=2; //try to decrease decoded image
Bitmap bitmap=BitmapFactory.decodeStream(is, null, options);
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos); //compressed bitmap to file
Following is the function to resize bitmap by keeping the same Aspect Ratio. Here I have also written a detailed blog post on the topic to explain this method. Resize a Bitmap by Keeping the Same Aspect Ratio.
public static Bitmap resizeBitmap(Bitmap source, int maxLength) {
try {
if (source.getHeight() >= source.getWidth()) {
int targetHeight = maxLength;
if (source.getHeight() <= targetHeight) { // if image already smaller than the required height
return source;
}
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (targetHeight * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
} else {
int targetWidth = maxLength;
if (source.getWidth() <= targetWidth) { // if image already smaller than the required height
return source;
}
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (targetWidth * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
}
}
catch (Exception e)
{
return source;
}
}
resized = Bitmap.createScaledBitmap(yourImageBitmap,(int)(yourImageBitmap.getWidth()*0.9), (int)(yourBitmap.getHeight()*0.9), true);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 10;
FixBitmap = BitmapFactory.decodeFile(ImagePath, options);
//FixBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.gv);
byteArrayOutputStream = new ByteArrayOutputStream();
FixBitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream); //compress to 50% of original image quality
byteArray = byteArrayOutputStream.toByteArray();
ConvertImage = Base64.encodeToString(byteArray, Base64.DEFAULT);
I'm trying to set a wallpaper but I get banding. I have a large gradient JPG which is saved on my device. I read it from file, scale it so that its height matches the height of the device then I set the wallpaper and the wallpaper hints. The scaling step seems to be converting it to a RGB565 format rather than the original ARGB888 format. Also, I dont seem to have any dither which might help aleviate the banding.
Here is my code:
public class WallpaperSetter {
public static void setWallpaper(String url, Context context) throws IOException {
FileCache cache = new FileCache(context);
File f = cache.getFile(url);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inDither = true;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, options);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int targetHeight = display.getHeight() > display.getWidth() ? display.getHeight() : display.getWidth() - 10;
int targetWidth = (int) ((float) targetHeight / (float) bmp.getHeight() * (float) bmp.getWidth());
Bitmap resizedBitmap = resize(bmp, targetHeight, targetWidth);
WallpaperManager manager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
manager.setBitmap(resizedBitmap);
int displayHeight = display.getHeight() > display.getWidth() ? display.getHeight() : display.getWidth();
int displayWidth = display.getHeight() > display.getWidth() ? display.getWidth() : display.getHeight();
int height = resizedBitmap.getHeight() > displayHeight ? resizedBitmap.getHeight() : displayHeight;
int width = resizedBitmap.getWidth() < displayWidth ? displayWidth : resizedBitmap.getWidth();
manager.suggestDesiredDimensions(width, height);
}
private static Bitmap resize(Bitmap bitmap, int targetHeight, int targetWidth) {
System.out.println("config start: " + bitmap.getConfig().name().toString());
Bitmap b = Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, false);
System.out.println("config: " + b.getConfig().name().toString());
return b;
}
}
I'm developing on a SGS2 with CyanogenMod if that makes a difference.
I found that adding some noise or subtle randomness to a gradient image helps reduce banding, but I suspect using a .png containing at least a pixel of alpha (weird but works) and RGB565 format is the way to go. Also I found that using the 'raw' resources folder instead of 'drawable' folder prevented Android assuming it could compress the image internally. Here's the code I used anyway:
private void generateBackgroundGraphic() {
background = BitmapFactory.decodeResource(res, R.raw.gradient);
//create local copy of 'background' bitmap size
Bitmap tempB = Bitmap.createBitmap(background.getWidth(), background.getHeight(), Bitmap.Config.RGB_565);
backgroundPaint.setDither(true);
//wrap a canvas around 'background' bitmap
Canvas tempC = new Canvas (tempB);
tempC.drawBitmap(background, 0, 0, null);
background = Bitmap.createScaledBitmap(tempB, globalCanvasSize.x, globalCanvasSize.y, false);
tempB.recycle();
tempB = null;
tempC = null;
}
I hope this is of some use to you... Android deals with images strangely sometimes :-/
Chris
My final code which works even though I suspect there is a much simpler way to do this:
public class WallpaperSetter {
public static void setWallpaper(String url, Context context) throws IOException {
FileCache cache = new FileCache(context);
File f = cache.getFile(url);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int targetHeight = display.getHeight() > display.getWidth() ? display.getHeight() : display.getWidth() - 10;
int targetWidth = (int) ((float) targetHeight / (float) o.outHeight * (float) o.outWidth);
while (true) {
if (width_tmp / 2 < targetWidth || height_tmp / 2 < targetHeight)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inPreferredConfig = Bitmap.Config.ARGB_8888;
o2.inDither = false;
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
Bitmap b565 = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(b565);
c.drawBitmap(b, 0, 0, null);
b = Bitmap.createScaledBitmap(b565, targetWidth, targetHeight, false);
b565.recycle();
b565 = null;
c = null;
WallpaperManager manager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
manager.setBitmap(b);
int displayHeight = display.getHeight() > display.getWidth() ? display.getHeight() : display.getWidth();
int displayWidth = display.getHeight() > display.getWidth() ? display.getWidth() : display.getHeight();
int height = b.getHeight() > displayHeight ? b.getHeight() : displayHeight;
int width = b.getWidth() < displayWidth ? displayWidth : b.getWidth();
manager.suggestDesiredDimensions(width, height);
}
}
I am downloading image using url, but after scaling it's crashing and scaling is not proper.
This is the code I have used,
//Code to fetch bitmap
Bitmap bmp=HttpFetch.fetchBitmap(imageUrl);
//Scale bitmap
Bitmap myBitmap = getResizedBitmap(bmp, viewWidth, viewHeight);
public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
int srcWidth = bm.getWidth();
int srcHeight = bm.getHeight();
int desiredWidth = newWidth;
int desiredHeight = newHeight;
int inSampleSize = 1;
while(srcWidth / 2 > desiredWidth){
srcWidth /= 2;
srcHeight /= 2;
inSampleSize *= 2;
}
float desiredWidthScale = (float) desiredWidth / srcWidth;
float desiredHeightScale = (float) desiredHeight / srcHeight;
// Decode with inSampleSize
options.inJustDecodeBounds = false;
options.inDither = false;
options.inSampleSize = inSampleSize;
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Matrix matrix = new Matrix();
matrix.postScale(desiredWidthScale, desiredHeightScale);
original = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
return original;
}
Could not find code to get BitmapFactory.Option using bitmap and most of the places it is using filename, is it possible to get BitmapFactory.Options using bitmap?
Kindly suggest better solution to scale bitmap when we download from network.
original = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
This line returns an immutable Bitmap, after calling getResizedBitmap(), if you are trying to modify this Bitmap, it might result in a crash.
Android#createBitmap()
Please look up LogCat for details.