紧接着上篇文章。我们继续HarmonyOS 中 HEIF 图像开发全流程。这篇主要记录如何进行图转码。

实战 :HEIF 图像自定义处理(进阶场景)

这里还是说一下环境吧。

环境要求

  • HarmonyOS 版本:需基于 HarmonyOS 5.0 及以上(HEIF 解码性能优化、硬件编码支持均从 5.0 开始)。
  • 开发工具:DevEco Studio 5.0 及以上(确保 ArkUI 组件与 Image Kit API 兼容)。
  • 测试设备:搭载 HarmonyOS 5.x 的真机或模拟器(部分硬件解码能力需真机支持)。
  • 图像资源:准备 1-2 张 HEIF 格式图片(后缀通常为 .heif 或 .heic,可通过手机拍摄或在线工具转换获取),并放入项目的 main_pages/images 目录下(需在 module.json5 中配置资源路径)。

部分旧应用或第三方接口可能仅支持 JPEG 格式,此时需将 HEIF 转码为 JPEG 并保存到本地。本实战将实现 “加载 HEIF 图片→转码为 JPEG→保存到应用沙箱目录” 的全流程。

1. 场景需求

加载 scenery.heic 图片,将其转码为质量 95 的 JPEG 格式,保存到应用的沙箱目录(/data/storage/el2/base/haps/应用包名/files/),并输出保存路径。

2. 操作步骤

步骤 1:申请文件读写权限

转码后需保存文件到本地,需在 module.json5 中申请 ohos.permission.WRITE_USER_STORAGE 权限:

{
  "module": {
    "abilities": [
      {
        "permissions": [
          {
            "name": "ohos.permission.WRITE_USER_STORAGE",
            "reason": "需要保存转码后的JPEG图片",
            "usedScene": { "when": "always" }
          }
        ]
      }
    ]
  }
}

步骤 2:编写转码代码

通过 image.createImagePacker() 创建编码器,配置 JPEG 编码参数(质量、是否保留 EXIF 信息),最后将转码后的文件保存到沙箱目录:

import image from '@ohos.multimedia.image';
import fs from '@ohos.file.fs';
import { Column, Button, Text, FlexAlign, AlertDialog } from '@ohos/ui';
import permission from '@ohos.permission';

@Entry
@Component
struct HEIFTranscodePage {
  private jpegSavePath: string = '';  // 存储 JPEG 保存路径

  // 申请文件读写权限
  async requestStoragePermission() {
    const result = await permission.requestPermissions(['ohos.permission.WRITE_USER_STORAGE']);
    return result[0].grantStatus === permission.GrantStatus.PERMISSION_GRANTED;
  }

  // 核心方法:HEIF 转码为 JPEG 并保存
  async transcodeHEIFToJPEG() {
    // 1. 先申请权限
    const hasPermission = await this.requestStoragePermission();
    if (!hasPermission) {
      AlertDialog.show({ message: '请授予文件读写权限,否则无法保存图片' });
      return;
    }

    try {
      // 2. 创建 HEIF 图像源
      const imageSource = image.createImageSource($r('app.image.scenery').uri);

      // 3. 创建图像编码器(用于转码)
      const imagePacker = image.createImagePacker();

      // 4. 配置 JPEG 编码选项
      const packOpts: image.PackingOption = {
        format: 'image/jpeg',          // 目标格式为 JPEG
        quality: 95,                   // 质量(0-100,95 为高质量)
        needsPackProperties: true      // 保留原图片的 EXIF 信息(如拍摄时间、分辨率)
      };

      // 5. 定义 JPEG 保存路径(应用沙箱的 files 目录)
      const appFilesDir = fs.getAppFilesDir();  // 获取应用沙箱目录
      this.jpegSavePath = `${appFilesDir}/transcoded_scenery.jpg`;

      // 6. 打开文件流,准备保存
      const file = await fs.open(this.jpegSavePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

      // 7. 执行转码并保存到文件
      await imagePacker.packToFile(imageSource, file.fd, packOpts);

      // 8. 关闭文件流、释放资源
      await fs.close(file.fd);
      imagePacker.release();
      imageSource.release();

      // 9. 提示转码成功并输出路径
      AlertDialog.show({
        title: '转码成功',
        message: `JPEG 保存路径:${this.jpegSavePath}`,
        confirm: { text: '确定' }
      });
    } catch (err) {
      console.error('HEIF 转码失败:', err);
      AlertDialog.show({ message: '转码失败,请检查图片格式或权限' });
    }
  }

  build() {
    Column({ space: 30, alignItems: FlexAlign.Center }) {
      Text('HEIF 转码为 JPEG')
        .fontSize(24)
        .fontWeight(FontWeight.Bold);

      // 触发转码的按钮
      Button('开始 HEIF 转码为 JPEG')
        .width(300)
        .height(50)
        .fontSize(16)
        .onClick(() => {
          this.transcodeHEIFToJPEG();
        });

      // 显示保存路径
      if (this.jpegSavePath) {
        Text(`JPEG 已保存至:\n${this.jpegSavePath}`)
          .fontSize(14)
          .width('90%')
          .textAlign(TextAlign.Center);
      }
    }
    .padding(20)
    .width('100%')
    .height('100%');
  }
}

步骤 3:验证转码结果

  1. 运行应用,点击 “开始 HEIF 转码为 JPEG” 按钮,授予权限后,会弹出 “转码成功” 提示。
  2. 通过 DevEco Studio 的 “Device File Explorer”(设备文件浏览器),导航到提示的 jpegSavePath 目录,下载 transcoded_scenery.jpg 到本地,用图片查看器确认:
    • 格式为 JPEG(后缀 .jpg)。
    • 图像质量无明显损失(因质量设为 95)。
    • EXIF 信息保留(可通过图片属性查看拍摄时间等)。

3. 关键注意点

  • 权限申请:HarmonyOS 6.0 及以上需动态申请 WRITE_USER_STORAGE 权限,静态配置后需通过 permission.requestPermissions() 触发用户授权。
  • 编码质量quality 设为 95 时,可在 “体积” 与 “质量” 间取得平衡;若需更小体积,可降至 80-90。
  • 文件覆盖:若目标路径已存在同名文件,需先删除或重命名,避免转码失败(可通过 fs.access() 判断文件是否存在)。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐