本篇学习图片处理能力和资源管理实现祝福卡片图片处理图图片处理与资源管理 的关键流程与实现要点。学习目标完成本篇后你将能够✅ 掌握图片资源类型✅ 配置图片组件属性✅ 使用图片处理能力✅ 管理应用资源文件预计学习时间约 90 分钟实战一图片资源类型第一步本地图片资源// 使用 $r 引用 media 目录下的图片 Image($r(app.media.icon)) .width(100) .height(100) // 使用 $rawfile 引用 rawfile 目录下的图片 Image($rawfile(images/photo.png)) .width(100) .height(100)第二步网络图片Image(https://example.com/image.png) .width(100) .height(100)第三步Base64 图片const base64Image data:image/png;base64,iVBORw0KGgo...; Image(base64Image) .width(100) .height(100)第四步PixelMap 图片import { image } from kit.ImageKit; State pixelMap: image.PixelMap | null null; // 使用 PixelMap if (this.pixelMap) { Image(this.pixelMap) .width(100) .height(100) }实战二图片组件配置第一步填充模式Image($r(app.media.photo)) .width(200) .height(150) .objectFit(ImageFit.Cover) // 填充模式模式说明Contain保持比例完整显示Cover保持比例填满容器Fill拉伸填满可能变形None原始尺寸ScaleDown缩小或原始尺寸案例效果┌─────────────────────────────────────────┐ │ 填充模式对比 │ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │ 福 │ │██████│ │██████│ │ │ │ │ │██福██│ │█福███│ │ │ │ 完整 │ │██████│ │██████│ │ │ └──────┘ └──────┘ └──────┘ │ │ Contain Cover Fill │ │ 保持比例 填满裁切 拉伸填满 │ └─────────────────────────────────────────┘第二步图片插值Image($r(app.media.photo)) .interpolation(ImageInterpolation.High) // 高质量插值第三步渲染模式// 原始模式 Image($r(app.media.icon)) .renderMode(ImageRenderMode.Original) // 模板模式可着色 Image($r(app.media.icon)) .renderMode(ImageRenderMode.Template) .fillColor(#c41e3a)第四步图片圆角和边框Image($r(app.media.avatar)) .width(80) .height(80) .borderRadius(40) // 圆形 .border({ width: 2, color: #c41e3a })实战三图片处理能力第一步创建 PixelMapimport { image } from kit.ImageKit; async function createPixelMap(width: number, height: number): Promiseimage.PixelMap { const options: image.InitializationOptions { size: { width, height }, pixelFormat: image.PixelMapFormat.RGBA_8888, alphaType: image.AlphaType.IMAGE_ALPHA_TYPE_OPAQUE }; return await image.createPixelMap(options); }第二步从资源创建 PixelMapasync function loadImageFromResource(resourceName: string): Promiseimage.PixelMap | null { try { const context getContext(this); const resourceManager context.resourceManager; // 读取资源 const imageData await resourceManager.getMediaContent($r(app.media.${resourceName})); // 创建 ImageSource const imageSource image.createImageSource(imageData.buffer); // 解码为 PixelMap const pixelMap await imageSource.createPixelMap(); return pixelMap; } catch (error) { console.error(加载图片失败:, error); return null; } }第三步图片裁剪async function cropImage( pixelMap: image.PixelMap, x: number, y: number, width: number, height: number ): Promisevoid { await pixelMap.crop({ x, y, size: { width, height } }); }第四步图片缩放async function scaleImage( pixelMap: image.PixelMap, scaleX: number, scaleY: number ): Promisevoid { await pixelMap.scale(scaleX, scaleY); }实战四资源管理器第一步获取资源管理器import { resourceManager } from kit.LocalizationKit; const context getContext(this); const resManager context.resourceManager;第二步读取 rawfile 资源async function readRawFile(fileName: string): PromiseUint8Array { const context getContext(this); const resManager context.resourceManager; const data await resManager.getRawFileContent(fileName); return data; }第三步读取媒体资源async function readMediaResource(resourceId: Resource): PromiseUint8Array { const context getContext(this); const resManager context.resourceManager; const data await resManager.getMediaContent(resourceId); return data; }第四步写入临时文件import { fileIo } from kit.CoreFileKit; async function writeToTempFile(data: Uint8Array, fileName: string): Promisestring { const context getContext(this); const tempDir context.tempDir; const filePath ${tempDir}/${fileName}; const file fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY); fileIo.writeSync(file.fd, data.buffer); fileIo.closeSync(file.fd); return filePath; }实战五祝福卡片图片处理第一步创建图片处理页面import { image } from kit.ImageKit; import { fileIo } from kit.CoreFileKit; interface BlessingCard { name: string; title: string; resource: Resource; } Entry Component struct Lesson22Page { State currentCard: BlessingCard | null null; State cardPixelMap: image.PixelMap | null null; State isLoading: boolean false; private blessingCards: BlessingCard[] [ { name: fortune, title: 福, resource: $r(app.media.blessing_fortune) }, { name: wealth, title: 财, resource: $r(app.media.blessing_gold_ingot) }, { name: happiness, title: 喜, resource: $r(app.media.blessing_happy_newyear) }, { name: longevity, title: 寿, resource: $r(app.media.blessing_good_luck) }, { name: prosperity, title: 禄, resource: $r(app.media.blessing_five_fortune) } ]; aboutToAppear() { this.selectRandomCard(); } selectRandomCard() { const index Math.floor(Math.random() * this.blessingCards.length); this.currentCard this.blessingCards[index]; } async loadCardImage() { if (!this.currentCard) return; this.isLoading true; try { const context getContext(this); const resManager context.resourceManager; // 读取图片资源 const imageData await resManager.getMediaContent(this.currentCard.resource); // 创建 ImageSource const imageSource image.createImageSource(imageData.buffer); // 解码为 PixelMap this.cardPixelMap await imageSource.createPixelMap(); } catch (error) { console.error(加载图片失败:, error); } finally { this.isLoading false; } } async saveToTempFile(): Promisestring | null { if (!this.currentCard) return null; try { const context getContext(this); const resManager context.resourceManager; // 读取图片资源 const imageData await resManager.getMediaContent(this.currentCard.resource); // 写入临时文件 const tempDir context.tempDir; const filePath ${tempDir}/${this.currentCard.name}.png; const file fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY); fileIo.writeSync(file.fd, imageData.buffer); fileIo.closeSync(file.fd); return filePath; } catch (error) { console.error(保存文件失败:, error); return null; } } build() { Column() { // 头部 Row() { Text(图片处理) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#1e293b) } .width(100%) .height(56) .padding({ left: 16, right: 16 }) .backgroundColor(Color.White) Scroll() { Column({ space: 20 }) { // 当前卡片 Column({ space: 12 }) { Text(当前祝福卡片) .fontSize(16) .fontWeight(FontWeight.Medium) .fontColor(#1e293b) if (this.currentCard) { Column({ space: 8 }) { Image(this.currentCard.resource) .width(200) .height(200) .objectFit(ImageFit.Contain) .borderRadius(12) Text(this.currentCard.title) .fontSize(24) .fontWeight(FontWeight.Bold) .fontColor(#c41e3a) } } Button(换一张) .onClick(() { this.selectRandomCard(); }) .backgroundColor(#c41e3a) } .width(100%) .padding(16) .backgroundColor(Color.White) .borderRadius(12) .alignItems(HorizontalAlign.Center) // 图片操作 Column({ space: 12 }) { Text(图片操作) .fontSize(16) .fontWeight(FontWeight.Medium) .fontColor(#1e293b) Row({ space: 12 }) { Button(加载 PixelMap) .layoutWeight(1) .onClick(async () { await this.loadCardImage(); }) Button(保存到临时目录) .layoutWeight(1) .onClick(async () { const path await this.saveToTempFile(); if (path) { AlertDialog.show({ title: 保存成功, message: 文件路径: ${path}, primaryButton: { value: 确定, action: () {} } }); } }) } .width(100%) if (this.isLoading) { LoadingProgress() .width(32) .height(32) } if (this.cardPixelMap) { Text(PixelMap 已加载) .fontSize(14) .fontColor(#22c55e) } } .width(100%) .padding(16) .backgroundColor(Color.White) .borderRadius(12) .alignItems(HorizontalAlign.Start) // 图片展示模式 Column({ space: 12 }) { Text(填充模式对比) .fontSize(16) .fontWeight(FontWeight.Medium) .fontColor(#1e293b) Row({ space: 8 }) { Column({ space: 4 }) { Image($r(app.media.blessing_fortune)) .width(80) .height(60) .objectFit(ImageFit.Contain) .backgroundColor(#f0f0f0) .borderRadius(4) Text(Contain) .fontSize(10) .fontColor(#64748b) } Column({ space: 4 }) { Image($r(app.media.blessing_fortune)) .width(80) .height(60) .objectFit(ImageFit.Cover) .backgroundColor(#f0f0f0) .borderRadius(4) Text(Cover) .fontSize(10) .fontColor(#64748b) } Column({ space: 4 }) { Image($r(app.media.blessing_fortune)) .width(80) .height(60) .objectFit(ImageFit.Fill) .backgroundColor(#f0f0f0) .borderRadius(4) Text(Fill) .fontSize(10) .fontColor(#64748b) } } } .width(100%) .padding(16) .backgroundColor(Color.White) .borderRadius(12) .alignItems(HorizontalAlign.Start) } .padding(16) } .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(#f8f6f5) } } Builder export function Lesson22PageBuilder() { Lesson22Page() }案例效果页面运行后展示如下界面┌─────────────────────────────────────┐ │ 图片处理 │ ├─────────────────────────────────────┤ │ │ │ ┌─────────────────────────────┐ │ │ │ 当前祝福卡片 │ │ │ │ │ │ │ │ ┌──────────┐ │ │ │ │ │ │ │ │ │ │ │ 福 │ │ │ │ │ │ │ │ │ │ │ └──────────┘ │ │ │ │ 福 │ │ │ │ │ │ │ │ [ 换一张 ] │ │ │ └─────────────────────────────┘ │ │ │ │ ┌─────────────────────────────┐ │ │ │ 图片操作 │ │ │ │ │ │ │ │ [加载PixelMap] [保存到临时] │ │ │ │ │ │ │ │ ✅ PixelMap 已加载 │ │ │ └─────────────────────────────┘ │ │ │ │ ┌─────────────────────────────┐ │ │ │ 填充模式对比 │ │ │ │ │ │ │ │ ┌────┐ ┌────┐ ┌────┐ │ │ │ │ │ 福 │ │█福█│ │█福█│ │ │ │ │ └────┘ └────┘ └────┘ │ │ │ │ Contain Cover Fill │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘效果说明 - 顶部展示随机抽取的祝福卡片图片和标题 - 点击「换一张」随机切换不同祝福卡片 - 「加载 PixelMap」按钮加载后显示绿色 ✅ 提示 - 「保存到临时目录」成功后弹出路径弹窗 - 底部展示 Contain/Cover/Fill 三种填充模式的对比效果第二步运行验证hvigorw assembleHap --no-daemon本课小结核心知识点知识点说明$r()引用 media 资源$rawfile()引用 rawfile 资源objectFit图片填充模式PixelMap图片像素数据resourceManager资源管理器图片处理流程获取资源管理器读取图片数据创建 ImageSource解码为 PixelMap进行图片处理保存或显示课后练习练习1实现图片滤镜为祝福卡片添加灰度、模糊等滤镜效果。练习2实现图片合成将祝福文字合成到卡片图片上。下一课预告第23课我们将进入案例实战篇完整开发职官词典模块包括需求分析与设计数据层实现列表页与详情页收藏功能项目开源地址https://gitcode.com/daleishen/gujinzhijian