压缩策略
分辨率与质量压缩或者组合压缩。
iOS
@implementation UIImage (SuperCompress)
+ (UIImage*)resizableImage:(NSString *)name
{
UIImage *normal = [UIImage imageNamed:name];
CGFloat imageW = normal.size.width * 0.5;
CGFloat imageH = normal.size.height * 0.5;
return [normal resizableImageWithCapInsets:UIEdgeInsetsMake(imageH, imageW, imageH, imageW)];
}
/**
* 压缩上传图片到指定字节
*
* @param image 压缩的图片
* @param maxLength 压缩后最大字节大小
*
* @return 压缩后图片的二进制
*/
+ (NSData *)compressImage:(UIImage *)image toMaxLength:(NSInteger)maxLength maxWidth:(NSInteger)maxWidth{
NSAssert(maxLength > 0, @"图片的大小必须大于 0");
NSAssert(maxWidth > 0, @"图片的最大边长必须大于 0");
CGSize newSize = [self scaleImage:image withLength:maxWidth];
UIImage *newImage = [self resizeImage:image withNewSize:newSize];
CGFloat compress = 0.9f;
NSData *data = UIImageJPEGRepresentation(newImage, compress);
while (data.length > maxLength && compress > 0.01) {
compress -= 0.02f;
data = UIImageJPEGRepresentation(newImage, compress);
}
return data;
}
/**
* 获得指定size的图片
*
* @param image 原始图片
* @param newSize 指定的size
*
* @return 调整后的图片
*/
+ (UIImage *) resizeImage:(UIImage *) image withNewSize:(CGSize) newSize{
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
/**
* 通过指定图片最长边,获得等比例的图片size
*
* @param image 原始图片
* @param imageLength 图片允许的最长宽度(高度)
*
* @return 获得等比例的size
*/
+ (CGSize) scaleImage:(UIImage *) image withLength:(CGFloat) imageLength{
CGFloat newWidth = 0.0f;
CGFloat newHeight = 0.0f;
CGFloat width = image.size.width;
CGFloat height = image.size.height;
if (width > imageLength || height > imageLength){
if (width > height) {
newWidth = imageLength;
newHeight = newWidth * height / width;
}else if(height > width){
newHeight = imageLength;
newWidth = newHeight * width / height;
}else{
newWidth = imageLength;
newHeight = imageLength;
}
}else{
return CGSizeMake(width, height);
}
return CGSizeMake(newWidth, newHeight);
}
@end
Android
package org.skyfox.pssprinter.Manager;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ImageCompresser {
/**
* 压缩图片到指定宽高,并进行质量压缩,最终大小保持在maxDiskSize K以下
*
* @param sourceBm
* @param targetWidth
* @param targetHeight
* @param maxDiskSize
* @return
*/
public static Bitmap compressImage(Bitmap sourceBm, float targetWidth, float targetHeight,float maxDiskSize) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
// 可删除
newOpts.inPurgeable = true;
// 可共享
newOpts.inInputShareable = true;
// 转成数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
sourceBm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] temp = baos.toByteArray();
// 此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = targetHeight;
float ww = targetWidth;
// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;// be=1表示不缩放
// 如果宽度大的话根据宽度固定大小缩放
if (w > h && w > ww) {
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {
// 如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0) {
be = 1;
}
// 设置缩放比例
newOpts.inSampleSize = be;
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
// 压缩好比例大小后再进行质量压缩
return compressImageWitDisksize(bitmap,maxDiskSize);
}
/**
* @Description 质量压缩方法
* @param image
* @param maxDiskSize 最大kb尺寸
* @return
*/
public static Bitmap compressImageWitDisksize(Bitmap image,float maxDiskSize) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
// 循环判断如果压缩后图片是否大于100kb,大于继续压缩
while (baos.toByteArray().length / 1024 > maxDiskSize) {
// 重置baos即清空baos
baos.reset();
// 这里压缩options%,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
// 每次都减少10
options -= 10;
}
// 把压缩后的数据baos存放到ByteArrayInputStream中
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
// 把ByteArrayInputStream数据生成图片
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
/**
* 只进行分辨率压缩,不进行图片的质量压缩
*
* @param sourceBm
* @param targetWidth
* @param targetHeight
* @return
*/
public static Bitmap compressImageWithResolution(Bitmap sourceBm, float targetWidth, float targetHeight) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
// 可删除
newOpts.inPurgeable = true;
// 可共享
newOpts.inInputShareable = true;
// 转成数组
ByteArrayOutputStream baos = new ByteArrayOutputStream();
sourceBm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] temp = baos.toByteArray();
// 此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = targetHeight;
float ww = targetWidth;
// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
// be=1表示不缩放
int be = 1;
if (w > h && w > ww) {
// 如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {
// 如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0) {
be = 1;
}
// 设置缩放比例
newOpts.inSampleSize = be;
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length, newOpts);
// 压缩好比例大小后再进行质量压缩
return bitmap;
}
/**
* 通过uri获取图片并进行压缩
*
* @param uri
*/
public static Bitmap getBitmapFormUri(Activity context, Uri uri,float maxSize) throws FileNotFoundException, IOException {
// InputStream input = context.getContentResolver().openInputStream(url);
// Bitmap bitmap = BitmapFactory.decodeStream(input);
// input.close();
InputStream input = context.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return compressImageWitDisksize(bitmap,maxSize);//再进行质量压缩
}
}