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
Related
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 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).
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.
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);
I like to resize an bitmap,if it is big make it small and place it on an specific location in the surface view, I need to get device width and height and then bitmap size and place them in an surface view and then take another image resize it and place it in any location has i like.
How to know the location co ordinates first(to place second image - this should be device independent if larger/smaller screen layout should not change)
and how to scale an big bitmap and set as background so i can draw an image over it.
my code :
final int canvasWidth = getWidth();
final int canvasHeight = getHeight();
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
float scaleFactor = Math.min( (float)canvasWidth / imageWidth,
(float)canvasHeight / imageHeight );
Bitmap scaled = Bitmap.createScaledBitmap( img,
(int)(scaleFactor * imageWidth),
(int)(scaleFactor * imageHeight),
true );
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(scaled, 10, 10, null);
this scale the big image but it doesn't fit the whole screen "img - bitmap is like an background image "
Someone can help me to understand the resize basics (I'm new so finding hard to understand resizing) to resize image to fit screen and resize any image to smaller one and place it in any location i like .
Store your bitmap as a source for manipulation and display it using ImageView:
Bitmap realImage = BitmapFactory.decodeFile(filePathFromActivity.toString());
Bitmap newBitmap = scaleDown(realImage, MAX_IMAGE_SIZE, true);
imageView.setImageBitmap(newBitmap);
//scale down method
public static Bitmap scaleDown(Bitmap realImage, float maxImageSize,
boolean filter) {
float ratio = Math.min(
(float) maxImageSize / realImage.getWidth(),
(float) maxImageSize / realImage.getHeight());
int width = Math.round((float) ratio * realImage.getWidth());
int height = Math.round((float) ratio * realImage.getHeight());
Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width,
height, filter);
return newBitmap;
}
And set your ImageView's width and height to "fill_parent".