Here is the method offered by this link from google.
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
If there is a 500*500 image which required to be resized to 100*100, the result of this snippet is 4 because they use halfWidth and halfHeight. But if I understand it correctly, the result should be 8. I think the code should be modified as:
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
inSampleSize *= 2;
Can anyone explain this? I found they had modified this code several times, but seems still wrong?
The idea is that the image is scaled down in 2 steps: first by the highest power of 2 less than or equal to the required down-sampling factor, and then by an amount less than 2 to end up with the final requested image size.
If there is a 500*500 image which required to be resized to 100*100, the result of this snippet is 4 because they use halfWidth and halfHeight. But if I understand it correctly, the result should be 8.
If the scale factor is 8, then a 500x500 pixel image will be scaled down to 62x62 pixels, and would then need to be scaled up to the requested size of 100x100 pixels.
As the code comment says:
Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width larger than the requested height and width.
This would be 4, because then you will end up with an image of 125x125 pixels, which is larger than the requested height and width of 100x100 pixels. The idea is that you want to end up scaling down in the last step, rather than scaling down too far and then having to scale back up and getting a blurry image.
The required down-sampling factor is 5, and the highest power of 2 less than or equal to that is 4.
Related
I am following this link to load large images. So according to this link I need to fix a target height and width i.e a target resolution and image resolution should not exceed this target resolution, if it exceeds then I need to scale it down. So according to the function calculateInSampleSize:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
inSampleSize is calculated using half height and width. My question is why we are making computation on the basis of half height and haldf width, why not on height on width like this:
while ((height / inSampleSize) >= reqHeight
&& (width / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
EDIT:
I think my question has been misunderstood. I want to ask why we are not comparing reqHeight and reqWidth with full height and width of the image in above example. Why Android developer page has used halfWidth and halfImage in above example??
You can find here that in documentation, when sampling happens, it returns an image that is 1/2^n the width/height of the original image. So, the sampled image depends on height and width to sample it.
We works on the half of the height and width, as when we divide height and width by 2 it is like we are doing sampling by 2 and when this half of the image is smaller than the requested height and width so we do not need to sample the original image as if we did it the sampled image will be pixeled "blurred".
I am making an Android app. Which will be using images which will cover the width of the screen. And the width/height ratio should be 16:9. The images would be loaded over the internet. What should be the size of the image stored on the server so that it has to be suitable for smallest devices to the largest devices. I don't want to keep very large size because that could reduce the performance.
You can keep image according to this screen and it will work on all screen sizes.
Normal xhdpi - 640×960 (1280×1920 in design)
You can find out the solution in the below link.
enter link description here
here you can find out the method
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;}
You can directly use like this
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
I have a set of image files stored in internal storage, each file size is about 750 KB. I need to create a 360 degrees animation like with this images, so, I load each image in a list, while I'm doing this process an out of memory exception appears.
I have been reading about bitmap processing on Android, but in this case is not about resize bitmap dimensions, the dimensions are OK (600, 450) because its a tablet application, is about image quality I think.
Is there a way to reduce the memory each bitmap takes?.
It is not possible without reducing image dimensions.
All images with the same dimensions require same amount of RAM, regardless it size on disk and compression. Graphics adapter don't understand different image types and compression and it needs only uncompressed raw array of pixels. And it size is constant
For example
size = width * height * 4; // for RGBA_8888
size = width * height * 2; // for RGB_565
So you should reduce image dimensions or use caching on the disk and remove bitmaps from the RAM that are currently invisible and reload from disk when needed.
There is a great resource on how to do this here:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Basically you need to load a bitmap at a different resolution using these two functions:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
Then set the image as follows:
imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
R.drawable.my_image_resource,
imageView.getWidth(),
imageView.getHeight()));
Hope that helps!
I have images more than 6000px height. Whenever I tried to display these images I got out of memory exception.
I have seen many links but none of matches my need. Because mostly people suggesting image re-sizing solution. But If I'll re-size my image than I am unable to read the text in images due to poor quality.
I want some help in creating some code that can open an image without re-sizing it also with zooming effect.
Any help would be really appreciated.
Try to use google recommendation for this problem.
For avoid OOM you need to implement this block of code:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
Try using a WebView to show the image, instead of ImageView
I would suggest you "cut" this image in 3 smaller ones and then load them as three images: the first one will be at y:0 and be height 2000px, the second one y:2000px and height 2000px and the third one at y: 4000px.
Do you think this could work?
Good luck
try this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen_view);
imageView = (ImageView) findViewById(R.id.full_image_view);
imageView.setImageBitmap(decodeSampledBitmapFromResource(imgpath));
}
//Load a bitmap from a resource with a target size
Bitmap decodeSampledBitmapFromResource(String res) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(res, options);
//Calculate display dimention for maximum reqwidth and reqheigth
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int xDim = size.x;
int yDim = size.y;
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, xDim, yDim);
// Decode bitmap with inSampleSize se5t
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(res, options);
}
int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int inSampleSize = 1; //Default subsampling size
// Calculate the largest inSampleSize value
while ((options.outHeight / inSampleSize) > reqHeight
|| (options.outWidth / inSampleSize) > reqWidth) {
inSampleSize += 1;
}
return inSampleSize;
}
In Application manifest file tag set largeHeap true
<application
android:largeHeap="true"
Also Use Picasso or Glide to load image in ImageView
In one of the tutorials Google proposes the following scaling bitmap algorithm to make a bitmap fit a given window:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
( http://developer.android.com/training/displaying-bitmaps/load-bitmap.html )
I don't understand the if(width > height) part
Suppose a bitmap has its height of 5 and its width of 2. Then suppose a window has the height of 1 and the width of 1. It looks like the bitmap won't fit the window then.
It makes sure that the size ratio is respected