Java 处理图片-压缩本地图片及远程图片,按照BASE64格式输出

很久没有写博客了,不是我颓废了,而是实在是太忙了,抽不出时间也抽不出经历写东西了,幸亏项目已经落地,没有那么的忙了,记录一下。

最近在做导出,发现很多时候导出的图片太大了,及其容易引起堆栈溢出,图片必须经过压缩再导出了,由于客户对图片质量要求不是特别高,能看清即可,所以直接等比例压缩即可,尽量保证质量不变,只改变其大小,废话不多说,整起
  1. 第一层入口,由于我们的图片信息是存放再json字段中的,为了避免转换时出现双引号,所以判断就或一下啦。方法支持base64压缩以及远程图片压缩两种方式,实际判断可以根据需求进行修改

     /**
         * 根据传递的参数来处理图片,不是图片时直接返回null
         *
         * @param str 图片info
         * @return 压缩后的图片
         */
        public static String strToImageBase64(String str) {
            if (StringUtils.hasLength(str) && (str.startsWith("data:image/png;base64,") || str.startsWith("\"data:image/png;base64,"))) {
                //去掉base64的头部信息
                String autonomyDeclareSign = str.replace("\"data:image/png;base64,", "").replace("\"", "");
                //压缩图片大小
                String autonomyDeclareSignPng = ImageUtils.scaleImage(autonomyDeclareSign, "png");
                return ObjectUtils.isEmpty(autonomyDeclareSignPng) || autonomyDeclareSignPng.equals("0") ? null : autonomyDeclareSignPng;
            } else {
                //不是base64时,直接按照远程url获取图片并压缩
                String autonomyDeclareSignPng = ImageUtils.imageToBase64(str, "png");
                return ObjectUtils.isEmpty(autonomyDeclareSignPng) || autonomyDeclareSignPng.equals("0") ? null : autonomyDeclareSignPng;
            }
        }
    

    2.BASE64图片压缩方法

        /**
     * 根据图片的base64数据缩放图片20kb
     *
     * @param base64ImagStr 原图的base64字符换
     * @param imageType     图片类型
     * @return base64数据缩放图片
     */
    public static String scaleImage(String base64ImagStr, String imageType) {
        if (StringUtils.hasLength(base64ImagStr) && !"0".equals(base64ImagStr)) {
            BufferedImage bufferedImage;
            try {
                //获取图片的buffer
                bufferedImage = ImgUtil.toImage(base64ImagStr);
            } catch (Exception e) {
                return null;
            }
            //获取图片的宽度
            int width = bufferedImage.getWidth();
            //获取图片的高度
            int height = bufferedImage.getHeight();
            //计算图片需要压缩的比例,宽高相等时,在原比例直接除以2
            if (width == height) {
                width = width / 2;
                height = height / 2;
                //宽大于高,先计算出宽高相差倍数,然后宽/2,高度=宽/原比例
            } else if (width > height) {
                double v = width / (height * 1.000000);
                width = width / 2;
                height = (int) (width / v);
            } else {
                //高大于宽,先计算出宽高相差倍数,然后高/2,宽度=高/原比例
                double v = width / (height * 1.000000);
                height = height / 2;
                width = (int) (height / v);
            }
            // 通过计算出的宽高来压缩图片,此时只压缩图片的大小,不压缩质量
            //质量:等比例质量,即原1024*1024 压缩后 512*512
            Image scaleImage = ImgUtil.scale(bufferedImage, width, height);
            //根据图片类型,转化图片为base64
            String resultBase64Str = ImgUtil.toBase64(scaleImage, imageType);
            //计算图片大小
            Integer imageSizeBase64 = imageSize(resultBase64Str);
            //如果图片大于20KB,继续压缩
            if (imageSizeBase64 > 20) {
                resultBase64Str = scaleImage(resultBase64Str, imageType);
            }
            return resultBase64Str;
        }
        return base64ImagStr;
    }
    
    /**
     * 计算图片的大小,返回单位为KB
     *
     * @param imageBase64Str 图片base64数据
     * @return 图片大小
     */
    public static Integer imageSize(String imageBase64Str) {
    
        //1.找到等号,把等号也去掉(=用来填充base64字符串长度用)
        int equalIndex = imageBase64Str.indexOf("=");
        if (imageBase64Str.indexOf("=") > 0) {
            imageBase64Str = imageBase64Str.substring(0, equalIndex);
        }
        //2.原来的字符流大小,单位为字节
        int strLength = imageBase64Str.length();
        System.out.println("imageBase64Str Length = " + strLength);
        //3.计算后得到的文件流大小,单位为字节
        int size = strLength - (strLength / 8) * 2;
        return bytesToKB(size);
    }
    
    /**
         * byte(字节)根据长度转成kb(千字节)
         *
         * @param bytes 字节
         * @return 大小
         */
        public static Integer bytesToKB(long bytes) {
            BigDecimal filesize = new BigDecimal(bytes);
            BigDecimal kilobyte = new BigDecimal(1024);
            float returnValue = filesize.divide(kilobyte, 1, RoundingMode.DOWN).floatValue();
            return (int) returnValue;
        }
    

    3.远程图片压缩(其中会调用BASE64压缩)

    /**
         * 通过图片的url获取图片的base64字符串,同时压缩图片
         *
         * @param imgUrl 图片url
         * @param suffix 图片后缀
         * @return 返回图片base64的字符串
         */
        public static String imageToBase64(String imgUrl, String suffix) {
            if (ObjectUtils.isEmpty(imgUrl) || "null".equals(imgUrl)) {
                return null;
            }
            URL url;
            InputStream is = null;
            ByteArrayOutputStream outStream = null;
            HttpURLConnection httpUrl = null;
            try {
                url = new URL(imgUrl);
                httpUrl = (HttpURLConnection) url.openConnection();
                httpUrl.connect();
                is = httpUrl.getInputStream();
                outStream = new ByteArrayOutputStream();
                //创建一个Buffer字符串
                byte[] buffer = new byte[1024];
                //每次读取的字符串长度,如果为-1,代表全部读取完毕
                int len;
                //使用一个输入流从buffer里把数据读取出来
                while ((len = is.read(buffer)) != -1) {
                    //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
                    outStream.write(buffer, 0, len);
                }
                // 对字节数组Base64编码
                Base64.Encoder base64Encoder = Base64.getEncoder();
                String encodeToString = base64Encoder.encodeToString(outStream.toByteArray());
                return scaleImage(encodeToString, suffix);
            } catch (Exception e) {
                System.out.println("图片解析失败" + imgUrl);
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (outStream != null) {
                    try {
                        outStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (httpUrl != null) {
                    httpUrl.disconnect();
                }
            }
            return null;
        }
    

好啦,到这里处理图片的过程基本结束啦,但是要注意哦,即便这样处理也是有堆栈溢出的风险的,所以最好是再导出或下载时缓冲一下。想要提升速度也可以做一下异步处理,但是由于该方法是单独图片处理所以提升不是那么的明显。

项目使用的依赖:hutool-core-5.7.22.jar 其他都是JDK自带的哦,也可以全部使用自带的,但是代码量会上来,所以偷下懒,嘿嘿!有时间下次见GIT:motcs 没有demo上传git哦
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值