I have very large bitmap image. My source
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_WIDTH = 1000;
final int REQUIRED_HIGHT = 500;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_WIDTH
&& o.outHeight / scale / 2 >= REQUIRED_HIGHT)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
i want to resize image correctly, i need resize image to maximum available size
for example
i downloaded image size 4000x4000 px and my phone supported 2000x1500 px size
i need anderstend how size suported my phone?
then i resize image to 2000x1500 (for example)
Here you have good to resize bitmap to maximum avaliabe size :
public void onClick() //for example
{
/*
Getting screen diemesions
*/
WindowManager w = getWindowManager();
Display d = w.getDefaultDisplay();
int width = d.getWidth();
int height = d.getHeight();
// "bigging" bitmap
Bitmap nowa = getResizedBitmap(yourbitmap, width, height);
}
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 hope I helped
Not So Perfect But here is My solution to Do That,
fun setScaleImageWithConstraint(bitmap: Bitmap): Bitmap {
val maxWidth = 500 //max Height Constraint
val maxHeight = 500 //max Width Constraint
var width = bitmap.width
var height = bitmap.height
if (width > maxWidth || height > maxHeight) {
//If Image is still Large than allowed W/H Half the Size
val quarterWidth = ((width / 2).toFloat() + (width / 3).toFloat()).toInt()
val quarterHeight = ((height / 2).toFloat() + (height / 3).toFloat()).toInt()
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, quarterWidth, quarterHeight, false)
//Recursive Call to Resize and return Resized One
return setScaleImageWithConstraint(scaledBitmap)
} else {
//This will be executed when Image is not violating the Constraints
return bitmap
}
}
Reduce Bitmap 1 Quarter Size Recursively Until the Allowed With And Height is reached.
Related
I am new to android. I want to reduce the size of a bitmap to 100kb exactly. I get an image from the sdcard, compress it and save it to the sdcard again with a different name into a different directory. Compression works fine (3 mb like image is compressed to around 100 kb). I trying to compress 1mb image to 100kb, but i am getting size of that image is 20kb. But i need that 1mb(or 2mb (or) 3mb (or) 4mb (or) 5mb.....) image also get resize to 100kb. and my code is,,
private Bitmap getResizedBitmap(Bitmap bm, int maxSize)
{
int width = bm.getWidth();
int height = bm.getHeight();
float bitmapRatio = (float)width / (float) height;
if (bitmapRatio > 0) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(bm, width, height, true);
}
public static Bitmap getResizedBitmap(Bitmap bm, float newHeight, float newWidth) {
float width = bm.getWidth();
float height = bm.getHeight();
float scaleWidth = (newWidth) / width;
float scaleHeight = (newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
return Bitmap.createBitmap(bm, 0, 0, (int) width, (int) height, matrix, false);
}
Using matrix
Resizing bitmap by pixel resolution is possible but resizing by its disk size is not as far as I know
is there a way i can compress an image of 115kb to be 4kb in android Without affecting it size?. just reducing it quality?
i only know of using
BitmapFactory.Options which reduces both size and quality
Bitmap.compress which does not give you options for specifying size in bytes.
public Bitmap compressImage(String imagePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bmp = BitmapFactory.decodeStream(new FileInputStream(imagePath),null, options);
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(new FileInputStream(imagePath),null, 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) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
return inSampleSize;
}
Image re sizing means you're going to shorten the resolution of the image. suppose user selects a 1000*1000 px image. you're going to convert the image into a 300*300 image. thus image size will be reduced.
And Image compression is lowering the file size of the image without compromising the resolution. Of course lowering file size will affect the quality of the image. There are many compression algorithm available which can reduce the file size without much affecting the image quality.
One handy way I found in here is :
Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
Log.e("Original dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());
gives
12-07 17:43:36.333: E/Original dimensions(278): 1024 768 12-07
17:43:36.333: E/Compressed dimensions(278): 1024 768
public static int getSquareCropDimensionForBitmap(Bitmap bitmap)
{
int dimension;
//If the bitmap is wider than it is tall
//use the height as the square crop dimension
if (bitmap.getWidth() >= bitmap.getHeight())
{
dimension = bitmap.getHeight();
}
//If the bitmap is taller than it is wide
//use the width as the square crop dimension
else
{
dimension = bitmap.getWidth();
}
return dimension;
}
int dimension = getSquareCropDimensionForBitmap(bitmap);
System.out.println("before cropped height " + bitmap.getHeight() + "and width: " + bitmap.getWidth());
Bitmap croppedBitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
System.out.println("after cropped height "+croppedBitmap.getHeight() +"and width: " + croppedBitmap.getWidth());
it can crop and can reduce size u can specify ur own size
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;
}
I am using camera API to take picture i have to open camera in different sizes according to my Image view size. I am following the sample project which we get inside Android sdk/sample/adroid-18 at the name "ApiDemo" the thing i have changed is not set camera on setcontentview. I have set the camera on Frame Layout. at first my camera preview was starched so i got the camera OptimalPreviewSize and make FrameLayout parameter width and height as wrap-content.Now the camera preview is smaller then ImageView (The size i want). If i make the size of FrameLayout parameter as match-parent then camera View is stretch.How to resolve this issue.
find this link for more specification. Android camera preview look strange
UPDATE
My camera preview size is fine now i use the on Layout method the idea was i have the bigger layout then my ImageView and now camera preview is looking good.
Now the Problem I am facing is set the image of proper size for this I have to center crop and scale in same size in like my ImageView.this Image i get by TakePicture method and saved in sdcard.
For this I am using this method:-
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left+50, top, left + scaledWidth, top + scaledHeight+50);
// RectF targetRect = new RectF(0, 0, newWidth, newHeight/2);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
But the result image quality is not good.Height Corners are cutting from top and bottom, and result image quality is not good.Pixels are stretching.
Don't tell me to use scaleType=Center_crop i can't use it in my case,and don't want to show cropping frame to user,this all process should not show on UI.
UPDATE
I used blow method for crop image from center and scale according to my imageView size
Bitmap dstBmp = ThumbnailUtils.extractThumbnail(source, newWidth, newHeight);
But the bitmap i got is not looking same the camera preview shown on FrameLayout. because camera preview is big.I think these code cropped the large area.
I tried to reduce the width and change the height but not getting the same cropped image in which ratio i want.
One more idea i have after picture crop a last image frame set automatically on FrameLayout. can we get that set frame from Frame Layout. How is this possible?
Here is question like this How to retrieve the visible part of a SurfaceView in Android do any one have solution.
I want to achieve this by this line ThumbnailUtils.extractThumbnail(source, newWidth, newHeight);and by this line i am getting src like image described in diagram .
What to change in this line exactly ????
Center crop an image may be help you this.
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
#Akanksha Please use this below code, you just need to pass the path of the saved image, and the hight and width of our imageview. This code works perfectly for me.
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class ImageHandler {
/**
* Decode and sample down a bitmap from a file to the requested width and
* height.
*
* #param filename
* The full path of the file to decode
* #param reqWidth
* The requested width of the resulting bitmap
* #param reqHeight
* The requested height of the resulting bitmap
* #return A bitmap sampled down from the original with the same aspect
* ratio and dimensions that are equal to or greater than the
* requested width and height
*/
public static Bitmap decodeSampledBitmapFromFile(String filename,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filename, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filename, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
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);
}
// This offers some additional logic in case the image has a
// strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might
// still
// end up being too large to fit comfortably in memory, so we
// should
// be more aggressive with sample down the image (=larger
// inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down
// further.
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
}
I call this method inside async task because it may take too much UImemory and time
Here is how I call it.
class Asyncing extends AsyncTask {
private int reqWidth;
private int reqHeight;
private ImageView iv;
private String fileName;
private ProgressDialog pd;
public Asyncing(int reqWidth, int reqHeight, ImageView iv,
String fileName) {
super();
this.reqWidth = reqWidth;
this.reqHeight = reqHeight;
this.fileName = fileName;
this.iv = iv;
}
#Override
protected Bitmap doInBackground(String... params) {
return ImageHandler.decodeSampledBitmapFromFile(params[0],
reqWidth, reqHeight);
}
#Override
protected void onPostExecute(Bitmap result) {
iv.setImageBitmap(result);
if (pd.isShowing()) {
pd.setMessage(getString(R.string.completed));
pd.dismiss();
}
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(CustomerDetailsActivity.this, "",
getString(R.string.processing_signature));
super.onPreExecute();
}
}
This is how you need to call the asynctask
signedImagePath = data.getExtras().getString("imagePath");
new Asyncing(signature_img.getWidth(), signature_img.getHeight(),
signature_img, "spenTest.png").execute(signedImagePath);
above code is written according to my requirements,you modify it according to yours.
I want to show 4 images in 2 x 2 grid format on the screen. Images are sourced from google image search and images are square of 200 X 200
This is my approach to scale them. RelativeLayout with 4 nested RelativeLayout and each layout has imageView in it. and this is how I get screen width to scale images. Setting internal layoutparams height and width to screenWidth/2 and then scaling images.
this is what I am doing to get the image height and width for particular screen. e.g if screen width is 550 then my image size would be 275 x 275.
public static int getOptionWidth(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return metrics.widthPixels;
}
optionWidth = (getOptionWidth(context) / 2)
This is for unscaled bitmap
public static Bitmap resourceDecoder(byte[] imgBytes, int destWidth, int destHeight) {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length, options);
options.inJustDecodeBounds = false;
float srcAspect = (float) srcWidth / (float) srcHeight;
float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
options.inSampleSize = srcHeight / dstHeight;
} else {
options.inSampleSize = srcWidth / dstWidth;
}
Bitmap unscaledBitmap = BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length, options);
return unscaledBitmap;
}
This will be my destination width and height because I need images in square. I have implemented basic method to get source rectangle (getSrcRect) and get destination rectangle (getDstRect)
Rect srcRect = getSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight);
Rect dstRect = getDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight);
Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(), Config.ARGB_8888);
Canvas canvas = new Canvas(scaledBitmap);
canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
This is working fine and results are coming as expected (tested on hdpi, xhdpi and mdpi). But now I am confused as I am no using dxtopx or pxTodX conversion. Am I missing something? though results are as expected I am little worried about the approach. I don't know should I use pxToDx or vice-versa. If I do how does it affect my result and how should I use these.
You don't have to use PX to DP conversion for this, because you already set all of your size variables relative to screen width by using getOptionWidth(context).