I want to create a scaled bitmap, but I seemingly get a dis-proportional image. It looks like a square while I want to be rectangular.
My code:
Bitmap resizedBitmap = Bitmap.createScaledBitmap(myBitmap, 960, 960, false);
I want the image to have a MAX of 960. How would I do that? Setting width to null doesn't compile. It's probably simple, but I can't wrap my head around it. Thanks
If you already have the original bitmap in memory, you don't need to do the whole process of inJustDecodeBounds, inSampleSize, etc. You just need to figure out what ratio to use and scale accordingly.
final int maxSize = 960;
int outWidth;
int outHeight;
int inWidth = myBitmap.getWidth();
int inHeight = myBitmap.getHeight();
if(inWidth > inHeight){
outWidth = maxSize;
outHeight = (inHeight * maxSize) / inWidth;
} else {
outHeight = maxSize;
outWidth = (inWidth * maxSize) / inHeight;
}
Bitmap resizedBitmap = Bitmap.createScaledBitmap(myBitmap, outWidth, outHeight, false);
If the only use for this image is a scaled version, you're better off using Tobiel's answer, to minimize memory usage.
Your image is square because you are setting width = 960 and height = 960.
You need to create a method where you pass the size of the image you want like this: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
In code this looks like:
public static Bitmap lessResolution (String filePath, int width, int height) {
int reqHeight = height;
int reqWidth = width;
BitmapFactory.Options options = new BitmapFactory.Options();
// First decode with inJustDecodeBounds=true to check dimensions
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
bmpimg = Bitmap.createScaledBitmap(srcimg, 100, 50, true);
Related
I'm trying to load an image from the internet using glide, but the size is too big for my application(The image size in dimensions 400X400 and the memory allocating is 352KB and the size of ImageView is same as the image dimensions),
I have tried to decode the bitmap after loading it and then apply it to the ImageView but it not working,
anyone can help me with this problem.
this is my Glide code:
Glide.with(this)
.asBitmap()
.load(url)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
int byteCount = resource.getAllocationByteCount();
int sizeInKB = (resource.getRowBytes() * resource.getHeight()) / 1024;
int sizeInMB = sizeInKB / 1024;
Glide.with(TestActivity.this)
.asBitmap()
.load(decodeSampledBitmapFromResource(resource, 400, 400))
.into(ss2);
sizeText.setText(sizeInKB + " KB");
}
});
and this is the code for decoding the bitmap:
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(Bitmap bitmap, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
ByteArrayOutputStream blob = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, blob);
byte[] bitmapData = blob.toByteArray();
BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bitmap.compress(Bitmap.CompressFormat.PNG, 0, blob);
byte[] bitmapData2 = blob.toByteArray();
return BitmapFactory.decodeByteArray(bitmapData2, 0, bitmapData2.length, options);
}
The size of an image depends of many things, one of them is it dimension and the quality; by default the quality format in Glide V4 is ARGB_8888 so if you are using it you can change it to RGB_565 that is smaller. You can found this and more information here.
In Picasso you can do it with .fit(), in Glide you have centerCrop() or fitCenter()
This methods resize the image to the container associated.
im trying to adapt a method to prevent an outOfMemoryError when reading from an internet bitmap. Do I use it right? Isnt the stream read twice from internet?
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
URL url = new URL(imageUrl);
InputStream inputStream = url.openConnection().getInputStream();
BitmapFactory.decodeStream(inputStream, null, options);
// Calculate inSampleSize
int coverDimensions = CommonTasks.getDisplayMinSize(getActivity());
options.inSampleSize = calculateInSampleSize(options, coverDimensions, coverDimensions);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(inputStream, null, options);
private 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;
}
In the while use || to keep both width and height withing bounds. And no, you cannot reread an InputStream.
No. Theoretically you could use reset() but internet is sequential I/O:
boolen canReset = inputStream.markSupported();
if (canReset) {
inputStream.mark(Integer.MAX_VALUE);
}
... first read
if (canReset) {
inputStream.reset();
}
... second read
Instead of a boolean flag, catching an IOException on reset would be easier: it might be thrown anyway when the read limit is exceeded for instance.
Simply reread. The second time it might come from cache.
I want to store bitmap in to SD card but when I pick large bitmap I faced "out of memory error" problem.
My code:
FileOutputStream out = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
I read many likely questions but they answers not solve my problem because all of answers says you must save bitmap in low quality.
Pleas don't answer me to reduce quality because I need to store bitmap in high quality.
You can check the available memory size before loading bitmap, by
BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
btmapOptions.inJustDecodeBounds = true;
then if the memory exceeds, you have to resize the bitmap, finaly set
BitmapFactory.Options btmapOptions = new BitmapFactory.Options();
btmapOptions.inJustDecodeBounds = false;
to load the bitmap.
For increasing allocated memory, you can use largeHeap set to true but which just increase the allocated memory,
Sample codeto resize bitmap,
public 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;
}
I am downloading an image and i want to display it in a RelativeLayout as background. However since android has so man different screens, i am finding it difficult to resize the image according to screen size.
Here is my layout
[Top Bar]
[Relative Layout] ..width= fill_parent , height = wrap_content
[ListView]
In my resizing i am using this code
bitmap = Utilities.decodeSampledBitmap(in, imageView.getWidth(), imageView.getWidth());
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)
{
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmap(InputStream in, int reqWidth, int reqHeight)
{
if (in != null)
{
byte[] image;
try {
image = readFully(in);
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeByteArray(image, 0, image.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(image, 0, image.length, options);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
else
return null;
}
However these are still stretching images and only in hdpi it seems something better, ldpi is worse, mdpi seems fine , xhdpi is bad too. Stetching is effecting. I can't fix the size of RelativeLayout or Use ImageView because It will then show space between Image and ListView..
What method should I adopt.
I suggest you not using the background image, but use ImageView and set his ScaleType to meet your needs.
I'm trying to create a resized Bitmap from an Uri.
While searching the web I saw couple of partial examples and only got confused.
What is the correct way to create this task?
Thanks.
There's a very nice resource article you should read:
http://developer.android.com/training/displaying-bitmaps/index.html
here some code, taken from this article:
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);
}
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);
}
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger
// inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down
// further.
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
Matrix matrix = new Matrix();
matrix.postScale(xScale, yScale);
Bitmap newBitmap = Bitmap.createBitmap(oldBitmap, 0, 0, orgWidth, orgHeight, matrix, true);
where xScale and yScale should be negative numbers if you want to reduce the size else positive :)