I want to scale image to fit screen width and keep aspect ratio
if image height is smaller than screen height. I want to strength
it.
if image height is larger than screen height. I want to crop it.
I google for it but set scaleType to FitXY & AdjustViewInBounds doesn't work.
I test with 50x50 image and it's not working
// Use createScaledBitmap will cause OOM, so I set image to imageView first.
ImageView image= (ImageView) mPageView.findViewById(R.id.image);
// Set image to get IntrinsicWidth & IntrinsicHeight
image.setImageResource(imageDrawable);
// Change scale type to matrix
image.setScaleType(ImageView.ScaleType.MATRIX);
// Calculate bottom crop matrix
Matrix matrix = getBottomCropMatrix(mContext, image.getDrawable().getIntrinsicWidth(), image.getDrawable().getIntrinsicHeight());
// Set matrixx
image.setImageMatrix(matrix);
// Redraw image
image_image.invalidate();
And my matrix use following method
Matrix matrix = new Matrix();
// Get screen size
int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
int screenHeight = context.getResources().getDisplayMetrics().heightPixels;
// Get scale to match parent
float scaleWidthRatio = screenWidth / imageWidth;
float scaleHeightRatio = screenHeight / imageHeight;
// screenHeight multi by width scale to get scaled image height
float scaledImageHeight = imageHeight * scaleWidthRatio;
// If scaledImageHeight < screenHeight, set scale to scaleHeightRatio to fit screen
// If scaledImageHeight >= screenHeight, use width scale as height scale
if (scaledImageHeight >= screenHeight) {
scaleHeightRatio = scaleWidthRatio;
}
matrix.setScale(scaleWidthRatio, scaleHeightRatio);
I don't know where I am wrong. It just leave some blank at the bottom.
========
Update. I found out the problem. My matrix is right. The blank at the bottom is soft navigation bar. Use following method will get wrong value.
getResources().getDisplayMetrics()
Change it to
DisplayMetrics displaymetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealMetrics(displaymetrics);
int screenWidth = displaymetrics.widthPixels;
int screenHeight = displaymetrics.heightPixels;
and it works!
Update. I found out the problem. My matrix is right. The blank at the bottom is soft navigation bar. Use following method will get wrong value.
getResources().getDisplayMetrics()
Change it to
DisplayMetrics displaymetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealMetrics(displaymetrics);
int screenWidth = displaymetrics.widthPixels;
int screenHeight = displaymetrics.heightPixels;
and it works!
Try this,
Use android:scaleType centerCrop instead of fitXY or matrix.
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
Related
I am trying to set bitmap as wallpaper. I am scaling the bitmap to the size of the screen (desired wallpaper size) before setting the wallpaper. Logging the desired size and the size of the scaled image shows confirms that the bitmap has the expected size. Still, the wallpaper gets zoomed in and the whole image isn't visible on the wallpaper. Could anyone point me in the correct direction? Here is the code I am using to scale and set the wallpaper.
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager =
(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
display.getMetrics(metrics);
final int screenWidth = metrics.widthPixels;
final int screenHeight = metrics.heightPixels;
Context thisContext = MyApplication.getApp().getApplicationContext();
WallpaperManager myWallpaperManager = WallpaperManager.getInstance(thisContext);
// myWallpaperManager.setWallpaperOffsetSteps(1, 1);
// myWallpaperManager.suggestDesiredDimensions(screenWidth, screenHeight);
// 3. Get the desired size.
final int width = myWallpaperManager.getDesiredMinimumWidth();
final int height = myWallpaperManager.getDesiredMinimumHeight();
// 4. Scale the wallpaper.
Bitmap bitmap = getBitmap();
Bitmap wallpaper = Bitmap.createScaledBitmap(bitmap, width, height, true);
Log.i("wapper", "updateWallpaper: "+width+" "+height+" "+wallpaper.getWidth()+" "+wallpaper.getHeight());
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
// sets both at same time
myWallpaperManager.setBitmap(
wallpaper,null, false,
WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM);
LogUtil.LOG_D(TAG, "completed updating wallpapers");
} else {
myWallpaperManager.setBitmap(wallpaper);
}
I am using following function to scale any image to screen width:
DisplayMetrics metrics = new DisplayMetrics();
((Activity)context)
.getWindowManager()
.getDefaultDisplay()
.getMetrics(metrics);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Calculate the ratio between height and width of Original Image
float ratio = (float) height / (float) width;
int newWidth = metrics.widthPixels; // This will be equal to screen width
float newHeight = newWidth * ratio; // This will be according to the ratio calulated
// calculate the scale
float scaleWidth = ((float) 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
Bitmap resizedBitmap
= Bitmap.createBitmap(
bitmap, 0, 0,
width, height,
matrix, true
);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
return new BitmapDrawable(resizedBitmap);
After putting some checks, the values are, metrics.widthPixels=540 and the width of new Bitmap is also 540. That means Bitmap or Imageview should use full screen width. Instead, the resulting imageviews are short of full screen width. I am including a screenshot:
As you can see in the image, the remaining blank part of the screen is shown in Black Color.
The code for creating ImageView is:
ImageView imageBanner = new ImageView(context);
imageBanner.setLayoutParams(new
LinearLayout.LayoutParams(
Globals.wrapContent,
Globals.wrapContent));
imageBanner.setBackgroundResource(R.drawable.imv_banner);
new SyncImage(context, imageBanner, urlImage).execute();
Globals.wrapContent are the explicit constants which contain same values for standard Layout Params, so don't think them as different.
SyncImage the Async Class used to download and show image in ImageView.
Please provide a solution to scale the image to full screen width and image should retain its original dimension ratio.
Thank You
Ram Ram
Set Width of imageView to MatchParent instead of WrapContent and calculate height to maintain the aspect ratio of the image. Try following code to resize the image:
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int newWidth = size.x;
//Get actual width and height of image
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Calculate the ratio between height and width of Original Image
float ratio = (float) height / (float) width;
float scale = getApplicationContext().getResources().getDisplayMetrics().density;
int newHeight = (int) (width * ratio)/scale;
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
I work out the width and height of my fragment and scale its image to a specific percentage of that fragment. This works for images that need to be scaled up to meet that size but larger images seem to ignore the scales (i think they shrink a bit but not to corretc size).
I get my imahes via http asyncTask call then on onPostexecute set the imageView control src and scale the imageView. Work for smaller images, not larger ones.
The larger image is 10kb, smaller is 1kb.
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
if (result != null) {
int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, 35, getContext().getResources().getDisplayMetrics());
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, 35, getContext().getResources().getDisplayMetrics());
bmImage.setMinimumWidth(width);
bmImage.setMinimumHeight(height);
bmImage.setMaxWidth(width);
bmImage.setMaxHeight(height);
}
I see the dimensions being calc'c correctly and afterwards set correctly in the imageView )(minimum and maxheight) but the mDrawable attr is big so perhaps this is an indicator of worng attr being set?
https://argillander.wordpress.com/2011/11/24/scale-image-into-imageview-then-resize-imageview-to-match-the-image/
private void scaleImage(ImageView view, int boundBoxInDp)
{
// Get the ImageView and its bitmap
Drawable drawing = view.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) boundBoxInDp) / width;
float yScale = ((float) boundBoxInDp) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
// Apply the scaled bitmap
view.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
I have many icons in 512 x 512 resolution and i want to set them
on ImageButtons. Ofcourse i dont want the ImageButtons to be
512 x 512 big i want them to be as big as its optimal for the
screen size of the current device.
I create my buttons like this:
this.buttonMeasure = new ImageButton(this);
this.buttonMeasure.setImageResource(R.drawable.ic_measure);
this.buttonMeasure.setOnLongClickListener(this);
How can i scale down the images to an optimal size dependent
to the screen size of the device programmatically?
I tried this but that leads to an outOfMemoryError:
public static Bitmap getScaledBitMap(Context context, Drawable sourceDrawable) {
Bitmap sourceBitmap = ((BitmapDrawable)sourceDrawable).getBitmap();
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(metrics);
int width = sourceBitmap.getWidth();
int height = sourceBitmap.getHeight();
float scaleWidth = metrics.scaledDensity;
float scaleHeight = metrics.scaledDensity;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true);
}
I don't think you will be needing this at all. You specify the size of your ImageButton using properties like android:layout_width and android:layout_height for different layouts in folders, Similarly you need to place copy of images of various resolutions in respective folders with the same name.The appropriate image is automatically picked up by android itself at run time.
I have a Bitmap that is larger than the ImageView that I'm putting it in. I have the ScaleType set to center_inside. How do I get the dimensions of the scaled down image?
Ok. I probably should have been clearer. I needed the height and width of the scaled Bitmap before it's ever drawn to the screen so that I could draw some overlays in the correct position. I knew the position of the overlays in the original Bitmap but not the scaled. I figured out some simple formulas to calculate where they should go on the scaled Bitmap.
I'll explain what I did in case someone else may one day need this.
I got the original width and height of the Bitmap. The ImageView's height and width are hard-coded in the xml file at 335.
int bitmap_width = bmp.getWidth();
int bitmap_height = bmp.getHeight();
I determined which one was larger so that I could correctly figure out which one to base the calculations off of. For my current example, width is larger. Since the width was scaled down to the the width of the ImageView, I have to find the scaled down height. I just multiplied the ratio of the ImageView's width to the Bitmap's width times the Bitmap's height. Division is done last because Integer division first would have resulted in an answer of 0.
int scaled_height = image_view_width * bitmap_height / bitmap_width;
With the scaled height I can determine the amount of blank space on either side of the scaled Bitmap by using:
int blank_space_buffer = (image_view_height - scaled_height) / 2;
To determine the x and y coordinates of where the overlay should go on the scaled Bitmap I have to use the original coordinates and these calculated numbers. The x coordinate in this example is easy. Since the scaled width is the width of the ImageView, I just have to multiply the ratio of the ImageView's width to the Bitmap's width with the original x coordinate.
int new_x_coord = image_view_width * start_x / bitmap_width;
The y coordinate is a bit trickier. Take the ratio of the Bitmap's scaled height to the Bitmap's original height. Multiply that value with the original y coordinate. Then add the blank area buffer.
int new_y_coord = scaled_height * start_y / bitmap_height + blank_space_buffer;
This works for what I need. If the height is greater than the width, just reverse the width and height variables.
Here's how I do it:
ImageView iv = (ImageView)findViewById(R.id.imageview);
Rect bounds = iv.getDrawable().getBounds();
int scaledHeight = bounds.height();
int scaledWidth = bounds.width();
You can use Drawable's getIntrinsicWidth() or height method if you want to get the original size.
EDIT: Okay, if you're trying to access these bounds at the time onCreate runs, you'll have to wait and retrieve them till after the layout pass. While I don't know that this is the best way, this is how I've been able to accomplish it. Basically, add a listener to the ImageView, and get your dimensions just before it's drawn to the screen. If you need to make any layout changes from the dimensions you retrieve, you should do it within onPreDraw().
ImageView iv = (ImageView)findViewById(R.id.imageview);
int scaledHeight, scaledWidth;
iv.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
Rect rect = iv.getDrawable().getBounds();
scaledHeight = rect.height();
scaledWidth = rect.width();
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
Try this code:
final ImageView iv = (ImageView) findViewById(R.id.myImageView);
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Toast.makeText(MyActivity.this, iv.getWidth() + " x " + iv.getHeight(), Toast.LENGTH_LONG).show();
iv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
Otherwise you can use onSizeChange() by making this view a custom one.