后端|压缩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; // 如果压缩失败,返回原图
        }
    }

### 实现全局广告组件的封装及调用 在 UniApp 开发过程中,为了提高代码复用性和维护性,可以将常用的广告组件进行全局挂载。这不仅简化了页面间的引用操作,还提高了开发效率[^1]。 #### 创建广告组件 首先创建一个名为 `AdComponent.vue` 的文件作为广告展示组件: ```vue <template> <view class="ad-container"> <!-- 广告位 --> <ad unit-id="your_ad_unit_id"></ad> </view> </template> <script> export default { name: 'AdComponent', }; </script> <style scoped> .ad-container { width: 100%; } </style> ``` 此部分实现了基础的广告容器结构并设置了样式。 #### 注册为全局组件 接着修改项目的入口文件 `main.js` 或者按照平台条件编译的要求放置相应位置,注册上述创建好的广告组件成为全局可用组件: ```javascript import Vue from 'vue'; // 导入自定义广告组件 import AdComponent from '@/components/AdComponent'; Vue.component('global-ad', AdComponent); // 将其命名为 global-ad 方便后续使用 new Vue({ render: h => h(App), }).$mount('#app'); ``` 这段代码完成了对 `AdComponent` 组件的导入以及将其注册成名称为 `global-ad` 的全局标签形式供各处调用。 #### 页面内调用全球广告组件 最后,在任何需要显示广告的位置只需简单加入如下 HTML 片段即可完成调用: ```html <!-- 使用已注册过的全局广告组件 --> <global-ad></global-ad> ``` 以上步骤即完成了整个流程——从构建独立功能模块到使其变为跨页共享资源的过程。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值