Android 处理大图片

本文介绍了一种高效的图片压缩方法,包括尺寸压缩和质量压缩,适用于多种应用场景。提供了详细的代码实现及参数说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.example.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;

public class BitmapUtils {


    public final static int getDegress(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;
    }

    public static Bitmap rotateBitmap(Bitmap bitmap, int degress) {
        if (bitmap != null) {
            Matrix m = new Matrix();
            m.postRotate(degress); 
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
            return bitmap;
        }
        return bitmap;
    }

    public final static int caculateInSampleSize(BitmapFactory.Options options, int rqsW, int rqsH) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (rqsW == 0 || rqsH == 0) return 1;
        if (height > rqsH || width > rqsW) {
            final int heightRatio = Math.round((float) height/ (float) rqsH);
            final int widthRatio = Math.round((float) width / (float) rqsW);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

    /**
     * 压缩指定路径的图片,并得到图片对象
     * @param context
     * @param path bitmap source path
     * @return Bitmap {@link android.graphics.Bitmap}
     */
    public final static Bitmap compressBitmap(String path, int rqsW, int rqsH) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        options.inSampleSize = caculateInSampleSize(options, rqsW, rqsH);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(path, options);
    }

    /**
     * 压缩指定路径图片,并将其保存在缓存目录中,通过isDelSrc判定是否删除源文件,并获取到缓存后的图片路径
     * @param context
     * @param srcPath
     * @param rqsW
     * @param rqsH
     * @param isDelSrc
     * @return
     */
    public final static String compressBitmap(Context context, String srcPath,String desPath, int rqsW, int rqsH, boolean isDelSrc) {
        Bitmap bitmap = compressBitmap(srcPath, rqsW, rqsH);
        File srcFile = new File(srcPath);
        int degree = getDegress(srcPath);
        try {
            if (degree != 0) bitmap = rotateBitmap(bitmap, degree);
            File file = new File(desPath);
            if(srcFile.getAbsolutePath() != file.getAbsolutePath()){

                FileOutputStream  fos = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.PNG, 40, fos);
                fos.close();
            }

            if (isDelSrc) srcFile.deleteOnExit();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return desPath;
    }

    /**
     * 刷新相册
     * @param context
     * @param imgFileName
     */
    private static void scanPhoto(Context context, String imgFileName)
    {
        Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        File file = new File(imgFileName);
        Uri contentUri = Uri.fromFile(file);
        mediaScanIntent.setData(contentUri);
        context.sendBroadcast(mediaScanIntent);
    }

    /**
     * 压缩某个输入流中的图片,可以解决网络输入流压缩问题,并得到图片对象
     * @param context
     * @param path bitmap source path
     * @return Bitmap {@link android.graphics.Bitmap}
     */
    public final static Bitmap compressBitmap(InputStream is, int reqsW, int reqsH) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ReadableByteChannel channel = Channels.newChannel(is);
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (channel.read(buffer) != -1) {
                buffer.flip();
                while (buffer.hasRemaining()) baos.write(buffer.get());
                buffer.clear();
            }
            byte[] bts = baos.toByteArray();
            Bitmap bitmap = compressBitmap(bts, reqsW, reqsH);
            is.close();
            channel.close();
            baos.close();
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 压缩指定byte[]图片,并得到压缩后的图像
     * @param bts
     * @param reqsW
     * @param reqsH
     * @return
     */
    public final static Bitmap compressBitmap(byte[] bts, int reqsW, int reqsH) {
        final Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
        options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeByteArray(bts, 0, bts.length, options);
    }

    /**
     * 压缩已存在的图片对象,并返回压缩后的图片
     * @param bitmap
     * @param reqsW
     * @param reqsH
     * @return
     */
    public final static Bitmap compressBitmap(Bitmap bitmap, int reqsW, int reqsH) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(CompressFormat.PNG, 100, baos);
            byte[] bts = baos.toByteArray();
            Bitmap res = compressBitmap(bts, reqsW, reqsH);
            baos.close();
            return res;
        } catch (IOException e) {
            e.printStackTrace();
            return bitmap;
        }
    }

    /**
     * 压缩资源图片,并返回图片对象
     * @param res {@link android.content.res.Resources}
     * @param resID
     * @param reqsW
     * @param reqsH
     * @return
     */
    public final static Bitmap compressBitmap(Resources res, int resID, int reqsW, int reqsH) {
        final Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resID, options);
        options.inSampleSize = caculateInSampleSize(options, reqsW, reqsH);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resID, options);
    }

    /**
     * 基于质量的压缩算法, 此方法未 解决压缩后图像失真问题
     * <br> 可先调用比例压缩适当压缩图片后,再调用此方法可解决上述问题
     * @param bts
     * @param maxBytes 压缩后的图像最大大小 单位为byte
     * @return
     */
    public final static Bitmap compressBitmap(Bitmap bitmap, long maxBytes) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(CompressFormat.PNG, 100, baos);
            int options = 90;
            while (baos.toByteArray().length > maxBytes) {
                baos.reset();
                bitmap.compress(CompressFormat.PNG, options, baos);
                options -= 10;
            }
            byte[] bts = baos.toByteArray();
            Bitmap bmp = BitmapFactory.decodeByteArray(bts, 0, bts.length);
            baos.close();
            return bmp;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 得到指定路径图片的options
     * @param srcPath
     * @return Options {@link android.graphics.BitmapFactory.Options}
     */
    public final static Options getBitmapOptions(String srcPath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcPath, options);
        return options;
    }



    /**
     * 获取本地图片byte[]
     * @param bmp
     * @param needRecycle
     * @return
     */
    public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public static void closeStream(OutputStream os){

        if(os != null){

            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    public static void closeStream(InputStream os){

        if(os != null){

            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }



    @SuppressLint("NewApi")
    public static int getBitmapsize(Bitmap bp){

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return bp.getByteCount() / 1024;
        }
        return bp.getRowBytes() * bp.getHeight() / 1024;

    }

    /**
     * 初步处理大图片 :大小压缩
     * @param imgFilePath
     * @param smartSpace
     * @return
     */
    public static Bitmap scaleCompressBp(String imgFilePath,long smartSpace){

        File file = new File(imgFilePath);
        if(!file.exists() || !file.isFile()){

            throw new IllegalArgumentException("file not exists or file is not a image file");
        }
        long scalebefore = (file.length()/1024)/smartSpace;
        double sqrt = Math.sqrt(scalebefore);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        if((int)sqrt <= 1) sqrt = 1;
        options.inSampleSize = (int) sqrt;
        return BitmapFactory.decodeFile(imgFilePath,options);
    }



    /**
     * 进一步处理图片 : 进行质量压缩
     * desSize 不能太小失真很严重
     * @param bitmap
     * @param desSize
     * @return
     */
    private static byte[] qualityCompressBp(Bitmap bitmap,int desSize) {  
        byte[] desBytes = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;  
        int length = baos.toByteArray().length;
        while (length / 1024 > desSize) {  
            baos.reset();
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 3;
            if(options <= 10) break;
        }  
        desBytes = baos.toByteArray();
        closeStream(baos);
        return desBytes;  
    }

    /**
     * 对图片进行压缩处理 
     * 在 华为4x 1300万摄像头下进行测试的结果 原始图片 2.49M 压缩后在300kb左右 其中smartSpace 50  desSize 300
     * 根据处理文件大小的不同 来设置相应的smartSpace因子 和 desSize;
     * @param imgFilePath  原始图片文件路径
     * @param smartSpace
     * @return
     */
    public static Bitmap smartCompressBp(String imgFilePath,long smartSpace,int desSize){

        Bitmap scaleCompressBp = scaleCompressBp(imgFilePath,smartSpace);
        byte[] qualityCompressBp = qualityCompressBp(scaleCompressBp,desSize);
        return BitmapFactory.decodeByteArray(qualityCompressBp, 0, qualityCompressBp.length);

    }

    // 初步压缩  :大小压缩
    public static Bitmap scaleCompressBp(Bitmap bp,long smartSpace){

        long scalebefore = getBitmapsize(bp)/smartSpace;
        double sqrt = Math.sqrt(scalebefore);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        if((int)sqrt <= 1) sqrt = 1;
        options.inSampleSize = (int) sqrt;

        ByteArrayOutputStream aos = new ByteArrayOutputStream();
        bp.compress(Bitmap.CompressFormat.JPEG, 100, aos);

        return BitmapFactory.decodeByteArray(aos.toByteArray(), 0, aos.toByteArray().length);
    }


    // 对中等大小的图片进行处理 比如对 700kb大图片进行处理
    public static Bitmap smartCompressBp(Bitmap srcBitmap,long smartSpace,int desSize){

        Bitmap scaleCompressBp = scaleCompressBp(srcBitmap,smartSpace);
        byte[] qualityCompressBp = qualityCompressBp(scaleCompressBp,desSize);
        return BitmapFactory.decodeByteArray(qualityCompressBp, 0, qualityCompressBp.length);
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值