Fork me on GitHub

Android图片压缩和图片大小的计算

图片压缩

图片的压缩大约有三种:

  • 采样率压缩,通过options.inSampleSize的参数
  • 质量压缩,通过 bitmap.compress()
  • 尺寸压缩,改变图片的大小重新进行裁剪,
Bitmap newBitmap = Bitmap.createBitmap(newWdith,newHeiht, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Rect rect = new Rect(0, 0, newWdith);
canvas.drawBitmap(oldBitmap, null, newBitmap, null);

实践

  • 1.定义压缩的策略
public abstract class AbstractStrategy {
    /**
     * 源图片的文件
     */
    protected File srcFile;
    /**
     * 目标文件
     */
    protected File outFile;
    protected Bitmap.CompressFormat format;
    protected int quality;
    protected int srcWidth;
    protected int srcHeight;
    protected float maxWidth;
    protected float maxHeight;

    public void setSrcFile(File srcFile) {
        this.srcFile = srcFile;
    }

    public void setOutFile(File outFile) {
        this.outFile = outFile;
    }

    public void setFormat(Bitmap.CompressFormat format) {
        this.format = format;
    }

    public void setQuality(int quality) {
        this.quality = quality;
    }

    public void setMaxWidth(float maxWidth) {
        this.maxWidth = maxWidth;
    }

    public void setMaxHeight(float maxHeight) {
        this.maxHeight = maxHeight;
    }

    /**
     * 执行压缩并返回图片
     *
     * @return
     */
    public void launch() {
        //读取图片信息
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcFile.getAbsolutePath(), options);
        this.srcWidth = options.outWidth;
        this.srcHeight = options.outHeight;
        //计算采样率
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
        options.inJustDecodeBounds = false;
        options.inDither = false;
        //大小压缩
        Bitmap scaledBitmap = BitmapFactory.decodeFile(srcFile.getAbsolutePath(), options);
        int degree = getRotateDegree(srcFile.getAbsolutePath());
        //旋转图片
        if (scaledBitmap != null && degree != 0) {
            scaledBitmap = rotateBitmap(scaledBitmap, degree);
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        scaledBitmap.compress(format, quality, baos);

        FileOutputStream fos = null;
        try {
            outFile.deleteOnExit();
            outFile.createNewFile();
            fos = new FileOutputStream(outFile);
            fos.write(baos.toByteArray());
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        scaledBitmap.recycle();
    }

    protected abstract int calculateInSampleSize(BitmapFactory.Options options, float reqWidth, float reqHeight);

    /**
     * 读取图片的当前角度
     *
     * @param path
     * @return
     */
    public int getRotateDegree(String path) {
        int degree = 0;
        ExifInterface exifInterface = null;
        try {
            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;
                default:
                    degree = 0;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转
     *
     * @param srcBitmap 原图
     * @param angle     旋转的角度
     * @return the rotated bitmap
     */
    protected Bitmap rotateBitmap(Bitmap srcBitmap, int angle) {
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        return Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true);
    }
  • 2.定义采样率的定义
public class SimpleStrategy extends AbstractStrategy {
    @Override
    protected int calculateInSampleSize(BitmapFactory.Options options, float reqWidth, float reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
}
  • 3.入口
public class Compress {
    private int DEFAULT_QUALITY = 75;
    private Bitmap.CompressFormat DEFAULT_FORMAT = Bitmap.CompressFormat.JPEG;
    /**
     * 最大宽度,默认为960
     */
    private float DEFAULT_MAX_WIDTH = 960f;
    /**
     * 最大高度,默认为960
     */
    private float DEFAULT_MAX_HEIGHT = 960f;

    private Context context;
    /**
     * 源图片文件
     */
    private File srcFile;
    /**
     * 压缩质量
     */
    private int quality = DEFAULT_QUALITY;
    /**
     * 图片格式
     */
    private Bitmap.CompressFormat format = DEFAULT_FORMAT;
    /**
     * 目标文件
     */
    private String targetDir;
    private String targetFileName;
    protected float maxWidth = DEFAULT_MAX_WIDTH;
    protected float maxHeight = DEFAULT_MAX_HEIGHT;

    public static Compress with(Context context, File srcFile) {
        return new Compress(context, srcFile, System.currentTimeMillis() + (int) (Math.random() * 1000) + ".jpg");
    }

    public static Compress with(Context context, File srcFile, String newFileName) {
        return new Compress(context, srcFile, newFileName);
    }

    private Compress(Context context, File srcFile, String newFileName) {
        this.context = context;
        this.srcFile = srcFile;
        this.targetFileName = newFileName;
    }

    public Compress setQuality(@IntRange(from = 0, to = 100) int quality) {
        this.quality = quality;
        return this;
    }

    public Compress setFormat(Bitmap.CompressFormat format) {
        this.format = format;
        return this;
    }

    public Compress setTargetDir(String targetDir) {
        this.targetDir = targetDir;
        return this;
    }

    public Compress setTargetFileName(String targetFileName) {
        this.targetFileName = targetFileName;
        return this;
    }

    public Compress setMaxWidth(float maxWidth) {
        this.maxWidth = maxWidth;
        return this;
    }

    public Compress setMaxHeight(float maxHeight) {
        this.maxHeight = maxHeight;
        return this;
    }

    /**
     * 定义图片的压缩策略
     *
     * @param strategy
     * @param <T>
     * @return
     */
    public <T extends AbstractStrategy> T strategy(T strategy) {
        strategy.setSrcFile(srcFile);
        strategy.setFormat(format);
        strategy.setQuality(quality);
        strategy.setOutFile(getOutFile());
        strategy.setMaxWidth(maxWidth);
        strategy.setMaxHeight(maxHeight);
        return strategy;
    }

    /**
     * 定义目标图片的位置
     *
     * @return
     */
    private File getOutFile() {
        if (isStorageWritable()) {
            this.targetDir = context.getExternalCacheDir().getAbsolutePath() + File.separator + "images" + File.separator;
        }
        if (TextUtils.isEmpty(targetDir)) {

            this.targetDir = context.getCacheDir().getAbsolutePath() + File.separator + "images" + File.separator;
        }
        //防止getExternalCacheDir拿不到文件路径
        File targetDir = new File(this.targetDir);
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }
        Log.d("SSS", "目标路径" + this.targetDir + this.targetFileName);
        File file = new File(this.targetDir + this.targetFileName);
        return file;
    }

    private static boolean isStorageWritable() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }
}
  • 4.使用
Compress.with(SampleActivity.this, imageFile)
    .setFormat(Bitmap.CompressFormat.JPEG)
    .setQuality(80)
    .strategy(new SimpleStrategy())
    .launch();

当前的图片压缩必须在子线程中进行处理,需要自己实现。图片保存的地址未开放出来,如果向开放出来,可以调整AbstractStrategy类的launch方法

图片大小的计算

    /**
     * size --> "B", "KB", "MB", "GB", "TB"
     */
public static String getReadableFileSize(long size) {
        if (size <= 0) {
            return "0";
        }
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
  }
posted @ 2021-05-19 15:37  KevinAt2022  阅读(282)  评论(0)    收藏  举报