package com.jiang.android.architecture.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.media.ExifInterface; import android.support.annotation.NonNull; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import static com.jiang.android.architecture.utils.Preconditions.checkNotNull; /** * Created by jiang on 2016/11/18. */ public class LuBan { private static final String TAG = "LuBan"; private static String DEFAULT_DISK_CACHE_DIR = "luban_disk_cache"; private final File mCacheDir; public LuBan(Context context) { mCacheDir = getPhotoCacheDir(context); } private static synchronized File getPhotoCacheDir(Context context) { return getPhotoCacheDir(context, LuBan.DEFAULT_DISK_CACHE_DIR); } private static File getPhotoCacheDir(Context context, String cacheName) { File cacheDir = context.getCacheDir(); 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; } File noMedia = new File(cacheDir + "/.nomedia"); if (!noMedia.mkdirs() && (!noMedia.exists() || !noMedia.isDirectory())) { return null; } return result; } if (Log.isLoggable(TAG, Log.ERROR)) { Log.e(TAG, "default disk cache dir is null"); } return null; } private static synchronized File getPhotoCacheDir() { return PathUtil.getInstance().getImagePath(); } public int[] getImageSize(String imagePath) { int[] res = new int[2]; BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = 1; BitmapFactory.decodeFile(imagePath, options); res[0] = options.outWidth; res[1] = options.outHeight; return res; } public File firstCompress(@NonNull File file) { int minSize = 60; int longSide = 720; int shortSide = 1280; String filePath = file.getAbsolutePath(); String thumbFilePath = mCacheDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "_" + CommonUtils.getNumberRadim(4) + ".jpg"; long size = 0; long maxSize = file.length() / 5; int angle = getImageSpinAngle(filePath); int[] imgSize = getImageSize(filePath); int width = 0, height = 0; if (imgSize[0] <= imgSize[1]) { double scale = (double) imgSize[0] / (double) imgSize[1]; if (scale <= 1.0 && scale > 0.5625) { width = imgSize[0] > shortSide ? shortSide : imgSize[0]; height = width * imgSize[1] / imgSize[0]; size = minSize; } else if (scale <= 0.5625) { height = imgSize[1] > longSide ? longSide : imgSize[1]; width = height * imgSize[0] / imgSize[1]; size = maxSize; } } else { double scale = (double) imgSize[1] / (double) imgSize[0]; if (scale <= 1.0 && scale > 0.5625) { height = imgSize[1] > shortSide ? shortSide : imgSize[1]; width = height * imgSize[0] / imgSize[1]; size = minSize; } else if (scale <= 0.5625) { width = imgSize[0] > longSide ? longSide : imgSize[0]; height = width * imgSize[1] / imgSize[0]; size = maxSize; } } return compress(filePath, thumbFilePath, width, height, angle, size); } public File thirdCompress(@NonNull File file) { String thumb = mCacheDir.getAbsolutePath() + File.separator + System.currentTimeMillis() + "_" + CommonUtils.getNumberRadim(4) + ".jpg"; double size; String filePath = file.getAbsolutePath(); int angle = getImageSpinAngle(filePath); int width = getImageSize(filePath)[0]; int height = getImageSize(filePath)[1]; int thumbW = width % 2 == 1 ? width + 1 : width; int thumbH = height % 2 == 1 ? height + 1 : height; width = thumbW > thumbH ? thumbH : thumbW; height = thumbW > thumbH ? thumbW : thumbH; double scale = ((double) width / height); if (scale <= 1 && scale > 0.5625) { if (height < 1664) { if (file.length() / 1024 < 150) return file; size = (width * height) / Math.pow(1664, 2) * 150; size = size < 60 ? 60 : size; } else if (height >= 1664 && height < 4990) { thumbW = width / 2; thumbH = height / 2; size = (thumbW * thumbH) / Math.pow(2495, 2) * 300; size = size < 60 ? 60 : size; } else if (height >= 4990 && height < 10240) { thumbW = width / 4; thumbH = height / 4; size = (thumbW * thumbH) / Math.pow(2560, 2) * 300; size = size < 100 ? 100 : size; } else { int multiple = height / 1280 == 0 ? 1 : height / 1280; thumbW = width / multiple; thumbH = height / multiple; size = (thumbW * thumbH) / Math.pow(2560, 2) * 300; size = size < 100 ? 100 : size; } } else if (scale <= 0.5625 && scale > 0.5) { if (height < 1280 && file.length() / 1024 < 200) return file; int multiple = height / 1280 == 0 ? 1 : height / 1280; thumbW = width / multiple; thumbH = height / multiple; size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400; size = size < 100 ? 100 : size; } else { int multiple = (int) Math.ceil(height / (1280.0 / scale)); thumbW = width / multiple; thumbH = height / multiple; size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500; size = size < 100 ? 100 : size; } return compress(filePath, thumb, thumbW, thumbH, angle, (long) size); } private File compress(String largeImagePath, String thumbFilePath, int width, int height, int angle, long size) { Bitmap thbBitmap = compress(largeImagePath, width, height); thbBitmap = rotatingImage(angle, thbBitmap); return saveImage(thumbFilePath, thbBitmap, size); } private Bitmap compress(String imagePath, int width, int height) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imagePath, options); int outH = options.outHeight; int outW = options.outWidth; int inSampleSize = 1; if (outH > height || outW > width) { int halfH = outH / 2; int halfW = outW / 2; while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) { inSampleSize *= 2; } } options.inSampleSize = inSampleSize; options.inJustDecodeBounds = false; int heightRatio = (int) Math.ceil(options.outHeight / (float) height); int widthRatio = (int) Math.ceil(options.outWidth / (float) width); if (heightRatio > 1 || widthRatio > 1) { if (heightRatio > widthRatio) { options.inSampleSize = heightRatio; } else { options.inSampleSize = widthRatio; } } options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(imagePath, options); } private int getImageSpinAngle(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace(); } return degree; } /** * 旋转图片 * rotate the image with specified angle * * @param angle the angle will be rotating 旋转的角度 * @param bitmap target image 目标图片 */ private static Bitmap rotatingImage(int angle, Bitmap bitmap) { //rotate image Matrix matrix = new Matrix(); matrix.postRotate(angle); //create a new image return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } /** * 保存图片到指定路径 * Save image with specified size * * @param filePath the image file save path 储存路径 * @param bitmap the image what be save 目标图片 * @param size the file size of image 期望大小 */ private File saveImage(String filePath, Bitmap bitmap, long size) { checkNotNull(bitmap, TAG + "bitmap cannot be null"); File result = new File(filePath.substring(0, filePath.lastIndexOf("/"))); if (!result.exists() && !result.mkdirs()) return null; ByteArrayOutputStream stream = new ByteArrayOutputStream(); int options = 100; bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream); while (stream.toByteArray().length / 1024 > size && options > 6) { stream.reset(); options -= 6; bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream); } bitmap.recycle(); try { FileOutputStream fos = new FileOutputStream(filePath); fos.write(stream.toByteArray()); fos.flush(); fos.close(); stream.close(); } catch (IOException e) { e.printStackTrace(); } return new File(filePath); } }