如何向图片编辑器添加自定义的图片编辑功能
1. 项目介绍
在日常生活中有很多APP都有图片编辑的功能,但由于APP间存在一定的功能差异,开发者往往要为每个APP单独实现一套图片编辑逻辑,使APP的开发成本大大增加。本篇Codelab将为开发者介绍DevEco中集成的图片编辑模板,旨在为开发者提供一个图片编辑模块开发的"地基",开发者只需要在此基础上添加业务所需的自定义图片编辑算法,从而减少代码量。
本模板主要分为两个部分:界面UI和图片编辑器。
模板界面UI部分主要为开发者提供了:图片编辑界面的设计参考,以及HarmonyOS界面UI开发样例工程。图片编辑器部分提供了实现图片编辑功能的框架以及两个样例图片编辑功能。
效果预览:
- 顶部App Bar部分:后退(Back)、撤销(Undo)、重做(Redo)以及保存(Save)按钮。
- 中间区域BackGroundLayer以及CropPicker用于预览图显示以及裁剪框绘制。
- 底部区域由下往上分为三级菜单,一级菜单用于选择图片编辑功能,二级菜单用于选择次级功能,三级菜单一般用于调节次级功能的编辑参数。
编辑功能展示:
拖动裁剪框,裁剪区域外的图片绘制阴影效果。预览效果满意后,切换其他功能来确认更改。点击撤销(Undo)按钮,返回上一步预览状态。
2. 代码结构解读
- animation: 动效目录,存放图片编辑过程中的各类动效实现类。
- exceptions:异常目录,存放各类编辑异常。
- handler:图片编辑器核心逻辑目录,包含图片编辑器、图片编辑代理、编辑操作消息队列实现。
- strategy:图片编辑功能实现目录。action中存放编辑器可识别的编辑IEditAction;bean中存放编辑操作所需参数;imp中存放实现action所对应的图片编辑strategy。
- utils:工具类存放目录。
- view:自定义控件存放目录。
3. 相关权限
使用本模板时如需使用用户外部存储中的媒体文件信息,需要申请以下权限,应用权限的申请可以参考权限章节。
ohos.permission.READ_MEDIA:用于允许应用读取用户外部存储中的媒体文件信息。
如需获得用户外部存储中的媒体文件信息,请在config.json文件中的module段内添加如下权限声明:
"reqPermissions": [
{
"name": "ohos.permission.READ_MEDIA"
"reason": "$string:read_media"
}
]
权限声明需要符合规范,具体规范详见权限开发指导。 READ_MEDIA权限属于用户敏感权限,声明后仍需要动态申请权限,我们已在模板中提供动态申请的样例:
private void requestPermission() {
String permission = "ohos.permission.READ_MEDIA";
if (verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
if (canRequestPermission(permission)) {
requestPermissionsFromUser(new String[]{permission}, 0);
}
else {
HiLog.error(LABEL, "user refused permission: " + permission);
}
}
else {
PermissionHelper.getInstance().grantPermission(permission);
HiLog.info(LABEL, "user granted permission: " + permission);
}
}
首次安装应用后,需要用户授予权限并重新进入应用以获取AVStorage中存储的媒体文件。
4. 图片编辑器详解
EditActionFactory:Action工厂类,提供createAction方法用于创建图片编辑Action。
EditActionPipeline:图片编辑Action队列,用于维持图片编辑操作的时序。
EditStrategyManager: 图片编辑Strategy管理器。
ImageEditorImp:图片编辑器实现类,从Pipeline接收processEvent操作指令,调用Action对应Strategy对图片进行编辑。
ImageEdtiorProxy:图片编辑引擎,本模板中挂载于ImageEditView上,接收用户编辑操作,转化为Action放入Action队列中。
5. 添加自定义图片编辑功能
本模板中预置了两种图片编辑功能:裁剪与调节,开发者也可以自行添加业务所需的其他图片编辑功能,比如滤镜、涂鸦等。添加的方式如下:
1.实现IEditStrategy。
public interface IEditStrategy {
/**
* Image processing method
*
* @param <T> Specifies the parameter type, which is defined by the image editing algorithm.
* @param origin Source PixelMap
* @param params Image editing algorithm parameters.
* @return PixelMap after edit
* @throws HandleStrategyException Handle exception
*/
<T> PixelMap handle(final PixelMap origin, EditParams<T> params) throws HandleStrategyException;
/**
* Obtains the strategy name.
*
* @return Strategy name
*/
String getName();
/**
* Create an corresponding action instance
*
* @return An empty action instance
*/
IEditAction createAction();
}
2.实现IEditAction。
public interface IEditAction {
enum ActionType {
ACT_EDIT(0x01), ACT_UNDO(0x11), ACT_REDO(0x12), ACT_DROP(0x14), ACT_EXPORT(0x15);
private int value = 0;
ActionType(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
/**
* Execute an edit-action against the PixelMap of which the content will be modified
*
* @param bmp the PixelMap to be modified
* @return the output PixelMap after process
* @throws EditActionException execution failed, the PixelMap should not be dropped because of dirty data
*/
PixelMap execute(PixelMap bmp) throws EditActionException;
ActionType getActionType();
<T> void setParams(T params);
}
3.在ImageEditProxy中挂载相应的Strategy。
// slice/MainAbilitySlice
private ImageEditorProxy createImageEditProxy(String imgFilePath, ImageEditView editorView)
throws EditActionException {
imageEditorImp = new ImageEditorImp(imgFilePath);
// Add ImageEdit strategy here
imageEditorImp.addEditStrategy(new CropEditStrategy());
imageEditorImp.addEditStrategy(new BrightnessStrategy());
imageEditorImp.addEditStrategy(new SaturationStrategy());
imageEditorImp.addEditStrategy(new ContrastStrategy());
// Bind image editor to proxy
final ImageEditorProxy editorProxy = new ImageEditorProxy(imageEditorImp);
// Observe proxy
editorProxy.addObserver(this);
return editorProxy;
}
6. 内置图片编辑功能实现介绍
此模板中内置的两种图片编辑功能也实现了上述的两个接口,为开发者提供两种不同类型的编辑功能实现样例。
裁剪功能实现:
// strategy/imp/CropEditStrategy
@Override
public <T> PixelMap handle(final PixelMap origin, EditParams<T> params) throws HandleStrategyException {
Rect operatingRect = handleParameters(origin, params);
PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
options.pixelFormat = PixelFormat.ARGB_8888;
options.size = new Size(operatingRect.width, operatingRect.height);
return PixelMap.create(origin, operatingRect, options);
}
private <T> Rect handleParameters(final PixelMap origin, EditParams<T> options) throws HandleStrategyException {
validateParameter(origin, options);
Rect cropRect = options.getProperty(Rect.class, "cropRect");
cropRect.width = cropRect.width - cropRect.minX;
cropRect.height = cropRect.height - cropRect.minY;
return getFinalCropRect(cropRect, origin);
}
handleParameters()方法使用了EditParams类中的getProperty()方法获取用户输入数据,建议开发者使用该类来包装用户输入数据。handle()方法中,我们使用了PixelMap.create()方法根据输入参数新建了一张用户所需范围内的图片。PixelMap的其他使用方法可以参考Java API - PixelMap.
调节功能实现:
// strategy/imp/BaseAdjustStrategy
// Set canvas
PixelMap newPm = PixelMap.create(getPixelMapOptions(optionBmp));
Canvas canvas = new Canvas(new Texture(newPm));
// Set paint
Paint editPaint = getEditPaint(convertProgress(strategyParams.getProgress()));
// Draw
PixelMapHolder pixelMapHolder = new PixelMapHolder(optionBmp);
canvas.drawPixelMapHolder(pixelMapHolder, 0, 0, editPaint);
return newPm;
调节功能使用HarmonyOS中Canvas提供的drawPixelMapHolder方法创建图片。关于Canvas的使用可以参考Java API - Canvas.
// strategy/imp/BrightnessStrategy
protected ColorMatrix setColorMatrix(float value) {
ColorMatrix cm = new ColorMatrix();
cm.setMatrix(getColorMatrix(value));
return cm;
}
本模板中的调节效果是通过配置画笔editPaint中的ColorMatrix来实现的。开发者可以通过调用Paint.setColorMatrix来修改画笔中的色彩矩阵,进而实现符合业务逻辑的调节或滤镜功能。有关于画笔Paint的更多信息,可以参考Java API - Paint.
7. 回顾与总结
本篇Codelab我们介绍了DevEco中的图片编辑模板,该模板提供了一个已经实现好的图片编辑器以及内置的两种图片编辑功能。该模板旨在为需要添加图片编辑业务的应用开发者们提供一个较容易上手的初始工程,降低图片编辑开发的门槛。
8. 恭喜您
目前你已经成功完成了Codelab并且学到了:
图片编辑器是如何工作的。
如何向该模板中添加自定义的图片编辑功能。
9. 参考
开发者可以直接从DevEco V2.1 Beta3(DevEco下载链接)之后的版本中新建该模板工程。