1. 介绍 HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像编码、基本的位图操作、图像编辑等。当然,也支持通过接口组合来实现更复杂的图像处理逻辑。本教程以图库图片中旋转、剪裁、缩放、镜像四种常见操作为例,给大家介绍HarmonyOS图像编解码的相关开发指导。
2. 搭建HarmonyOS环境
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
- 安装DevEco Studio,详情请参考下载和安装软件。
- 设置DevEco Studio开发环境,DevEco Studio开发环境依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
- 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
- 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
- 开发者可以参考以下链接,完成设备调试的相关配置:
3. 将图片转换为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;
- }
复制代码 4. 图片参数设置本例使用图片像素的尺寸为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);
复制代码 5. 图片镜像操作图片镜像操作就是对图片以纵坐标为轴制作对称图片。image绘制的时候会调用onDraw方法,本例采用对图像Canvas画布的镜像操作实现图片的镜像显示,示例代码如下所示:
- private void mirrorImage(PixelMap pixelMap) {
- scaleX = -scaleX;
- image.addDrawTask(
- new Component.DrawTask() {
- [url=home.php?mod=space&uid=2735960]@Override[/url]
- 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());
- }
- }
- });
- }
复制代码 6. 完整示例 以手机为例,初始化页面如图1所示,依次点击按钮可以实现图片的旋转、剪裁、缩放、镜像,效果如下所示(您需要准备一张像素尺寸为1024*768的图片,放到ImageDemoentrysrcmainresourcesbasemedia目录下):
示例代码如下:
- 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
- *
- * [url=home.php?mod=space&uid=3142012]@param[/url] resourceId 图片的资源ID
- * [url=home.php?mod=space&uid=1141835]@Return[/url] 图片的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演示参考使用,产品化的代码需要考虑数据校验和国际化。
7. 恭喜你
通过对本教程的学习,你已经学会HarmonyOS图像编解码的基本操作。