压缩策略
分辨率与质量压缩或者组合压缩。
iOS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
@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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
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);//再进行质量压缩 } } |