Android图片压缩的代码实现
来源:互联网 发布:神机妙算软件打不开 编辑:程序博客网 时间:2024/05/29 03:39
参考文章:http://www.codeceo.com/article/android-image-compression.html
在App开发过程中,免不了要上传图片到Server端。考虑到大图片带来的请求时长及传输失败风险,通常情况下都会对图片进行压缩处理后再上传。目前常用的两种压缩方式是:
1.通过降低图片质量;
2.通过减小图片分辨率;
详见开篇提到的参考文章。
这里再补充一下实现过程中的注意事项:
1.图片质量Quality不能无限制过低;需要根据压缩后图片的展示区域作调整。在200x200的展示区域下,图片质量不宜低于40;
2.有些图片的Exif信息里图片原始的方向是有转向的,比如具体展示时需要根据exif里的方向信息转向90度或者180度再显示。这些信息在图片压缩时可能会被压缩掉;从而导致这些图片展示时方向不对。
下面给出的代码实现综合考虑了上述因素后,实现原理如下:
1.根据图片的最大限制值来判断是否是需要压缩;
2.压缩前,先读取图片的exif信息;如果需要转向,则先对图片进行转向处理;
3.对纠正了转向之后的图片先进行图片分辨率的压缩,再进行图片质量的压缩;
下面是具体实现:
其中方法:
ArrayList<String> compress(Context context, ArrayList<String> srcPicList)是入口方法。
package com.wuba.job.parttime.utils;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.media.ExifInterface;import android.net.Uri;import android.os.SystemClock;import android.text.TextUtils;import com.wuba.commons.AppCommonInfo;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;/** * Created by changwenna on 2016/11/25. */public class PtBitmapUtils { private final static String PT_CACHE_TEMP_PIC_PATH = AppCommonInfo.sDatadir + File.separator + "ptjob" + File.separator + "temp" + File.separator; private static int UPLOAD_MAX_FILE_SIZE = 512000;// 500K private static int UPLOAD_QUALITY_LOW = 40; public static ArrayList<String> compress(Context context, ArrayList<String> srcPicList) { ArrayList<String> destPicList = new ArrayList<>(); File file; for (int i = 0; i < srcPicList.size(); i++) { String sourceUrl = srcPicList.get(i); if (TextUtils.isEmpty(sourceUrl) || sourceUrl.startsWith("http")) { continue; } file = new File(sourceUrl); if (file.exists() && file.length() > UPLOAD_MAX_FILE_SIZE) { //超过限制,需要压缩 String procedUrl = procPicFile(context, file.getAbsolutePath()); if (TextUtils.isEmpty(procedUrl)) { //压缩失败,则返回原图 destPicList.add(sourceUrl); } File procedFile = new File(procedUrl); if (procedFile.exists()) { destPicList.add(procedFile.getAbsolutePath()); } } else{ destPicList.add(sourceUrl); } } return destPicList; } /** * 是否需要调整图片方向 * * @param filePath * @return */ public static boolean needRotate(String filePath) { try { ExifInterface exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: return true; case ExifInterface.ORIENTATION_ROTATE_270: return true; case ExifInterface.ORIENTATION_ROTATE_180: return true; } return false; } catch (IOException e) { e.printStackTrace(); return false; } } public static void rotatedBitmap(Context context, String filePath, String dstFilePath) throws IOException { File file = new File(dstFilePath); if (file.getParentFile() != null && !file.getParentFile().exists()) { file.getParentFile().mkdirs(); } ExifInterface exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); Matrix matrix = null; switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: matrix = new Matrix(); matrix.postRotate(90); break; case ExifInterface.ORIENTATION_ROTATE_270: matrix = new Matrix(); matrix.postRotate(270); break; case ExifInterface.ORIENTATION_ROTATE_180: matrix = new Matrix(); matrix.postRotate(180); break; } Bitmap bmp = getSmallBitmap(context, Uri.fromFile(new File(filePath))); if (matrix != null) { Bitmap bmp2 = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); bmp.recycle(); FileOutputStream fos = new FileOutputStream(dstFilePath); bmp2.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.close(); bmp2.recycle(); } else { FileOutputStream fos = new FileOutputStream(dstFilePath); FileInputStream fis = new FileInputStream(filePath); byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.close(); fis.close(); } } /** * 通过压缩图片质量来压缩图片 * 常用于图片上传 * * @param image * @param dstFilePath */ public static void compressImageByQuality(Bitmap image, String dstFilePath) { if (image == null) { return; } if (TextUtils.isEmpty(dstFilePath)) { return; } File sourecFile = new File(dstFilePath); if (!sourecFile.exists()) { return; } int quality = 100; ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, quality, baos); while (baos.toByteArray().length / 1024 > UPLOAD_MAX_FILE_SIZE) { baos.reset(); try { image.compress(Bitmap.CompressFormat.JPEG, quality, baos); } catch (Exception e) { e.printStackTrace(); break; } if (quality <= UPLOAD_QUALITY_LOW) { break; } quality -= 10; } image.recycle(); ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null); FileOutputStream fos; try { fos = new FileOutputStream(dstFilePath); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } bitmap.recycle(); } /** * 默认先进行像素压缩,如果还达高于大小的限制,再进行图片质量的压缩 * * @param srcPath * @param dstFilePath */ public static void compressImage(String srcPath, String dstFilePath) { if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(dstFilePath)) { return; } File sourecFile = new File(srcPath); if (!sourecFile.exists()) { return; } if (sourecFile.length() / 1024 <= UPLOAD_MAX_FILE_SIZE) { //原始文件不需要压缩 return; } BitmapFactory.Options newOpts = new BitmapFactory.Options(); newOpts.inJustDecodeBounds = true; BitmapFactory.decodeFile(srcPath, newOpts); int w = newOpts.outWidth; int h = newOpts.outHeight; //现在主流手机比较多是800*480分辨率,所以目标高和宽我们设置为: float hh = 800f; float ww = 480f; //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 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; newOpts.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts); FileOutputStream fos; try { fos = new FileOutputStream(dstFilePath); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } File dstFile = new File(dstFilePath); if (!dstFile.exists()) { return; } if (dstFile.length() <= UPLOAD_MAX_FILE_SIZE) { return; } compressImageByQuality(bitmap, dstFilePath); } public static Bitmap getSmallBitmap(Context context, Uri uri) { return getBitmap(context, uri, -1, 128 * 128); } public static Bitmap getBitmap(Context context, Uri uri, int maxWidth, int maxHeight) { try { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream is = context.getContentResolver().openInputStream(uri); BitmapFactory.decodeStream(is, null, options); is.close(); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; is = context.getContentResolver().openInputStream(uri); Bitmap bmp = BitmapFactory.decodeStream(is, null, options); is.close(); return bmp; } catch (Exception e) { e.printStackTrace(); return null; } } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int initialSize = computeInitialSampleSize(options, reqWidth, reqHeight); int roundedSize; if (initialSize <= 8) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 2; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } } /** * @param context * @param mySourecUrl * @return */ public static String procPicFile(Context context, String mySourecUrl) { String procedUrl = null; if (TextUtils.isEmpty(mySourecUrl)) { return procedUrl; } File sourecFile = new File(mySourecUrl); if (!sourecFile.exists()) { return procedUrl; } if (sourecFile.length() / 1024 <= UPLOAD_MAX_FILE_SIZE) { return mySourecUrl; } // 压缩前准备:调整图片方向,以免压缩后丢掉了exif信息导致图片显示方向异常 if (needRotate(mySourecUrl)) { String urlRotated = PT_CACHE_TEMP_PIC_PATH + "tmp_rotate" + SystemClock.currentThreadTimeMillis() + ".jpg"; File rotatedFile = new File(urlRotated); if (rotatedFile.exists()) { rotatedFile.delete(); try { rotatedFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } try { rotatedBitmap(context, mySourecUrl, urlRotated); procedUrl = urlRotated; } catch (Exception e) { e.printStackTrace(); procedUrl = mySourecUrl; } } else { procedUrl = mySourecUrl; } String urlCompressed = PT_CACHE_TEMP_PIC_PATH + "tmp_compress" + SystemClock.currentThreadTimeMillis() + ".jpg"; File compressFile = new File(urlCompressed); if (compressFile.exists()) { compressFile.delete(); } //开始压缩图片文件 compressImage(procedUrl, urlCompressed); File compressedFile = new File(urlCompressed); if (compressedFile.exists()) { procedUrl = urlCompressed; } else { procedUrl = null; } return procedUrl; }}
0 0
- Android图片压缩的代码实现
- Android 图片压缩实现过程代码
- android 代码压缩图片
- 关于图片压缩的代码实现Swift
- 【教程】Android图片压缩实现过程及代码
- JAVA图片压缩代码实现
- java代码实现图片压缩
- Android webview实现上传图片的效果(图片压缩)
- android 的图片压缩
- C#图片截取压缩(百分比压缩/大小压缩)实现代码
- C#图片截取压缩(百分比压缩/大小压缩)实现代码
- C#图片截取压缩(百分比压缩/大小压缩)实现代码
- 图片压缩的一则代码
- Android-图片选择,压缩,上传,加载的实例 (图片选择,压缩实现 )
- java代码实现对图片压缩大小
- Java实现图片压缩代码,图片大小转换
- Android图片压缩解析与应用实现图片压缩缓存
- Android中的图片按比例大小压缩代码
- 分布式部署下润乾报表调用、API调用、权限问题以及性能方案
- xml写入
- Android Studio快速开发之道
- Java内存回收机制
- base64编码是怎么工作的?
- Android图片压缩的代码实现
- activiti学习笔记2——–activiti5.22 jar包依赖
- the device is locked 解决方法
- java 基本数据类型 及引用数据类型
- 开辟新的吐槽领域
- mybatis配置
- 各种距离
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- iOS10 UI教程视图调试