鸿蒙基于图像模块实现图库图片的四种常见操作开发分享

开发
文章由鸿蒙社区产出,想要了解更多内容请前往:51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com

[[388488]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

1. 项目介绍

HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像编码、基本的位图操作、图像编辑等。当然,也支持通过接口组合来实现更复杂的图像处理逻辑。本教程以图库图片中旋转、剪裁、缩放、镜像四种常见操作为例,给大家介绍HarmonyOS图像编解码的相关开发指导。

2. 将图片转换为PixelMap

图像解码就是将所支持格式的存档图片解码成统一的PixelMap图像,用于后续图像显示或其他处理,比如旋转、缩放、剪裁等。当前支持格式包括JPEG、PNG、GIF、HEIF、WebP、BMP。本例为您提供了getPixelMapFromResource函数,可以将resources/base/media目录下的图片资源转换为PixelMap图像,其中入参为图片的资源ID。

  1. private PixelMap getPixelMapFromResource(int resourceId) { 
  2.     InputStream inputStream = null
  3.     try { 
  4.         // 创建图像数据源ImageSource对象 
  5.         inputStream = getContext().getResourceManager().getResource(resourceId); 
  6.         ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); 
  7.         srcOpts.formatHint = "image/jpg"
  8.         ImageSource imageSource = ImageSource.create(inputStream, srcOpts); 
  9.  
  10.  
  11.         // 设置图片参数 
  12.         ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); 
  13.         return imageSource.createPixelmap(decodingOptions); 
  14.     } catch (IOException e) { 
  15.         HiLog.info(LABEL_LOG, "IOException"); 
  16.     } catch (NotExistException e) { 
  17.         HiLog.info(LABEL_LOG, "NotExistException"); 
  18.     } finally { 
  19.         if (inputStream != null) { 
  20.             try { 
  21.                 inputStream.close(); 
  22.             } catch (IOException e) { 
  23.                 HiLog.info(LABEL_LOG, "inputStream IOException"); 
  24.             } 
  25.         } 
  26.     } 
  27.     return null

3. 图片参数设置

本例使用图片像素的尺寸为1024*768,点击一次旋转按钮会进行90度的旋转,缩放是按照2:1的比例进行缩放,剪裁是保证宽度不变的情况下对高度进行400像素的剪裁,相关参数设置如下所示:

  1. // 设置图片参数  
  2. ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();  
  3. // 旋转  
  4. decodingOptions.rotateDegrees = 90 * whirlCount;  
  5. // 缩放  
  6. decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0);  
  7. // 剪裁  
  8. decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0); 

4. 图片镜像操作

图片镜像操作就是对图片以纵坐标为轴制作对称图片。image绘制的时候会调用onDraw方法,本例采用对图像Canvas画布的镜像操作实现图片的镜像显示,示例代码如下所示:

  1. private void mirrorImage(PixelMap pixelMap) {  
  2.     scaleX = -scaleX;  
  3.     image.addDrawTask(  
  4.             new Component.DrawTask() {  
  5.                 @Override  
  6.                 public void onDraw(Component component, Canvas canvas) {  
  7.                     if (isMirror) {  
  8.                         isMirror = false;  
  9.                         PixelMapHolder pmh = new PixelMapHolder(pixelMap);  
  10.                         canvas.scale(  
  11.                                 scaleX,  
  12.                                 1.0f,  
  13.                                 (float) pixelMap.getImageInfo().size.width / 2,  
  14.                                 (float) pixelMap.getImageInfo().size.height / 2);  
  15.                         canvas.drawPixelMapHolder(  
  16.                                 pmh,  
  17.                                 0,  
  18.                                 0,  
  19.                                 new Paint());  
  20.                     }  
  21.                 }  
  22.             });  

5. 完整示例

以手机为例,初始化页面如图1所示,依次点击按钮可以实现图片的旋转、剪裁、缩放、镜像,效果如下所示(您需要准备一张像素尺寸为1024*768的图片,放到ImageDemo\entry\src\main\resources\base\media目录下):

示例代码如下:

  1. import com.huawei.codelab.ResourceTable;  
  2.   
  3. import ohos.aafwk.ability.AbilitySlice;  
  4. import ohos.aafwk.content.Intent;  
  5. import ohos.agp.components.Button;  
  6. import ohos.agp.components.Component;  
  7. import ohos.agp.components.Image;  
  8. import ohos.agp.render.Canvas;  
  9. import ohos.agp.render.Paint;  
  10. import ohos.agp.render.PixelMapHolder;  
  11. import ohos.global.resource.NotExistException;  
  12. import ohos.hiviewdfx.HiLog;  
  13. import ohos.hiviewdfx.HiLogLabel;  
  14. import ohos.media.image.ImageSource;  
  15. import ohos.media.image.PixelMap;  
  16. import ohos.media.image.common.PixelFormat;  
  17. import ohos.media.image.common.Rect;  
  18. import ohos.media.image.common.Size;  
  19.   
  20. import java.io.IOException;  
  21. import java.io.InputStream;  
  22.   
  23. /**  
  24.  * 图像主页面  
  25.  */  
  26. public class MainAbilitySlice extends AbilitySlice {  
  27.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice");  
  28.     Image image;  
  29.     PixelMap imagePixelMap;  
  30.     Button whirlImageBtn;  
  31.     Button cropImageBtn;  
  32.     Button scaleImageBtn;  
  33.     Button mirrorImageBtn;  
  34.     private int whirlCount = 0;  
  35.     private boolean isCorp = false;  
  36.     private boolean isScale = false;  
  37.     private boolean isMirror = false;  
  38.     private float scaleX = 1.0f;  
  39.   
  40.     @Override  
  41.     public void onStart(Intent intent) {  
  42.         super.onStart(intent);  
  43.         super.setUIContent(ResourceTable.Layout_ability_main);  
  44.         initView();  
  45.     }  
  46.   
  47.     private void initView() {  
  48.         if (findComponentById(ResourceTable.Id_whirl_image) instanceof Button) {  
  49.             whirlImageBtn = (Button) findComponentById(ResourceTable.Id_whirl_image);  
  50.         }  
  51.         if (findComponentById(ResourceTable.Id_crop_image) instanceof Button) {  
  52.             cropImageBtn = (Button) findComponentById(ResourceTable.Id_crop_image);  
  53.         }  
  54.         if (findComponentById(ResourceTable.Id_scale_image) instanceof Button) {  
  55.             scaleImageBtn = (Button) findComponentById(ResourceTable.Id_scale_image);  
  56.         }  
  57.         if (findComponentById(ResourceTable.Id_mirror_image) instanceof Button) {  
  58.             mirrorImageBtn = (Button) findComponentById(ResourceTable.Id_mirror_image);  
  59.         }  
  60.         if (findComponentById(ResourceTable.Id_image) instanceof Image) {  
  61.             image = (Image) findComponentById(ResourceTable.Id_image);  
  62.         }  
  63.         whirlImageBtn.setClickedListener(new ButtonClick());  
  64.         cropImageBtn.setClickedListener(new ButtonClick());  
  65.         scaleImageBtn.setClickedListener(new ButtonClick());  
  66.         mirrorImageBtn.setClickedListener(new ButtonClick());  
  67.     }  
  68.   
  69.     private class ButtonClick implements Component.ClickedListener {  
  70.         @Override  
  71.         public void onClick(Component component) {  
  72.             int btnId = component.getId();  
  73.             switch (btnId) {  
  74.                 case ResourceTable.Id_whirl_image:  
  75.                     // 旋转图片  
  76.                     whirlCount++;  
  77.                     isCorp = false;  
  78.                     isScale = false;  
  79.                     isMirror = false;  
  80.                     imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai);  
  81.                     image.setPixelMap(imagePixelMap);  
  82.                     break;  
  83.                 case ResourceTable.Id_crop_image:  
  84.                     // 剪裁图片  
  85.                     whirlCount = 0;  
  86.                     isCorp = !isCorp;  
  87.                     isScale = false;  
  88.                     isMirror = false;  
  89.                     imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai);  
  90.                     image.setPixelMap(imagePixelMap);  
  91.                     break;  
  92.                 case ResourceTable.Id_scale_image:  
  93.                     // 缩放图片  
  94.                     whirlCount = 0;  
  95.                     isCorp = false;  
  96.                     isScale = !isScale;  
  97.                     isMirror = false;  
  98.                     imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai);  
  99.                     image.setPixelMap(imagePixelMap);  
  100.                     break;  
  101.                 case ResourceTable.Id_mirror_image:  
  102.                     // 镜像图片  
  103.                     whirlCount = 0;  
  104.                     isCorp = false;  
  105.                     isScale = false;  
  106.                     isMirror = true;  
  107.                     imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai);  
  108.                     mirrorImage(imagePixelMap);  
  109.                     image.setPixelMap(imagePixelMap);  
  110.                     break;  
  111.                 default:  
  112.                     break;  
  113.             }  
  114.         }  
  115.     }  
  116.   
  117.     private void mirrorImage(PixelMap pixelMap) {  
  118.         scaleX = -scaleX;  
  119.         image.addDrawTask(  
  120.                 new Component.DrawTask() {  
  121.                     @Override  
  122.                     public void onDraw(Component component, Canvas canvas) {  
  123.                         if (isMirror) {  
  124.                             isMirror = false;  
  125.                             PixelMapHolder pmh = new PixelMapHolder(pixelMap);  
  126.                             canvas.scale(  
  127.                                     scaleX,  
  128.                                     1.0f,  
  129.                                     (float) pixelMap.getImageInfo().size.width / 2,  
  130.                                     (float) pixelMap.getImageInfo().size.height / 2);  
  131.                             canvas.drawPixelMapHolder(  
  132.                                     pmh,  
  133.                                     0,  
  134.                                     0,  
  135.                                     new Paint());  
  136.                         }  
  137.                     }  
  138.                 });  
  139.     }  
  140.   
  141.     /**  
  142.      * 通过图片ID返回PixelMap  
  143.      *  
  144.      * @param resourceId 图片的资源ID  
  145.      * @return 图片的PixelMap  
  146.      */  
  147.     private PixelMap getPixelMapFromResource(int resourceId) {  
  148.         InputStream inputStream = null;  
  149.         try {  
  150.             // 创建图像数据源ImageSource对象  
  151.             inputStream = getContext().getResourceManager().getResource(resourceId);  
  152.             ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();  
  153.             srcOpts.formatHint = "image/jpg";  
  154.             ImageSource imageSource = ImageSource.create(inputStream, srcOpts);  
  155.   
  156.             // 设置图片参数  
  157.             ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();  
  158.             // 旋转  
  159.             decodingOptions.rotateDegrees = 90 * whirlCount;  
  160.             // 缩放  
  161.             decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0);  
  162.             // 剪裁  
  163.             decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0);  
  164.             decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;  
  165.             return imageSource.createPixelmap(decodingOptions);  
  166.         } catch (IOException e) {  
  167.             HiLog.info(LABEL_LOG, "IOException");  
  168.         } catch (NotExistException e) {  
  169.             HiLog.info(LABEL_LOG, "NotExistException");  
  170.         } finally {  
  171.             if (inputStream != null) {  
  172.                 try {  
  173.                     inputStream.close();  
  174.                 } catch (IOException e) {  
  175.                     HiLog.info(LABEL_LOG, "inputStream IOException");  
  176.                 }  
  177.             }  
  178.         }  
  179.         return null;  
  180.     }  
  181.   
  182.     @Override  
  183.     public void onActive() {  
  184.         super.onActive();  
  185.     }  
  186.   
  187.     @Override  
  188.     public void onForeground(Intent intent) {  
  189.         super.onForeground(intent);  
  190.     }  
  191. }  

布局代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <DirectionalLayout  
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  4.     ohos:height="match_parent"  
  5.     ohos:width="match_parent"  
  6.     ohos:orientation="vertical">  
  7.   
  8.     <Text  
  9.         ohos:height="match_content"  
  10.         ohos:width="match_content"  
  11.         ohos:layout_alignment="horizontal_center"  
  12.         ohos:text="HarmonyOS图像开发"  
  13.         ohos:text_size="80"  
  14.         ohos:top_margin="40vp"  
  15.         />  
  16.   
  17.     <DirectionalLayout  
  18.         xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  19.         ohos:height="match_content"  
  20.         ohos:width="match_content"  
  21.         ohos:layout_alignment="horizontal_center"  
  22.         ohos:orientation="horizontal"  
  23.         ohos:top_margin="20vp">  
  24.   
  25.         <Button  
  26.             ohos:id="$+id:whirl_image"  
  27.             ohos:height="match_content"  
  28.             ohos:width="match_content"  
  29.             ohos:background_element="$graphic:background_button"  
  30.             ohos:padding="12vp"  
  31.             ohos:right_margin="5vp"  
  32.             ohos:text="旋转"  
  33.             ohos:text_size="20vp"  
  34.             ohos:top_margin="10vp">  
  35.         </Button>  
  36.   
  37.         <Button  
  38.             ohos:id="$+id:crop_image"  
  39.             ohos:height="match_content"  
  40.             ohos:width="match_content"  
  41.             ohos:background_element="$graphic:background_button"  
  42.             ohos:left_margin="5vp"  
  43.             ohos:padding="12vp"  
  44.             ohos:text="剪裁"  
  45.             ohos:text_size="20vp"  
  46.             ohos:top_margin="10vp">  
  47.         </Button>  
  48.   
  49.         <Button  
  50.             ohos:id="$+id:scale_image"  
  51.             ohos:height="match_content"  
  52.             ohos:width="match_content"  
  53.             ohos:background_element="$graphic:background_button"  
  54.             ohos:left_margin="5vp"  
  55.             ohos:padding="12vp"  
  56.             ohos:text="缩放"  
  57.             ohos:text_size="20vp"  
  58.             ohos:top_margin="10vp">  
  59.         </Button>  
  60.   
  61.         <Button  
  62.             ohos:id="$+id:mirror_image"  
  63.             ohos:height="match_content"  
  64.             ohos:width="match_content"  
  65.             ohos:background_element="$graphic:background_button"  
  66.             ohos:left_margin="5vp"  
  67.             ohos:padding="12vp"  
  68.             ohos:text="镜像"  
  69.             ohos:text_size="20vp"  
  70.             ohos:top_margin="10vp"/>  
  71.     </DirectionalLayout>  
  72.   
  73.     <Image  
  74.         ohos:id="$+id:image"  
  75.         ohos:height="match_content"  
  76.         ohos:width="match_content"  
  77.         ohos:image_src="$media:shanghai.jpg"  
  78.         ohos:layout_alignment="horizontal_center"  
  79.         ohos:top_margin="20vp">  
  80.     </Image>  
  81.   
  82. </DirectionalLayout> 

此外您还需在resource/base/graphic目录下添加background_button.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"  
  3.        ohos:shape="rectangle">  
  4.     <corners  
  5.         ohos:radius="40"/>  
  6.     <solid  
  7.         ohos:color="#e9e9e9"/>  
  8. </shape> 

说明

以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2011-11-24 16:34:39

Java

2024-11-07 11:17:50

2021-06-04 10:45:31

软件架构分布式

2010-06-18 09:19:39

UML面向对象建模

2011-03-16 09:05:53

NATiptables

2010-06-17 09:34:50

UML面向对象建模

2024-10-24 08:04:00

2017-07-14 16:28:21

2010-08-13 13:31:48

Flex效果组件

2021-08-12 11:37:23

数据分析错误

2011-06-30 14:45:52

外链

2021-12-22 09:34:01

Golagn配置方式

2015-04-13 11:39:26

VDI灾难恢复

2015-04-02 16:54:52

灾难恢复VDI灾难恢复

2010-08-05 09:33:08

Flex页面跳转

2024-11-29 11:39:30

MapStruct映射

2018-06-20 08:47:44

DevOps微服务UX设计师

2023-10-30 11:40:36

OOM线程池单线程

2016-09-06 16:53:55

2012-03-13 09:17:38

开发
点赞
收藏

51CTO技术栈公众号