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);
Related
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.)
I want that load images from sdcard to listview but i dont need image in big size. size 60dip * 60dip is Sufficient. i am using below codes in thread but however this is slow.i need load images in fast way.
public Bitmap loadImage(String imagePath){
//load bitmap in real size
Bitmap bmp = BitmapFactory.decodeFile(imagePath);
int width = bmp.getWidth();
int height = bmp.getHeight();
//determine size and scale
float newWidth = convertDipToPixel(60, getApplicationContext());//60 dip
float scale = ((float) newWidth) / width;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scale, scale);
Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true);
return resizedBitmap;}
check android query and image loading using android query
its really fast, try it.
File file = new File(path);
//load image from file, down sample to target width of 300 pixels
aq.id(R.id.avatar).image(file, 300);
you can also use Android-Universal-Image-Loader
String imageUri = "file:///mnt/sdcard/image.png"; // from SD card
// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view
// which implements ImageAware interface)
imageLoader.displayImage(imageUri, imageView);
Simple question where the simple answer isn't working. I have a bitmap and I want to get its dimensions as scaled to the display by the system for different DPI screens within the onDraw() method. bitmap.width() returns its unscaled width successfully. However, bitmap.getScaledWidth() returns zero. I have tried getScaledWidth(canvas) and getScaledWidth(canvas.getDensity()), but both return 0. Indeed, canvas.getDensity() returns zero so I can't even calculate it manually.
What am I doing wrong?
Bit more detail. I'm using a custom view. The bitmap is declared in the class and loaded in the constructor.
Edit:
I've found that using:
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
bitmap.getScaledHeight(metrics) returns the same value as bitmap.getHeight().
It would appear that bitmap.getWidth() returns the dimension of the resident bitmap after it has been scaled, meaning there's no apparent way to get the bitmap's original width.
The Canvas class has a lots of overloads for the drawBitmap() function. One of them allows you to scale/cut a Bitmap through a pretty comfortable interface.
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
Where
Bitmap bitmap - is your bitmap you want to draw
Rect src - the source rect from your bitmap. If its not null, it will
cut out a piece from your bitmap (in the size and position of src)
RectF dst - This Rect will represent the Rectangle, your Bitmap will
fit in.
Paint paint - optional paint
And now an example! Lets say, you want to shrink your Bitmaps width to 1/2 and increase its height to 2 times of the original:
float startX = 0; //the left
float startY = 0; //and top corner (place it wherever you want)
float endX = startX + bitmap.getWidth() * 0.5f; //right
float endY = startY + bitmap.getHeight() * 2.0f; //and bottom corner
canvas.drawBitmap(bitmap, null, new RectF(startX, startY, endX, endY), null);
UPDATE
I don't really understand, what you are trying to acomplish, after reading your comment, but here is some extra info to get started:
Get the original size of a Bitmap without loading it into the memory:
BitmapFactory.Options options = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true; // bitmap wont be loaded into the memory
//won't load the Bitmap, but the options will contain the required information.
BitmapFactory.decodeStream(inputStream, null, options);
/*or*/ BitmapFactory.decodeFile(pathName, options);
int originalWidth = bitmapOptions.outWidth;
int originalHeight = bitmapOptions.outHeight;
Now if you have another your actual (scaled) Bitmap, or an ImageView, what you want to compare to the original, then you can use this (to get the width and height use getWidth() and getHeight()):
/*Get these values*/
int originalWidth, originalHeight, scaledWidth, scaledHeight;
float scaleWidthRatio = (float)scaledWidth / originalWidth;
float scaleHeightRatio = (float)scaledHeight / originalHeight;
How about this? You scale the bitmap yourself. :-)
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Drawable drawable = getDrawable();
if(drawable==null)
Log.d("onDraw()","getDrawable returns null");
Bitmap fullSizeBitmap,scaledBitmap = null,roundBitmap = null;
fullSizeBitmap = ((BitmapDrawable)drawable).getBitmap() ;
//get width & height of ImageView
int scaledWidth = getMeasuredWidth();
int scaledHeight = getMeasuredHeight();
//bitmap, which will receive the reference to a bitmap scaled to the bounds of the ImageView.
if(fullSizeBitmap!=null)
scaledBitmap= getScaledBitmap(fullSizeBitmap,scaledWidth,scaledHeight);
//Now, draw the bitmap on the canvas
if(roundBitmap!=null)
canvas.drawBitmap(roundBitmap, 0,0 , null);
}
I have an image on a private file.
I read the file, create the drawable, and assign it to an ImageView.
The ImageView has WRAP_CONTENT so the size is automatic.
On 320x480 screens, the image looks good
But on screens with more resolution and high density 480x800 or 480x854 (N1, droid) , when the image is for example 150x150, I see the image as 100x100.
Of course it has something to do with the density but not sure how should I resolve this.
This is my code:
FileInputStream fis = this.openFileInput("icon.png");
icon = Drawable.createFromStream(fis, "icon");
fis.close();
imageView.setImageDrawable(icon);
thanks
================================================================
update:
with the following code:
FileInputStream fis = this.openFileInput("icon.png");
icon = Drawable.createFromStream(fis, "icon");
if I then inspect the size of the icon, android thinks the size is 100x100, when really is 150x150.
Looks like its reducing the image by the density.
Can anybody explain this and how to avoid this.
Thanks
I am working on a similar issue, try this:
TypedValue typedValue = new TypedValue();
//density none divides by the density, density default keeps the original size
typedValue.density = TypedValue.DENSITY_DEFAULT;
Drawable d = Drawable.createFromResourceStream(null, typedValue, fis, "icon");
I am still working through how to develop a general solution to pick resolution/resize images from a generic stream instead of the drawable-* directories.
Rescale the image to desired dimension:
d = Drawable.createFromPath(filePath);
if (d != null) {
Bitmap bitmapOrg = ((BitmapDrawable) d).getBitmap();
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = 170;
int newHeight = 170;
// calculate the scale
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);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
d = new BitmapDrawable(resizedBitmap);
}
Try BitmapDrawable#setTargetDensity:
Bitmap b = BitmapFactory.decodeFile(path)
BitmapDrawable bmd = new BitmapDrawable(b);
bmd.setTargetDensity(getResources().getDisplayMetrics());
Set some dimensions in device independent pixels (or DIPs).
I have a large sized image. At runtime, I want to read the image from storage and scale it so that its weight and size gets reduced and I can use it as a thumbnail. When a user clicks on the thumbnail, I want to display the full-sized image.
Try this
Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath), THUMBSIZE, THUMBSIZE);
This Utility is available from API_LEVEl 8. [Source]
My Solution
byte[] imageData = null;
try
{
final int THUMBNAIL_SIZE = 64;
FileInputStream fis = new FileInputStream(fileName);
Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
imageData = baos.toByteArray();
}
catch(Exception ex) {
}
The best solution I found is the following. Compared with the other solutions this one does not need to load the full image for creating a thumbnail, so it is more efficient!
Its limit is that you can not have a thumbnail with exact width and height but the solution as near as possible.
File file = ...; // the image file
Options bitmapOptions = new Options();
bitmapOptions.inJustDecodeBounds = true; // obtain the size of the image, without loading it in memory
BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);
// find the best scaling factor for the desired dimensions
int desiredWidth = 400;
int desiredHeight = 300;
float widthScale = (float)bitmapOptions.outWidth/desiredWidth;
float heightScale = (float)bitmapOptions.outHeight/desiredHeight;
float scale = Math.min(widthScale, heightScale);
int sampleSize = 1;
while (sampleSize < scale) {
sampleSize *= 2;
}
bitmapOptions.inSampleSize = sampleSize; // this value must be a power of 2,
// this is why you can not have an image scaled as you would like
bitmapOptions.inJustDecodeBounds = false; // now we want to load the image
// Let's load just the part of the image necessary for creating the thumbnail, not the whole image
Bitmap thumbnail = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);
// Save the thumbnail
File thumbnailFile = ...;
FileOutputStream fos = new FileOutputStream(thumbnailFile);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();
// Use the thumbail on an ImageView or recycle it!
thumbnail.recycle();
Here is a more complete solution to scaling down a Bitmap to thumbnail size. It expands on the Bitmap.createScaledBitmap solution by maintaining the aspect ratio of the images and also padding them to the same width so that they look good in a ListView.
Also, it would be best to do this scaling once and store the resulting Bitmap as a blob in your Sqlite database. I have included a snippet on how to convert the Bitmap to a byte array for this purpose.
public static final int THUMBNAIL_HEIGHT = 48;
public static final int THUMBNAIL_WIDTH = 66;
imageBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
Float width = new Float(imageBitmap.getWidth());
Float height = new Float(imageBitmap.getHeight());
Float ratio = width/height;
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(THUMBNAIL_HEIGHT*ratio), THUMBNAIL_HEIGHT, false);
int padding = (THUMBNAIL_WIDTH - imageBitmap.getWidth())/2;
imageView.setPadding(padding, 0, padding, 0);
imageView.setImageBitmap(imageBitmap);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] byteArray = baos.toByteArray();
Use BitmapFactory.decodeFile(...) to get your Bitmap object and set it to an ImageView with ImageView.setImageBitmap().
On the ImageView set the layout dimensions to something small, eg:
android:layout_width="66dip" android:layout_height="48dip"
Add an onClickListener to the ImageView and launch a new activity, where you display the image in full size with
android:layout_width="wrap_content" android:layout_height="wrap_content"
or specify some larger size.
/**
* Creates a centered bitmap of the desired size.
*
* #param source original bitmap source
* #param width targeted width
* #param height targeted height
* #param options options used during thumbnail extraction
*/
public static Bitmap extractThumbnail(
Bitmap source, int width, int height, int options) {
if (source == null) {
return null;
}
float scale;
if (source.getWidth() < source.getHeight()) {
scale = width / (float) source.getWidth();
} else {
scale = height / (float) source.getHeight();
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
Bitmap thumbnail = transform(matrix, source, width, height,
OPTIONS_SCALE_UP | options);
return thumbnail;
}
I found an easy way to do this
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(mPath),200,200)
Syntax
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)
OR
use Picasso dependancy
compile 'com.squareup.picasso:picasso:2.5.2'
Picasso.with(context)
.load("file:///android_asset/DvpvklR.png")
.resize(50, 50)
.into(imageView2);
Reference Picasso
If you want high quality result, so use [RapidDecoder][1] library. It is simple as follow:
import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image)
.scale(width, height)
.useBuiltInDecoder(true)
.decode();
Don't forget to use builtin decoder if you want to scale down less than 50% and a HQ result.
This answer is based on the solution presented in https://developer.android.com/topic/performance/graphics/load-bitmap.html (without using of external libraries) with some changes by me to make its functionality better and more practical.
Some notes about this solution:
It is assumed that you want to keep the aspect ratio. In other words:
finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth() (Regardless of casting and rounding issues)
It is assumed that you have two values (maxWidth & maxHeight) that you want any of the dimensions of your final bitmap doesn't exceed its corresponding value. In other words:
finalWidth <= maxWidth && finalHeight <= maxHeight
So minRatio has been placed as the basis of calculations (See the implementation). UNLIKE the basic solution that has placed maxRatio as the basis of calculations in actual. Also, the calculation of inSampleSize has been so much better (more logic, brief and efficient).
It is assumed that you want to (at least) one of the final dimensions has exactly the value of its corresponding maxValue (each one was possible, by considering the above assumptions). In other words:
finalWidth == maxWidth || finalHeight == maxHeight
The final additional step in compare to the basic solution (Bitmap.createScaledBitmap(...)) is for this "exactly" constraint. The very important note is you shouldn't take this step at first (like the accepted answer), because of its significant consumption of memory in case of huge images!
It is for decoding a file. You can change it like the basic solution to decode a resource (or everything that BitmapFactory supports).
The implementation:
public static Bitmap decodeSampledBitmap(String pathName, int maxWidth, int maxHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
final float wRatio_inv = (float) options.outWidth / maxWidth,
hRatio_inv = (float) options.outHeight / maxHeight; // Working with inverse ratios is more comfortable
final int finalW, finalH, minRatio_inv /* = max{Ratio_inv} */;
if (wRatio_inv > hRatio_inv) {
minRatio_inv = (int) wRatio_inv;
finalW = maxWidth;
finalH = Math.round(options.outHeight / wRatio_inv);
} else {
minRatio_inv = (int) hRatio_inv;
finalH = maxHeight;
finalW = Math.round(options.outWidth / hRatio_inv);
}
options.inSampleSize = pow2Ceil(minRatio_inv); // pow2Ceil: A utility function that comes later
options.inJustDecodeBounds = false; // Decode bitmap with inSampleSize set
return Bitmap.createScaledBitmap(BitmapFactory.decodeFile(pathName, options),
finalW, finalH, true);
}
/**
* #return the largest power of 2 that is smaller than or equal to number.
* WARNING: return {0b1000000...000} for ZERO input.
*/
public static int pow2Ceil(int number) {
return 1 << -(Integer.numberOfLeadingZeros(number) + 1); // is equivalent to:
// return Integer.rotateRight(1, Integer.numberOfLeadingZeros(number) + 1);
}
Sample Usage, in case of you have an imageView with a determined value for layout_width (match_parent or a explicit value) and a indeterminate value for layout_height (wrap_content) and instead a determined value for maxHeight:
imageView.setImageBitmap(decodeSampledBitmap(filePath,
imageView.getWidth(), imageView.getMaxHeight()));