diff --git a/Drawing/ArkTSGraphicsDraw/.gitignore b/Drawing/ArkTSGraphicsDraw/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/AppScope/app.json5 b/Drawing/ArkTSGraphicsDraw/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0f0064e2e2d1a9ff0a42df04df493a82e5875a14 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.ArkTSGraphicsDraw", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/element/string.json b/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..030035c3348210b3ebe8d27ab811961227f24697 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ArkTSGraphicsDraw" + } + ] +} diff --git a/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/media/app_icon.png b/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/AppScope/resources/base/media/app_icon.png differ diff --git a/Drawing/ArkTSGraphicsDraw/README.md b/Drawing/ArkTSGraphicsDraw/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c30357da4c2f99c26c7a39d5282df59420c6883e --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/README.md @@ -0,0 +1,94 @@ +# ArkTSGraphicsDraw + +## 介绍 + +本示例基于开发>图形->ArkGraphics 2D(方舟2D图形服务)-> [图形绘制与显示](https://gitee.com/openharmony/docs/tree/OpenHarmony-5.0.1-Release/zh-cn/application-dev/graphics#/openharmony/docs/blob/OpenHarmony-5.0.1-Release/zh-cn/application-dev/graphics/textblock-drawing-arkts.md)中的ArkTS部分开发。 + +本示例主要功能如下: + +- 演示画布的获取与绘制结果的显示,画布的类型分为直接画布与离屏画布。 +- 演示画布操作及状态处理,通过对画布进行裁剪、平移等操作控制绘图结果 +- 演示绘制效果,绘制经过填充、描边、着色器、滤波器等效果处理过后的图形。 +- 演示图元绘制,绘制多种几何形状、绘制位图及绘制字块。 + +## 效果预览 + +| 主页 | 画布获取 | 绘制效果 | 图元绘制 | +| --------------------------------- | ----------------------------------- | ----------------------------------- | --------------------------------- | +| ![index](./screenshot/index.jpeg) | ![canvas](./screenshot/canvas.jpeg) | ![effect](./screenshot/effect.jpeg) | ![shape](./screenshot/shape.jpeg) | + + +使用说明: + +1. 点击主页的导航标签组件,进入对应的演示页面。演示页面包括: + - 画布的获取与绘制结果的显示 + - 画布操作及状态处理 + - 基础绘制效果 + - 复杂绘制效果 + - 几何图形绘制 + - 图片绘制 + - 字块绘制 +2. 在演示页面内点击绘制按钮,界面绘制出对应图案。 +3. 点击返回按钮,退出应用。 + +## 工程目录 + +``` +ArkTSGraphicsDraw +entry/src/main +├──ets +│ ├──drawing +| | └──pages +| | ├──BasicEffect.ets (基础渲染效果界面) +| | ├──CanvasGetResult.ets (画布的获取与绘制结果的显示界面) +| | ├──CanvasOperationState.ets (画布操作及状态处理界面) +| | ├──ComplexEffect.ets (复杂绘制效果界面) +| | ├──PixelMapDrawing.ets (图片绘制界面) +| | ├──ShapeDrawing.ets (几何形状绘制界面) +| | └──TextBlockDrawing.ets (字块绘制界面) +│ └──pages +│ └──Index.ets (UI主界面) +└──resources (资源文件) +entry/src/ohosTest/ets/ +├── test +| ├── Ability.test.ets (UI测试代码) +| └── List.test.ets (测试套件列表) +└── utils + └── Logger.ets (logger日志类) +``` + +## 具体实现 + +1. 自定义渲染节点 (`MyRenderNode`):继承自 `RenderNode`,重写draw函数绘制图案。 +2. 自定义节点控制器 (`MyNodeController`):继承自 `NodeController`,自定义`makeNode` 方法。创建了一个根节点 (`rootNode`),并将 `myRenderNode` 添加为根节点的子节点。通过设置 `backgroundColor`、`frame`、`pivot`、`scale` 等属性,来控制渲染节点的显示效果。 +3. 绘制内容的切换:`MyRenderNode`中的`drawFunctions` 数组存储了多个绘制函数,`draw` 方法根据当前的绘制函数索引调用对应的绘制函数。当绘制索引更改时,调用 `invalidate()`触发重绘,切换绘制内容。 + +## 相关权限 + +不涉及 + +## 依赖 + +不涉及。 + +## 约束和限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.0.4 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.0.4 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.0.4 Release及以上。 + +## 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/Drawing/ArkTSGraphicsDraw/ > .git/info/sparse-checkout +git remote add origin OpenHarmony/applications_app_samples +git pull origin master +``` \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/build-profile.json5 b/Drawing/ArkTSGraphicsDraw/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2f3c86865016b9cfbc04190d6b99d9b149ec7d7c --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/build-profile.json5 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.4(16)", + "targetSdkVersion": "5.0.4(16)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/.gitignore b/Drawing/ArkTSGraphicsDraw/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/build-profile.json5 b/Drawing/ArkTSGraphicsDraw/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e7569e3056e27af38e9991b7ea73ec10f3ba8a05 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/hvigorfile.ts b/Drawing/ArkTSGraphicsDraw/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Drawing/ArkTSGraphicsDraw/entry/obfuscation-rules.txt b/Drawing/ArkTSGraphicsDraw/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/oh-package.json5 b/Drawing/ArkTSGraphicsDraw/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/BasicEffect.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/BasicEffect.ets new file mode 100644 index 0000000000000000000000000000000000000000..628b3fa4ba698168f0f3bf24ab82ca2e89d43606 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/BasicEffect.ets @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'; +import { drawing } from '@kit.ArkGraphics2D'; +import { VALUE_100, VALUE_400, VALUE_800 } from '../../pages/Index'; + +function drawFilling(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_create_brush] + // 设置画刷 + const brush = new drawing.Brush(); + // [End arkts_graphics_draw_create_brush] + // [Start arkts_graphics_draw_brush_set_color] + // 填充颜色设为红色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // [End arkts_graphics_draw_brush_set_color] + // [Start arkts_graphics_draw_brush_set_antialias] + // 开启抗锯齿效果 + brush.setAntiAlias(true); + // [End arkts_graphics_draw_brush_set_antialias] + // [Start arkts_graphics_draw_canvas_attach_brush] + // 为画布设置画刷 + canvas.attachBrush(brush); + // [End arkts_graphics_draw_canvas_attach_brush] + // 绘制一个圆心坐标(400,400)半径400的圆 + canvas.drawCircle(VALUE_400, VALUE_400, VALUE_400); + // [Start arkts_graphics_draw_canvas_detach_brush] + // 去除画刷 + canvas.detachBrush(); + // [End arkts_graphics_draw_canvas_detach_brush] +} + +function drawStroke(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_create_drawing_pen] + // 创建画笔 + let pen = new drawing.Pen(); + // [End arkts_graphics_draw_create_drawing_pen] + // [Start arkts_graphics_draw_pen_set_color] + // 设置颜色为红色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // [End arkts_graphics_draw_pen_set_color] + // [Start arkts_graphics_draw_pen_set_stroke_width] + // 设置线宽 + pen.setStrokeWidth(15); + // [End arkts_graphics_draw_pen_set_stroke_width] + // [Start arkts_graphics_draw_pen_set_antialias] + // 设置抗锯齿效果 + pen.setAntiAlias(true); + // [End arkts_graphics_draw_pen_set_antialias] + // [Start arkts_graphics_draw_pen_set_cap_style] + // 设置画笔线帽样式 + pen.setCapStyle(drawing.CapStyle.SQUARE_CAP); + // [End arkts_graphics_draw_pen_set_cap_style] + // [Start arkts_graphics_draw_pen_set_join_style] + // 设置画笔转角样式 + pen.setJoinStyle(drawing.JoinStyle.ROUND_JOIN); + // [End arkts_graphics_draw_pen_set_join_style] + // [Start arkts_graphics_draw_canvas_attach_pen] + // 为画布设置画笔 + canvas.attachPen(pen); + // [End arkts_graphics_draw_canvas_attach_pen] + // 创建U型路径 + let aX = VALUE_100; + let aY = VALUE_100; + let bX = VALUE_100; + let bY = VALUE_800; + let cX = VALUE_800; + let cY = VALUE_800; + let dX = VALUE_800; + let dY = VALUE_100; + let path = new drawing.Path(); + path.moveTo(aX, aY); + path.lineTo(bX, bY); + path.lineTo(cX, cY); + path.lineTo(dX, dY); + // 绘制U型路径 + canvas.drawPath(path); + // [Start arkts_graphics_draw_canvas_detach_pen] + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_canvas_detach_pen] +} + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private rootNode: FrameNode | null = null; + private myRenderNode = new MyRenderNode(); + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawFilling); + this.myRenderNode.addDrawFunction(drawStroke); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; // 白色背景 + this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + } +} + +@Entry +@Component +struct BaseEffect { + private nodeController: MyNodeController = new MyNodeController(); + @State flag: boolean = false; + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.Filling')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制填充效果 + }); + Button($r('app.string.Stroke')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击绘制描边效果 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasGetResult.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasGetResult.ets new file mode 100644 index 0000000000000000000000000000000000000000..4245fef6eac8107c72c834d549d30ecf48194487 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasGetResult.ets @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UIContext, NodeController, FrameNode, RenderNode, DrawContext} from '@kit.ArkUI'; +import { image } from '@kit.ImageKit'; +import { taskpool } from '@kit.ArkTS'; +import { drawing } from '@kit.ArkGraphics2D'; + +// [Start arkts_graphics_draw_direct_canvas_api] +// 1. 自定义 RenderNode +class MyRenderNodeDirectDisplay extends RenderNode { + async draw(context: DrawContext) { + const canvas = context.canvas; + if (canvas === null) { + console.error('Canvas is null.'); + return; + } + // 3. 自定义的绘制相关操作 + const brush = new drawing.Brush(); + if (brush === null) { + console.error('Brush is null.'); + return; + } else { + brush.setColor({red: 255, blue: 0, green: 0, alpha: 255}); + canvas.attachBrush(brush); + canvas.drawRect({left: 0, right: 300, top: 0, bottom: 300}); + } + } +} + +// 2. 自定义 NodeController +class MyNodeControllerDirectDisplay extends NodeController { + private rootNode: FrameNode | null = null; + private myRenderNode = new MyRenderNodeDirectDisplay(); + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; + this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } +} +// [End arkts_graphics_draw_direct_canvas_api] + +// [Start arkts_graphics_draw_indirect_canvas_api] +// 1. 自定义RenderNode +export class MyRenderNodeIndirectDisplay extends RenderNode { + private pixelMap: image.PixelMap | null = null; + setPixelMap(pixelMap: image.PixelMap) { + this.pixelMap = pixelMap; + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + if (this.pixelMap != null) { + // 4.1 利用3中创建的PixelMap构造离屏Canvas + const canvas_ = new drawing.Canvas(this.pixelMap); + + // 4.2 离屏绘制 + const brush = new drawing.Brush(); + brush.setColor({ alpha: 255, red: 0, green: 0, blue: 255 }); + canvas_.attachBrush(brush); + canvas_.drawRect({ left: 150, right: 575, top: 0, bottom: 600 }); + + // 4.3 将离屏Canvas的绘制结果交给RenderNode + canvas.drawImage(this.pixelMap, 0, 0); + } + } +} + +@Concurrent +async function createPixelMapAsync() { + const color : ArrayBuffer = new ArrayBuffer(4000000); // 40000为需要创建的像素buffer大小,取值为:height * width *4 + let opts : image.InitializationOptions = { editable: true, pixelFormat: 3, size: { height: 1000, width: 1000 } }; + const pixel = await image.createPixelMap(color, opts); + return pixel; +} + +// 2. 自定义NodeController +export class MyNodeControllerIndirectDisplay extends NodeController { + private rootNode: FrameNode | null = null; + private myRenderNode = new MyRenderNodeIndirectDisplay(); + + // 3. 在MyNodeController的aboutToAppear中创建PixeMap + aboutToAppear(): void { + let task = new taskpool.Task(createPixelMapAsync); + taskpool.execute(task).then((pixel:Object)=>{ + this.myRenderNode.setPixelMap(pixel as image.PixelMap); + this.myRenderNode.invalidate(); + }) + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; + this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } +} +// [End arkts_graphics_draw_indirect_canvas_api] + +// [Start arkts_graphics_draw_direct_and_indirect_canvas] +@Entry +@Component +struct RenderTest { + @State message: string = 'hello'; + myNodeController_1 = new MyNodeControllerDirectDisplay(); + myNodeController_2 = new MyNodeControllerIndirectDisplay(); + + build() { + Row() { + Column() { + Column(){ + Text($r('app.string.DirectCanvas')) + // 直接画布 + NodeContainer(this.myNodeController_1) + .width('100%') + .height('40%') + } + Column(){ + Text($r('app.string.OffScreenCanvas')) + // 离屏画布 + NodeContainer(this.myNodeController_2) + .width('100%') + .height('40%') + .margin({ top: 20 }) + } + } + } + } +} +// [End arkts_graphics_draw_direct_and_indirect_canvas] \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasOperationState.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasOperationState.ets new file mode 100644 index 0000000000000000000000000000000000000000..b15ceccce83b21f86b98a849961b7ddd4231e2ee --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/CanvasOperationState.ets @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'; +import { common2D, drawing } from '@kit.ArkGraphics2D'; +import { VALUE_200, VALUE_300, VALUE_600 } from '../../pages/Index'; + + +function drawClipOperation(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_canvas_clip] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色为蓝色 + brush.setColor(0xFF, 0x00, 0x00, 0xFF); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 创建矩形对象 + let rect: common2D.Rect = { left: VALUE_200, top: VALUE_200, right: VALUE_600, bottom: VALUE_600 }; + // 裁剪矩形区域 + canvas.clipRect(rect); + // 绘制圆形 + canvas.drawCircle(VALUE_300, VALUE_300, VALUE_300); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_canvas_clip] +} + +function drawTranslationOperation(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_canvas_translation] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色为红色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 执行平移操作 + canvas.translate(VALUE_300, VALUE_300); + // 绘制矩形 + canvas.drawRect({ left: VALUE_200, top: VALUE_200, right: VALUE_600, bottom: VALUE_600 }); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_canvas_translation] +} + +function drawRotationOperation(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_canvas_rotation] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色为红色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 顺时针旋转45度 + canvas.rotate(45, VALUE_200, VALUE_200); + // 绘制矩形 + canvas.drawRect({ left: VALUE_200, top: VALUE_200, right: VALUE_600, bottom: VALUE_600 }); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_canvas_rotation] +} + +function drawScaleOperation(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_canvas_scale] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色为红色 + brush.setColor({ alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 执行放大操作 + canvas.scale(2, 2); + // 绘制矩形 + canvas.drawRect({ left: VALUE_200, top: VALUE_200, right: VALUE_600, bottom: VALUE_600 }); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_canvas_scale] +} + +function drawStateOperation(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_canvas_state_operation] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置颜色为红色 + pen.setColor({ alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }); + // 设置描边宽度为20px + pen.setStrokeWidth(20); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 保存操作,当前是不存在放大等操作的,这个原始状态会被保存下来 + canvas.save(); + // x轴和y轴放行分别放大2倍 + canvas.scale(2, 2); + // 绘制圆形,因为执行过放大操作,所以此时绘制的是大圆 + canvas.drawCircle(VALUE_300, VALUE_300, VALUE_200); + // 恢复操作,恢复到没有放大的原始状态 + canvas.restore(); + // 绘制圆形,因为已经恢复到没有放大的原始状态,所以此时绘制的是小圆 + canvas.drawCircle(VALUE_300, VALUE_300, VALUE_200); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_canvas_state_operation] +} + + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private rootNode: FrameNode | null = null; + private myRenderNode = new MyRenderNode(); + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawClipOperation); + this.myRenderNode.addDrawFunction(drawTranslationOperation); + this.myRenderNode.addDrawFunction(drawRotationOperation); + this.myRenderNode.addDrawFunction(drawScaleOperation); + this.myRenderNode.addDrawFunction(drawStateOperation); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; // 白色背景 + this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + } +} + +@Entry +@Component +struct CanvasOperationState { + private nodeController: MyNodeController = new MyNodeController(); + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.ClipOperation')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制裁剪操作 + }); + Button($r('app.string.TranslationOperation')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击绘制平移操作 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + Row() { + Button($r('app.string.RotationOperation')) + .onClick(() => { + this.nodeController.setDrawIndex(2); // 点击绘制旋转操作 + }); + Button($r('app.string.ScaleOperation')) + .onClick(() => { + this.nodeController.setDrawIndex(3); // 点击绘制缩放操作 + }); + Button($r('app.string.StateOperation')) + .onClick(() => { + this.nodeController.setDrawIndex(4); // 点击绘制画布状态操作 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ComplexEffect.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ComplexEffect.ets new file mode 100644 index 0000000000000000000000000000000000000000..693fab14e6afdb55c9ab493acf5a638288d3c860 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ComplexEffect.ets @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DrawContext, FrameNode, NodeController, RenderNode, UIContext } from '@kit.ArkUI'; +import { common2D, drawing } from '@kit.ArkGraphics2D'; +import { + VALUE_100, + VALUE_200, + VALUE_300, + VALUE_500, + VALUE_600, + VALUE_700, + VALUE_900, + VALUE_1000 +} from '../../pages/Index'; + +function drawMixedMode(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_mixed_mode] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置目标像素颜色,即矩形的颜色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 将目标像素的画刷效果设置到Canvas中 + canvas.attachBrush(brush); + // 创建矩形对象 + let rect: common2D.Rect = { + left: VALUE_100, + top: VALUE_100, + right: VALUE_600, + bottom: VALUE_600 + }; + // 绘制矩形(目标像素) + canvas.drawRect(rect); + // 设置源像素颜色,即圆形的颜色 + brush.setColor(0xFF, 0x00, 0x00, 0xFF); + // 设置混合模式为叠加模式 + brush.setBlendMode(drawing.BlendMode.PLUS); + // 将源像素的画刷效果设置到Canvas中 + canvas.attachBrush(brush); + // 绘制圆(源像素) + canvas.drawCircle(VALUE_600, VALUE_600, VALUE_300); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_mixed_mode] +} + +function drawPathEffect(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_path_effect] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置线宽 + pen.setStrokeWidth(10.0); + // 设置颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 表示10px的实线,5px的间隔,2px的实线,5px的间隔,以此循环 + let intervals = [10, 5, 2, 5]; + // 设置虚线路径效果 + let effect = drawing.PathEffect.createDashPathEffect(intervals, 0); + pen.setPathEffect(effect); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 创建矩形 + let rect: common2D.Rect = { + left: VALUE_200, + top: VALUE_200, + right: VALUE_1000, + bottom: VALUE_700 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_path_effect] +} + +function drawLinearGradient(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_linear_gradient] + let startPt: common2D.Point = { x: VALUE_100, y: VALUE_100 }; + let endPt: common2D.Point = { x: VALUE_900, y: VALUE_900 }; + let colors = [0xFFFFFF00, 0xFFFF0000, 0xFF0000FF]; + // 创建线性渐变着色器 + let shaderEffect = drawing.ShaderEffect.createLinearGradient(startPt, endPt, colors, drawing.TileMode.CLAMP); + // 创建画刷 + let brush = new drawing.Brush(); + // 设置线性着色器 + brush.setShaderEffect(shaderEffect); + // 设置画刷填充效果 + canvas.attachBrush(brush); + let rect: common2D.Rect = { + left: VALUE_100, + top: VALUE_100, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_linear_gradient] +} + +function drawPathGradient(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_path_gradient] + let centerPt: common2D.Point = { x: VALUE_500, y: VALUE_500 }; + let colors = [0xFFFF0000, 0xFF00FF00, 0xFF0000FF]; + // 创建径向渐变着色器 + let shaderEffect = drawing.ShaderEffect.createRadialGradient(centerPt, VALUE_600, colors, drawing.TileMode.CLAMP); + // 创建画刷 + let brush = new drawing.Brush(); + // 设置径向渐变着色器 + brush.setShaderEffect(shaderEffect); + // 设置画刷填充效果 + canvas.attachBrush(brush); + let rect: common2D.Rect = { + left: VALUE_100, + top: VALUE_100, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_path_gradient] +} + +function drawSectorGradient(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_sector_gradient] + let centerPt: common2D.Point = { x: VALUE_500, y: VALUE_500 }; + let colors = [0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00]; + // 创建扇形渐变着色器 + let shaderEffect = drawing.ShaderEffect.createSweepGradient(centerPt, colors, drawing.TileMode.CLAMP, 0, 360); + // 创建画刷 + let brush = new drawing.Brush(); + // 设置扇形渐变着色器 + brush.setShaderEffect(shaderEffect); + // 设置画刷填充效果 + canvas.attachBrush(brush); + let rect: common2D.Rect = { + left: VALUE_100, + top: VALUE_100, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_sector_gradient] +} + +function drawColorFilter(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_color_filter] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置颜色矩阵 + let matrix: number[] = [ + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0.5, 0.5, 0, + 0, 0, 0.5, 0.5, 0 + ]; + // 创建5x4颜色矩阵的颜色滤波器 + let filter = drawing.ColorFilter.createMatrixColorFilter(matrix); + // 设置颜色滤波器 + brush.setColorFilter(filter); + // 设置画刷填充效果 + canvas.attachBrush(brush); + let rect: common2D.Rect = { + left: VALUE_300, + top: VALUE_300, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_color_filter] +} + +function drawImageFilter(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_image_filter] + // 设置画笔 + let pen = new drawing.Pen(); + // 设置线宽 + pen.setStrokeWidth(10.0); + // 设置颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 创建模糊效果图像滤波器 + let filter = drawing.ImageFilter.createBlurImageFilter(20, 20, drawing.TileMode.CLAMP); + // 设置图像滤波器 + pen.setImageFilter(filter); + // 设置画笔描边效果 + canvas.attachPen(pen); + let rect: common2D.Rect = { + left: VALUE_300, + top: VALUE_300, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_image_filter] +} + +function drawMaskFilter(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_mask_filter] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置线宽 + pen.setStrokeWidth(10.0); + // 设置颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 创建模糊效果的蒙版滤波器 + let filter = drawing.MaskFilter.createBlurMaskFilter(drawing.BlurType.NORMAL, 20); + // 设置模糊效果 + pen.setMaskFilter(filter); + // 设置画笔描边效果 + canvas.attachPen(pen); + let rect: common2D.Rect = { + left: VALUE_300, + top: VALUE_300, + right: VALUE_900, + bottom: VALUE_900 + }; + // 绘制矩形 + canvas.drawRect(rect); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_mask_filter] +} + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private myRenderNode = new MyRenderNode(); + private rootNode: FrameNode | null = null; + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawMixedMode); + this.myRenderNode.addDrawFunction(drawPathEffect); + this.myRenderNode.addDrawFunction(drawLinearGradient); + this.myRenderNode.addDrawFunction(drawPathGradient); + this.myRenderNode.addDrawFunction(drawSectorGradient); + this.myRenderNode.addDrawFunction(drawColorFilter); + this.myRenderNode.addDrawFunction(drawImageFilter); + this.myRenderNode.addDrawFunction(drawMaskFilter); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xff000000; // 黑色背景 + this.myRenderNode.frame = { + x: 0, + y: 0, + width: 4800, + height: 4800 + }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + if (index === 0) { + this.myRenderNode.backgroundColor = 0xff000000; // 混合模式效果需要使用黑色背景展示 + } else { + this.myRenderNode.backgroundColor = 0xffffffff; // 其余模式使用白色背景 + } + + } +} + +@Entry +@Component +struct ComplexEffect { + private nodeController: MyNodeController = new MyNodeController(); + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.MixedMode')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制混合模式 + }); + Button($r('app.string.PathEffect')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击绘制路径效果 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + + Row() { + Button($r('app.string.LinearGradient')) + .onClick(() => { + this.nodeController.setDrawIndex(2); // 点击绘制线性渐变着色器效果 + }); + Button($r('app.string.PathGradient')) + .onClick(() => { + this.nodeController.setDrawIndex(3); // 点击绘制径向渐变着色器效果 + }); + Button($r('app.string.SectorGradient')) + .onClick(() => { + this.nodeController.setDrawIndex(4); // 点击绘制扇形渐变着色器效果 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + + Row() { + Button($r('app.string.ColorFilter')) + .onClick(() => { + this.nodeController.setDrawIndex(5); // 点击绘制颜色滤波器效果 + }); + Button($r('app.string.ImageFilter')) + .onClick(() => { + this.nodeController.setDrawIndex(6); // 点击绘制图像滤波器效果 + }); + Button($r('app.string.MaskFilter')) + .onClick(() => { + this.nodeController.setDrawIndex(7); // 点击绘制蒙版滤波器效果 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/PixelMapDrawing.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/PixelMapDrawing.ets new file mode 100644 index 0000000000000000000000000000000000000000..e2bc466fed8ba7484321ec5282b6589d2861f1fd --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/PixelMapDrawing.ets @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DrawContext, FrameNode, NodeController, RenderNode, UIContext } from '@kit.ArkUI'; +import { drawing } from '@kit.ArkGraphics2D'; +import { image } from '@kit.ImageKit'; +import { VALUE_100, VALUE_200 } from '../../pages/Index'; + +let pixelMap: image.PixelMap; + +function drawImage(canvas: drawing.Canvas) { + // Start arkts_graphics_draw_image] + // 图片宽高 + let width = 600; + let height = 400; + // 字节长度,RGBA_8888每个像素占4字节 + let bytelength = width * height * 4; + const color: ArrayBuffer = new ArrayBuffer(bytelength); + let bufferArr = new Uint8Array(color); + for (let i = 0; i < bufferArr.length; i += 4) { + // 遍历并编辑每个像素,从而形成红绿蓝相间的条纹 + bufferArr[i] = 0x00; + bufferArr[i+1] = 0x00; + bufferArr[i+2] = 0x00; + bufferArr[i+3] = 0xFF; + let n = Math.floor(i / 80) % 3; + if (n == 0) { + bufferArr[i] = 0xFF; + } else if (n == 1) { + bufferArr[i+1] = 0xFF; + } else { + bufferArr[i+2] = 0xFF; + } + } + // 设置像素属性 + let opts: image.InitializationOptions = + { editable: true, pixelFormat: image.PixelMapFormat.RGBA_8888, size: { height: height, width: width } }; + // 创建PixelMap + pixelMap = image.createPixelMapSync(color, opts); + // 为了使图片完全显示,修改绘制起点参数为(0,0) + canvas.drawImage(pixelMap, 0, 0); + // End arkts_graphics_draw_image] +} + +function editPixel(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_edit_pixel] + // 设置编辑区域的宽高 + let innerWidth = 400; + let innerHeight = 200; + // 编辑区域的字节长度,RGBA_8888每个像素占4字节 + let innerByteLength = innerWidth * innerHeight * 4; + const innerColor: ArrayBuffer = new ArrayBuffer(innerByteLength); + let innerBufferArr = new Uint8Array(innerColor); + for (let i = 0; i < innerBufferArr.length; i += 4) { + // 编辑区域的像素都设置为黑白相间条纹 + let n = Math.floor(i / 80) % 2; + if (n == 0) { + innerBufferArr[i] = 0x00; + innerBufferArr[i+1] = 0x00; + innerBufferArr[i+2] = 0x00; + } else { + innerBufferArr[i] = 0xFF; + innerBufferArr[i+1] = 0xFF; + innerBufferArr[i+2] = 0xFF; + } + innerBufferArr[i+3] = 0xFF; + } + // 设置编辑区域的像素、宽高、偏移量等 + const area: image.PositionArea = { + pixels: innerColor, + offset: 0, + stride: innerWidth * 4, + region: { size: { height: innerHeight, width: innerWidth }, x: 100, y: 100 } + }; + // 编辑位图,形成中间的黑白相间条纹 + pixelMap.writePixelsSync(area); + // 为了使图片完全显示,修改绘制起点参数为(0,0) + canvas.drawImage(pixelMap, 0, 0); + // [End arkts_graphics_draw_edit_pixel] +} + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private myRenderNode = new MyRenderNode(); + private rootNode: FrameNode | null = null; + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawImage); + this.myRenderNode.addDrawFunction(editPixel); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; // 白色背景 + this.myRenderNode.frame = { + x: 0, + y: 0, + width: 4800, + height: 4800 + }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + } +} + +@Entry +@Component +struct ImageDrawing { + private nodeController: MyNodeController = new MyNodeController(); + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.PixelMap')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制位图 + }); + Button($r('app.string.EditMiddlePixel')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击编辑位图像素 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ShapeDrawing.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ShapeDrawing.ets new file mode 100644 index 0000000000000000000000000000000000000000..5df7176e9af7a1019ebef30ad2d4fc0b61722bf0 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/ShapeDrawing.ets @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DrawContext, FrameNode, NodeController, RenderNode, UIContext } from '@kit.ArkUI'; +import { common2D, drawing } from '@kit.ArkGraphics2D'; +import { + VALUE_100, + VALUE_200, + VALUE_300, + VALUE_400, + VALUE_500, + VALUE_600, + VALUE_630, + VALUE_700, + VALUE_800, + VALUE_900, + VALUE_1000, + VALUE_1800 +} from '../../pages/Index'; + +function drawPoint(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_point] + // 设置画笔 + let pen = new drawing.Pen(); + // 设置颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置线宽 + pen.setStrokeWidth(40); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 绘制5个点 + canvas.drawPoint(VALUE_200, VALUE_200); + canvas.drawPoint(VALUE_400, VALUE_400); + canvas.drawPoint(VALUE_600, VALUE_600); + canvas.drawPoint(VALUE_800, VALUE_800); + canvas.drawPoint(VALUE_1000, VALUE_1000); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_point] +} + +function drawArc(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_arc] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置颜色 + pen.setColor({ + alpha: 0xFF, + red: 0xFF, + green: 0x00, + blue: 0x00 + }); + // 设置线宽 + pen.setStrokeWidth(20); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 创建矩形对象 + const rect: common2D.Rect = { + left: VALUE_100, + top: VALUE_200, + right: VALUE_1000, + bottom: VALUE_600 + }; + // 绘制矩形 + canvas.drawArc(rect, 0, 180); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_arc] +} + +function drawCircle(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_circle] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置颜色 + pen.setColor({ + alpha: 0xFF, + red: 0xFF, + green: 0x00, + blue: 0x00 + }); + // 设置线宽 + pen.setStrokeWidth(20); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 绘制圆 + canvas.drawCircle(VALUE_630, VALUE_630, VALUE_500); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_circle] +} + +function drawPath(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_path] + let height_ = VALUE_1800; + let width_ = VALUE_1800; + let len = height_ / 4; + let aX = width_ / 3; + let aY = height_ / 6; + let dX = aX - len * Math.sin(18.0); + let dY = aY + len * Math.cos(18.0); + let cX = aX + len * Math.sin(18.0); + let cY = dY; + let bX = aX + (len / 2.0); + let bY = aY + Math.sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0)); + let eX = aX - (len / 2.0); + let eY = bY; + + // 创建一个path对象,然后使用接口连接成一个五角星形状 + let path = new drawing.Path(); + // 指定path的起始位置 + path.moveTo(aX, aY); + // 用直线连接到目标点 + path.lineTo(bX, bY); + path.lineTo(cX, cY); + path.lineTo(dX, dY); + path.lineTo(eX, eY); + // 闭合形状,path绘制完毕 + path.close(); + + // 创建画笔对象 + let pen = new drawing.Pen(); + // 设置抗锯齿 + pen.setAntiAlias(true); + // 设置描边颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置线宽 + pen.setStrokeWidth(10.0); + // 设置画笔描边效果 + canvas.attachPen(pen); + // 创建画刷 + let brush = new drawing.Brush(); + // 设置填充颜色 + brush.setColor(0xFF, 0x00, 0xFF, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 绘制路径 + canvas.drawPath(path); + // 去除填充效果 + canvas.detachBrush(); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_path] +} + +function drawRegion(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_region] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 创建左上角的region1 + let region1 = new drawing.Region(); + region1.setRect(VALUE_100, VALUE_100, VALUE_600, VALUE_600); + // 创建右下角的region2 + let region2 = new drawing.Region(); + region2.setRect(VALUE_300, VALUE_300, VALUE_900, VALUE_900); + // 将两个区域以XOR的方式组合 + region1.op(region2, drawing.RegionOp.XOR); + // 绘制区域 + canvas.drawRegion(region1); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_region] +} + +function drawRect(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_rect] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 绘制矩形 + canvas.drawRect(VALUE_200, VALUE_200, VALUE_1000, VALUE_700); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_rect] +} + +function drawRoundRect(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_round_rect] + // 创建画刷 + let brush = new drawing.Brush(); + // 设置颜色 + brush.setColor(0xFF, 0xFF, 0x00, 0x00); + // 设置画刷填充效果 + canvas.attachBrush(brush); + // 创建矩形对象 + let rect: common2D.Rect = { + left: VALUE_200, + top: VALUE_200, + right: VALUE_1000, + bottom: VALUE_700 + }; + console.info('rect:', rect.right); + // 创建圆角矩形对象 + let rrect = new drawing.RoundRect(rect, 30, 30); + // 绘制圆角矩形 + canvas.drawRoundRect(rrect); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_round_rect] +} + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private myRenderNode = new MyRenderNode(); + private rootNode: FrameNode | null = null; + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawPoint); + this.myRenderNode.addDrawFunction(drawArc); + this.myRenderNode.addDrawFunction(drawCircle); + this.myRenderNode.addDrawFunction(drawPath); + this.myRenderNode.addDrawFunction(drawRegion); + this.myRenderNode.addDrawFunction(drawRect); + this.myRenderNode.addDrawFunction(drawRoundRect); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; // 白色背景 + this.myRenderNode.frame = { + x: 0, + y: 0, + width: 4800, + height: 4800 + }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + } +} + +@Entry +@Component +struct ShapeDrawing { + private nodeController: MyNodeController = new MyNodeController(); + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.Point')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制点 + }); + Button($r('app.string.Arc')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击绘制圆弧 + }); + Button($r('app.string.Circle')) + .onClick(() => { + this.nodeController.setDrawIndex(2); // 点击绘制圆 + }); + Button($r('app.string.Path')) + .onClick(() => { + this.nodeController.setDrawIndex(3); // 点击绘制路径 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + + Row() { + Button($r('app.string.Region')) + .onClick(() => { + this.nodeController.setDrawIndex(4); // 点击绘制区域 + }); + Button($r('app.string.Rect')) + .onClick(() => { + this.nodeController.setDrawIndex(5); // 点击绘制矩形 + }); + Button($r('app.string.RoundRect')) + .onClick(() => { + this.nodeController.setDrawIndex(6); // 点击绘制圆角矩形 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/TextBlockDrawing.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/TextBlockDrawing.ets new file mode 100644 index 0000000000000000000000000000000000000000..9bc8d6f0a3d48f74a381805b7685a610d4cbff60 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/drawing/pages/TextBlockDrawing.ets @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'; +import { common2D, drawing } from '@kit.ArkGraphics2D'; +import { VALUE_100, VALUE_200, VALUE_300, VALUE_900 } from '../../pages/Index'; + +function drawBaseText(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_base_text] + // 创建字型对象 + const font = new drawing.Font(); + // 设置字体大小 + font.setSize(100); + // 创建字块对象 + const textBlob = drawing.TextBlob.makeFromString('Hello world', font, drawing.TextEncoding.TEXT_ENCODING_UTF8); + // 绘制字块 + canvas.drawTextBlob(textBlob, VALUE_200, VALUE_300); + // [End arkts_graphics_draw_base_text] +} + +function drawStrokeText(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_stroke_text] + // 创建画笔 + let pen = new drawing.Pen(); + // 设置抗锯齿 + pen.setAntiAlias(true); + // 设置描边线宽 + pen.setStrokeWidth(3.0); + // 设置描边颜色 + pen.setColor(0xFF, 0xFF, 0x00, 0x00); + // 创建字型对象 + const font = new drawing.Font(); + // 设置字体大小 + font.setSize(100); + // 添加画笔描边效果 + canvas.attachPen(pen); + // 创建字块对象 + const textBlob = drawing.TextBlob.makeFromString('Hello world', font, drawing.TextEncoding.TEXT_ENCODING_UTF8); + // 绘制字块 + canvas.drawTextBlob(textBlob, VALUE_200, VALUE_300); + // 去除描边效果 + canvas.detachPen(); + // [End arkts_graphics_draw_stroke_text] +} + +function drawGradientText(canvas: drawing.Canvas) { + // [Start arkts_graphics_draw_gradient_text] + let startPt: common2D.Point = { x: VALUE_100, y: VALUE_100 }; + let endPt: common2D.Point = { x: VALUE_900, y: VALUE_900 }; + let colors = [0xFFFFFF00, 0xFFFF0000, 0xFF0000FF]; + // 创建线性渐变着色器 + let shaderEffect = drawing.ShaderEffect.createLinearGradient(startPt, endPt, colors, drawing.TileMode.CLAMP); + // 创建画刷 + let brush = new drawing.Brush(); + // 设置着色器 + brush.setShaderEffect(shaderEffect); + // 添加画刷填充效果 + canvas.attachBrush(brush); + // 创建字型 + const font = new drawing.Font(); + // 设置字体大小 + font.setSize(VALUE_200); + // 创建字块 + const textBlob = drawing.TextBlob.makeFromString('Hello world', font, drawing.TextEncoding.TEXT_ENCODING_UTF8); + // 绘制字块 + canvas.drawTextBlob(textBlob, VALUE_100, VALUE_300); + // 去除填充效果 + canvas.detachBrush(); + // [End arkts_graphics_draw_gradient_text] +} + +// 自定义RenderNode +class MyRenderNode extends RenderNode { + private drawFunctions: ((canvas: drawing.Canvas) => void)[] = []; // 存储绘制函数的数组 + private currentDrawIndex: number = 0; // 当前绘制函数的下标 + + // 添加绘制函数的接口 + addDrawFunction(func: (canvas: drawing.Canvas) => void) { + this.drawFunctions.push(func); + } + + // 设置当前绘制函数的下标 + setDrawIndex(index: number) { + if (index >= 0 && index < this.drawFunctions.length) { + this.currentDrawIndex = index; + this.invalidate(); // 触发重绘 + } + } + + async draw(context: DrawContext) { + const canvas = context.canvas; + const drawFunction = this.drawFunctions[this.currentDrawIndex]; + if (drawFunction) { + drawFunction(canvas); + } + } +} + +// 自定义NodeController +class MyNodeController extends NodeController { + private rootNode: FrameNode | null = null; + private myRenderNode = new MyRenderNode(); + + constructor() { + super(); + // 添加绘制函数 + this.myRenderNode.addDrawFunction(drawBaseText); + this.myRenderNode.addDrawFunction(drawStrokeText); + this.myRenderNode.addDrawFunction(drawGradientText); + } + + makeNode(uiContext: UIContext): FrameNode { + this.rootNode = new FrameNode(uiContext); + if (this.rootNode === null) { + return this.rootNode; + } + + const renderNode = this.rootNode.getRenderNode(); + if (renderNode !== null) { + this.myRenderNode.backgroundColor = 0xffffffff; // 白色背景 + this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; + this.myRenderNode.pivot = { x: 0.2, y: 0.8 }; + this.myRenderNode.scale = { x: 1, y: 1 }; + renderNode.appendChild(this.myRenderNode); + renderNode.clipToFrame = true; + } + return this.rootNode; + } + + // 暴露设置绘制函数下标的方法 + setDrawIndex(index: number) { + this.myRenderNode.setDrawIndex(index); + } +} + +@Entry +@Component +struct TextBlobDrawing { + private nodeController: MyNodeController = new MyNodeController(); + + build() { + Row() { + Column() { + // 将自定义NodeController进行显示 + NodeContainer(this.nodeController) + .width('100%') + .height('70%'); + Row() { + Button($r('app.string.BaseText')) + .onClick(() => { + this.nodeController.setDrawIndex(0); // 点击绘制基本文字 + }); + Button($r('app.string.StrokeText')) + .onClick(() => { + this.nodeController.setDrawIndex(1); // 点击绘制描边文字 + }); + Button($r('app.string.GradientText')) + .onClick(() => { + this.nodeController.setDrawIndex(2); // 点击绘制渐变文字 + }); + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('8%') + } + } + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entryability/EntryAbility.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..edc2839f203ba057c186e19b0cbbbf80c8faa8b3 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/pages/Index.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f592b9de39e219d8234899375b8cec9ae096446 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import router from '@ohos.router'; +import { AdaptationUtil } from '../utils/AdaptationUtil'; + +// 示例代码默认设备为真机,所以在开发板上某些绘制结果显示不全 +// 通过设备宽度等比例缩放参数,以此适配开发板显示 +let adaptationUtil = new AdaptationUtil(); +export const VALUE_100 = adaptationUtil.getWidth(100); +export const VALUE_200 = adaptationUtil.getWidth(200); +export const VALUE_300 = adaptationUtil.getWidth(300); +export const VALUE_400 = adaptationUtil.getWidth(400); +export const VALUE_500 = adaptationUtil.getWidth(500); +export const VALUE_600 = adaptationUtil.getWidth(600); +export const VALUE_630 = adaptationUtil.getWidth(630); +export const VALUE_700 = adaptationUtil.getWidth(700); +export const VALUE_800 = adaptationUtil.getWidth(800); +export const VALUE_900 = adaptationUtil.getWidth(900); +export const VALUE_1000 = adaptationUtil.getWidth(1000); +export const VALUE_1800 = adaptationUtil.getWidth(1800); + +interface Item { + text: string; +} + +const operationUrls: string[] = [ + 'drawing/pages/CanvasGetResult', + 'drawing/pages/CanvasOperationState', + 'drawing/pages/BasicEffect', + 'drawing/pages/ComplexEffect', + 'drawing/pages/ShapeDrawing', + 'drawing/pages/PixelMapDrawing', + 'drawing/pages/TextBlockDrawing' +]; + +@Entry +@Component +struct Index { + ResourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + @State listItem: Item[] = [ + { text: this.ResourceToString($r('app.string.CanvasGetResult')) }, + { text: this.ResourceToString($r('app.string.CanvasOperationState')) }, + { text: this.ResourceToString($r("app.string.BasicEffect")) }, + { text: this.ResourceToString($r('app.string.ComplexEffect')) }, + { text: this.ResourceToString($r('app.string.Shape_Drawing')) }, + { text: this.ResourceToString($r("app.string.PixelMap_Drawing")) }, + { text: this.ResourceToString($r("app.string.TextBlock_Drawing")) } + ] + + build() { + Column() { + List() { + ForEach(this.listItem, (item: Item, index) => { + ListItem() { + Row() { + Blank().width('4%') + Text(item.text) + .fontSize(16) + .fontColor('black') + .width('90%') + Image($r('app.media.right')) + .height(12) + .width(12) + } + .onClick(() => { + router.pushUrl({ + url: operationUrls[index] + }); + }) + .border({ radius: 20 }) + .width('90%') + .height('8%') + .backgroundColor(Color.White) + .margin({ top: 12, left: 15, right: 8 }) + } + }) + } + .height('90%') + .width('100%') + } + .width('100%') + .height('100%') + .backgroundColor('#F1F3F5') + } +} diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/utils/AdaptationUtil.ets b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/utils/AdaptationUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..2495dcfbb626d9e544b6b9ba741d74392661aaaf --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/ets/utils/AdaptationUtil.ets @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { display } from '@kit.ArkUI'; + +export class AdaptationUtil { + private screenWidth = 0; + private screenHeight = 0; + private static readonly STANDARD_WIDTH = 1260; + private static readonly STANDARD_HEIGHT = 2720; + + constructor() { + let screenWidth = display.getDefaultDisplaySync().width; + let screenHeight = display.getDefaultDisplaySync().height; + this.screenWidth = Math.min(screenWidth, screenHeight); + this.screenHeight = Math.max(screenWidth, screenHeight); + console.info('screenWidth ', this.screenWidth.toString(), 'screenHeight ', this.screenHeight.toString()); + } + + public getWidth(width: number): number { + let realWidth: number = Math.floor(width * this.screenWidth / AdaptationUtil.STANDARD_WIDTH); + return realWidth; + } + + public getHeight(height: number): number { + let realHeight: number = Math.floor(height * this.screenWidth / AdaptationUtil.STANDARD_HEIGHT); + return realHeight; + } +} + diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/module.json5 b/Drawing/ArkTSGraphicsDraw/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/module.json5 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/color.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/string.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..530d00214b35267892b6e637fc61205a906c55aa --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/element/string.json @@ -0,0 +1,160 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ArkTSGraphicsDraw" + }, + { + "name": "CanvasGetResult", + "value": "画布的获取与绘制结果的显示" + }, + { + "name": "CanvasOperationState", + "value": "画布操作及状态处理" + }, + { + "name": "BasicEffect", + "value": "基础绘制效果" + }, + { + "name": "ComplexEffect", + "value": "复杂绘制效果" + }, + { + "name": "Shape_Drawing", + "value": "几何图形绘制" + }, + { + "name": "PixelMap_Drawing", + "value": "图片绘制" + }, + { + "name": "TextBlock_Drawing", + "value": "字块绘制" + }, + { + "name": "DirectCanvas", + "value": "获取直接画布绘图结果" + }, + { + "name": "OffScreenCanvas", + "value": "获取离屏画布绘图结果" + }, + { + "name": "ClipOperation", + "value": "裁剪操作" + }, + { + "name": "TranslationOperation", + "value": "平移操作" + }, + { + "name": "RotationOperation", + "value": "旋转操作" + }, + { + "name": "ScaleOperation", + "value": "缩放操作" + }, + { + "name": "StateOperation", + "value": "画布状态操作" + }, + { + "name": "Filling", + "value": "填充效果" + }, + { + "name": "Stroke", + "value": "描边效果" + }, + { + "name": "MixedMode", + "value": "混合模式" + }, + { + "name": "PathEffect", + "value": "路径效果" + }, + { + "name": "LinearGradient", + "value": "线性渐变" + }, + { + "name": "PathGradient", + "value": "径向渐变" + }, + { + "name": "SectorGradient", + "value": "扇形渐变" + }, + { + "name": "ColorFilter", + "value": "颜色滤波器" + }, + { + "name": "ImageFilter", + "value": "图像滤波器" + }, + { + "name": "MaskFilter", + "value": "蒙版滤波器" + }, + { + "name": "Point", + "value": "点" + }, + { + "name": "Arc", + "value": "圆弧" + }, + { + "name": "Circle", + "value": "圆" + }, + { + "name": "Path", + "value": "路径" + }, + { + "name": "Region", + "value": "区域" + }, + { + "name": "Rect", + "value": "矩形" + }, + { + "name": "RoundRect", + "value": "圆角矩形" + }, + { + "name": "PixelMap", + "value": "绘制图片" + }, + { + "name": "EditMiddlePixel", + "value": "编辑中间像素" + }, + { + "name": "BaseText", + "value": "基本文字" + }, + { + "name": "StrokeText", + "value": "文字描边" + }, + { + "name": "GradientText", + "value": "文字渐变" + } + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/background.png b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/background.png differ diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/foreground.png b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/foreground.png differ diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/layered_image.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/right.png b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/right.png new file mode 100644 index 0000000000000000000000000000000000000000..812a7bd2dc2efcb999d962575b43139077cb7d16 Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/right.png differ diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/startIcon.png b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/media/startIcon.png differ diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/backup_config.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/main_pages.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..d703eb23eeb1ede4bd8427eff21eba9eb8f0b946 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,12 @@ +{ + "src": [ + "pages/Index", + "drawing/pages/CanvasGetResult", + "drawing/pages/CanvasOperationState", + "drawing/pages/BasicEffect", + "drawing/pages/ComplexEffect", + "drawing/pages/ShapeDrawing", + "drawing/pages/PixelMapDrawing", + "drawing/pages/TextBlockDrawing" + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/dark/element/color.json b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/mock/mock-config.json5 b/Drawing/ArkTSGraphicsDraw/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/Ability.test.ets b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d8f5d71e5fa057df869053b05a5dc5612d620c9 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect } from '@ohos/hypium'; +import { Driver, ON } from '@ohos.UiTest'; +import Logger from '../utils/Logger'; +import { abilityDelegatorRegistry } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + +const TAG = '[Sample_ArkTSGraphicsDraw]'; +const DELAY_SHORT = 400; +const DELAY_LONG = 1000; + +const delegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; + +function getString(resourceData: Resource): string { + let manage = delegator.getAppContext().resourceManager; + return manage.getStringSync(resourceData); +} + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + /** + * @tc.number StartAbility_001 + * @tc.name StartAbility_001 + * @tc.desc 启动Ability + */ + it('ArkTSGraphicsDraw_StartAbility_001',0, async (done: Function) => { + console.info('StartAbility_001 begin'); + //start tested ability + const want: Want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + let driver = Driver.create(); + await driver.delayMs(DELAY_LONG); + //check top display ability + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info('get top ability'); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + done(); + console.info('StartAbility_001 end'); + }) + + /** + * @tc.number:CanvasGetResult_001 + * @tc.name:CanvasGetResult_001 + * @tc.desc:直接画布与离屏画布的获取与绘制结果测试 + */ + it('ArkTSGraphicsDraw_CanvasGetResult_001', 0, async (done: Function) => { + Logger.info(TAG, 'CanvasGetResult_001 begin'); + let driver = Driver.create(); + let canvasGetResultStr = getString($r('app.string.CanvasGetResult')); + // 断言“画布的获取与绘制结果的显示”页面导航组件是否存在于主页上 + await driver.assertComponentExist(ON.text(canvasGetResultStr)); + // 获取该导航组件 + let canvasButton = await driver.findComponent(ON.text(canvasGetResultStr)); + // 点击导航组件,跳转至“画布的获取与绘制结果的显示”页面 + await canvasButton.click(); + await driver.delayMs(DELAY_LONG); + + await driver.assertComponentExist(ON.text(getString($r('app.string.DirectCanvas')))); + await driver.assertComponentExist(ON.text(getString($r('app.string.OffScreenCanvas')))); + + // 返回主页 + await driver.pressBack(); + done(); + Logger.info(TAG, 'CanvasGetResult_001 end'); + }); + + /** + * @tc.number:CanvasOperationState_001 + * @tc.name:CanvasOperationState_001 + * @tc.desc:画布操作与状态操作结果测试 + */ + it('ArkTSGraphicsDraw_CanvasOperationState_001', 0, async (done: Function) => { + Logger.info(TAG, 'CanvasOperationState_001 begin'); + let driver = Driver.create(); + let canvasOperationStr = getString($r('app.string.CanvasOperationState')); + await driver.assertComponentExist(ON.text(canvasOperationStr)); + let canvasOperationButton = await driver.findComponent(ON.text(canvasOperationStr)); + await canvasOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + let clipOperationStr = getString($r('app.string.ClipOperation')); + await driver.assertComponentExist(ON.text(clipOperationStr)); + let clipOperationButton = await driver.findComponent(ON.text(clipOperationStr)); + await clipOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + let translationOperationStr = getString($r('app.string.TranslationOperation')); + await driver.assertComponentExist(ON.text(translationOperationStr)); + let translationOperationButton = await driver.findComponent(ON.text(translationOperationStr)); + await translationOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + let rotationOperationStr = getString($r('app.string.RotationOperation')); + await driver.assertComponentExist(ON.text(rotationOperationStr)); + let rotationOperationButton = await driver.findComponent(ON.text(rotationOperationStr)); + await rotationOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + let scaleOperationStr = getString($r('app.string.ScaleOperation')); + await driver.assertComponentExist(ON.text(scaleOperationStr)); + let scaleOperationButton = await driver.findComponent(ON.text(scaleOperationStr)); + await scaleOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + let stateOperationStr = getString($r('app.string.StateOperation')); + await driver.assertComponentExist(ON.text(stateOperationStr)); + let stateOperationButton = await driver.findComponent(ON.text(stateOperationStr)); + await stateOperationButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'CanvasOperationState_001 end'); + }); + + /** + * @tc.number:BasicEffect_001 + * @tc.name:BasicEffect_001 + * @tc.desc:基础绘制效果结果测试 + */ + it('ArkTSGraphicsDraw_BasicEffect_001', 0, async (done: Function) => { + Logger.info(TAG, 'BasicEffect_001 begin'); + let driver = Driver.create(); + let basicEffectStr = getString($r('app.string.BasicEffect')); + await driver.assertComponentExist(ON.text(basicEffectStr)); + let basicEffectButton = await driver.findComponent(ON.text(basicEffectStr)); + await basicEffectButton.click(); + await driver.delayMs(DELAY_SHORT); + + let fillingStr = getString($r('app.string.Filling')); + await driver.assertComponentExist(ON.text(fillingStr)); + let fillingButton = await driver.findComponent(ON.text(fillingStr)); + await fillingButton.click(); + await driver.delayMs(DELAY_SHORT); + + let strokeStr = getString($r('app.string.Stroke')); + await driver.assertComponentExist(ON.text(strokeStr)); + let strokeButton = await driver.findComponent(ON.text(strokeStr)); + await strokeButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'BasicEffect_001 end'); + }); + + /** + * @tc.number:ComplexEffect_001 + * @tc.name:ComplexEffect_001 + * @tc.desc:复杂绘制效果结果测试 + */ + it('ArkTSGraphicsDraw_ComplexEffect_001', 0, async (done: Function) => { + Logger.info(TAG, 'ComplexEffect_001 begin'); + let driver = Driver.create(); + let complexEffectStr = getString($r('app.string.ComplexEffect')); + await driver.assertComponentExist(ON.text(complexEffectStr)); + let complexEffectButton = await driver.findComponent(ON.text(complexEffectStr)); + await complexEffectButton.click(); + await driver.delayMs(DELAY_SHORT); + + let mixedModeStr = getString($r('app.string.MixedMode')); + await driver.assertComponentExist(ON.text(mixedModeStr)); + let mixedModeButton = await driver.findComponent(ON.text(mixedModeStr)); + await mixedModeButton.click(); + await driver.delayMs(DELAY_SHORT); + + let pathEffectStr = getString($r('app.string.PathEffect')); + await driver.assertComponentExist(ON.text(pathEffectStr)); + let pathEffectButton = await driver.findComponent(ON.text(pathEffectStr)); + await pathEffectButton.click(); + await driver.delayMs(DELAY_SHORT); + + let linearGradientStr = getString($r('app.string.LinearGradient')); + await driver.assertComponentExist(ON.text(linearGradientStr)); + let linearGradientButton = await driver.findComponent(ON.text(linearGradientStr)); + await linearGradientButton.click(); + await driver.delayMs(DELAY_SHORT); + + let pathGradientStr = getString($r('app.string.PathGradient')); + await driver.assertComponentExist(ON.text(pathGradientStr)); + let pathGradientButton = await driver.findComponent(ON.text(pathGradientStr)); + await pathGradientButton.click(); + await driver.delayMs(DELAY_SHORT); + + let sectorGradientStr = getString($r('app.string.SectorGradient')); + await driver.assertComponentExist(ON.text(sectorGradientStr)); + let sectorGradientButton = await driver.findComponent(ON.text(sectorGradientStr)); + await sectorGradientButton.click(); + await driver.delayMs(DELAY_SHORT); + + let colorFilterStr = getString($r('app.string.ColorFilter')); + await driver.assertComponentExist(ON.text(colorFilterStr)); + let colorFilterButton = await driver.findComponent(ON.text(colorFilterStr)); + await colorFilterButton.click(); + await driver.delayMs(DELAY_SHORT); + + let imageFilterStr = getString($r('app.string.ImageFilter')); + await driver.assertComponentExist(ON.text(imageFilterStr)); + let imageFilterButton = await driver.findComponent(ON.text(imageFilterStr)); + await imageFilterButton.click(); + await driver.delayMs(DELAY_SHORT); + + let maskFilterStr = getString($r('app.string.MaskFilter')); + await driver.assertComponentExist(ON.text(maskFilterStr)); + let maskFilterButton = await driver.findComponent(ON.text(maskFilterStr)); + await maskFilterButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'ComplexEffect_001 end'); + }); + + /** + * @tc.number:ShapeDrawing_001 + * @tc.name:ShapeDrawing_001 + * @tc.desc:几何形状绘制结果测试 + */ + it('ArkTSGraphicsDraw_ShapeDrawing_001', 0, async (done: Function) => { + Logger.info(TAG, 'ShapeDrawing_001 begin'); + let driver = Driver.create(); + let shapeDrawingStr = getString($r('app.string.Shape_Drawing')); + await driver.assertComponentExist(ON.text(shapeDrawingStr)); + let shapeDrawingButton = await driver.findComponent(ON.text(shapeDrawingStr)); + await shapeDrawingButton.click(); + await driver.delayMs(DELAY_SHORT); + + let pointStr = getString($r('app.string.Point')); + await driver.assertComponentExist(ON.text(pointStr)); + let pointButton = await driver.findComponent(ON.text(pointStr)); + await pointButton.click(); + await driver.delayMs(DELAY_SHORT); + + let arcStr = getString($r('app.string.Arc')); + await driver.assertComponentExist(ON.text(arcStr)); + let arcButton = await driver.findComponent(ON.text(arcStr)); + await arcButton.click(); + await driver.delayMs(DELAY_SHORT); + + let circleStr = getString($r('app.string.Circle')); + await driver.assertComponentExist(ON.text(circleStr)); + let circleButton = await driver.findComponent(ON.text(circleStr)); + await circleButton.click(); + await driver.delayMs(DELAY_SHORT); + + let pathStr = getString($r('app.string.Path')); + await driver.assertComponentExist(ON.text(pathStr)); + let pathButton = await driver.findComponent(ON.text(pathStr)); + await pathButton.click(); + await driver.delayMs(DELAY_SHORT); + + let regionStr = getString($r('app.string.Region')); + await driver.assertComponentExist(ON.text(regionStr)); + let regionButton = await driver.findComponent(ON.text(regionStr)); + await regionButton.click(); + await driver.delayMs(DELAY_SHORT); + + let rectStr = getString($r('app.string.Rect')); + await driver.assertComponentExist(ON.text(rectStr)); + let rectButton = await driver.findComponent(ON.text(rectStr)); + await rectButton.click(); + await driver.delayMs(DELAY_SHORT); + + let roundRectStr = getString($r('app.string.RoundRect')); + await driver.assertComponentExist(ON.text(roundRectStr)); + let roundRectButton = await driver.findComponent(ON.text(roundRectStr)); + await roundRectButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'ShapeDrawing_001 end'); + }); + + /** + * @tc.number:PixelMapDrawing_001 + * @tc.name:PixelMapDrawing_001 + * @tc.desc:图片绘制结果测试 + */ + it('ArkTSGraphicsDraw_PixelMapDrawing_001', 0, async (done: Function) => { + Logger.info(TAG, 'PixelMapDrawing_001 begin'); + let driver = Driver.create(); + let pixelMapDrawingStr = getString($r('app.string.PixelMap_Drawing')); + await driver.assertComponentExist(ON.text(pixelMapDrawingStr)); + let pixelMapDrawingButton = await driver.findComponent(ON.text(pixelMapDrawingStr)); + await pixelMapDrawingButton.click(); + await driver.delayMs(DELAY_SHORT); + + let pixelMapStr = getString($r('app.string.PixelMap')); + await driver.assertComponentExist(ON.text(pixelMapStr)); + let pixelMapButton = await driver.findComponent(ON.text(pixelMapStr)); + await pixelMapButton.click(); + await driver.delayMs(DELAY_SHORT); + + let editMiddlePixelMapStr = getString($r('app.string.EditMiddlePixel')); + await driver.assertComponentExist(ON.text(editMiddlePixelMapStr)); + let editMiddlePixelMapButton = await driver.findComponent(ON.text(editMiddlePixelMapStr)); + await editMiddlePixelMapButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'PixelMapDrawing_001 end'); + }); + + /** + * @tc.number:TextBlockDrawing_001 + * @tc.name:TextBlockDrawing_001 + * @tc.desc:字块绘制结果测试 + */ + it('ArkTSGraphicsDraw_TextBlockDrawing_001', 0, async (done: Function) => { + Logger.info(TAG, 'TextBlockDrawing_001 begin'); + let driver = Driver.create(); + let textBlockDrawingStr = getString($r('app.string.TextBlock_Drawing')); + await driver.assertComponentExist(ON.text(textBlockDrawingStr)); + let textBlockDrawingButton = await driver.findComponent(ON.text(textBlockDrawingStr)); + await textBlockDrawingButton.click(); + await driver.delayMs(DELAY_SHORT); + + let baseTextStr = getString($r('app.string.BaseText')); + await driver.assertComponentExist(ON.text(baseTextStr)); + let baseTextButton = await driver.findComponent(ON.text(baseTextStr)); + await baseTextButton.click(); + await driver.delayMs(DELAY_SHORT); + + let strokeTextStr = getString($r('app.string.StrokeText')); + await driver.assertComponentExist(ON.text(strokeTextStr)); + let strokeTextButton = await driver.findComponent(ON.text(strokeTextStr)); + await strokeTextButton.click(); + await driver.delayMs(DELAY_SHORT); + + let gradientTextStr = getString($r('app.string.GradientText')); + await driver.assertComponentExist(ON.text(gradientTextStr)); + let gradientTextButton = await driver.findComponent(ON.text(gradientTextStr)); + await gradientTextButton.click(); + await driver.delayMs(DELAY_SHORT); + + await driver.pressBack(); + done(); + Logger.info(TAG, 'TextBlockDrawing_001 end'); + }); + }) +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/List.test.ets b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/utils/Logger.ets b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..5320999da38fa56c15d98e34c39cc9b4054a0242 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/ets/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number = 0xF811; + private prefix: string = ''; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_ArkTSGraphicsDraw]'); \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/module.json5 b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/Drawing/ArkTSGraphicsDraw/hvigor/hvigor-config.json5 b/Drawing/ArkTSGraphicsDraw/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/Drawing/ArkTSGraphicsDraw/hvigorfile.ts b/Drawing/ArkTSGraphicsDraw/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156 --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Drawing/ArkTSGraphicsDraw/oh-package.json5 b/Drawing/ArkTSGraphicsDraw/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/Drawing/ArkTSGraphicsDraw/ohosTest.md b/Drawing/ArkTSGraphicsDraw/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..19d70b9292cb31c616bc901b3e1e0271eb6c221f --- /dev/null +++ b/Drawing/ArkTSGraphicsDraw/ohosTest.md @@ -0,0 +1,14 @@ +# ArkTSGraphicDraw测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ---------------------- | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------ | -------- | -------- | +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 画布获取功能 | 进入“画布的获取与绘制结果的显示”页面 | | 页面显示“获取直接绘图结果”与“获取离屏画布绘图结果” | 是 | Pass | +| 画布操作及状态处理功能 | 进入“画布操作及状态处理”界面 | 依次点击裁剪操作、平移操作、旋转操作、缩放操作、画布状态操作五个按钮 | 在每个按钮点击后,绘制出对应的操作结果图案 | 是 | Pass | +| 基础绘制效果功能 | 进入“基础绘制效果”界面 | 依次点击填充效果、描边效果两个按钮 | 页面显示填充效果图案、描边效果图案 | 是 | Pass | +| 复杂绘制效果功能 | 进入“复杂绘制效果”界面 | 依次点击混合模式、路径效果、线性渐变、径向渐变、扇形渐变、颜色滤波器、图像滤波器、蒙版滤波器八个按钮 | 在每个按钮点击后,绘制出对应的绘制效果图案 | 是 | Pass | +| 几何图形绘制功能 | 进入“几何图形绘制”界面 | 依次点击点、圆弧、圆、路径、区域、矩形、圆角矩形七个按钮 | 在每个按钮点击后,绘制出对应的图案 | 是 | Pass | +| 图片绘制功能 | 进入“图片绘制”界面 | 依次点击绘制图片、编辑中间像素两个按钮 | 先绘制出一幅矩形像素图,而后像素图中间的像素变为黑白色 | 是 | Pass | +| 字块绘制功能 | 进入“字块绘制”界面 | 依次点击基本文字、文字描边、文字渐变三个按钮 | 依次绘制出基本文字图案、描边文字图案和渐变文字图案 | 是 | Pass | \ No newline at end of file diff --git a/Drawing/ArkTSGraphicsDraw/screenshot/canvas.jpeg b/Drawing/ArkTSGraphicsDraw/screenshot/canvas.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e84db1b598db79ea066c5893351bbff812ca7e6d Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/screenshot/canvas.jpeg differ diff --git a/Drawing/ArkTSGraphicsDraw/screenshot/effect.jpeg b/Drawing/ArkTSGraphicsDraw/screenshot/effect.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c9b0d49b5ded04df66b99cde18916224ee267b34 Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/screenshot/effect.jpeg differ diff --git a/Drawing/ArkTSGraphicsDraw/screenshot/index.jpeg b/Drawing/ArkTSGraphicsDraw/screenshot/index.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8031df6bd0368cc86103292aa412c8596114c56e Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/screenshot/index.jpeg differ diff --git a/Drawing/ArkTSGraphicsDraw/screenshot/shape.jpeg b/Drawing/ArkTSGraphicsDraw/screenshot/shape.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3809faecc9fb33daaa3996662b5bd79dee110ce8 Binary files /dev/null and b/Drawing/ArkTSGraphicsDraw/screenshot/shape.jpeg differ