I have image 640*480 in sd card and i want to set it as home screen wallpaper. How Can I do this with small quality loss? With my code Wallpaper has a not good clarity. That's my code:
private void setWallpaper(String filePath) throws IOException{
if(filePath!=null){
// set options for decoding
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inDither = false;
options.inJustDecodeBounds = true;
//get bitmap from filepath
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
//get sizes of bitmap
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//get sizes of screen and scale level
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int newWidth = display.getWidth()*2;
int newHeight = display.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
//set matrix of the scaling
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
//get new bitmap for wallpaper
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
width, height, matrix, true);
//set bitmap as wallpaper
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
wallpaperManager.clear();
wallpaperManager.setBitmap(resizedBitmap);
}
}
Any time you scale upwards you're going to suffer quality loss. What size screen are you trying to display this image one? Keep in mind the Android wallpaper dimensions are the height of the screen by 2 times the width of the screen (e.g. 800x480 screen needs a 800x960 image).
My recommendation would be to have a larger image and scale downwards. The quality loss from downsampling is far less noticeable than from upscaling. You could, if space is not an issue, include multiple sizes of the image for differing screen resolutions.
Related
I want to resize an image to a smaller image like thumbnail. I have used following options
Bitmap imageBitmap = Bitmap.createScaledBitmap(mBitmap, 200, 700, false);
and
ThumbnailUtils.extractThumbnail()
Both of these options cut parts of images. So they don't look good. I just want to reduce image dimensions and don't want to loose image content.
you have to try like this
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;
}
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeFile(filepath,bmOptions);
//Part 1 :withcompression Sacle image 200 pixels x 700 pixels this size you can customize as per your requirement
Bitmap withCompressed = Bitmap.createScaledBitmap(bitmap,200,700,true);
If you want to resize an image without losing quality and images are from drawable/mipmap then you should try pngquant.
https://pngquant.org/
Is there any method that gets the phones resolution (or dp) and scales bitmaps accordingly? I have all my images in xhdpi folder and at the moment they do not scale the way they should.
I want an efficiant and memory-friendly method that can do the scaling automatically. If not, what is the next best thing? completely new area for me. So any tutorial-link is also appriciated.
this is what I use to load bitmaps atm:
public Bitmap loadBitmap(int resourceID) {
Options options = new BitmapFactory.Options();
options.inScaled = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap tempBmp = null;
try {
tempBmp = BitmapFactory.decodeResource(getResources(), resourceID,
options);
} catch (OutOfMemoryError e) {
} catch (Error e) {
}
return tempBmp;
}
If you wanna scale bitmap for each phone resolution, you should know phone screen size, scale ratio.
This code will return width (w) & height (h) of screen.
DisplayMetrics dMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
float density = dMetrics.density;
int w = Math.round(dMetrics.widthPixels / density);
int h = Math.round(dMetrics.heightPixels / density);
activity is instance of Activity which would you like to get screen size.
You have to remember that: When your device is in landscape orientation, w > h. When it in portrait orientation w < h.
So from width & height you can detect your device is in what orientation.
Example:
From w & h of device and ratio (which you want to scale) you can calculate new bitmap size to scale it.
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;
}
My app uses the camera to take pictures and sends the data someplace else. However, the picture sizes are too big in terms of bytes, or unecessarily big. But I'm not sure how to force the camera to take a smaller picture or after taking the picture, send a scaled down version of it.
This is how I go to the Camera screen.
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(getTempFile()));
startActivityForResult(intent, PIC_ONE);//first picture
And then onActivityResult I have:
...
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=4;
Bitmap mBitmap = BitmapFactory.decodeFile(getPath(myURI),options);
photoView.setImageBitmap(bmp);
Which shows the user a quarter sized thumbnail of the saved image. But of course the actual image is still retains its large size.
How can I reduce the image size?
Have a look at Reduce Bitmap size using BitmapFactory.Options.inSampleSize
You can also try createScaledBitmap()
public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
Since: API Level 1
Creates a new bitmap, scaled from an existing bitmap.
Parameters
src The source bitmap.
dstWidth The new bitmap's desired width.
dstHeight The new bitmap's desired height.
filter true if the source should be filtered.
Returns the new scaled bitmap.
It also reduces the file size,
You can also use Following function for resizing:
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;
}
I wrote a program that at any time displays 8 user selected images on the screen. Each image is taken from its original form and scaled down to a uniform size. In order to do this I am using the code below:
Bitmap bitmapOrg = BitmapFactory.decodeFile(File Location Here);
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = 100;
int newHeight = 100;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width,
height, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
//ImageView imageView = new ImageView(this);
ImageView iv = (ImageView) findViewById(R.id.imageView1);
// set the Drawable on the ImageView
iv.setImageDrawable(bmd);
// center the Image
iv.setScaleType(ScaleType.CENTER);
Even though my code works its not perfect. It seems like I'm using up a lot of memory especially calling this code possibly 8 times at once. Where in the code would I "recycle" the memory and how could I make this code possibly run better?
EDIT:
So I implemented the code in my project and it was working perfect and then I tried to add it to other sections and it just stopped working all together. My code looks like this: any idea what am I doing wrong?
BitmapFactory.Options options = new BitmapFactory.Options();
options.outWidth = 50;
options.outHeight = 50; Bitmap bitmap = BitmapFactory.decodeFile(path, options);
ImageView iv = (ImageView) findViewById(R.id.imageView7);
iv.setImageBitmap(bitmap);
You can use BitmapFactory.Options to scale the image as you decode it rather than reading in a full image and then scaling it.
BitmapFactory.Options options = new BitmapFactory.Options();
// You can play with this setting depending on how large your images are
// For example, to scale ~400x400 images to ~100x100, you can use 4.
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
Edit - George is correct. You should use inSampleSize to create a smaller image of the general size you need and then have it resized to the exact size you want using your ImageView. I've corrected my answer above to reflect this.
In any case, you should be much better off memory-wise if you are scaling the bitmaps during decode.
#matthew-willis I do not think you can use outWidth and outHeight to scale a bitmap. I believe they are output parameters only: they report the size of the bitmap created after the fact--setting them prior to decoding has no effect. You should use inSampleSize if you want to scale as you decode. George
I've got a bitmap... and if the bitmap's height is greater than maxHeight, or the width is greater than maxWidth, I'd like to proportionally resize the image so that it fits in maxWidth X maxHeight. Here's what I'm trying:
BitmapDrawable bmp = new BitmapDrawable(getResources(), PHOTO_PATH);
int width = bmp.getIntrinsicWidth();
int height = bmp.getIntrinsicHeight();
float ratio = (float)width/(float)height;
float scaleWidth = width;
float scaleHeight = height;
if((float)mMaxWidth/(float)mMaxHeight > ratio) {
scaleWidth = (float)mMaxHeight * ratio;
}
else {
scaleHeight = (float)mMaxWidth / ratio;
}
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap out = Bitmap.createBitmap(bmp.getBitmap(),
0, 0, width, height, matrix, true);
try {
out.compress(Bitmap.CompressFormat.JPEG, 100,
new FileOutputStream(PHOTO_PATH));
}
catch(FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
I get the following exception:
java.lang.IllegalArgumentException: bitmap size exceeds 32bits
What am I doing wrong here?
Your scaleWidth and scaleHeight should be scale factors (so not very big numbers) but your code seems to pass in the actual width and height you're looking for. So you're ending up massively increasing the size of your bitmap.
I think there are other problems with the code to derive scaleWidth and scaleHeight as well though. For one thing your code always has either scaleWidth = width or scaleHeight = height, and changes only one of them, so you're going to be distorting the aspect ratio of your image as well. If you just want to resize the image then you should just have a single scaleFactor.
Also, why does your if statement check for, effectively, maxRatio > ratio ? Shouldn't you be checking for width > maxWidth or height > maxHeight?
This is because the value of scaleWidth or scaleHeight is too large,scaleWidth or scaleHeight is mean enlarge or shrink 's rate,but not width or height,too large rate lead to bitmap size exceeds 32 bits
matrix.postScale(scaleWidth, scaleHeight);
this is how i did it:
public Bitmap decodeAbtoBm(byte[] b){
Bitmap bm; // prepare object to return
// clear system and runtime of rubbish
System.gc();
Runtime.getRuntime().gc();
//Decode image size only
BitmapFactory.Options oo = new BitmapFactory.Options();
// only decodes size, not the whole image
// See Android documentation for more info.
oo.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(b, 0, b.length ,oo);
//The new size we want to scale to
final int REQUIRED_SIZE=200;
// Important function to resize proportionally.
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(oo.outWidth/scale/2>=REQUIRED_SIZE
&& oo.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2; // Actual scaler
//Decode Options: byte array image with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale; // set scaler
o2.inPurgeable = true; // for effeciency
o2.inInputShareable = true;
// Do actual decoding, this takes up resources and could crash
// your app if you do not do it properly
bm = BitmapFactory.decodeByteArray(b, 0, b.length,o2);
// Just to be safe, clear system and runtime of rubbish again!
System.gc();
Runtime.getRuntime().gc();
return bm; // return Bitmap to the method that called it
}