Android 超清大尺寸图片压缩转Base64中卡顿/速度优化问题整理(在子线程压缩Bitmap卡的主线程进度条走不动了。。。)

        最近遇到需求是前后端传输图片使用的是Base64,但是前端(Android 端)图片很大(尺寸很大4480 × 2520,质量也很大7-10M),需要压缩到一定尺寸(1280 × 960,当然还可以压得更小),然后传给后端,本来认为是一个简单的压缩,可是在子线程压缩过程中发现很卡,卡的主线程的进度条都走不动了,一开始用的模拟器测试的,以为模拟器性能比较差,可是换成手机测试,还是很卡,卡的主线程的进度条都走不动了。为了解决这个问题,请看以下步骤:

以下代码在项目里,项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2

1.先申请权限,关于如何申请权限请查看RxPermissions的使用(简单实用)_ErwinNakajima的博客-CSDN博客_rxpermissions

2.添加bitmap管理类。

package com.phone.base64_and_file.manager;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.YuvImage;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.phone.common_library.manager.LogManager;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;

import id.zelory.compressor.Compressor;

public class BitmapManager {

    private static final String TAG = "BitmapManager";
    /**
     * 图像的旋转方向是0
     */
    public static final int ROTATE0 = 0;
    /**
     * 图像的旋转方向是90
     */
    public static final int ROTATE90 = 90;
    /**
     * 图像的旋转方向是180
     */
    public static final int ROTATE180 = 180;
    /**
     * 图像的旋转方向是270
     */
    public static final int ROTATE270 = 270;
    /**
     * 图像的旋转方向是360
     */
    public static final int ROTATE360 = 360;
    /**
     * 图片太大内存溢出后压缩的比例
     */
    public static final int PIC_COMPRESS_SIZE = 4;
    /**
     * 图像压缩边界
     */
    public static final int IMAGEBOUND = 128;
    /**
     * 图片显示最大边的像素
     */
    public static final int MAXLENTH = 1024;
    /**
     * Log switch
     */
    private static final boolean DEBUG = false;
    /**
     * 保存图片的质量:100
     */
    private static final int QUALITY = 100;
    /**
     * 默认的最大尺寸
     */
    private static final int DEFAULT_MAX_SIZE_CELL_NETWORK = 600;
    /**
     * 题编辑wifi环境下压缩的最大尺寸
     */
    private static final int QUESTION_MAX_SIZE_CELL_NETWORK = 1024;
    /**
     * 图片压缩的质量
     */
    private static final int QUESTION_IMAGE_JPG_QUALITY = 75;
    /**
     * 默认的图片压缩的质量
     */
    private static final int DEFAULT_IMAGE_JPG_QUALITY = 50;
    /**
     * 网络请求超时时间
     */
    private static final int CONNECTTIMEOUT = 3000;

    /**
     * Private constructor to prohibit nonsense instance creation.
     */
    private BitmapManager() {
    }

    /**
     * 图片合成
     *
     * @param bitmap 位图1
     * @param mark   位图2
     * @return Bitmap
     */
    public static Bitmap createBitmap(Bitmap bitmap, Bitmap mark) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        int mW = mark.getWidth();
        int mH = mark.getHeight();
        Bitmap newbitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);// 创建一个长宽一样的位图

        Canvas cv = new Canvas(newbitmap);
        cv.drawBitmap(bitmap, 0, 0, null);// 在 0,0坐标开始画入bitmap
        cv.drawBitmap(mark, w - mW, h - mH, null);// 在右下角画入水印mark
        cv.save();// 保存
        cv.restore();// 存储
        return newbitmap;
    }

    /**
     * 放大缩小图片
     *
     * @param bitmap 位图
     * @param w      新的宽度
     * @param h      新的高度
     * @return Bitmap
     */
    public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidht = ((float) w / width);
        float scaleHeight = ((float) h / height);
        matrix.postScale(scaleWidht, scaleHeight);
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    }

    /**
     * 旋转图片
     *
     * @param bitmap 要旋转的图片
     * @param angle  旋转角度
     * @return bitmap
     */
    public static Bitmap rotate(Bitmap bitmap, int angle) {
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
    }

    /**
     * 圆形图片
     *
     * @param source      位图
     * @param strokeWidth 裁剪范围 0表示最大
     * @param bl          是否需要描边
     * @param bl          画笔粗细
     * @param bl          颜色代码
     * @return bitmap
     */
    public static Bitmap createCircleBitmap(Bitmap source, int strokeWidth, boolean bl, int edge, int color) {

        int diameter = source.getWidth() < source.getHeight() ? source.getWidth() : source.getHeight();
        Bitmap target = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(target);//创建画布

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint);//绘制圆形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//取相交裁剪
        canvas.drawBitmap(source, strokeWidth, strokeWidth, paint);
        if (bl) {
            if (color == 0) color = 0xFFFEA248;//默认橘黄色
            paint.setColor(color);
            paint.setStyle(Paint.Style.STROKE);//描边
            paint.setStrokeWidth(edge);
            canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, paint);
        }
        return target;
    }

    /**
     * 圆角图片
     *
     * @param bitmap 位图
     * @param rx     x方向上的圆角半径
     * @param ry     y方向上的圆角半径
     * @param bl     是否需要描边
     * @param bl     画笔粗细
     * @param bl     颜色代码
     * @return bitmap
     */
    public static Bitmap createCornerBitmap(Bitmap bitmap, int rx, int ry, boolean bl, int edge, int color) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);//创建画布

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        RectF rectF = new RectF(rect);
        canvas.drawRoundRect(rectF, rx, ry, paint);//绘制圆角矩形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//取相交裁剪
        canvas.drawBitmap(bitmap, rect, rect, paint);
        if (bl) {
            if (color == 0) color = 0xFFFEA248;//默认橘黄色
            paint.setColor(color);
            paint.setColor(color);
            paint.setStyle(Paint.Style.STROKE);//描边
            paint.setStrokeWidth(edge);
            canvas.drawRoundRect(rectF, rx, ry, paint);
        }
        return output;
    }

    /**
     * 按比例裁剪图片
     *
     * @param bitmap 位图
     * @param wScale 裁剪宽 0~100%
     * @param hScale 裁剪高 0~100%
     * @return bitmap
     */
    public static Bitmap cropBitmap(Bitmap bitmap, float wScale, float hScale) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        int wh = (int) (w * wScale);
        int hw = (int) (h * hScale);

        int retX = (int) (w * (1 - wScale) / 2);
        int retY = (int) (h * (1 - hScale) / 2);

        return Bitmap.createBitmap(bitmap, retX, retY, wh, hw, null, false);
    }

    /**
     * 获得带倒影的图片方法
     *
     * @param bitmap 位图
     * @param region 倒影区域 0.1~1
     * @return bitmap
     */
    public static Bitmap createReflectionBitmap(Bitmap bitmap, float region) {

        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);//镜像缩放
        Bitmap reflectionBitmap = Bitmap.createBitmap(
                bitmap, 0
                , (int) (height * (1 - region))//从哪个点开始绘制
                , width
                , (int) (height * region)//绘制多高
                , matrix, false);

        Bitmap reflectionWithBitmap = Bitmap.createBitmap(width, height + (int) (height * region),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(reflectionWithBitmap);
        canvas.drawBitmap(bitmap, 0, 0, null);
        canvas.drawBitmap(reflectionBitmap, 0, height, null);

        LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
                reflectionWithBitmap.getHeight()
                , 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);

        Paint paint = new Paint();
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//取两层绘制交集。显示下层。
        canvas.drawRect(0, height, width, reflectionWithBitmap.getHeight(), paint);
        return reflectionWithBitmap;
    }

    /**
     * 图片质量压缩
     *
     * @param bitmap
     * @param many   百分比
     * @return
     */
    public static Bitmap compressBitmap(Bitmap bitmap, float many) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, (int) many * 100, baos);
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        return BitmapFactory.decodeStream(isBm, null, null);
    }

    /**
     * 高级图片质量压缩
     *
     * @param bitmap  位图
     * @param maxSize 压缩后的大小,单位kb
     */
    public static Bitmap imageZoom(Bitmap bitmap, double maxSize) {
        // 将bitmap放至数组中,意在获得bitmap的大小(与实际读取的原文件要大)
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 格式、质量、输出流
        bitmap.compress(Bitmap.CompressFormat.PNG, 70, baos);
        byte[] b = baos.toByteArray();
        // 将字节换成KB
        double mid = b.length / 1024;
        // 获取bitmap大小 是允许最大大小的多少倍
        double i = mid / maxSize;
        // 判断bitmap占用空间是否大于允许最大空间 如果大于则压缩 小于则不压缩
        doRecycledIfNot(bitmap);
        if (i > 1) {
            // 缩放图片 此处用到平方根 将宽带和高度压缩掉对应的平方根倍
            // (保持宽高不变,缩放后也达到了最大占用空间的大小)
            return scaleWithWH(bitmap, bitmap.getWidth() / Math.sqrt(i),
                    bitmap.getHeight() / Math.sqrt(i));
        }
        return null;
    }

    /***
     * 图片缩放
     *@param bitmap 位图
     * @param w 新的宽度
     * @param h 新的高度
     * @return Bitmap
     */
    public static Bitmap scaleWithWH(Bitmap bitmap, double w, double h) {
        if (w == 0 || h == 0 || bitmap == null) {
            return bitmap;
        } else {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();

            Matrix matrix = new Matrix();
            float scaleWidth = (float) (w / width);
            float scaleHeight = (float) (h / height);

            matrix.postScale(scaleWidth, scaleHeight);
            return Bitmap.createBitmap(bitmap, 0, 0, width, height,
                    matrix, true);
        }
    }

    /**
     * YUV视频流格式转bitmap
     *
     * @param data YUV视频流格式
     * @return width 设置高度
     */
    public static Bitmap getBitmap(byte[] data, int width, int height) {
        Bitmap bitmap;
        YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21, width, height, null);
        //data是onPreviewFrame参数提供
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        yuvimage.compressToJpeg(new Rect(0, 0, yuvimage.getWidth(), yuvimage.getHeight()), 100, baos);//
        // 80--JPG图片的质量[0-100],100最高
        byte[] rawImage = baos.toByteArray();
        BitmapFactory.Options options = new BitmapFactory.Options();
        SoftReference<Bitmap> softRef = new SoftReference<Bitmap>(BitmapFactory.decodeByteArray(rawImage, 0, rawImage
                .length, options));
        bitmap = softRef.get();
        return bitmap;
    }

    /**
     * 图片资源文件转bitmap
     *
     * @param context
     * @param resId
     * @return bitmap
     */
    public static Bitmap getBitmapResources(Context context, int resId) {
        return BitmapFactory.decodeResource(context.getResources(), resId);
    }

    /**
     * 将图片路径转Bitmap
     *
     * @return Bitmap
     * @Param path 图片路径
     */
    public static Bitmap getBitmapPath(String path) {
        return BitmapFactory.decodeFile(path);
    }

    /**
     * bitmap保存到指定路径
     *
     * @param path 图片的绝对路径
     * @param bmp  位图
     * @return bitmap
     */
    public static boolean saveFile(String path, Bitmap bmp) {
        if (TextUtils.isEmpty(path) || bmp == null) return false;

        File file = new File(path);
        if (file.exists()) {
            file.delete();
        } else {
            File p = file.getParentFile();
            if (!p.exists()) {
                p.mkdirs();
            }
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 回收一个未被回收的Bitmap
     *
     * @param bitmap
     */
    public static void doRecycledIfNot(Bitmap bitmap) {
        if (!bitmap.isRecycled()) {
            bitmap.recycle();
        }
    }

    /**
     * 等比压缩图片
     *
     * @param resBitmap 原图
     * @param desWidth  压缩后图片的宽度
     * @param desHeight 压缩后图片的高度
     * @return 压缩后的图片
     */
    public static Bitmap scaleImage(Bitmap resBitmap, int desWidth, int desHeight) {
        int resWidth = resBitmap.getWidth();
        int resHeight = resBitmap.getHeight();
        if (resHeight > desHeight || resWidth > desWidth) {
            // 计算出实际宽高和目标宽高的比率
            final float heightRatio = (float) desHeight / (float) resHeight;
            final float widthRatio = (float) desWidth / (float) resWidth;
            float scale = heightRatio < widthRatio ? heightRatio : widthRatio;
            LogManager.i(TAG, "scaleImage scale*****" + scale);
            //開平方會有一點損失精度
            float prescription = (float) Math.sqrt(scale);
            //再次开平方
            float prescription2 = (float) Math.sqrt(prescription);
//            LogManager.i(TAG, "scaleImage prescription*****" + prescription);
            LogManager.i(TAG, "scaleImage prescription2*****" + prescription2);
            Bitmap bitmap = null;
            //循環壓縮bitmap,防止一次壓縮bitmap卡頓問題(子線程把主線成卡頓了)
            for (int i = 0; i < 4; i++) {
                if (bitmap != null) {
//                    bitmap = scale(bitmap, prescription);
                    bitmap = scale(bitmap, prescription2);
                } else {
//                    bitmap = scale(resBitmap, prescription);
                    bitmap = scale(resBitmap, prescription2);
                }
//                LogManager.i(TAG, i + "scaleImage prescription*****" + prescription);
                LogManager.i(TAG, i + "scaleImage prescription2*****" + prescription2);
            }
            return bitmap;
        }
        return resBitmap;
    }

    /**
     * 等比压缩图片
     *
     * @param bitmap 原图
     * @param scale  压缩因子
     * @return 压缩后的图片
     */
    private static Bitmap scale(Bitmap bitmap, float scale) {
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 尺寸缩放
     *
     * @param bitmap bitmap
     * @param w      width
     * @param h      height
     * @return scaleBitmap
     */
    public static Bitmap scale(Bitmap bitmap, int w, int h) {
        if (bitmap == null) {
            return null;
        }
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidth = ((float) w / width);
        float scaleHeight = ((float) h / height);
        matrix.postScale(scaleWidth, scaleHeight);
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

    }

    /**
     * byte转Uri
     *
     * @param context
     * @param data
     * @return
     */
    public static Uri saveTakePictureImage(Context context, byte[] data) {
        File file = context.getExternalFilesDir("file1");
        file = new File(file.getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            fos.write(data);
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();

            // 异常时删除保存失败的文件
            try {
                if (file != null && file.exists() && file.isFile()) {
                    file.delete();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            return null;
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        Log.e(TAG, file.getAbsolutePath());
        return Uri.fromFile(file);
    }

    /**
     * byte转成bitmap
     *
     * @param data
     * @param width
     * @param height
     * @return
     */
    public static Bitmap yuvToBitmap(byte[] data, int width, int height) {
        int frameSize = width * height;
        int[] rgba = new int[frameSize];

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int y = (0xff & ((int) data[i * width + j]));
                int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0]));
                int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1]));
                y = y < 16 ? 16 : y;

                int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128));
                int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
                int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));

                r = r < 0 ? 0 : (r > 255 ? 255 : r);
                g = g < 0 ? 0 : (g > 255 ? 255 : g);
                b = b < 0 ? 0 : (b > 255 ? 255 : b);

                rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
            }
        }

        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bmp.setPixels(rgba, 0, width, 0, 0, width, height);
        return bmp;
    }

    /**
     * byte转成bitmap
     *
     * @param depthBytes
     * @param width
     * @param height
     * @return
     */
    public static Bitmap depthToBitmap(byte[] depthBytes, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        int[] argbData = new int[width * height];
        for (int i = 0; i < width * height; i++) {
            argbData[i] = (((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10 & 0x000000ff)
                    | ((((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10) & 0x000000ff) << 8
                    | ((((int) depthBytes[i * 2] + depthBytes[i * 2 + 1] * 256) / 10) & 0x000000ff) << 16
                    | 0xff000000;

        }
        bitmap.setPixels(argbData, 0, width, 0, 0, width, height);
        return bitmap;
    }

    /**
     * byte转bitmap
     *
     * @param bytes
     * @param width
     * @param height
     * @return
     */
    public static Bitmap rGBToBitmap(byte[] bytes, int width, int height) {
        // use Bitmap.Config.ARGB_8888 instead of type is OK
        Bitmap stitchBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        byte[] rgba = new byte[width * height * 4];
        for (int i = 0; i < width * height; i++) {
            byte b1 = bytes[i * 3 + 0];
            byte b2 = bytes[i * 3 + 1];
            byte b3 = bytes[i * 3 + 2];
            // set value
            rgba[i * 4 + 0] = b1;
            rgba[i * 4 + 1] = b2;
            rgba[i * 4 + 2] = b3;
            rgba[i * 4 + 3] = (byte) 255;
        }
        stitchBmp.copyPixelsFromBuffer(ByteBuffer.wrap(rgba));
        return stitchBmp;
    }

    /**
     * byte转bitmap
     *
     * @param bytes
     * @param width
     * @param height
     * @return
     */
    public static Bitmap bGRToBitmap(byte[] bytes, int width, int height) {
        // use Bitmap.Config.ARGB_8888 instead of type is OK
        Bitmap stitchBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        byte[] rgba = new byte[width * height * 4];
        for (int i = 0; i < width * height; i++) {
            byte b1 = bytes[i * 3 + 0];
            byte b2 = bytes[i * 3 + 1];
            byte b3 = bytes[i * 3 + 2];
            // set value
            rgba[i * 4 + 0] = b3;
            rgba[i * 4 + 1] = b2;
            rgba[i * 4 + 2] = b1;
            rgba[i * 4 + 3] = (byte) 255;
        }
        stitchBmp.copyPixelsFromBuffer(ByteBuffer.wrap(rgba));
        return stitchBmp;
    }

    public static byte[] aRGBToR(byte[] bytes, int width, int height) {
        byte[] IR = new byte[width * height];
        for (int i = 0; i < width * height; i++) {
            IR[i] = bytes[i * 4];
        }
        return IR;
    }

//    /**
//     * 百度人脸图片转换
//     *
//     * @param newInstance
//     * @return
//     */
//    public static Bitmap getInstaceBmp(BDFaceImageInstance newInstance) {
//        Bitmap transBmp = null;
//        if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_RGBA) {
//            transBmp = Bitmap.createBitmap(newInstance.width, newInstance.height, Bitmap.Config.ARGB_8888);
//            transBmp.copyPixelsFromBuffer(ByteBuffer.wrap(newInstance.data));
//        } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_BGR) {
//            transBmp = BitmapManager.BGR2Bitmap(newInstance.data, newInstance.width, newInstance.height);
//        } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_YUV_NV21) {
//            transBmp = BitmapManager.yuv2Bitmap(newInstance.data, newInstance.width, newInstance.height);
//        } else if (newInstance.imageType == BDFaceSDKCommon.BDFaceImageType.BDFACE_IMAGE_TYPE_GRAY) {
//            transBmp = Depth2Bitmap(newInstance.data, newInstance.width, newInstance.height);
//        }
//        return transBmp;
//    }

    /**
     * 获取图片数据
     *
     * @param path
     * @return
     */
    public static Bitmap getBitmap(String path) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        Bitmap bm = null;
        try {
            fis = new FileInputStream(path);
            BitmapFactory.Options options = new BitmapFactory.Options();
//            options.inSampleSize = 8;//图片的长宽都是原来的1/8
            bis = new BufferedInputStream(fis);
            bm = BitmapFactory.decodeStream(bis, null, options);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bm;
    }

    /**
     * @param bitmap
     * @return
     */
    public static InputStream bitmapToInputStream(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        ByteArrayInputStream byteArrInputStream = new ByteArrayInputStream(
                baos.toByteArray());

        return byteArrInputStream;
    }

    /**
     * 这个是把文件变成二进制流
     *
     * @param imagepath
     * @return
     * @throws Exception
     */
    public static byte[] readStream(String imagepath) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(imagepath);
            bis = new BufferedInputStream(fis);

            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while (-1 != (len = bis.read(buffer))) {
                baos.write(buffer, 0, len);
            }
            //刷新此输出流并强制写出所有缓冲的输出字节
            baos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return baos.toByteArray();
    }

    /**
     * 将Bitmap转换成文件
     * 保存文件
     *
     * @param bitmap
     * @param fileName
     * @throws IOException
     */
    public static File saveFile(Bitmap bitmap, String dirsPath, String fileName) {
        File dirs = new File(dirsPath);
        if (!dirs.exists()) {
            dirs.mkdirs();
        }
        File captureFile = new File(dirs, fileName);
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(captureFile));
            //刷新此输出流并强制写出所有缓冲的输出字节
            bos.flush();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return captureFile;
    }

    /**
     * 读取文件的大小
     */

    public static long getFileSize(File file) {
        long size = 0;
        if (file.exists()) {
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                size = bis.available();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return size;
        }
        return 0;
    }

    /**
     * 返回byte的数据大小对应的文本
     *
     * @param size
     * @return
     */
    public static String getDataSize(long size) {
        DecimalFormat formater = new DecimalFormat("####.00");
        if (size < 1024) {
            return size + "bytes";
        } else if (size < 1024 * 1024) {
            float kbsize = size / 1024f;
            return formater.format(kbsize) + "KB";
        } else if (size < 1024 * 1024 * 1024) {
            float mbsize = size / 1024f / 1024f;
            return formater.format(mbsize) + "MB";
        } else if (size < 1024 * 1024 * 1024 * 1024) {
            float gbsize = size / 1024f / 1024f / 1024f;
            return formater.format(gbsize) + "GB";
        } else {
            return "size: error";
        }
    }

    /**
     * 使用Compressor IO模式自定义压缩
     *
     * @param path .setMaxWidth(640).setMaxHeight(480)这两个数值越高,压缩力度越小,图片也不清晰
     *             .setQuality(75)这个方法只是设置图片质量,并不影响压缩图片的大小KB
     *             .setCompressFormat(Bitmap.CompressFormat.WEBP) WEBP图片格式是Google推出的 压缩强,质量 高,但是IOS不识别,需要把图片转为字节流然后转PNG格式
     *             .setCompressFormat(Bitmap.CompressFormat.PNG)PNG格式的压缩,会导致图片变大,并耗过大的内 存,手机反应缓慢
     *             .setCompressFormat(Bitmap.CompressFormat.JPEG)JPEG压缩;压缩速度比PNG快,质量一般,基本上属于1/10的压缩比例
     */
    public static File initCompressorIO(Context context, String path, String dirsPath) {
        File dirs2 = new File(dirsPath);
        if (!dirs2.exists()) {
            dirs2.mkdirs();
        }

        File file = null;
        try {
            file = new Compressor(context)
//                    .setMaxWidth(1280)
//                    .setMaxHeight(960)
                    .setQuality(50)
                    .setCompressFormat(Bitmap.CompressFormat.PNG)
                    .setDestinationDirectoryPath(dirsPath)
                    .compressToFile(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    public static File getAssetFile(Context context, String dirsPath, String assetFileName) {
        AssetManager assetManager = context.getAssets();
        File dirs = new File(dirsPath);
        if (!dirs.exists()) {
            dirs.mkdirs();
        }
        File file = new File(dirs, assetFileName);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        InputStream is = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            is = assetManager.open(assetFileName);
            bis = new BufferedInputStream(is);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);

            byte[] buffer = new byte[1024];
            int len = 0;
            while (-1 != (len = bis.read(buffer))) {
                bos.write(buffer, 0, len);
            }
            //刷新此输出流并强制写出所有缓冲的输出字节
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return file;
    }

    /**
     * base64转bitmap
     *
     * @param base64String
     * @return
     */
    public static Bitmap base64ToBitmap(String base64String) {
        base64String = Uri.decode(base64String);
        byte[] decode = Base64.decode(base64String, Base64.DEFAULT);
        Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
        return bitmap;
    }

}

3.把本地图片转化成bitmap。

String dirsPath = Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator + "Pictures";
        String dirsPathCompressed = Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator + "PicturesCompressed";
        String dirsPathCompressedRecover = Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator + "PicturesCompressedRecover";
        Base64AndFileBean base64AndFileBean = new Base64AndFileBean();
        base64AndFileBean.setDirsPath(dirsPath);
        base64AndFileBean.setDirsPathCompressed(dirsPathCompressed);
        base64AndFileBean.setDirsPathCompressedRecover(dirsPathCompressedRecover);

Bitmap bitmap = BitmapManager.getBitmap(base64AndFileBean.getFile().getAbsolutePath());
                        LogManager.i(TAG, "bitmap mWidth*****" + bitmap.getWidth());
                        LogManager.i(TAG, "bitmap mHeight*****" + bitmap.getHeight());
                        base64AndFileBean.setBitmap(bitmap);

4.再压缩bitmap,循環壓縮bitmap(分成4次压缩了),防止一次壓縮bitmap卡頓問題,如果图片太大,就分成更多次压缩。

Bitmap bitmapCompressed = BitmapManager.scaleImage(base64AndFileBean.getBitmap(), 1280, 960);
                        LogManager.i(TAG, "bitmapCompressed mWidth*****" + bitmapCompressed.getWidth());
                        LogManager.i(TAG, "bitmapCompressed mHeight*****" + bitmapCompressed.getHeight());
                        base64AndFileBean.setBitmapCompressed(bitmapCompressed);

5.再把压缩后的bitmap保存到本地。

File fileCompressed = BitmapManager.saveFile(base64AndFileBean.getBitmapCompressed(), base64AndFileBean.getDirsPathCompressed(), "picture_large_compressed.png");
                        base64AndFileBean.setFileCompressed(fileCompressed);
                        LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getPath()*****" + base64AndFileBean.getFileCompressed().getPath());
                        LogManager.i(TAG, "base64AndFileBean.getFileCompressed().getAbsolutePath()*****" + base64AndFileBean.getFileCompressed().getAbsolutePath());

6.最后把File转成Base64。

String base64Str = null;
                        if (base64AndFileBean.getFileCompressed().exists()) {
                            base64Str = Base64AndFileManager.fileToBase64(base64AndFileBean.getFileCompressed());
//                base64Str = Base64AndFileManager.fileToBase64Test(file);
//                    base64Str = Base64AndFileManager.fileToBase64Second(file);
                            base64AndFileBean.setBase64Str(base64Str);
                        }
                        if (!TextUtils.isEmpty(base64Str)) {
                            String fileName = "base64Str.txt";
                            String txtFilePath = FileManager.writeStrToTextFile(base64Str, base64AndFileBean.getDirsPathCompressed(), fileName);
                            base64AndFileBean.setTxtFilePath(txtFilePath);
                            base64AndFileBean.setBase64StrList(Base64AndFileManager.getBase64StrList(txtFilePath));
//                base64Str = "";
//                StringBuilder stringBuilder = new StringBuilder();
//                for (int i = 0; i < base64StrList.size(); i++) {
//                    stringBuilder.append(base64StrList.get(i));
//                }
//                base64Str = stringBuilder.toString();

//                    //把字符串的最後一個打印出來,然後看看和RecyclerView顯示的最後一個字符串是否一致
//                    LogManager.i(TAG, "base64StrList******" + base64StrList.get(base64StrList.size() - 1));
                        }

以上是我总结的超清大尺寸图片压缩转Base64速度优化问题,重点在第3点,循環壓縮bitmap(分成4次压缩了),防止一次壓縮bitmap卡頓問題,如果图片太大,就分成更多次压缩。

如对此有疑问,请联系qq1164688204。

推荐Android开源项目

项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。

项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值