HarmonyOS Next 将ArrayBuffer压缩到指定大小并转化为base64返回

鸿蒙开发中图片压缩至固定大小的实现

在鸿蒙应用开发中,图片压缩是一个常见的需求,尤其是在需要将图片上传到服务器或存储到本地时。为了满足项目中对图片大小的严格要求,我们需要将图片压缩到固定大小。本文将详细介绍如何在鸿蒙开发中实现这一功能,包括图片压缩、大小检查以及循环压缩直至达到目标大小的实现方法。


1. 图片压缩的基本原理

鸿蒙系统提供了 image.ImagePacker 类,用于对图片进行压缩。通过设置图片格式和质量参数,可以实现对图片的压缩。然而,直接设置质量参数并不能保证压缩后的图片大小符合预期,因此需要结合循环检查和逐步调整质量参数的方式来实现目标。


2. 实现步骤

以下是实现图片压缩至固定大小的详细步骤:

(1)初始化图片数据和目标大小

首先,我们需要获取待压缩的图片数据和目标大小:

let bitmap: ArrayBuffer; // 需要压缩的图片数据
let compressSize: number; // 目标大小(单位:KB)
let considerBase64: boolean; // 是否考虑 Base64 编码的影响
let result = ''; // 压缩后的结果

(2)创建图片源和压缩器

使用 image.createImageSourceimage.createImagePacker 创建图片源和压缩器:

if (bitmap) {
    try {
        let imageSource = image.createImageSource(bitmap);
        let packer = image.createImagePacker();
        let packerData = await packer.packing(imageSource, {
            format: 'image/jpeg',
            quality: 100 // 初始质量设置为 100
        });

(3)考虑 Base64 编码的影响

如果需要对压缩后的图片进行 Base64 编码,则需要考虑 Base64 编码会将字节数扩大约 4/3 倍的影响:

if (considerBase64 && compressSize > 0) {
    compressSize = Math.ceil(compressSize * 3.0 / 4.0 - 0.5);
}

(4)循环压缩直至达到目标大小

通过 while 循环逐步降低图片质量,直到压缩后的图片大小小于或等于目标大小:

let optionQuality = 90; // 初始质量设置为 90
while (compressSize > 0
    && packerData.byteLength / 1024 > compressSize
    && optionQuality > 0) {
    let whilePacker = image.createImagePacker();
    let whileImageSource = image.createImageSource(packerData);
    packerData = await whilePacker.packing(whileImageSource, {
        format: 'image/jpeg',
        quality: optionQuality
    });
    optionQuality -= 10; // 每次降低质量 10
}

(5)将压缩后的图片转换为 Base64 字符串

最后,将压缩后的图片数据转换为 Base64 字符串:

result = buffer.from(packerData).toString('base64');

(6)错误处理

在压缩过程中,可能会遇到各种错误(如图片格式不支持、内存不足等),需要进行捕获和处理:

} catch (error) {
    hilog.error(0x0000, 'error: ' + JSON.stringify(error), '%{public}s');
}

3. 完整代码示例

以下是一个完整的代码示例,包括图片压缩、大小检查和循环压缩的实现:

import image from '@ohos.multimedia.image';
import hilog from '@ohos.hilog';
import buffer from '@ohos.buffer';

async function compressImageToSize(bitmap: ArrayBuffer, compressSize: number, considerBase64: boolean): Promise<string> {
    let result = '';

    if (bitmap) {
        try {
            // 创建图片源和压缩器
            let imageSource = image.createImageSource(bitmap);
            let packer = image.createImagePacker();
            let packerData = await packer.packing(imageSource, {
                format: 'image/jpeg',
                quality: 100 // 初始质量设置为 100
            });

            // 考虑 Base64 编码的影响
            if (considerBase64 && compressSize > 0) {
                compressSize = Math.ceil(compressSize * 3.0 / 4.0 - 0.5);
            }

            // 循环压缩直至达到目标大小
            let optionQuality = 90; // 初始质量设置为 90
            while (compressSize > 0
                && packerData.byteLength / 1024 > compressSize
                && optionQuality > 0) {
                let whilePacker = image.createImagePacker();
                let whileImageSource = image.createImageSource(packerData);
                packerData = await whilePacker.packing(whileImageSource, {
                    format: 'image/jpeg',
                    quality: optionQuality
                });
                optionQuality -= 10; // 每次降低质量 10
            }

            // 将压缩后的图片转换为 Base64 字符串
            result = buffer.from(packerData).toString('base64');
        } catch (error) {
            hilog.error(0x0000, 'error: ' + JSON.stringify(error), '%{public}s');
        }
    }

    return result;
}

4. 注意事项

在实际开发中,需要注意以下几点:

(1)性能优化

  • 如果图片较大,循环压缩可能会占用较多 CPU 资源,建议在子线程中执行压缩操作。
  • 可以设置最大循环次数,避免无限循环。

(2)图片质量

  • 逐步降低图片质量可能会导致图片失真,需要根据实际需求调整质量参数。

(3)错误处理

  • 捕获并处理压缩过程中可能出现的异常,确保程序的健壮性。

5. 总结

通过以上方法,我们可以在鸿蒙开发中实现将图片压缩至固定大小的功能。这种方法结合了图片质量调整和大小检查,能够有效满足项目中对图片大小的严格要求。希望本文的介绍能为您的开发工作提供帮助!

posted @ 2025-03-20 14:37  水滴石轩  阅读(263)  评论(0)    收藏  举报