AFAIK, the inSampleSize attribute of BitmapFactory.options will read a sampled image as per the inSampleSize value. Eg: If value is 4, it will effectively read 1/16 pixels and thus memory required to load it will drastically reduce.
Here in fact, it is maintaining the aspect ratio in the sense that it has skipped 1/4th pixels along height and 1/4th pixels along the width.
When I load this bitmap in a smaller ImageView, aspect ratio is maintained and it looks good. I have used the following formula to derive the inSampleSize = max(Width/reqWidth, height/reqHeight)
size of the imageview = 100dp * 100dp, I have converted 100dp to pixels as per the screen density and used that result as the reqWidth and reqHeight.
(Note: All my images are bigger than the reqWidth and reqHeight)
However If I apply another operation Bitmap.createScaledBitmap() on above reduced version of bitmap, the image gets stretched and does not look good in the View.
I am not able to understand what createScaledBitmap() exactly does?
Given a Bitmap, let's call it bmp1, the create Scaled bitmap method creates a new Bitmap from bmp1 which is upscaled/downscaled to a new size.
However, since you're doing the scaling yourself, perhaps you should simply call createBitmap() instead? That one will respect the new size you tell it to be, and won't scale the original image, which is what you want from what i understood.
Please correct me if I'm wrong, however.
Related
I have been using Picasso from a long time. Today, I am migrating to Glide. In Picasso, I used to use following loading pattern:
Picasso.get()
.load(file)
.resize(targetSize, 0)
.onlyScaleDown()
.placeholder(R.color.default_surface)
.error(R.color.default_surface_error)
.into(imageView)
According to resize(int, int) documentation,
Use 0 as desired dimension to resize keeping aspect ratio
According to onlyScaleDown() documentation,
Only resize an image if the original image size is bigger than the target size specified by resize(int, int)
Here's what I am trying:
Glide.with(imageView)
.log(this, thumbnailUrl?.toString())
.load(thumbnailUrl)
.override(600)
.placeholder(R.color.default_surface)
.error(R.color.default_surface_error)
.into(imageView)
Glide uses a default downsampling strategy when loading images using DownsampleStrategy.CENTER_OUTSIDE. It says that image is upscaled to match the overridden size such that one of the dimension (smallest?) is equal to overridden size. And, following comment:
Scales, maintaining the original aspect ratio, so that one of the image's dimensions is exactly equal to the requested size and the other dimension is greater than or equal to the requested size.
This method will upscale if the requested width and height are greater than the source width and height. To avoid upscaling, use {#link #AT_LEAST}, {#link #AT_MOST}, or {#link #CENTER_INSIDE}.
Options in DownsampleStrategy.java confused me. I don't know which one I should use. I want the large images to scale down to overridden size, and small images to never upscale. How to achieve this in Glide?
I have found an answer in Github Issue #3215 where following is suggested:
Pick a useful DownsampleStrategy, in particular CENTER_INSIDE may be what you're looking for. The default DownsampleStrategy will upscale to maximimize Bitmap re-use, but typically there's an equivalent strategy available that will not upscale.
And, DownsampleStrategy.CENTER_INSIDE fits what I wanted:
Returns the original image if it is smaller than the target, otherwise it will be downscaled maintaining its original aspect ratio, so that one of the image's dimensions is exactly equal to the requested size and the other is less or equal than the requested size. Does not upscale if the requested dimensions are larger than the original dimensions.
I was confused by the documentation for DownsampleStrategy.CENTER_INSIDE in code.
I have added an Image View, and set these values.
<ImageView
android:id="#ivNewsHeader
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop" />
I get images from server, and they are very high res images, if i add them as is, i end up getting OutOfMemoryError.
So i learnt that picasso offers a great way to tackle this. I used following, and this scale down any image which is higher than the mentioned dimensions.
Picasso.with(getApplicationContext()).load(imageURL).
resize(180, 130).
onlyScaleDown()
.into(ivNews);
Now when i choose these resize(180, 130), the performance is very good and i don't get any OutOfMemoryError, but the image quality is very poor.
So my question is how to choose resize number, and what equation should is use to put correct width-height numbers in resize() method to get the perfect image without compromising the quality and performance.
My imageView height is 250dp and width is match_parent
Specify scale value based on device size
Device width in pixel
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
Convert DP to Pixel
public static int dpToPx(int dp)
{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
Now use these two function
Picasso.with(getApplicationContext()).load(imageURL).
resize(getScreenWidth(), dpToPx(250)).
onlyScaleDown()
.into(ivNews);
I think fit() is what you need, because will crop your image to ImageView size on screen. In this case, you don't need do to any more calculations.
Picasso.with(getApplicationContext())
.load(imageURL)
.fit()
.centerInside()
.into(imageView);
Try using fit() which is measuring the dimensions of the target ImageView and internally uses resize() to reduce the image size to the dimensions of the ImageView.
Quoting from this article
I need to load some images from URI to Bitmap variables and perform some operation with them togheter. I need the bitmaps to be squared images with fixes size, scaled down and cropped. By now I use this code:
return Picasso.with(c).load(imageUri).resize(size, size).get();
but, obviously, the image will be resized without keep its aspect ratio.
I want to resize the image with these requirements:
the smaller dimension (width or height) should be equals to size
the greater dimension should be cropped to size, keep image centered
The key is using centerInside after resize. See link
Picasso.with(c).load(imageUri).resize(size, size).centerInside().get()
set your imageview height and width fix inside xml and then set image to imageview like
Picasso.with(YourActivityName.this)
.load(imageUri)
.into(imageview_id);
I do some operations with my Views that scale then trough:
imageView.setScaleX(2);
imageView.setScaleY(2);
On that ImageView I put a image that is two times greater than it, as expected when the scale is 1, the Bitmap is scaled down to the view size, my question is:
When the view is scaled up, the portion of the bitmap I see is the original image or the scaled-down image scaled up.
The difference is that if a tiny image is scaled up we lost contrast on letters, if it's the original image it wont.
When you scale an image up you're loosing quality. In you're case, you're doubling the width and height therefore, for each pixel you get 4 pixels assigned to it. The extra 3 pixels won't give you the quality you wanted.
If you want to go back to the original size you should decode the source again. This way you'll get the quality you're looking for.
is it possible to query for images from CAMERA folder with height and width?
I am querying it with only URL right now. I want to avoid loading image into Bitmap and I need to have width and height of it beforehand so I can figure out proper scaling. Right now some of the photos I load can be really large size and some can be tiny. If I set same scaling on them they don't look right. Small images get resized for no reason. Knowing width and height would solve this. Also I cannot sample load a bitmap because that causes memory issue when images are really large, like those taken with 3 megapixel camera.
Here is how I load them:
https://stackoverflow.com/questions/5710036/android-camera-folder-images-not-all-show-up
Thank you.
You should do decoding for the image without getting its whole data.
the reason it doesn't exist on the DB is that the user can always modify the images to have different dimensions than the original one.
in order to get just the minimal information of the bitmap, use something like:
public static BitmapFactory.Options getBitmapOptions(final String filePath) {
final BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, bitmapOptions);
return bitmapOptions;
}