HarmonyOS 6.1.1-Image Kit WebP:读取WebPMetadata时,如何把缺失字段显示为页面状态

WebP 素材检查页最容易犯的错误,是把“没有显示数值”直接写成“素材有问题”,或者反过来,在字段缺失时仍用一张完整的绿色卡片表示通过。前端页面应先忠实呈现 WebPMetadata 实际返回的字段,再把“未提供”作为可以被用户继续处理的显示状态。
当前页面读取 WEBP_METADATA 后,将画布宽高、延时、未裁剪延时和循环次数拆为五个字段显示,并把元数据对象为空与字段个数不足分开说明。
每个字段都要有自己的空值文案
private valueText(value?: number): string {
return value === undefined ? '未提供' : `${value}`;
}
const metadata = await source.readImageMetadataByType([image.MetadataType.WEBP_METADATA]);
const webp = metadata.webPMetadata;
this.canvasWidth = this.valueText(webp?.canvasWidth);
this.canvasHeight = this.valueText(webp?.canvasHeight);
this.delayTime = this.valueText(webp?.delayTime);
this.unclampedDelayTime = this.valueText(webp?.unclampedDelayTime);
this.loopCount = this.valueText(webp?.loopCount);
这段代码能说明页面以 undefined 为边界,把字段显示为“未提供”而不是编造默认数值。它不能判断素材是否合格;字段的业务要求仍取决于当前素材用途。

字段汇总不替代字段详情
页面计算 provided/5 并写入 fieldSummary,方便用户快速了解当前返回范围;但具体卡片仍逐项展示。这能防止“4/5”被误认为某一个固定字段缺失,也便于用户直接看到当前缺少的是画布大小还是动画时序。
队列状态与元数据状态分开
queueStates 表示素材在当前页面队列中的本地阅读进度,loadState 与 readState 表示读取过程,字段卡片表示本次返回内容。三者各自回答不同问题。即使队列标记为“已读取”,页面也不会据此把缺失字段补齐为“已确认”。
缺失字段不是错误数值,而是一种明确输出
元数据读取页面最常见的伪完整,是把缺失字段自动显示为 0、空白或上一张素材的旧值。这三种做法都会改变事实:0 是有业务含义的数值,空白无法区分“没有返回”还是“没有渲染”,旧值则会让当前素材看起来携带了前一次信息。当前页面用“未提供”这一固定文本表达 undefined,使字段缺失成为可以阅读、可以复核的状态。
private valueText(value?: number): string {
return value === undefined ? '未提供' : `${value}`;
}
const webp = metadata.webPMetadata;
this.canvasWidth = this.valueText(webp?.canvasWidth);
this.canvasHeight = this.valueText(webp?.canvasHeight);
this.delayTime = this.valueText(webp?.delayTime);
this.unclampedDelayTime = this.valueText(webp?.unclampedDelayTime);
this.loopCount = this.valueText(webp?.loopCount);
这段代码能够说明:页面只把实际获得的数值转换为文本,未获得的字段统一保留为“未提供”。它不能据此判断素材是否符合某个投放或制作标准;字段是否必须存在、允许何种取值,仍取决于当前业务的素材规范。
| 页面显示 | 对应读取事实 | 不应误读为 |
|---|---|---|
| 具体数值 | 当前对象返回了该字段 | 素材整体已通过检查 |
| 未提供 | 当前字段为 undefined | 字段数值一定为 0 |
| 元数据对象为空 | 当前读取没有得到 webPMetadata | 文件一定不是 WebP |
| 读取调用失败 | 调用链在当前轮出现异常 | 页面已完成任何业务处置 |
五个字段要逐项展示,汇总只负责导航
画布宽高、延时、未裁剪延时与循环次数描述的是不同方向的信息。用一条“字段已返回 4/5”可以帮助使用者快速发现存在缺项,却不能告诉他缺的是哪一项。当前页面既保留 fieldSummary,又逐项输出字段卡,让汇总与详情分别承担职责。
let provided: number = 0;
if (webp?.canvasWidth !== undefined) provided += 1;
if (webp?.canvasHeight !== undefined) provided += 1;
if (webp?.delayTime !== undefined) provided += 1;
if (webp?.unclampedDelayTime !== undefined) provided += 1;
if (webp?.loopCount !== undefined) provided += 1;
this.fieldSummary = webp === undefined
? 'WEBP 元数据对象为空'
: `已返回字段 ${provided}/5`;
这段代码能够说明:页面按实际字段是否存在计算返回范围,并把对象为空与部分字段缺失区分开。它不能表示五项字段具有同等业务优先级;具体场景可能只关心尺寸,也可能只关心动画时序,页面不应由一个汇总数字替业务做判断。
新一轮读取前必须清空旧字段
素材切换时,页面如果直接开始读下一份资源而不清理字段,最容易形成“新文件名 + 旧元数据”的假象。当前页面在开始读取前调用 resetMetadata(),将五个字段、汇总、错误文本等恢复到本轮的初始状态。这样,读取过程即使尚未结束,用户也不会把上一张素材的信息当成当前结果。
private async loadSelectedSample(): Promise<void> {
const requestedIndex: number = this.selectedQueueIndex;
const sample: LiveCoverSample = this.currentSample();
this.resetMetadata();
this.loadState = '正在读取当前素材';
this.readState = '正在调用 readImageMetadataByType()';
this.releaseState = '等待创建 ImageSource';
// 创建资源并读取当前 WebPMetadata。
}
这段代码能够说明:可见字段在新请求开始前先回到明确初始状态,且页面保存了本轮请求的索引。它不能保证读取一定成功;初始态只是避免旧数据污染当前观察,不是成功结论。
| 切换时刻 | 页面应显示 | 目的 |
|---|---|---|
| 新请求尚未开始 | 未提供、待读取字段 | 清除旧素材信息 |
| 正在读取 | 当前素材名、读取调用中 | 标明本轮请求来源 |
| 已返回对象 | 五项字段与汇总 | 显示本轮实际结果 |
| 读取异常 | 失败状态、错误边界、已知字段 | 保留事实但不补齐结论 |
| 释放完成 | 对象释放状态 | 说明本轮对象生命周期边界 |
![]() |
素材队列状态不能替代元数据结果
页面中的队列状态“待检查 / 已读取”描述的是本地浏览进度。它可以帮助用户知道哪一项已经进入过读取流程,却不能作为“字段完整”“素材可用”或“已通过”的替代标签。当前读取成功后,页面更新队列状态,同时仍保留字段汇总与五项详情。
const nextStates: string[] = this.queueStates.slice();
nextStates[requestedIndex] = '已读取';
this.queueStates = nextStates;
this.localNotice = `${sample.fileName} 已完成本机读取,结论仅适用于当前样本与当前设备。`;
这段代码能够说明:已读取仅表示本地页面完成了一轮读取动作,且状态更新采用新数组避免直接修改旧状态。它不能证明元数据字段齐全、动画播放正常或素材已进入任何外部流程。前端页面应把“动作完成”和“内容符合要求”分开显示。

预览、文件大小和元数据也不是同一种证据
用户能看到封面预览,说明页面可以展示当前资源;文件大小说明原始资源读取到的字节规模;WebPMetadata 字段说明 Image Kit 在本轮调用中返回的元数据信息。三个区域经常同时出现在检查页,但它们不应互相推导。
| 可见信息 | 可以说明什么 | 不能说明什么 |
|---|---|---|
| 封面预览 | 当前页面能显示资源 | 五项元数据一定完整 |
| 文件字节数 | 当前读取到资源内容规模 | 动画时序或循环规则 |
| WebPMetadata 字段 | 当前 API 返回的字段范围 | 素材整体业务准入 |
| 队列“已读取” | 已完成本地读取动作 | 已上传、转码或发布 |
这种证据分层使页面更诚实:预览区不替字段区背书,字段区也不替素材业务结果背书。用户需要的不是一个无条件绿色状态,而是明确知道当前完成了哪一种检查、还有哪些字段需要进一步判断。
完整字段、缺失字段和快速切换分别怎样进入页面
路径一:对象与字段均返回
选择素材后,先确认当前文件名与读取状态一致;再查看五项字段和汇总是否来自同一轮读取;最后确认“已读取”只出现在队列进度中,而没有被写成准入结论。
路径二:对象为空或字段不全
查看页面是显示“元数据对象为空”还是具体的“未提供”字段。两者都应保留在本轮素材下,不能由页面预填零值、上一轮数值或业务假设。下一步应基于具体缺项判断,而不是从汇总数字猜测。
路径三:快速切换素材
连续切换两个素材时,确认页面先清空旧字段,再开始当前读取;若前一轮异步返回晚于后一轮,页面仍只允许当前选中索引写入可见结果。这样可以避免新旧素材字段混杂。
异步切换时,只允许当前选择写入页面
素材读取是异步过程。用户先选择素材 A、随后立刻切换到素材 B 时,A 的读取回调可能晚于 B 返回。若页面不保存发起读取时的索引,A 的字段就会覆盖 B 的文件名和预览,形成最难排查的一类错位:每个字段都来自真实读取,但它们不属于当前正在看的素材。
当前页面在读取开始时记录 requestedIndex,并在读取完成后确认它仍与当前选中项相同:
const requestedIndex: number = this.selectedQueueIndex;
const sample: LiveCoverSample = this.currentSample();
// 异步创建资源并读取元数据。
const metadata = await source.readImageMetadataByType([image.MetadataType.WEBP_METADATA]);
if (requestedIndex !== this.selectedQueueIndex) {
return;
}
const webp = metadata.webPMetadata;
这段代码能够说明:页面会阻止旧请求在晚到时覆盖新的可见选择。它不能取消已经发起的读取,也不能保证资源层没有继续完成后续操作;显示边界与资源释放仍要在当前方法的其他分支中分别处理。
这条保护将“当前用户正在看什么”作为可见状态的第一原则。页面并没有否认 A 的读取发生过,只是不允许它把 B 的字段卡改成自己的结果。对于任何支持连续切换的素材检查界面,这种边界比在结果区追加更多说明文字更重要。
读取状态应反映调用阶段,而不是一句总结果
页面将 loadState、readState、releaseState 和 errorMessage 分开保存。它们都与一次读取有关,却分别对应资源内容、元数据调用、对象生命周期和异常边界。若只保留一个“检查完成”状态,用户无法判断字段为空是因为调用没开始、对象为空,还是读取过程失败。
| 状态字段 | 所属阶段 | 页面解释 | 不能替代 |
|---|---|---|---|
loadState | 当前素材资源读取 | 当前样本是否进入加载过程 | 元数据是否完整 |
readState | readImageMetadataByType 调用 | API 调用处在等待、完成或失败 | 对象是否已释放 |
fieldSummary | 字段解析 | 对象为空或已返回字段数量 | 每项字段详情 |
releaseState | ImageSource 生命周期 | 当前对象是否已走到释放结果 | 素材文件是否被删除 |
errorMessage | 错误边界 | 本轮捕获到的异常位置 | 异常的唯一根因 |
这种分层让“未提供”不会被误读为“加载失败”。例如素材资源可读、元数据调用可完成,但其中一个字段未提供;这是一份完整的页面读取结果,只是字段范围有限。反之,读取调用失败时,页面应保留失败状态与错误文本,而不是把上次的字段汇总留作当前结果。
错误分支要保留当前素材身份
读取出现异常时,最不应该做的是把错误写成没有对象的“系统异常”。当前页面已有当前素材名、队列索引和读取阶段,错误信息应作为这份上下文的补充,而不是覆盖它。这样用户知道失败发生在正在阅读的哪一项素材,而不是误以为整个列表不可用。
} catch (error) {
if (requestedIndex === this.selectedQueueIndex) {
this.loadState = '样本读取失败';
this.readState = '读取调用失败';
this.errorMessage = `readImageMetadataByType: ${JSON.stringify(error)}`;
this.localNotice = '本机读取失败,未生成通过结论。';
}
}
这段代码能够说明:异常只会在请求索引仍对应当前选择时写入可见页面,且错误文本保留具体调用位置。它不能断言错误一定由素材文件导致;可能的原因需要结合实际运行环境、资源状态和 API 返回进一步判断。
对用户而言,“未生成通过结论”比“检查失败”更有边界感。页面知道本轮调用没有完成,但并不代替素材验收流程给出超出当前读取范围的否决或通过结论。
字段卡的阅读顺序应与业务判断顺序一致
五项元数据不是随意排成一列。页面可先放画布宽度与高度,帮助用户确认基础尺寸;随后放延时与未裁剪延时,便于理解动画时序;最后放循环次数。这样的顺序并不表示前面的字段更重要,而是让阅读者先建立画面空间,再进入时间与循环信息。
| 阅读顺序 | 字段 | 页面为什么先放它 |
|---|---|---|
| 1 | Canvas 宽度 | 建立横向尺寸认知 |
| 2 | Canvas 高度 | 与宽度共同形成基础画布范围 |
| 3 | delayTime | 呈现当前帧延时信息 |
| 4 | unclampedDelayTime | 保留未经裁剪的延时字段 |
| 5 | loopCount | 表达循环相关信息 |
即使某项显示“未提供”,仍应保留其位置和标签。删除整行会让用户不知道页面是否支持读取该字段,也无法判断缺失发生在什么位置。固定字段顺序使不同素材之间可直接对照,也使异常页面不会因少一行内容而改变整体布局。
小屏布局优先保留当前素材与字段值的对应关系
在较窄页面里,素材预览、队列、字段卡和状态区不宜硬塞成多列。优先保持“当前素材名称—读取状态—字段详情”连续出现,再将队列和辅助说明下移。这样用户切换素材后无需在屏幕不同位置来回核对自己正在看哪一个文件。
| 小屏优先保留 | 可以压缩或下移 |
|---|---|
| 当前素材名称、队列状态与读取状态 | 装饰性封面说明 |
| 五项字段标签和值 | 辅助历史文字 |
| 错误边界与重新读取入口 | 非关键筛选控件 |
| 释放状态 | 额外的展示性统计 |
字段值允许按行展示,但不应通过无标签的图标或颜色来缩短。缺失字段尤其需要明确文字;在小屏上把“未提供”藏进省略号,会让页面重新失去它最重要的真实性。
发布前的最小界面检查
- 初始进入时,字段区显示“未提供 / 待读取”,不出现上一轮素材数据。
- 开始读取后,素材名称、加载状态和读取状态属于同一当前选择。
- 对象存在时,五项字段逐项显示,汇总与字段数量相符。
- 对象为空或字段缺失时,页面保留对应状态,不写入 0 或猜测值。
- 快速切换素材后,旧请求不得覆盖当前选择的字段。
- 读取异常时,错误文本与当前素材上下文同时可见。
- 本地队列“已读取”不被表述成素材通过、上传或发布。
这些检查不评价素材的业务质量,只确认前端没有在字段读取、异步切换和状态解释中制造伪数据。页面把真实返回范围呈现清楚,后续质量规则才能建立在可信的输入上。
页面负责呈现,业务规则负责判断
同一份 WebPMetadata 在不同场景可能有不同要求:展示封面可能只关心画布尺寸,动画素材可能更关心延时与循环次数。前端字段页应稳定地呈现“返回了什么、没有返回什么”,但不应把一个通用的绿色或红色标签强加到所有素材上。只有当业务明确提供对应字段的验收规则时,页面才适合在字段卡旁给出针对性的判断;在此之前,“未提供”就是最准确、也最有价值的状态。

把缺失值补成0,会改变WebPMetadata的原始含义
将 undefined 直接显示为空白
空白不能解释字段为什么没有内容。固定使用“未提供”让用户知道页面已处理到该字段,但对象没有返回数值。
把缺失字段填为 0
0 是可能具有业务意义的值。页面没有得到数值时不应制造数值,否则后续判断将基于伪数据。
只显示 4/5,不展示五项详情
汇总无法指出缺失项。字段卡必须逐项保留,汇总只作为快速阅读入口。
用队列“已读取”表示素材通过
它只表示本地读过一次当前资源。字段完整性、素材质量和业务是否采用需要分别判断。
FAQ
webPMetadata 为空是否代表文件不是 WebP?
不能直接这样判断。页面只说明本次读取没有得到该对象;文件类型和业务处置应结合实际资源与调用结果继续判断。
为什么不把缺失字段填成 0?
0 是一个有业务含义的数值。用“未提供”保留真实边界,避免前端显示制造伪数据。
为什么页面同时显示字节数和元数据字段?
字节数说明已读取到的资源内容规模,元数据字段说明解码后返回的信息范围;两者并不互相替代。
元数据对象存在,是否意味着五个字段一定都有值?
不一定。对象存在与每一个可选字段是否提供是两层事实。页面需要逐项显示,而不能用对象存在替代字段完整。
为什么切换素材时先显示“未提供”?
这是新一轮读取开始后的明确初始态,用于阻止上一张素材的字段留在当前界面。它不表示新素材已经确认缺失,只表示尚未获得本轮结果。
页面显示“已读取”后能否直接当作素材准入?
不能。已读取只是本地调用完成的进度。是否准入还需依据当前业务对尺寸、时序、循环或其他质量条件的要求逐项判断。
缺失字段是否一定需要当作错误?
不一定。页面应先如实显示缺失,再由素材用途决定是否需要补齐或人工复核。前端不应把“未提供”自动升级为“失败”。
附录:HarmonyOS 6.1.1 新特性开发环境与真机验证准入
1. 版本硬基线
本批新特性统一以 HarmonyOS 6.1.1 API 24 为目标版本。项目 sourceproject/build-profile.json5 必须保持:
{
"compatibleSdkVersion": "6.1.1(24)",
"targetSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
开发者不得为了绕过构建错误,把项目静默改为 API 26 或其他版本。版本变化会同时改变 API 声明、兼容设备、文章结论和文章事实范围。
2. 编译环境准入
在 DevEco Studio 的 SDK Manager 中,必须选择与项目一致的 HarmonyOS 6.1.1(API 24) SDK。仅有 system-image 只能启动模拟器,不能证明 ArkTS 项目可以编译。至少应核对以下编译组件:

| 组件 | 作用 | 准入要求 |
|---|---|---|
hms/ets | ArkTS/ETS API 声明与编译 | 目录存在,元数据与 Hvigor 兼容 |
hms/native | Native 编译支持 | 目录存在,元数据与 Hvigor 兼容 |
hms/toolchains | 编译、签名和设备工具链 | 目录存在,hdc 可执行 |
hms/previewer | 预览与设计期支持 | 目录存在,版本与 SDK 对齐 |
openharmony/toolchains | 设备安装、启动与调试 | hdc.exe 可调用 |
硬性判定不是“SDK Manager 显示了 API 24”,而是构建已经越过 SDK 扫描并进入 CompileArkTS。本项目曾遇到组件 metaVersion: 3.1.0 与项目自带 Hvigor 扫描器不兼容,最终报 00303168 SDK component missing;此时不能进入特性 API 编码和文章结论阶段。
3. 推荐构建链路
当前已验证可用的是 DevEco Studio 内置 Hvigor 与 DevEco JBR,而不是项目自带的旧/不兼容 Hvigor 组合:
$env:DEVECO_SDK_HOME='D:\Program Files\Huawei\DevEco Studio\sdk'
$env:JAVA_HOME='D:\Program Files\Huawei\DevEco Studio\jbr'
$env:Path="$env:JAVA_HOME\bin;$env:Path"
& 'D:\Program Files\Huawei\DevEco Studio\tools\hvigor\bin\hvigorw.bat' `
--no-daemon --mode module -p module=entry@default -p product=default assembleHap --stacktrace
准入日志必须至少出现:
Finished :entry:default@CompileArkTS
Finished :entry:default@PackageHap
BUILD SUCCESSFUL
如果失败停在 SDK 扫描、依赖解析或 ArkTS 编译之前,结论只能写“环境未解锁”。不要根据 IDE 能打开项目、预览器能显示页面或旧 HAP 仍能安装,推导新特性 API 可用。
4. HAP 安装与启动环境
安装验证至少记录设备、包名、HAP 来源和结果。当前项目基线如下:
| 项目 | 要求/已验证值 |
|---|---|
| 包名 | com.csdn.harmonyos.featuredemos |
| 项目 API | compatibleSdkVersion=6.1.1(24)、targetSdkVersion=6.1.1(24) |
| 设备 API | 与项目兼容范围匹配,当前 API 24 |
releaseType | 项目、SDK、设备保持一致,当前为 Release |
| 设备形态 | 本批 Demo 以横向 Pad 为主要截图形态;手机需单独复核 |
| HAP 来源 | 当前 SDK 重新构建的产物,不沿用旧 HAP |
$hdc='D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\hdc.exe'
& $hdc install -r 'sourceproject\entry\build\default\outputs\default\entry-default-unsigned.hap'
& $hdc shell aa start -a EntryAbility -b com.csdn.harmonyos.featuredemos
install bundle successfully 只证明 HAP 与设备的安装条件匹配;start ability successfully 只证明应用可以启动。两者均不证明 Map、Camera、Notification 听觉、AI 字幕或通行证识别已经成功。

更多推荐



所有评论(0)