Android load drawable programmatically and resize it - android

How can I load drawable from InputStream (assets, file system) and resize it dynamically based on the screen resolution hdpi, mdpi or ldpi?
The original image is in hdpi, I only need resizing for mdpi and ldpi.
How does Android do dynamic resizing of the drawables in /res?

This is nice and easy (the other answers weren't working for me), found here:
ImageView iv = (ImageView) findViewById(R.id.imageView);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
Bitmap bMapScaled = Bitmap.createScaledBitmap(bMap, newWidth, newHeight, true);
iv.setImageBitmap(bMapScaled);
Android documentation is available here.

Found it:
/**
* Loads image from file system.
*
* #param context the application context
* #param filename the filename of the image
* #param originalDensity the density of the image, it will be automatically
* resized to the device density
* #return image drawable or null if the image is not found or IO error occurs
*/
public static Drawable loadImageFromFilesystem(Context context, String filename, int originalDensity) {
Drawable drawable = null;
InputStream is = null;
// set options to resize the image
Options opts = new BitmapFactory.Options();
opts.inDensity = originalDensity;
try {
is = context.openFileInput(filename);
drawable = Drawable.createFromResourceStream(context.getResources(), null, is, filename, opts);
} catch (Exception e) {
// handle
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e1) {
// log
}
}
}
return drawable;
}
Use like this:
loadImageFromFilesystem(context, filename, DisplayMetrics.DENSITY_MEDIUM);

If you want to display an image but unfortunately this image is of large size, lets example, you want to display an image in 30 by 30 format, then check its size if it is greater than your require size, then divide it by your amount(30*30 here in this case), and what you got is again take and use for dividing the image area again.
drawable = this.getResources().getDrawable(R.drawable.pirImg);
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (width > 30)//means if the size of an image is greater than 30*30
{
width = drawable.getIntrinsicWidth() / 30;
height = drawable.getIntrinsicWidth() / 30;
}
drawable.setBounds(
0, 0,
drawable.getIntrinsicWidth() / width,
drawable.getIntrinsicHeight() / height);
//and now add the modified image in your overlay
overlayitem[i].setMarker(drawable)

after you load your picture and set it to imageview
you can use layoutparamsto size your image to match_parent
like this
android.view.ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.width =MATCH_PARENT;
layoutParams.height =MATCH_PARENT;
imageView.setLayoutParams(layoutParams);

Related

How to resize an image to fit multiple screen densities

I need to add an avatar to a grid item.
I want to know how to handle the resizing of an image chosen from the phones gallery. Once chosen, I imagine some resizing will be needed, to fit it into the grid.
However, do I need to store a resized image for each screen density; store one xhdpi version and scale down for other devices, or be clever in some other way?
The reason is, the app stores this image to a cloud db and other people can download this image. They may see the image on different devices (hence the requirement of different image sizes). How should the managment of this image be processed?
I hope you find the code below useful. It will return image with reqd dimensions with minimum overhead. I have used this many times, works like charm. You can set the required dimension according to target device. Scaling will cause blur in picture but this doesn't.
private Bitmap getBitmap(Uri uri) {
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 200000; // 0.2MP
in = my_context.getContentResolver().openInputStream(uri);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true; //request only the dimesion
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
scale++;
}
Bitmap b = null;
in = my_context.getContentResolver().openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
o = new BitmapFactory.Options();
o.inSampleSize = scale;
b = BitmapFactory.decodeStream(in, null, o);
// resize to desired dimensions
int height = b.getHeight();
int width = b.getWidth();
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, (int) y, true);
b.recycle();
b = scaledBitmap;
System.gc();
} else {
b = BitmapFactory.decodeStream(in);
}
in.close();
return b;
} catch (IOException e) {
return null;
}
}
android:scaleType="fitXY"
android:layout_gravity="center"
Will scale an image and center it Size the Size a container to fill_parent with and it should do just that.
You can put your images to drawable (without creating xhdpi,hdpi,mdpi,ldpi...) (global images).
Then you can create 4 same layouts for different screensizes . All of your layout can use the images in your drawable director. So you can resize your image easly.

Image Quality distort when minimize the height and width of bitmap

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);

Android - Setting background on canvas using PNG file

I'm trying to set a .PNG file as background on Canvas in my app. I've made an image 480 x 800 and used this method:
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
R.drawable.image_1), 0, 0, null);
I've started an emulator (WVGA800) but my image looks greater than screen of the device.
How do I resize this image or what kind of methods should I use to make this image well-matched.
Secondly, is there any way to make backgrounds like this universal for devices with different screen resolutions?
Thank you in advance.
Try this one ...
Set bitmap
Bitmap mFinalbitmap= BitmapFactory.decodeResource(getResources(), R.drawable.image_1);
Resize bitmap as per your width and height
mFinalbitmap= resizeImage(mFinalbitmap, width ,height);
Set Canvas of Bitmap
canvas.drawBitmap(mFinalbitmap, 0, 0, null);
Resize Function: As per maintain x and y of image
public Bitmap resizeImage(Bitmap image,int maxWidth, int maxHeight)
{
Bitmap resizedImage = null;
try {
int imageHeight = image.getHeight();
if (imageHeight > maxHeight)
imageHeight = maxHeight;
int imageWidth = (imageHeight * image.getWidth())
/ image.getHeight();
if (imageWidth > maxWidth) {
imageWidth = maxWidth;
imageHeight = (imageWidth * image.getHeight())
/ image.getWidth();
}
if (imageHeight > maxHeight)
imageHeight = maxHeight;
if (imageWidth > maxWidth)
imageWidth = maxWidth;
resizedImage = Bitmap.createScaledBitmap(image, imageWidth,
imageHeight, true);
} catch (OutOfMemoryError e) {
e.printStackTrace();
}catch(NullPointerException e)
{
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return resizedImage;
}
where did you put the image? if it's in the drawable or the drawable-mdpi , it will be larger than what you've told , since WVGA800 has a high density (hdpi) .
even if you put it on the drawable-hdpi folder , it will work for WVGA800 , but it might not show well on other devices , which have different resolutions and aspect ratio .
you need to handle the scaling and keeping of aspect ratio (if you wish) . otherwise , you will have the same problems on other devices.
The easiest way:
declare static Bitmap in your class:
Bitmap bitmap;
setup the resized bitmap, for example you want resized bitmap to 100x100:
private void initBitmap(){
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.Your_bitmap);
bitmap = Bitmap.createScaledBitmap(bitmap, 100,100,true);
}
and call method in constructor

Android WallpaperManager crops image

I am working on a simple wallpaper app of some images that I have. They are .png files in drawable folders.
Here are some code snippets:
WallpaperManager myWallpaperManager = WallpaperManager.getInstance(getApplicationContext());
....
myWallpaperManager.setResource(R.drawable.image1);
No matter what size or resolution I seem to use, when the wallpaper is set it crops the original image. When I use the same image as a background it is the correct size and shows the entire image. I thought it might be a problem with my emulator so I have tried running it on an actual device (HTC eris) and I am having the same problem. I have made the image the screen size and resolution for the eris and it is still cropping it. I then made the image only one inch high and a resolution of 100 dpi. It was very pixelated on the eris, but still cropped the image.
Any help would be greatly appreciated.
I attempted to add some images to show the before and after, but as a newer user I was prevented from doing so.
Check the values returned by http://developer.android.com/reference/android/app/WallpaperManager.html#getDesiredMinimumWidth() and http://developer.android.com/reference/android/app/WallpaperManager.html#getDesiredMinimumHeight() and try to use these values as the dimensions of your wallpaper.
Maybe I can help.
// 1. Get screen size.
DisplayMetrics metrics = new DisplayMetrics();
Display display = getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
final int screenWidth = metrics.widthPixels;
final int screenHeight = metrics.heightPixels;
// 2. Make the wallpaperManager fit the screen size.
final WallpaperManager wallpaperManager = WallpaperManager.getInstance(ViewWallpaperActivity.this);
wallpaperManager.suggestDesiredDimensions(screenWidth, screenHeight);
// 3. Get the desired size.
final int width = wallpaperManager.getDesiredMinimumWidth();
final int height = wallpaperManager.getDesiredMinimumHeight();
// 4. Scale the wallpaper.
Bitmap bitmap = getBitmap(); // getBitmap(): Get the image to be set as wallpaper.
Bitmap wallpaper = Bitmap.createScaledBitmap(bitmap, width, height, true);
// 5. Set the image as wallpaper.
try {
wallpaperManager.setBitmap(wallpaper);
} catch (IOException e) {
e.printStackTrace();
}
Note that you should call suggestDesiredDimensions, then call getDesiredMinimumWidth and getDesiredMinimumHeight to get the size to be scaled to.
I had the same problem. I made an image that is the size of the screen and adding padding to the image so that it is as large as the WallpaperManager getDesiredMinimumWidth() and getDesiredMinimumHeight().
It seemed better to have some code automatically add the padding so that is what I used below. Make sure the image is the same size as the screen.
private void setWallpaper() {
try {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
//import non-scaled bitmap wallpaper
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap wallpaper = BitmapFactory.decodeResource(getResources(), R.drawable.wallpaper, options);
if (wallpaperManager.getDesiredMinimumWidth() > wallpaper.getWidth() &&
wallpaperManager.getDesiredMinimumHeight() > wallpaper.getHeight()) {
//add padding to wallpaper so background image scales correctly
int xPadding = Math.max(0, wallpaperManager.getDesiredMinimumWidth() - wallpaper.getWidth()) / 2;
int yPadding = Math.max(0, wallpaperManager.getDesiredMinimumHeight() - wallpaper.getHeight()) / 2;
Bitmap paddedWallpaper = Bitmap.createBitmap(wallpaperManager.getDesiredMinimumWidth(), wallpaperManager.getDesiredMinimumHeight(), Bitmap.Config.ARGB_8888);
int[] pixels = new int[wallpaper.getWidth() * wallpaper.getHeight()];
wallpaper.getPixels(pixels, 0, wallpaper.getWidth(), 0, 0, wallpaper.getWidth(), wallpaper.getHeight());
paddedWallpaper.setPixels(pixels, 0, wallpaper.getWidth(), xPadding, yPadding, wallpaper.getWidth(), wallpaper.getHeight());
wallpaperManager.setBitmap(paddedWallpaper);
} else {
wallpaperManager.setBitmap(wallpaper);
}
} catch (IOException e) {
Log.e(TAG,"failed to set wallpaper");
}
}

Android how to create runtime thumbnail

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()));

Categories

Resources