android 提供了一些图片压缩的方法 ,都测试了一下不尽人意
去github上找了一遍 ,有个Luban图片压缩,当时他返回来的是一个File文件,我觉得没什么卵用,改了一下返回的数据,改成文件的路径,这样下来可以直接使用文件了,调用方便,效果不错,记录一下,分享给大家 ,
启动方法 :
Luban.with(UpdateImageAdActivity.this) .load(updatePath) // 传人要压缩的图片列表 .ignoreBy(100) // 忽略不压缩图片的大小 .setTargetDir(ApInfo.IMAGE_URL) // 设置压缩后文件存储位置,文件夹路径 .setCompressListener(new OnCompressListener() { //设置回调 @Override public void onStart() { Log.e("update", "========图片开始压缩====="); showTaost("开始压缩图片"); } @Override public void onSuccess(String savePath) { Log.e("update", "========图片压缩success=====" + savePath); updateImageParsener.updateImage(et_title.getText().toString().trim(), savePath, updateTag); } @Override public void onError(Throwable e) { Log.e("update", "========图片压缩failed=====" + e.toString()); showTaost("图片压缩异常:" + e.toString()); } }).launch(); //启动压缩
package com.cdl.image.compress; import android.text.TextUtils; import java.io.File; import java.util.ArrayList; import java.util.List; class Checker { private static List<String> format = new ArrayList<>(); private static final String JPG = "jpg"; private static final String JPEG = "jpeg"; private static final String PNG = "png"; private static final String WEBP = "webp"; private static final String GIF = "gif"; static { format.add(JPG); format.add(JPEG); format.add(PNG); format.add(WEBP); format.add(GIF); } static boolean isImage(String path) { if (TextUtils.isEmpty(path)) { return false; } String suffix = path.substring(path.lastIndexOf(".") + 1, path.length()); return format.contains(suffix.toLowerCase()); } static boolean isJPG(String path) { if (TextUtils.isEmpty(path)) { return false; } String suffix = path.substring(path.lastIndexOf("."), path.length()).toLowerCase(); return suffix.contains(JPG) || suffix.contains(JPEG); } static String checkSuffix(String path) { if (TextUtils.isEmpty(path)) { return ".jpg"; } return path.substring(path.lastIndexOf("."), path.length()); } static boolean isNeedCompress(int leastCompressSize, String path) { if (leastCompressSize > 0) { File source = new File(path); if (!source.exists()) { return false; } if (source.length() <= (leastCompressSize << 10)) { return false; } } return true; } }
package com.cdl.image.compress; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.ExifInterface; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * Responsible for starting compress and managing active and cached resources. */ class Engine { private ExifInterface srcExif; private String srcImg; private File tagImg; private int srcWidth; private int srcHeight; Engine(String srcImg, File tagImg) throws IOException { if (Checker.isJPG(srcImg)) { this.srcExif = new ExifInterface(srcImg); } this.tagImg = tagImg; this.srcImg = srcImg; BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = 1; BitmapFactory.decodeFile(srcImg, options); this.srcWidth = options.outWidth; this.srcHeight = options.outHeight; } private int computeSize() { srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth; srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight; int longSide = Math.max(srcWidth, srcHeight); int shortSide = Math.min(srcWidth, srcHeight); float scale = ((float) shortSide / longSide); if (scale <= 1 && scale > 0.5625) { if (longSide < 1664) { return 1; } else if (longSide >= 1664 && longSide < 4990) { return 2; } else if (longSide > 4990 && longSide < 10240) { return 4; } else { return longSide / 1280 == 0 ? 1 : longSide / 1280; } } else if (scale <= 0.5625 && scale > 0.5) { return longSide / 1280 == 0 ? 1 : longSide / 1280; } else { return (int) Math.ceil(longSide / (1280.0 / scale)); } } private Bitmap rotatingImage(Bitmap bitmap) { if (srcExif == null) return bitmap; Matrix matrix = new Matrix(); int angle = 0; int orientation = srcExif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: angle = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: angle = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: angle = 270; break; } matrix.postRotate(angle); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } File compress() throws IOException { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = computeSize(); Bitmap tagBitmap = BitmapFactory.decodeFile(srcImg, options); ByteArrayOutputStream stream = new ByteArrayOutputStream(); tagBitmap = rotatingImage(tagBitmap); tagBitmap.compress(Bitmap.CompressFormat.JPEG, 60, stream); tagBitmap.recycle(); FileOutputStream fos = new FileOutputStream(tagImg); fos.write(stream.toByteArray()); fos.flush(); fos.close(); stream.close(); return tagImg; } }
package com.cdl.image.compress; import android.content.Context; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.text.TextUtils; import android.util.Log; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Luban implements Handler.Callback { private static final String TAG = "Luban"; private static final String DEFAULT_DISK_CACHE_DIR = "luban_disk_cache"; private static final int MSG_COMPRESS_SUCCESS = 0; private static final int MSG_COMPRESS_START = 1; private static final int MSG_COMPRESS_ERROR = 2; private String mTargetDir; private List<String> mPaths; private int mLeastCompressSize; private OnCompressListener mCompressListener; private Handler mHandler; private Luban(Builder builder) { this.mPaths = builder.mPaths; this.mTargetDir = builder.mTargetDir; this.mCompressListener = builder.mCompressListener; this.mLeastCompressSize = builder.mLeastCompressSize; mHandler = new Handler(Looper.getMainLooper(), this); } public static Builder with(Context context) { return new Builder(context); } /** * Returns a mFile with a cache audio name in the private cache directory. * * @param context A context. */ private File getImageCacheFile(Context context, String suffix) { if (TextUtils.isEmpty(mTargetDir)) { mTargetDir = getImageCacheDir(context).getAbsolutePath(); } String cacheBuilder = mTargetDir + "/" + System.currentTimeMillis() + (int) (Math.random() * 1000) + (TextUtils.isEmpty(suffix) ? ".jpg" : suffix); return new File(cacheBuilder); } /** * Returns a directory with a default name in the private cache directory of the application to * use to store retrieved audio. * * @param context A context. * @see #getImageCacheDir(Context, String) */ @Nullable private File getImageCacheDir(Context context) { return getImageCacheDir(context, DEFAULT_DISK_CACHE_DIR); } /** * Returns a directory with the given name in the private cache directory of the application to * use to store retrieved media and thumbnails. * * @param context A context. * @param cacheName The name of the subdirectory in which to store the cache. * @see #getImageCacheDir(Context) */ @Nullable private File getImageCacheDir(Context context, String cacheName) { File cacheDir = context.getExternalCacheDir(); if (cacheDir != null) { File result = new File(cacheDir, cacheName); if (!result.mkdirs() && (!result.exists() || !result.isDirectory())) { // File wasn't able to create a directory, or the result exists but not a directory return null; } return result; } if (Log.isLoggable(TAG, Log.ERROR)) { Log.e(TAG, "default disk cache dir is null"); } return null; } /** * start asynchronous compress thread */ @UiThread private void launch(final Context context) { if (mPaths == null || mPaths.size() == 0 && mCompressListener != null) { mCompressListener.onError(new NullPointerException("image file cannot be null")); } Iterator<String> iterator = mPaths.iterator(); while (iterator.hasNext()) { final String path = iterator.next(); if (Checker.isImage(path)) { AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() { @Override public void run() { try { mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_START)); File result = Checker.isNeedCompress(mLeastCompressSize, path) ? new Engine(path, getImageCacheFile(context, Checker.checkSuffix(path))).compress() : new File(path); String filePath = result.getPath(); Message message = new Message(); message.what = MSG_COMPRESS_SUCCESS; message.obj = filePath; mHandler.sendMessage(message); // mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_SUCCESS, result)); } catch (IOException e) { mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, e)); } } }); } else { mCompressListener.onError(new IllegalArgumentException("can not read the path : " + path)); } iterator.remove(); } } /** * start compress and return the mFile */ @WorkerThread private File get(String path, Context context) throws IOException { return new Engine(path, getImageCacheFile(context, Checker.checkSuffix(path))).compress(); } @WorkerThread private List<File> get(Context context) throws IOException { List<File> results = new ArrayList<>(); Iterator<String> iterator = mPaths.iterator(); while (iterator.hasNext()) { String path = iterator.next(); if (Checker.isImage(path)) { results.add(new Engine(path, getImageCacheFile(context, Checker.checkSuffix(path))).compress()); } iterator.remove(); } return results; } @Override public boolean handleMessage(Message msg) { if (mCompressListener == null) return false; switch (msg.what) { case MSG_COMPRESS_START: mCompressListener.onStart(); break; case MSG_COMPRESS_SUCCESS: String filePath = (String) msg.obj; mCompressListener.onSuccess(filePath); break; case MSG_COMPRESS_ERROR: mCompressListener.onError((Throwable) msg.obj); break; } return false; } public static class Builder { private Context context; private String mTargetDir; private List<String> mPaths; private int mLeastCompressSize = 100; private OnCompressListener mCompressListener; Builder(Context context) { this.context = context; this.mPaths = new ArrayList<>(); } private Luban build() { return new Luban(this); } public Builder load(File file) { this.mPaths.add(file.getAbsolutePath()); return this; } public Builder load(String string) { this.mPaths.add(string); return this; } public Builder load(List<String> list) { this.mPaths.addAll(list); return this; } public Builder putGear(int gear) { return this; } public Builder setCompressListener(OnCompressListener listener) { this.mCompressListener = listener; return this; } public Builder setTargetDir(String targetDir) { this.mTargetDir = targetDir; return this; } /** * do not compress when the origin image file size less than one value * * @param size the value of file size, unit KB, default 100K */ public Builder ignoreBy(int size) { this.mLeastCompressSize = size; return this; } /** * begin compress image with asynchronous */ public void launch() { build().launch(context); } public File get(String path) throws IOException { return build().get(path, context); } /** * begin compress image with synchronize * * @return the thumb image file list */ public List<File> get() throws IOException { return build().get(context); } } }
package com.cdl.image.compress; import java.io.File; public interface OnCompressListener { /** * Fired when the compression is started, override to handle in your own code */ void onStart(); /** * Fired when a compression returns successfully, override to handle in your own code */ void onSuccess(String savePath); // void onSuccess(File file ); /** * Fired when a compression fails to complete, override to handle in your own code */ void onError(Throwable e); }