您现在的位置是:亿华云 > IT科技
鸿蒙基于图像模块实现图库图片的四种常见操作开发分享
亿华云2025-10-09 03:40:41【IT科技】9人已围观
简介想了解更多内容,请访问:和华为官方合作共建的鸿蒙技术社区https://harmonyos.51cto.com1. 项目介绍HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像编码、
想了解更多内容,鸿蒙请访问:
和华为官方合作共建的基于鸿蒙技术社区
https://harmonyos.51cto.com
1. 项目介绍
HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像图库图片图像编码、模块基本的实现位图操作、图像编辑等。常见操作当然,分享也支持通过接口组合来实现更复杂的鸿蒙图像处理逻辑。本教程以图库图片中旋转、基于剪裁、图像图库图片缩放、模块镜像四种常见操作为例,实现给大家介绍HarmonyOS图像编解码的常见操作相关开发指导。
2. 将图片转换为PixelMap
图像解码就是分享将所支持格式的存档图片解码成统一的PixelMap图像,用于后续图像显示或其他处理,鸿蒙比如旋转、缩放、网站模板剪裁等。当前支持格式包括JPEG、PNG、GIF、HEIF、WebP、BMP。本例为您提供了getPixelMapFromResource函数,可以将resources/base/media目录下的图片资源转换为PixelMap图像,其中入参为图片的资源ID。
private PixelMap getPixelMapFromResource(int resourceId) { InputStream inputStream = null; try { // 创建图像数据源ImageSource对象 inputStream = getContext().getResourceManager().getResource(resourceId); ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); srcOpts.formatHint = "image/jpg"; ImageSource imageSource = ImageSource.create(inputStream, srcOpts); // 设置图片参数 ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); return imageSource.createPixelmap(decodingOptions); } catch (IOException e) { HiLog.info(LABEL_LOG, "IOException"); } catch (NotExistException e) { HiLog.info(LABEL_LOG, "NotExistException"); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { HiLog.info(LABEL_LOG, "inputStream IOException"); } } } return null; }3. 图片参数设置
本例使用图片像素的尺寸为1024*768,点击一次旋转按钮会进行90度的旋转,缩放是按照2:1的比例进行缩放,剪裁是保证宽度不变的情况下对高度进行400像素的剪裁,相关参数设置如下所示:
// 设置图片参数 ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); // 旋转 decodingOptions.rotateDegrees = 90 * whirlCount; // 缩放 decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0); // 剪裁 decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0);4. 图片镜像操作
图片镜像操作就是源码下载对图片以纵坐标为轴制作对称图片。image绘制的时候会调用onDraw方法,本例采用对图像Canvas画布的镜像操作实现图片的镜像显示,示例代码如下所示:
private void mirrorImage(PixelMap pixelMap) { scaleX = -scaleX; image.addDrawTask( new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { if (isMirror) { isMirror = false; PixelMapHolder pmh = new PixelMapHolder(pixelMap); canvas.scale( scaleX, 1.0f, (float) pixelMap.getImageInfo().size.width / 2, (float) pixelMap.getImageInfo().size.height / 2); canvas.drawPixelMapHolder( pmh, 0, 0, new Paint()); } } }); }5. 完整示例
以手机为例,初始化页面如图1所示,依次点击按钮可以实现图片的旋转、剪裁、缩放、镜像,效果如下所示(您需要准备一张像素尺寸为1024*768的图片,放到ImageDemo\entry\src\main\resources\base\media目录下):
示例代码如下:
import com.huawei.codelab.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.Button; import ohos.agp.components.Component; import ohos.agp.components.Image; import ohos.agp.render.Canvas; import ohos.agp.render.Paint; import ohos.agp.render.PixelMapHolder; import ohos.global.resource.NotExistException; import ohos.hiviewdfx.HiLog; import ohos.hiviewdfx.HiLogLabel; import ohos.media.image.ImageSource; import ohos.media.image.PixelMap; import ohos.media.image.common.PixelFormat; import ohos.media.image.common.Rect; import ohos.media.image.common.Size; import java.io.IOException; import java.io.InputStream; /** * 图像主页面 */ public class MainAbilitySlice extends AbilitySlice { private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice"); Image image; PixelMap imagePixelMap; Button whirlImageBtn; Button cropImageBtn; Button scaleImageBtn; Button mirrorImageBtn; private int whirlCount = 0; private boolean isCorp = false; private boolean isScale = false; private boolean isMirror = false; private float scaleX = 1.0f; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initView(); } private void initView() { if (findComponentById(ResourceTable.Id_whirl_image) instanceof Button) { whirlImageBtn = (Button) findComponentById(ResourceTable.Id_whirl_image); } if (findComponentById(ResourceTable.Id_crop_image) instanceof Button) { cropImageBtn = (Button) findComponentById(ResourceTable.Id_crop_image); } if (findComponentById(ResourceTable.Id_scale_image) instanceof Button) { scaleImageBtn = (Button) findComponentById(ResourceTable.Id_scale_image); } if (findComponentById(ResourceTable.Id_mirror_image) instanceof Button) { mirrorImageBtn = (Button) findComponentById(ResourceTable.Id_mirror_image); } if (findComponentById(ResourceTable.Id_image) instanceof Image) { image = (Image) findComponentById(ResourceTable.Id_image); } whirlImageBtn.setClickedListener(new ButtonClick()); cropImageBtn.setClickedListener(new ButtonClick()); scaleImageBtn.setClickedListener(new ButtonClick()); mirrorImageBtn.setClickedListener(new ButtonClick()); } private class ButtonClick implements Component.ClickedListener { @Override public void onClick(Component component) { int btnId = component.getId(); switch (btnId) { case ResourceTable.Id_whirl_image: // 旋转图片 whirlCount++; isCorp = false; isScale = false; isMirror = false; imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); image.setPixelMap(imagePixelMap); break; case ResourceTable.Id_crop_image: // 剪裁图片 whirlCount = 0; isCorp = !isCorp; isScale = false; isMirror = false; imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); image.setPixelMap(imagePixelMap); break; case ResourceTable.Id_scale_image: // 缩放图片 whirlCount = 0; isCorp = false; isScale = !isScale; isMirror = false; imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); image.setPixelMap(imagePixelMap); break; case ResourceTable.Id_mirror_image: // 镜像图片 whirlCount = 0; isCorp = false; isScale = false; isMirror = true; imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); mirrorImage(imagePixelMap); image.setPixelMap(imagePixelMap); break; default: break; } } } private void mirrorImage(PixelMap pixelMap) { scaleX = -scaleX; image.addDrawTask( new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { if (isMirror) { isMirror = false; PixelMapHolder pmh = new PixelMapHolder(pixelMap); canvas.scale( scaleX, 1.0f, (float) pixelMap.getImageInfo().size.width / 2, (float) pixelMap.getImageInfo().size.height / 2); canvas.drawPixelMapHolder( pmh, 0, 0, new Paint()); } } }); } /** * 通过图片ID返回PixelMap * * @param resourceId 图片的资源ID * @return 图片的PixelMap */ private PixelMap getPixelMapFromResource(int resourceId) { InputStream inputStream = null; try { // 创建图像数据源ImageSource对象 inputStream = getContext().getResourceManager().getResource(resourceId); ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); srcOpts.formatHint = "image/jpg"; ImageSource imageSource = ImageSource.create(inputStream, srcOpts); // 设置图片参数 ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); // 旋转 decodingOptions.rotateDegrees = 90 * whirlCount; // 缩放 decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0); // 剪裁 decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0); decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888; return imageSource.createPixelmap(decodingOptions); } catch (IOException e) { HiLog.info(LABEL_LOG, "IOException"); } catch (NotExistException e) { HiLog.info(LABEL_LOG, "NotExistException"); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { HiLog.info(LABEL_LOG, "inputStream IOException"); } } } return null; } @Override public void onActive() { super.onActive(); } @Override public void onForeground(Intent intent) { super.onForeground(intent); } }布局代码如下:
<?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:orientation="vertical"> <Text ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="HarmonyOS图像开发" ohos:text_size="80" ohos:top_margin="40vp" /> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:orientation="horizontal" ohos:top_margin="20vp"> <Button ohos:id="$+id:whirl_image" ohos:height="match_content" ohos:width="match_content" ohos:background_element="$graphic:background_button" ohos:padding="12vp" ohos:right_margin="5vp" ohos:text="旋转" ohos:text_size="20vp" ohos:top_margin="10vp"> </Button> <Button ohos:id="$+id:crop_image" ohos:height="match_content" ohos:width="match_content" ohos:background_element="$graphic:background_button" ohos:left_margin="5vp" ohos:padding="12vp" ohos:text="剪裁" ohos:text_size="20vp" ohos:top_margin="10vp"> </Button> <Button ohos:id="$+id:scale_image" ohos:height="match_content" ohos:width="match_content" ohos:background_element="$graphic:background_button" ohos:left_margin="5vp" ohos:padding="12vp" ohos:text="缩放" ohos:text_size="20vp" ohos:top_margin="10vp"> </Button> <Button ohos:id="$+id:mirror_image" ohos:height="match_content" ohos:width="match_content" ohos:background_element="$graphic:background_button" ohos:left_margin="5vp" ohos:padding="12vp" ohos:text="镜像" ohos:text_size="20vp" ohos:top_margin="10vp"/> </DirectionalLayout> <Image ohos:id="$+id:image" ohos:height="match_content" ohos:width="match_content" ohos:image_src="$media:shanghai.jpg" ohos:layout_alignment="horizontal_center" ohos:top_margin="20vp"> </Image> </DirectionalLayout>此外您还需在resource/base/graphic目录下添加background_button.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="40"/> <solid ohos:color="#e9e9e9"/> </shape>说明
以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。
想了解更多内容,请访问:
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com
很赞哦!(35)
上一篇: 个人域名转为公司需要什么条件?个人域名转为公司该怎么做?
下一篇: 3、考虑出售域名
相关文章
- 3、商标域名一经注册,就可以作为域名裁决过程中的主要信息之一。这可以大大增加公司被抢注的相关域名胜诉的机会。
- AnnotationAwareAspectJAutoProxyCreator类是干嘛的?
- 一篇文章搞定Java字符串的基本操作知识
- 中国移动韩柳燕:SPN进展符合预期,已形成“健壮”产业链
- 在更换域名后,并不是就万事大吉了,我们需要将旧域名做301重定向到新域名上,转移旧域名的权重到新域名上。
- 从对 Vue 中 mixin 的批评,到对模块间依赖关系的探讨
- AnnotationAwareAspectJAutoProxyCreator类是干嘛的?
- 双链表,这回彻底搞dong了
- 一下域名,看有没有显示出你所解析的IP,如果有,就说明解析是生效的;如果没有,就说明解析是不生效的。
- MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?
站长推荐
(4) 使用何种形式的域名后缀对网页搜索影响不大,但域名后缀也需要考虑方便用户记忆
Kubernetes的CLI是使用什么技术实现的?
APICloud发布低代码开发平台 效率工具引领IT人效革命
布局儿童编程教育,童心制物两大编程新品激发孩子创造力
域名不仅仅是一个简单的网站。对于有长远眼光的公司来说,在运营网站之前确定一个优秀的域名对有长远眼光的公司来说是非常重要的。这对今后的市场营销、产品营销和企业品牌建设都具有十分重要的意义。优秀的域名是企业在市场竞争中获得持久优势的利器。
Python中正则表达式的巧妙使用 !包你必掌握正则!
如何在 ASP.NET Core 5 中生成 PDF
进行架构设计要了解的几种思维方式