我花了很多时间来了解如何在没有内存不足异常的情况下缩放图像,我想分享我的知识,我编写了将图像(从大到小)缩放到精确大小的函数。算法是:
- 我们使用尽可能匹配的快速算法缩放图像,但图像的尺寸仍应大于所需的尺寸。
- 我们将图像缩放到精确的结果大小。
该功能注释很好,因此很容易理解。如果您发现错误或者您知道如何使其更正确和更快,请发表评论。
我花了很多时间来了解如何在没有内存不足异常的情况下缩放图像,我想分享我的知识,我编写了将图像(从大到小)缩放到精确大小的函数。算法是:
该功能注释很好,因此很容易理解。如果您发现错误或者您知道如何使其更正确和更快,请发表评论。
享受!
//this function change image size(from big to small) using low memory(as possible)
//the bigger side of result image will equals to IMAGE_BIGGER_SIDE_SIZE
//and second side will be scaled proportionally
//for example if you have image 800x400 and call decodeBitmapSize(bm, 200)
//you will receive image 200x100
//algorithm:
//1. we scale image using quick algorihtm as match as possible,
// but image will still has sizes more then required
//2. we scale image to exactly result size
public static Bitmap decodeBitmapSize(Bitmap bm, int IMAGE_BIGGER_SIDE_SIZE){
//we will return this Bitmap
Bitmap b = null;
//convert Bitmap to byte[]
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
//We need to know image width and height,
//for it we create BitmapFactory.Options object and do BitmapFactory.decodeByteArray
//inJustDecodeBounds = true - means that we do not need load Bitmap to memory
//but we need just know width and height of it
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, opt);
int CurrentWidth = opt.outWidth;
int CurrentHeight = opt.outHeight;
//there is function that can quick scale images
//but we need to give in scale parameter, and scale - it is power of 2
//for example 0,1,2,4,8,16...
//what scale we need? for example our image 1000x1000 and we want it will be 100x100
//we need scale image as match as possible but should leave it more then required size
//in our case scale=8, we receive image 1000/8 = 125 so 125x125,
//scale = 16 is incorrect in our case, because we receive 1000/16 = 63 so 63x63 image
//and it is less then 100X100
//this block of code calculate scale(we can do it another way, but this way it more clear to read)
int scale = 1;
int PowerOf2 = 0;
int ResW = CurrentWidth;
int ResH = CurrentHeight;
if (ResW > IMAGE_BIGGER_SIDE_SIZE || ResH > IMAGE_BIGGER_SIDE_SIZE) {
while(1==1)
{
PowerOf2++;
scale = (int) Math.pow(2,PowerOf2);
ResW = (int)((double)opt.outWidth / (double)scale);
ResH = (int)((double)opt.outHeight / (double)scale);
if(Math.max(ResW,ResH ) < IMAGE_BIGGER_SIDE_SIZE)
{
PowerOf2--;
scale = (int) Math.pow(2,PowerOf2);
ResW = (int)((double)opt.outWidth / (double)scale);
ResH = (int)((double)opt.outHeight / (double)scale);
break;
}
}
}
//Decode our image using scale that we calculated
BitmapFactory.Options opt2 = new BitmapFactory.Options();
opt2.inSampleSize = scale;
b = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, opt2);
//calculating new width and height
int w = b.getWidth();
int h = b.getHeight();
if(w>=h)
{
w = IMAGE_BIGGER_SIDE_SIZE;
h =(int)( (double)b.getHeight() * ((double)w/b.getWidth()));
}
else
{
h = IMAGE_BIGGER_SIDE_SIZE;
w =(int)( (double)b.getWidth() * ((double)h/b.getHeight()));
}
//if we lucky and image already has correct sizes after quick scaling - return result
if(opt2.outHeight==h && opt2.outWidth==w)
{
return b;
}
//we scaled our image as match as possible using quick method
//and now we need to scale image to exactly size
b = Bitmap.createScaledBitmap(b, w,h,true);
return b;
}