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

36 图像预处理与裁剪:AnalyzingPage 中的图片处理

36 图像预处理与裁剪:AnalyzingPage 中的图片处理

前言

图:36 图像预处理与裁剪:AnalyzingPage 中的图片处理 运行效果截图(HarmonyOS NEXT)

拍摄或选择图片后,应用通常需要对原始图片进行预处理——裁剪、缩放、格式转换等。这既是 UI 展示的需要,也是后续 AI 分析(OCR、特征提取)的前置条件。

本文以"鹿鹿·笔迹心理分析"项目中 [CapturePage.ets](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/pages/CapturePage.ets) 和 [AnalyzingPage.ets](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/pages/AnalyzingPage.ets) 之间的图片传递链路为例,解析鸿蒙应用中图像的处理路径和优化策略。

鸿蒙官方·图像处理文档:developer.huawei.com
项目源码仓库:harmony-app GitHub

图:图像处理管道——原始图片 → ImageSource → PixelMap → 裁剪/缩放 → 编码输出

原始图片
Camera / Album

image.createImageSource
解码图片

PixelMap
像素图对象

crop 裁剪
提取手写区域

scale 缩放
统一到 512x512

rotate 旋转
修正 EXIF 方向

ImagePacker 编码
压缩为 JPEG/PNG

写入本地文件
缓存目录

一、图像处理链路

1.1 数据流

拍照/相册选择 ↓ 原始图片路径(URI / 文件路径) ↓ 图片解码(PixelMap) ↓ 图片裁剪 / 缩放(可选) ↓ 保存至缓存目录 ↓ 传入 AnalyzingPage ↓ OCR 识别 + 特征提取(AI 服务)

1.2 项目中的图片传递

// CapturePage — 确认使用照片privateconfirmPhoto(){AppStorage.setOrCreate<string>('capture_image_path',this.previewPath)this.getUIContext().getRouter().pushUrl({url:'pages/AnalyzingPage',params:{imagePath:this.previewPath}})}// AnalyzingPage — 接收图片privateasyncstartAnalysis(){constimagePath=AppStorage.get<string>('capture_image_path')??''constsource=AppStorage.get<string>('capture_source')??'camera'// ...}

二、图片解码:PixelMap

2.1 从文件加载 PixelMap

import{image}from'@kit.ImageKit'asyncfunctionloadPixelMap(filePath:string):Promise<image.PixelMap>{constsource=image.createImageSource(filePath)constpixelMap=awaitsource.createPixelMap({desiredPixelFormat:image.ImagePixelFormat.RGBA_8888,desiredSize:{width:1080,height:1920},fitDensity:0})source.release()returnpixelMap}

参数说明:

参数作用推荐值说明
desiredPixelFormat像素格式RGBA_8888最高质量
desiredSize目标尺寸1080x1920限制最大分辨率
fitDensity密度适配0不需要适配

2.2 从 PixelMap 保存为文件

asyncfunctionsavePixelMap(pixelMap:image.PixelMap,outputPath:string):Promise<void>{constpacker=image.createImagePacker()constpackedImage=awaitpacker.packing(pixelMap,{format:'image/jpeg',quality:85})constfile=fs.openSync(outputPath,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE)file.writeSync(packedImage.data.buffer)fs.closeSync(file)packer.release()}

三、图片裁剪

3.1 裁剪功能

asyncfunctioncropImage(sourcePath:string,outputPath:string,region:image.Region):Promise<void>{constsource=image.createImageSource(sourcePath)constpixelMap=awaitsource.createPixelMap({cropRegion:region,// 裁剪区域desiredPixelFormat:image.ImagePixelFormat.RGBA_8888,})// 保存裁剪后的图片constpacker=image.createImagePacker()constpackedImage=awaitpacker.packing(pixelMap,{format:'image/jpeg',quality:85})constfile=fs.openSync(outputPath,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE)file.writeSync(packedImage.data.buffer)fs.closeSync(file)source.release()packer.release()}// 使用示例image.Region={x:50,y:100,// 左上角坐标width:800,height:1000// 裁剪尺寸}awaitcropImage(inputPath,outputPath,region)

四、图片缩放

4.1 缩放到指定尺寸

asyncfunctionresizeImage(sourcePath:string,outputPath:string,maxWidth:number,maxHeight:number):Promise<void>{constsource=image.createImageSource(sourcePath)// 获取原始尺寸constinfo=awaitsource.getImageInfo(0)as{size?:{width:number,height:number}}constsrcWidth=info.size?.width??1920constsrcHeight=info.size?.height??1080// 等比缩放计算lettargetWidth=srcWidthlettargetHeight=srcHeightif(targetWidth>maxWidth){targetHeight=Math.round(targetHeight*maxWidth/targetWidth)targetWidth=maxWidth}if(targetHeight>maxHeight){targetWidth=Math.round(targetWidth*maxHeight/targetHeight)targetHeight=maxHeight}// 创建缩放的 PixelMapconstpixelMap=awaitsource.createPixelMap({desiredSize:{width:targetWidth,height:targetHeight},desiredPixelFormat:image.ImagePixelFormat.RGBA_8888,})// 保存constpacker=image.createImagePacker()constpackedImage=awaitpacker.packing(pixelMap,{format:'image/jpeg',quality:80})constfile=fs.openSync(outputPath,fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE)file.writeSync(packedImage.data.buffer)fs.closeSync(file)source.release()packer.release()}

五、图像旋转与方向修正

5.1 EXIF 方向处理

拍摄的图片可能包含 EXIF 方向信息,需要修正:

asyncfunctioncorrectOrientation(filePath:string):Promise<void>{constsource=image.createImageSource(filePath)// 读取图像属性constinfo=awaitsource.getImageInfo(0)constorientation=(infoasRecord<string,Object>)['exifOrientation']asnumber??0// 根据方向旋转letrotation=0switch(orientation){case3:rotation=180;breakcase6:rotation=90;breakcase8:rotation=270;break}if(rotation>0){// 如需旋转,重新生成 PixelMap 并保存覆盖原文件// ...}source.release()}

六、AnalyzingPage 中的图片使用

6.1 页面入口

// AnalyzingPage.etsaboutToAppear(){this.startAnalysis()// ...}privateasyncstartAnalysis(){constimagePath=AppStorage.get<string>('capture_image_path')??''constsource=AppStorage.get<string>('capture_source')??'camera'// 模拟 5 层分析进度for(leti=0;i<5;i++){this.currentStep=iawaitnewPromise<void>(resolve=>setTimeout(()=>resolve(),800))}// 生成模拟推理结果constresult=this.generateMockResult(source,archiveId)// 写入 DBawaitHandwritingDao.create({/* ... */})awaitReportDao.create({/* ... */})// 跳转到报告详情页this.getUIContext().getRouter().replaceUrl({url:'pages/ReportDetailPage',params:{imagePath,reportId}})}

6.2 图片路径传递方式对比

方式项目使用优点缺点
文件路径previewPath简单直接,可跨页面传递文件可能被清理
AppStorage✅ 全局存储跨页面共享,不依赖路由参数需要手动清理
路由参数✅ pushUrl params与导航绑定仅适用于相邻页面

七、图片处理的常见问题

问题原因解决方案
图片方向不对EXIF 方向未处理correctOrientation()修正
图片太大导致 OOM原始分辨率过高createPixelMap时指定desiredSize
JPEG 压缩质量过低设置不当quality: 80-85平衡质量与文件大小
处理耗时导致 ANR同步操作全部使用async/await异步 API

八、图像处理 API 汇总

API模块用途是否异步
image.createImageSource(path)@kit.ImageKit创建图片源
source.createPixelMap(options)@kit.ImageKit解码为 PixelMap
image.createImagePacker()@kit.ImageKit编码为文件格式
packer.packing(pixelMap, options)@kit.ImageKit压缩编码
fs.openSync(path, mode)@kit.CoreFileKit打开文件❌(无同步版本)
file.writeSync(data)@kit.CoreFileKit写入数据

总结

本文解析了鸿蒙应用中图像预处理到 AI 分析的完整链路:

  1. 图片传递:通过文件路径 + AppStorage + 路由参数 3 种方式跨页面传递
  2. PixelMap 解码image.createImageSource()createPixelMap()加载图片
  3. 裁剪与缩放cropRegion裁剪区域,desiredSize控制目标尺寸
  4. 方向修正:读取 EXIF orientation,90/180/270 度旋转
  5. 输出编码ImagePacker.packing()输出为 JPEG 文件
  6. 分析链路:图片路径 → AnalyzingPage → 模拟推理 → 写入 DB → 报告详情

下一篇文章将介绍相册读取与图片选择——PhotoViewPicker 的完整使用。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


参考资源:

  • Image Kit 开发指南
  • PixelMap API 参考
  • [CapturePage 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/pages/CapturePage.ets)
  • [AnalyzingPage 项目源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/pages/AnalyzingPage.ets)
  • ImagePacker 压缩编码
  • EXIF 方向处理
  • @kit.ImageKit 模块
  • HarmonyOS 开发文档

七、图像处理性能优化

7.1 异步处理避免 UI 阻塞

图像解码和压缩是 CPU 密集型操作,必须在异步上下文中执行:

// ✅ 正确:在 async 函数中执行,不阻塞 UIprivateasyncprocessImage(imagePath:string):Promise<string>{// 1. 解码图片(耗时操作)constimageSource=image.createImageSource(imagePath)constpixelMap=awaitimageSource.createPixelMap({desiredSize:{width:1024,height:1024},desiredSamplingQuality:image.SamplingQuality.MEDIUM})// 2. 压缩编码(耗时操作)constpacker=image.createImagePacker()constpackOptions:image.PackingOption={format:'image/jpeg',quality:80}constarrayBuffer=awaitpacker.packing(pixelMap,packOptions)// 3. 写入文件constoutputPath=`${getContext().cacheDir}/processed_${Date.now()}.jpg`constfile=fs.openSync(outputPath,fs.OpenMode.CREATE|fs.OpenMode.WRITE_ONLY)fs.writeSync(file.fd,arrayBuffer)fs.closeSync(file)// 4. 释放 PixelMap 内存pixelMap.release()returnoutputPath}

7.2 PixelMap 内存管理

PixelMap 占用大量内存,使用后必须及时释放:

letpixelMap:image.PixelMap|null=nulltry{pixelMap=awaitimageSource.createPixelMap(options)// ... 处理图片}finally{if(pixelMap){pixelMap.release()// 释放 native 内存pixelMap=null}}

7.3 图像处理性能指标

操作耗时参考(4000x3000 图片)优化建议
解码(原始)200-500ms设置 desiredSize 减小尺寸
裁剪< 50msPixelMap.crop() 原地裁剪
缩放50-150msdesiredSize 在解码时同步缩放
JPEG 编码(quality=80)100-300ms适当降低 quality 提速

7.4 图像处理工具函数封装

// 项目中封装的图像处理工具exportclassImageUtils{// 解码图片为 PixelMap(带缩放)staticasyncdecodeImage(path:string,maxSize:number=1024):Promise<image.PixelMap>{constsource=image.createImageSource(path)returnsource.createPixelMap({desiredSize:{width:maxSize,height:maxSize}})}// 压缩 PixelMap 并写入文件staticasynccompressToFile(pixelMap:image.PixelMap,outputPath:string,quality:number=80):Promise<void>{constpacker=image.createImagePacker()constbuffer=awaitpacker.packing(pixelMap,{format:'image/jpeg',quality})constfile=fs.openSync(outputPath,fs.OpenMode.CREATE|fs.OpenMode.WRITE_ONLY)fs.writeSync(file.fd,buffer)fs.closeSync(file)}}

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

http://www.jsqmd.com/news/1165935/

相关文章:

  • 2026预算 200 蓝牙耳机推荐:基于声学实测的 5 款机型降噪、续航、蓝牙方案全解析
  • ArcGIS Pro 3.2 与 Python GDAL 协同:5步自动化生成语义分割数据集
  • 双喷嘴3D打印机如何重构打印工作流:从调平到混材的闭环设计
  • Cocos Creator 3.8.x集成Tiled地图:原理、实现与性能优化全解析
  • C++/Qt 工业协议中的数据类型的选择原则和典型用法。
  • AI实战拦截供应链攻击:从依赖投毒到Log4j 3.0变种防御
  • 大模型安全合规部署与AI网安工程实践指南
  • 3大痛点1个方案:用Harepacker-resurrected打造你的专属冒险岛世界
  • 如何3步轻松获取国家中小学智慧教育平台电子课本的终极指南
  • SRWE:打破Windows窗口限制的终极窗口编辑器
  • 当你有CC,你就可以这么学ES
  • 计算机毕业设计之摄影师分享交流社区
  • 技术专访|首席GEO落地工程师、名九至天人网络创始人罗长才:基于合规数据体系构建AI推荐入口全域抢占工程框架
  • GLM-5.1编程模型实战:SWE-bench 45.3分背后的工程化突破
  • 国产大模型桌面应用工程实践:Tauri+GLM-5流式对话全链路解析
  • 3种信道编码方案对比:(2,1,5)卷积码、(7,4)汉明码与重复码在LabVIEW中的性能实测
  • 在Windows上实现macOS级三指拖拽:技术解析与实战配置指南
  • TEDS 与 4 种 DOM 树相似度算法对比:在网页信息抽取中的性能实测
  • 亲身到店探访北京天梭官方售后服务中心|完整热线和最新维修地址(2026年7月最新) - 天梭服务中心
  • 从 CoT 到 ReAct:AI Agent 是怎么“长出来”的
  • code0 gemini-3.1-flash-lite-preview 企业实战:企业轻量自动化任务配置指南
  • STM32H7 Cache 配置避坑指南:4个常见错误场景与SCB函数精准修复
  • Unity与虚幻引擎核心技术对比:从编程、渲染到项目选型全解析
  • 【Springboot毕设全套源码+文档】基于SpringBoot+Vue的宠物生活馆网站的设计与实现(丰富项目+远程调试+讲解+定制)
  • TDA7468与STM32L152RE构建高性能音频处理系统
  • 37 相册读取与图片选择:PhotoViewPicker 实战
  • 2026 智能体全景盘点:六大核心维度下的主流阵营横向对比
  • 上电瞬间的过冲电压烧毁芯片-----原因在这里
  • Chrome-Charset终极指南:3分钟彻底解决网页乱码的完整方案
  • 【GitHub】Meetily:隐私优先的本地 AI 会议助手深度解析