1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <cmath>
16 #include <string>
17 #include "napi/native_api.h"
18 #include <bits/alltypes.h>
19 #include <multimedia/image_framework/image_mdk_common.h>
20 #include <multimedia/image_framework/image_pixel_map_mdk.h>
21 #include <native_window/external_window.h>
22 #include <native_drawing/drawing_bitmap.h>
23 #include <native_drawing/drawing_color.h>
24 #include <native_drawing/drawing_color_filter.h>
25 #include <native_drawing/drawing_canvas.h>
26 #include <native_drawing/drawing_pen.h>
27 #include <native_drawing/drawing_pixel_map.h>
28 #include <native_drawing/drawing_brush.h>
29 #include <native_drawing/drawing_path.h>
30 #include <native_drawing/drawing_rect.h>
31 #include <native_drawing/drawing_register_font.h>
32 #include <native_drawing/drawing_filter.h>
33 #include <native_drawing/drawing_font.h>
34 #include <native_drawing/drawing_font_collection.h>
35 #include <native_drawing/drawing_sampling_options.h>
36 #include <native_drawing/drawing_text_blob.h>
37 #include <native_drawing/drawing_text_declaration.h>
38 #include <native_drawing/drawing_text_typography.h>
39 #include <native_drawing/drawing_types.h>
40 #include <native_drawing/drawing_typeface.h>
41 #include "common/log_common.h"
42
43 enum DrawType {
44 NONE,
45 PATH,
46 TEXT,
47 IMAGE
48 };
49
50 const int FONT_COUNT = 2;
51 const char *TEXT_DEMO = "Hello, OpenHarmony! 你好,鸿蒙!";
52 const char *g_paths[FONT_COUNT] = {"system/fonts/NotoSansBengaliUI-Bold.ttf",
53 "system/fonts/NotoSansDevanagariUI-Regular.ttf"};
54
NativeOnDrawPath(OH_Drawing_Canvas * canvas,int32_t width,int32_t height)55 static void NativeOnDrawPath(OH_Drawing_Canvas *canvas, int32_t width, int32_t height)
56 {
57 // native node draw function
58 int len = height / 4;
59 float aX = width / 2;
60 float aY = height / 6;
61 float dX = aX - len * std::sin(18.0f);
62 float dY = aY + len * std::cos(18.0f);
63 float cX = aX + len * std::sin(18.0f);
64 float cY = dY;
65 float bX = aX + (len / 2.0);
66 float bY = aY + std::sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0));
67 float eX = aX - (len / 2.0);
68 float eY = bY;
69 // 创建一个path对象,然后使用接口连接成一个五角星形状
70 OH_Drawing_Path *cPath = OH_Drawing_PathCreate();
71 // 指定path的起始位置
72 OH_Drawing_PathMoveTo(cPath, aX, aY);
73 // 用直线连接到目标点
74 OH_Drawing_PathLineTo(cPath, bX, bY);
75 OH_Drawing_PathLineTo(cPath, cX, cY);
76 OH_Drawing_PathLineTo(cPath, dX, dY);
77 OH_Drawing_PathLineTo(cPath, eX, eY);
78 // 闭合形状,path绘制完毕
79 OH_Drawing_PathClose(cPath);
80
81 constexpr float penWidth = 10.0f; // pen width 10
82 // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制
83 OH_Drawing_Pen *cPen = OH_Drawing_PenCreate();
84 OH_Drawing_PenSetAntiAlias(cPen, true);
85 OH_Drawing_PenSetColor(cPen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
86 OH_Drawing_PenSetWidth(cPen, penWidth);
87 OH_Drawing_PenSetJoin(cPen, LINE_ROUND_JOIN);
88 // 将Pen画笔设置到canvas中
89 OH_Drawing_CanvasAttachPen(canvas, cPen);
90
91 // 创建一个画刷Brush对象,Brush对象用于形状的填充
92 OH_Drawing_Brush *cBrush = OH_Drawing_BrushCreate();
93 OH_Drawing_BrushSetColor(cBrush, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
94
95 // 将Brush画刷设置到canvas中
96 OH_Drawing_CanvasAttachBrush(canvas, cBrush);
97
98 // 在画布上画path的形状,五角星的边框样式为pen设置,颜色填充为Brush设置
99 OH_Drawing_CanvasDrawPath(canvas, cPath);
100
101 // 绘制完成后将画笔和画刷从画布上清空并销毁
102 OH_Drawing_CanvasDetachPen(canvas);
103 OH_Drawing_CanvasDetachBrush(canvas);
104 OH_Drawing_PenDestroy(cPen);
105 OH_Drawing_BrushDestroy(cBrush);
106 OH_Drawing_PathDestroy(cPath);
107 }
108
109 // 字体引擎提供的文字绘制能力,可指定字体,自带排版,支持字体退化
NativeOnDrawText(OH_Drawing_Canvas * canvas,int32_t width,int32_t height)110 static void NativeOnDrawText(OH_Drawing_Canvas *canvas, int32_t width, int32_t height)
111 {
112 // 选择从左到右/左对齐等排版属性
113 OH_Drawing_TypographyStyle *typoStyle = OH_Drawing_CreateTypographyStyle();
114 OH_Drawing_SetTypographyTextDirection(typoStyle, TEXT_DIRECTION_LTR);
115 OH_Drawing_SetTypographyTextAlign(typoStyle, TEXT_ALIGN_JUSTIFY);
116
117 // TEXT_ALIGN_JUSTIFY
118 // 设置文字颜色,例如黑色
119 OH_Drawing_TextStyle *txtStyle = OH_Drawing_CreateTextStyle();
120 OH_Drawing_SetTextStyleColor(txtStyle, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
121 // 设置文字大小、字重等属性
122 double fontSize = width / 16;
123 OH_Drawing_SetTextStyleFontSize(txtStyle, fontSize);
124 OH_Drawing_SetTextStyleFontWeight(txtStyle, FONT_WEIGHT_400);
125 OH_Drawing_SetTextStyleBaseLine(txtStyle, TEXT_BASELINE_ALPHABETIC);
126 OH_Drawing_SetTextStyleFontHeight(txtStyle, 1);
127 // 设置字体类型等
128 for (int i = 0; i < FONT_COUNT; ++i) {
129 OH_Drawing_FontCollection *fontCollection = OH_Drawing_CreateFontCollection();
130 const char *fontFamily = "myFamilyName";
131 const char *fontPath = g_paths[i];
132 OH_Drawing_RegisterFont(fontCollection, fontFamily, fontPath);
133 const char *myFontFamilies[] = {"myFamilyName"};
134 OH_Drawing_SetTextStyleFontFamilies(txtStyle, 1, myFontFamilies);
135 OH_Drawing_SetTextStyleFontStyle(txtStyle, FONT_STYLE_NORMAL);
136 OH_Drawing_SetTextStyleLocale(txtStyle, "en");
137 OH_Drawing_TypographyCreate *handler =
138 OH_Drawing_CreateTypographyHandler(typoStyle, fontCollection);
139 OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle);
140 // 设置文字内容
141 OH_Drawing_TypographyHandlerAddText(handler, TEXT_DEMO);
142 OH_Drawing_TypographyHandlerPopTextStyle(handler);
143 OH_Drawing_Typography *typography = OH_Drawing_CreateTypography(handler);
144 // 设置页面最大宽度
145 double maxWidth = width - 100;
146 OH_Drawing_TypographyLayout(typography, maxWidth);
147 // 设置文本在画布上绘制的起始位置
148 double position[2] = {width / 10.0, height / 5.0 + fontSize * i * 2};
149 // 将文本绘制到画布上
150 OH_Drawing_TypographyPaint(typography, canvas, position[0], position[1]);
151 // 销毁创建的资源
152 OH_Drawing_DestroyTypography(typography);
153 OH_Drawing_DestroyTypographyHandler(handler);
154 OH_Drawing_DestroyFontCollection(fontCollection);
155 }
156 OH_Drawing_DestroyTypographyStyle(typoStyle);
157 OH_Drawing_DestroyTextStyle(txtStyle);
158 }
159
NativeOnDrawTextBlob(OH_Drawing_Canvas * canvas,int32_t width,int32_t height)160 static void NativeOnDrawTextBlob(OH_Drawing_Canvas *canvas, int32_t width, int32_t height)
161 {
162 OH_Drawing_Brush *brush = OH_Drawing_BrushCreate();
163 OH_Drawing_BrushSetColor(brush, OH_Drawing_ColorSetArgb(0xff, 0xff, 0x00, 0x00));
164 OH_Drawing_CanvasAttachBrush(canvas, brush);
165 float textSize = width / 16;
166 for (int i = 0; i < FONT_COUNT; ++i) {
167 OH_Drawing_TextBlobBuilder *builder = OH_Drawing_TextBlobBuilderCreate();
168 OH_Drawing_Font *font = OH_Drawing_FontCreate();
169 OH_Drawing_Typeface *typeface = OH_Drawing_TypefaceCreateFromFile(g_paths[i], 0);
170 OH_Drawing_FontSetTypeface(font, typeface);
171 OH_Drawing_FontSetTextSize(font, textSize);
172 int textCount = OH_Drawing_FontCountText(font, TEXT_DEMO, strlen(TEXT_DEMO), TEXT_ENCODING_UTF8);
173 uint16_t glyphs[textCount];
174 // 获取文本对应的glyphsID
175 uint32_t glyphsCount =
176 OH_Drawing_FontTextToGlyphs(font, TEXT_DEMO, strlen(TEXT_DEMO), TEXT_ENCODING_UTF8, glyphs, textCount);
177 float textWidth[glyphsCount];
178 // 获取文本中每个字符的宽度,以此来确定排版横坐标
179 OH_Drawing_FontGetWidths(font, glyphs, glyphsCount, textWidth);
180 OH_Drawing_Font_Metrics metrics;
181 OH_Drawing_FontGetMetrics(font, &metrics);
182 // 计算字体高度用于换行
183 const float textHeight = metrics.descent - metrics.ascent;
184 const OH_Drawing_RunBuffer *runBuffer =
185 OH_Drawing_TextBlobBuilderAllocRunPos(builder, font, glyphsCount, nullptr);
186 // 以下为计算每个字的坐标设置的数据,无具体含义
187 const float posX = width / 10.0;
188 const float posY = height / 2.0;
189 const float enlargeY = 1.2;
190 const int numberTwo = 2;
191 float bufferPosX = posX;
192 float bufferPosY = posY + enlargeY * textSize * i * numberTwo;
193 for (int j = 0; j < glyphsCount; ++j) {
194 runBuffer->glyphs[j] = glyphs[j];
195 // 自定义字体排版中的横坐标
196 runBuffer->pos[j * numberTwo] = bufferPosX;
197 // 自定义字体排版中的纵坐标
198 runBuffer->pos[j * numberTwo + 1] = bufferPosY;
199 bufferPosX += textWidth[j];
200 if (bufferPosX >= width) {
201 bufferPosX = posX;
202 bufferPosY += textHeight;
203 }
204 }
205 OH_Drawing_TextBlob *textBlob = OH_Drawing_TextBlobBuilderMake(builder);
206 OH_Drawing_CanvasDrawTextBlob(canvas, textBlob, 0, 0);
207
208 // 第二种textBlob创建方式,通过字符串创建,带有基础的排版,且不支持字体退化
209 const float tempY = 1.3;
210 OH_Drawing_TextBlob *stringTextBlob =
211 OH_Drawing_TextBlobCreateFromString(TEXT_DEMO, font, TEXT_ENCODING_UTF8);
212 OH_Drawing_CanvasDrawTextBlob(canvas, stringTextBlob, posX, height / tempY + textSize * i);
213
214 OH_Drawing_TextBlobDestroy(textBlob);
215 OH_Drawing_TextBlobBuilderDestroy(builder);
216 OH_Drawing_TextBlobDestroy(stringTextBlob);
217 OH_Drawing_TypefaceDestroy(typeface);
218 OH_Drawing_FontDestroy(font);
219 }
220 OH_Drawing_CanvasDetachBrush(canvas);
221 OH_Drawing_BrushDestroy(brush);
222 }
223
NativeOnDrawPixelMap(OH_Drawing_Canvas * canvas,NativePixelMap * native)224 static void NativeOnDrawPixelMap(OH_Drawing_Canvas *canvas, NativePixelMap *native)
225 {
226 OH_Drawing_CanvasSave(canvas);
227 OH_Drawing_PixelMap *pixelMap = OH_Drawing_PixelMapGetFromNativePixelMap(native);
228 OH_Drawing_SamplingOptions *sampling = OH_Drawing_SamplingOptionsCreate(FILTER_MODE_NEAREST, MIPMAP_MODE_NONE);
229 OH_Drawing_Rect *src = OH_Drawing_RectCreate(0, 0, 550, 564);
230 OH_Drawing_Rect *dst = OH_Drawing_RectCreate(25, 300, 300, 582);
231 OH_Drawing_Brush *brush = OH_Drawing_BrushCreate();
232 OH_Drawing_CanvasAttachBrush(canvas, brush);
233 OH_Drawing_CanvasDrawPixelMapRect(canvas, pixelMap, src, dst, sampling);
234 OH_Drawing_CanvasDetachBrush(canvas);
235
236 // 设置样式,绘制时生效
237 const float array[] = {
238 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 1, 0,
239 };
240 OH_Drawing_ColorFilter *colorFilter = OH_Drawing_ColorFilterCreateMatrix(array);
241 OH_Drawing_Filter *filter = OH_Drawing_FilterCreate();
242 OH_Drawing_FilterSetColorFilter(filter, colorFilter);
243 OH_Drawing_BrushSetFilter(brush, filter);
244 OH_Drawing_CanvasAttachBrush(canvas, brush);
245 OH_Drawing_CanvasTranslate(canvas, 300.f, 0.f);
246 OH_Drawing_CanvasDrawPixelMapRect(canvas, pixelMap, src, dst, sampling);
247 OH_Drawing_CanvasDetachBrush(canvas);
248
249 OH_Drawing_PixelMapDissolve(pixelMap);
250 OH_Drawing_BrushDestroy(brush);
251 OH_Drawing_CanvasRestore(canvas);
252 OH_Drawing_FilterDestroy(filter);
253 OH_Drawing_ColorFilterDestroy(colorFilter);
254 OH_Drawing_SamplingOptionsDestroy(sampling);
255 OH_Drawing_RectDestroy(src);
256 OH_Drawing_RectDestroy(dst);
257 }
258
259 // 开发者提供的native方法,入参有且仅有如下两个,开发者不需进行变更。
260 // napi_env 为当前运行的上下文
261 // napi_callback_info 记录了一些信息,包括从ArkTS侧传递过来参数等。
OnDraw(napi_env env,napi_callback_info info)262 static napi_value OnDraw(napi_env env, napi_callback_info info)
263 {
264 size_t argc = 6;
265 napi_value args[6] = {nullptr};
266 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
267
268 int32_t id;
269 napi_get_value_int32(env, args[0], &id);
270 void *temp = nullptr;
271 napi_unwrap(env, args[1], &temp);
272
273 OH_Drawing_Canvas *canvas = reinterpret_cast<OH_Drawing_Canvas *>(temp);
274 int32_t width;
275 napi_get_value_int32(env, args[2], &width); // 2 means the second argument
276 int32_t height;
277 napi_get_value_int32(env, args[3], &height); // 3 means the third argument
278 int32_t drawOption;
279 napi_get_value_int32(env, args[4], &drawOption); // 4 means the forth argument
280 NativePixelMap *nativePixelMap = OH_PixelMap_InitNativePixelMap(env, args[5]); // 5 means the forth argument
281
282 if (drawOption == PATH) {
283 NativeOnDrawPath(canvas, width, height);
284 } else if (drawOption == TEXT) {
285 NativeOnDrawText(canvas, width, height);
286 NativeOnDrawTextBlob(canvas, width, height);
287 } else if (drawOption == IMAGE) {
288 NativeOnDrawPixelMap(canvas, nativePixelMap);
289 }
290 return nullptr;
291 }
292
GetNodeDescriptors(napi_env env,napi_callback_info info)293 static napi_value GetNodeDescriptors(napi_env env, napi_callback_info info) { return nullptr; }
294
295 EXTERN_C_START
296 // Init将在exports上挂上Add/NativeCallArkTS这些native方法,此处的exports就是开发者import之后获取到的ArkTS对象。
Init(napi_env env,napi_value exports)297 static napi_value Init(napi_env env, napi_value exports)
298 {
299 napi_property_descriptor desc[] = {
300 {"nativeGetNodeDescriptors", nullptr, GetNodeDescriptors, nullptr, nullptr, nullptr, napi_default, nullptr},
301 {"nativeOnDraw", nullptr, OnDraw, nullptr, nullptr, nullptr, napi_default, nullptr},
302 };
303 // 在exports这个ArkTs对象上,挂载native方法
304 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
305 return exports;
306 }
307 EXTERN_C_END
308
309 static napi_module demoModule = {
310 .nm_version = 1,
311 .nm_flags = 0,
312 .nm_filename = nullptr,
313 .nm_register_func = Init,
314 .nm_modname = "entry",
315 .nm_priv = ((void *)0),
316 .reserved = {0},
317 };
318
RegisterEntryModule(void)319 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
320