后端|压缩Base64图片的两种方式

        Base64是一种将二进制数据编码为ASCII字符串的方法。它通过将3个字节的二进制数据转换为4个可打印字符的ASCII字符,从而将二进制数据转换为可传输的文本格式。Base64编码常用于传输图片或音频文件。Base64编码可以保证数据在传输过程中不丢失,同时可以避免某些系统不支持二进制数据的问题。

        但是Base64转换成图片之前,如何压缩目标图片的大小呢?本文提供两种方式。

方法一:按尺寸压缩(不保证图片质量)


    /**
     * 去掉Base64图片数据的前缀
     *
     * @param base64Str 含前缀的Base64字符串
     * @return 不含前缀的Base64字符串
     */
    private static String removeBase64Prefix(String base64Str) {
        // 使用正则表达式去掉"data:image/\w+;base64,"前缀
        Pattern pattern = Pattern.compile("^data:image/\\w+;base64,");
        Matcher matcher = pattern.matcher(base64Str);
        return matcher.replaceFirst("");
    }


    /**
     * 添加Base64图片数据的前缀
     *
     * @param base64Str 不含或含其他前缀的Base64字符串
     * @param prefix 想要添加的Base64前缀,默认为"data:image/png;base64,"
     * @return 含指定前缀的Base64字符串
     */
    public static String addBase64Prefix(String base64Str, String prefix) {
        // 检查是否已存在指定的前缀,如果有,则直接返回
        if (base64Str.startsWith(prefix)) {
            return base64Str;
        }
        return prefix + base64Str;
    }

    /**
     * 压缩base64编码至200K以内
     *
     * @param base64Img
     * @return
     */
    public static String resizeImageTo200K(String base64Img) {
        try {

            byte[] bytes1 =  Base64.getDecoder().decode(removeBase64Prefix(base64Img));
            System.out.println( bytes1.length);
            InputStream stream = new ByteArrayInputStream(bytes1);
            BufferedImage src = ImageIO.read(stream);
            // 压缩的尺寸
            BufferedImage output = output=Thumbnails.of(src).size(640, 480).asBufferedImage();
            String base64 = imageToBase64(output);
            double minScalingFactor = 0.7; // 设置最小缩放因子
            if (base64.length() - base64.length() / 8 * 2 > 200000) {
                double scalingFactor = Math.max(minScalingFactor, 1 - (base64.length() / 200000));

                output = Thumbnails.of(output).scale(scalingFactor).asBufferedImage();
                base64 = imageToBase64(output);
            }
            return addBase64Prefix(base64, "data:image/png;base64,");
        } catch (Exception e) {
            return addBase64Prefix(base64Img, "data:image/png;base64,");
        }
    }

    // BufferedImage转换成base64,在这里需要设置图片格式,如下是png格式图片:
    public static String imageToBase64(BufferedImage bufferedImage) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "png", baos);
        } catch (IOException e) {
        }
        String str = new String(Base64.getEncoder().encode(baos.toByteArray()));
        return str;
    }

}



方法二:等质量压缩

 /**
     * 压缩base64编码图片至目标大小附近,尽量保持图片质量
     *
     * @param base64Img base64编码的图片字符串
     * @param targetSize 目标大小(例如:200KB)
     * @return 调整大小后的base64编码图片字符串
     */
    public static String resizeImageToTargetSize(String base64Img, int targetSize) {
        try {
            String s = removeBase64Prefix(base64Img);
            byte[] imageBytes = Base64.getDecoder().decode(s);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
            BufferedImage src = ImageIO.read(inputStream);

            // 初始化压缩质量为最高,根据需要逐步降低
            float quality = 1.0f;
            float step = 0.1f;
            boolean compressMore = true;

            byte[] compressedBytes = null;
            while (compressMore) {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
                if (!writers.hasNext()) throw new IllegalStateException("No writers found");

                ImageWriter writer = writers.next();
                ImageWriteParam param = writer.getDefaultWriteParam();

                // 设置压缩质量
                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                param.setCompressionQuality(quality);

                MemoryCacheImageOutputStream memStream = new MemoryCacheImageOutputStream(outputStream);
                writer.setOutput(memStream);

                IIOImage outputImage = new IIOImage(src, null, null);
                writer.write(null, outputImage, param);

                writer.dispose();

                compressedBytes = outputStream.toByteArray();
                int currentSize = compressedBytes.length;
                System.out.println("尝试质量: " + quality + ", 大小: " + currentSize);

                // 如果压缩后大小仍超过目标大小,降低质量继续尝试;否则停止循环
                if (currentSize > targetSize) {
                    quality -= step;
                    if (quality < 0.1f) { // 防止质量降得过低
                        quality = 0.1f;
                    }
                } else {
                    compressMore = false;
                }
            }

            String base64Encoded = Base64.getEncoder().encodeToString(compressedBytes);
            return addBase64Prefix(base64Encoded, "data:image/png;base64,");
        } catch (Exception e) {
            return base64Img; // 如果压缩失败,返回原图
        }
    }

上一篇:HTML 中使用 JavaScript 的具体方式


下一篇:stm32MP135裸机编程:修改官方GPIO例程在DDR中点亮第一颗LED灯