压缩策略
分辨率与质量压缩或者组合压缩。
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);//再进行质量压缩 } }