当前位置: 首页 > news >正文

HarmonyOS APP<<古今职鉴定>>开源教程第22篇:图片处理与资源管理

本篇学习图片处理能力和资源管理实现祝福卡片图片处理图图片处理与资源管理 的关键流程与实现要点。学习目标完成本篇后你将能够✅ 掌握图片资源类型✅ 配置图片组件属性✅ 使用图片处理能力✅ 管理应用资源文件预计学习时间约 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
http://www.gsyq.cn/news/1347714.html

相关文章:

  • HarmonyOS APP<<古今职鉴定>>开源教程第21篇:弹窗与对话框设计
  • 调用云端或线上顶尖大模型办法(以DeepSeek为例)
  • HCIP-Datacom Core Technology V1.0_18 IGMP原理与配置
  • AI产品经理入门实战:如何理解知识图谱?
  • Engage2026会议各种Notes/Domino演示文档可以下载了
  • 哈尔滨口碑过硬系统窗品牌排行:5家实力企业盘点 - 奔跑123
  • 农业电商|基于SprinBoot+vue的农业电商服务系统(源码+数据库+文档)
  • Neo4j 知识图谱:实体建模+Cypher查询+LangChain接入
  • Forza Painter完整指南:如何将任何图片转换为《极限竞速》专业车辆涂装
  • PLIP终极指南:蛋白质-配体相互作用分析从入门到精通
  • 【Perplexity奖学金搜索黑箱破解】:斯坦福教育技术实验室2024最新测评报告首次公开
  • 证件照怎样换底色?免费换底色证件照软件推荐 2026 实测方法 - AI测评专家
  • 企业AI项目紧急叫停!DeepSeek许可证新增限制条款(2024.06.18生效)及72小时补救路径
  • Perseus:5分钟解锁碧蓝航线全皮肤的神奇补丁
  • 【信息科学与工程学】计算机科学与自动化——第十五篇 云计算 第三系列 亿级并发的算法
  • 2026甘肃高低压配电柜厂家推荐|陇源恒业领跑区域成套电气服务——从配电柜到消防巡检柜的一站式解决方案深度评测 - 深度智识库
  • 查看月度账单明细理解不同模型调用成本的具体构成
  • -微信评选活动怎么做?2026免费投票工具实测盘点 - 资讯速览
  • 百度网盘提取码智能查询工具:10秒内自动获取分享密码的终极指南
  • 问了4个AI模型,推荐门店稽查公司竟没有一家提到小零科技?问题出在哪
  • 手机拍证件照怎样才规范?2026 手机拍证件照完整方法与工具对比指南
  • 从0开始的Claude Code
  • 2026低空城市治理平台管理系统推荐:冰柏科技三维数智平台实践解析 - 品牌2025
  • Nodejs后端服务如何集成Taotoken为多个AI Agent提供模型服务
  • 2026年义乌高端全屋定制甄选指南:整木定制与木作定制深度评测 | 门墙柜一体别墅全屋定制大平层定制原木定制ENF级环保板材全案设计定制终身售后 - 企业品牌优选推荐官
  • 一寸照片尺寸规格怎么搞?2026年最全制作方法对比盘点
  • AI 超声波加湿器智能功率 MOSFET 高效静音选型方案
  • 2026年西安本地防水补漏靠谱服务商深度市场分析与场景选型指南 专业防水公司排名推荐(2026年5月份专业防水补漏修缮精选口碑排行) - 冠盾建筑修缮
  • 2026芜湖黄金回收商家推荐:靠谱到底,无隐形费用 - 鸿运名品
  • Rescuezilla:当系统崩溃时,你的数据救援专家