1 // Tencent is pleased to support the open source community by making ncnn available.
2 //
3 // Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
4 //
5 // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // https://opensource.org/licenses/BSD-3-Clause
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #include "mat.h"
16 
17 #include <ctype.h>
18 
19 #include "platform.h"
20 
21 namespace ncnn {
22 
23 #if NCNN_PIXEL_DRAWING
24 
25 #include "mat_pixel_drawing_font.h"
26 
draw_rectangle_c1(unsigned char * pixels,int w,int h,int rx,int ry,int rw,int rh,unsigned int color,int thickness)27 void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
28 {
29     return draw_rectangle_c1(pixels, w, h, w, rx, ry, rw, rh, color, thickness);
30 }
31 
draw_rectangle_c2(unsigned char * pixels,int w,int h,int rx,int ry,int rw,int rh,unsigned int color,int thickness)32 void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
33 {
34     return draw_rectangle_c2(pixels, w, h, w * 2, rx, ry, rw, rh, color, thickness);
35 }
36 
draw_rectangle_c3(unsigned char * pixels,int w,int h,int rx,int ry,int rw,int rh,unsigned int color,int thickness)37 void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
38 {
39     return draw_rectangle_c3(pixels, w, h, w * 3, rx, ry, rw, rh, color, thickness);
40 }
41 
draw_rectangle_c4(unsigned char * pixels,int w,int h,int rx,int ry,int rw,int rh,unsigned int color,int thickness)42 void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
43 {
44     return draw_rectangle_c4(pixels, w, h, w * 4, rx, ry, rw, rh, color, thickness);
45 }
46 
draw_rectangle_c1(unsigned char * pixels,int w,int h,int stride,int rx,int ry,int rw,int rh,unsigned int color,int thickness)47 void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
48 {
49     const unsigned char* pen_color = (const unsigned char*)&color;
50 
51     if (thickness == -1)
52     {
53         // filled
54         for (int y = ry; y < ry + rh; y++)
55         {
56             if (y < 0)
57                 continue;
58 
59             if (y >= h)
60                 break;
61 
62             unsigned char* p = pixels + stride * y;
63 
64             for (int x = rx; x < rx + rw; x++)
65             {
66                 if (x < 0)
67                     continue;
68 
69                 if (x >= w)
70                     break;
71 
72                 p[x] = pen_color[0];
73             }
74         }
75 
76         return;
77     }
78 
79     const int t0 = thickness / 2;
80     const int t1 = thickness - t0;
81 
82     // draw top
83     {
84         for (int y = ry - t0; y < ry + t1; y++)
85         {
86             if (y < 0)
87                 continue;
88 
89             if (y >= h)
90                 break;
91 
92             unsigned char* p = pixels + stride * y;
93 
94             for (int x = rx - t0; x < rx + rw + t1; x++)
95             {
96                 if (x < 0)
97                     continue;
98 
99                 if (x >= w)
100                     break;
101 
102                 p[x] = pen_color[0];
103             }
104         }
105     }
106 
107     // draw bottom
108     {
109         for (int y = ry + rh - t0; y < ry + rh + t1; y++)
110         {
111             if (y < 0)
112                 continue;
113 
114             if (y >= h)
115                 break;
116 
117             unsigned char* p = pixels + stride * y;
118 
119             for (int x = rx - t0; x < rx + rw + t1; x++)
120             {
121                 if (x < 0)
122                     continue;
123 
124                 if (x >= w)
125                     break;
126 
127                 p[x] = pen_color[0];
128             }
129         }
130     }
131 
132     // draw left
133     for (int x = rx - t0; x < rx + t1; x++)
134     {
135         if (x < 0)
136             continue;
137 
138         if (x >= w)
139             break;
140 
141         for (int y = ry + t1; y < ry + rh - t0; y++)
142         {
143             if (y < 0)
144                 continue;
145 
146             if (y >= h)
147                 break;
148 
149             unsigned char* p = pixels + stride * y;
150 
151             p[x] = pen_color[0];
152         }
153     }
154 
155     // draw right
156     for (int x = rx + rw - t0; x < rx + rw + t1; x++)
157     {
158         if (x < 0)
159             continue;
160 
161         if (x >= w)
162             break;
163 
164         for (int y = ry + t1; y < ry + rh - t0; y++)
165         {
166             if (y < 0)
167                 continue;
168 
169             if (y >= h)
170                 break;
171 
172             unsigned char* p = pixels + stride * y;
173 
174             p[x] = pen_color[0];
175         }
176     }
177 }
178 
draw_rectangle_c2(unsigned char * pixels,int w,int h,int stride,int rx,int ry,int rw,int rh,unsigned int color,int thickness)179 void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
180 {
181     const unsigned char* pen_color = (const unsigned char*)&color;
182 
183     if (thickness == -1)
184     {
185         // filled
186         for (int y = ry; y < ry + rh; y++)
187         {
188             if (y < 0)
189                 continue;
190 
191             if (y >= h)
192                 break;
193 
194             unsigned char* p = pixels + stride * y;
195 
196             for (int x = rx; x < rx + rw; x++)
197             {
198                 if (x < 0)
199                     continue;
200 
201                 if (x >= w)
202                     break;
203 
204                 p[x * 2 + 0] = pen_color[0];
205                 p[x * 2 + 1] = pen_color[1];
206             }
207         }
208 
209         return;
210     }
211 
212     const int t0 = thickness / 2;
213     const int t1 = thickness - t0;
214 
215     // draw top
216     {
217         for (int y = ry - t0; y < ry + t1; y++)
218         {
219             if (y < 0)
220                 continue;
221 
222             if (y >= h)
223                 break;
224 
225             unsigned char* p = pixels + stride * y;
226 
227             for (int x = rx - t0; x < rx + rw + t1; x++)
228             {
229                 if (x < 0)
230                     continue;
231 
232                 if (x >= w)
233                     break;
234 
235                 p[x * 2 + 0] = pen_color[0];
236                 p[x * 2 + 1] = pen_color[1];
237             }
238         }
239     }
240 
241     // draw bottom
242     {
243         for (int y = ry + rh - t0; y < ry + rh + t1; y++)
244         {
245             if (y < 0)
246                 continue;
247 
248             if (y >= h)
249                 break;
250 
251             unsigned char* p = pixels + stride * y;
252 
253             for (int x = rx - t0; x < rx + rw + t1; x++)
254             {
255                 if (x < 0)
256                     continue;
257 
258                 if (x >= w)
259                     break;
260 
261                 p[x * 2 + 0] = pen_color[0];
262                 p[x * 2 + 1] = pen_color[1];
263             }
264         }
265     }
266 
267     // draw left
268     for (int x = rx - t0; x < rx + t1; x++)
269     {
270         if (x < 0)
271             continue;
272 
273         if (x >= w)
274             break;
275 
276         for (int y = ry + t1; y < ry + rh - t0; y++)
277         {
278             if (y < 0)
279                 continue;
280 
281             if (y >= h)
282                 break;
283 
284             unsigned char* p = pixels + stride * y;
285 
286             p[x * 2 + 0] = pen_color[0];
287             p[x * 2 + 1] = pen_color[1];
288         }
289     }
290 
291     // draw right
292     for (int x = rx + rw - t0; x < rx + rw + t1; x++)
293     {
294         if (x < 0)
295             continue;
296 
297         if (x >= w)
298             break;
299 
300         for (int y = ry + t1; y < ry + rh - t0; y++)
301         {
302             if (y < 0)
303                 continue;
304 
305             if (y >= h)
306                 break;
307 
308             unsigned char* p = pixels + stride * y;
309 
310             p[x * 2 + 0] = pen_color[0];
311             p[x * 2 + 1] = pen_color[1];
312         }
313     }
314 }
315 
draw_rectangle_c3(unsigned char * pixels,int w,int h,int stride,int rx,int ry,int rw,int rh,unsigned int color,int thickness)316 void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
317 {
318     const unsigned char* pen_color = (const unsigned char*)&color;
319 
320     if (thickness == -1)
321     {
322         // filled
323         for (int y = ry; y < ry + rh; y++)
324         {
325             if (y < 0)
326                 continue;
327 
328             if (y >= h)
329                 break;
330 
331             unsigned char* p = pixels + stride * y;
332 
333             for (int x = rx; x < rx + rw; x++)
334             {
335                 if (x < 0)
336                     continue;
337 
338                 if (x >= w)
339                     break;
340 
341                 p[x * 3 + 0] = pen_color[0];
342                 p[x * 3 + 1] = pen_color[1];
343                 p[x * 3 + 2] = pen_color[2];
344             }
345         }
346 
347         return;
348     }
349 
350     const int t0 = thickness / 2;
351     const int t1 = thickness - t0;
352 
353     // draw top
354     {
355         for (int y = ry - t0; y < ry + t1; y++)
356         {
357             if (y < 0)
358                 continue;
359 
360             if (y >= h)
361                 break;
362 
363             unsigned char* p = pixels + stride * y;
364 
365             for (int x = rx - t0; x < rx + rw + t1; x++)
366             {
367                 if (x < 0)
368                     continue;
369 
370                 if (x >= w)
371                     break;
372 
373                 p[x * 3 + 0] = pen_color[0];
374                 p[x * 3 + 1] = pen_color[1];
375                 p[x * 3 + 2] = pen_color[2];
376             }
377         }
378     }
379 
380     // draw bottom
381     {
382         for (int y = ry + rh - t0; y < ry + rh + t1; y++)
383         {
384             if (y < 0)
385                 continue;
386 
387             if (y >= h)
388                 break;
389 
390             unsigned char* p = pixels + stride * y;
391 
392             for (int x = rx - t0; x < rx + rw + t1; x++)
393             {
394                 if (x < 0)
395                     continue;
396 
397                 if (x >= w)
398                     break;
399 
400                 p[x * 3 + 0] = pen_color[0];
401                 p[x * 3 + 1] = pen_color[1];
402                 p[x * 3 + 2] = pen_color[2];
403             }
404         }
405     }
406 
407     // draw left
408     for (int x = rx - t0; x < rx + t1; x++)
409     {
410         if (x < 0)
411             continue;
412 
413         if (x >= w)
414             break;
415 
416         for (int y = ry + t1; y < ry + rh - t0; y++)
417         {
418             if (y < 0)
419                 continue;
420 
421             if (y >= h)
422                 break;
423 
424             unsigned char* p = pixels + stride * y;
425 
426             p[x * 3 + 0] = pen_color[0];
427             p[x * 3 + 1] = pen_color[1];
428             p[x * 3 + 2] = pen_color[2];
429         }
430     }
431 
432     // draw right
433     for (int x = rx + rw - t0; x < rx + rw + t1; x++)
434     {
435         if (x < 0)
436             continue;
437 
438         if (x >= w)
439             break;
440 
441         for (int y = ry + t1; y < ry + rh - t0; y++)
442         {
443             if (y < 0)
444                 continue;
445 
446             if (y >= h)
447                 break;
448 
449             unsigned char* p = pixels + stride * y;
450 
451             p[x * 3 + 0] = pen_color[0];
452             p[x * 3 + 1] = pen_color[1];
453             p[x * 3 + 2] = pen_color[2];
454         }
455     }
456 }
457 
draw_rectangle_c4(unsigned char * pixels,int w,int h,int stride,int rx,int ry,int rw,int rh,unsigned int color,int thickness)458 void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
459 {
460     const unsigned char* pen_color = (const unsigned char*)&color;
461 
462     if (thickness == -1)
463     {
464         // filled
465         for (int y = ry; y < ry + rh; y++)
466         {
467             if (y < 0)
468                 continue;
469 
470             if (y >= h)
471                 break;
472 
473             unsigned char* p = pixels + stride * y;
474 
475             for (int x = rx; x < rx + rw; x++)
476             {
477                 if (x < 0)
478                     continue;
479 
480                 if (x >= w)
481                     break;
482 
483                 p[x * 4 + 0] = pen_color[0];
484                 p[x * 4 + 1] = pen_color[1];
485                 p[x * 4 + 2] = pen_color[2];
486                 p[x * 4 + 3] = pen_color[3];
487             }
488         }
489 
490         return;
491     }
492 
493     const int t0 = thickness / 2;
494     const int t1 = thickness - t0;
495 
496     // draw top
497     {
498         for (int y = ry - t0; y < ry + t1; y++)
499         {
500             if (y < 0)
501                 continue;
502 
503             if (y >= h)
504                 break;
505 
506             unsigned char* p = pixels + stride * y;
507 
508             for (int x = rx - t0; x < rx + rw + t1; x++)
509             {
510                 if (x < 0)
511                     continue;
512 
513                 if (x >= w)
514                     break;
515 
516                 p[x * 4 + 0] = pen_color[0];
517                 p[x * 4 + 1] = pen_color[1];
518                 p[x * 4 + 2] = pen_color[2];
519                 p[x * 4 + 3] = pen_color[3];
520             }
521         }
522     }
523 
524     // draw bottom
525     {
526         for (int y = ry + rh - t0; y < ry + rh + t1; y++)
527         {
528             if (y < 0)
529                 continue;
530 
531             if (y >= h)
532                 break;
533 
534             unsigned char* p = pixels + stride * y;
535 
536             for (int x = rx - t0; x < rx + rw + t1; x++)
537             {
538                 if (x < 0)
539                     continue;
540 
541                 if (x >= w)
542                     break;
543 
544                 p[x * 4 + 0] = pen_color[0];
545                 p[x * 4 + 1] = pen_color[1];
546                 p[x * 4 + 2] = pen_color[2];
547                 p[x * 4 + 3] = pen_color[3];
548             }
549         }
550     }
551 
552     // draw left
553     for (int x = rx - t0; x < rx + t1; x++)
554     {
555         if (x < 0)
556             continue;
557 
558         if (x >= w)
559             break;
560 
561         for (int y = ry + t1; y < ry + rh - t0; y++)
562         {
563             if (y < 0)
564                 continue;
565 
566             if (y >= h)
567                 break;
568 
569             unsigned char* p = pixels + stride * y;
570 
571             p[x * 4 + 0] = pen_color[0];
572             p[x * 4 + 1] = pen_color[1];
573             p[x * 4 + 2] = pen_color[2];
574             p[x * 4 + 3] = pen_color[3];
575         }
576     }
577 
578     // draw right
579     for (int x = rx + rw - t0; x < rx + rw + t1; x++)
580     {
581         if (x < 0)
582             continue;
583 
584         if (x >= w)
585             break;
586 
587         for (int y = ry + t1; y < ry + rh - t0; y++)
588         {
589             if (y < 0)
590                 continue;
591 
592             if (y >= h)
593                 break;
594 
595             unsigned char* p = pixels + stride * y;
596 
597             p[x * 4 + 0] = pen_color[0];
598             p[x * 4 + 1] = pen_color[1];
599             p[x * 4 + 2] = pen_color[2];
600             p[x * 4 + 3] = pen_color[3];
601         }
602     }
603 }
604 
draw_rectangle_yuv420sp(unsigned char * yuv420sp,int w,int h,int rx,int ry,int rw,int rh,unsigned int color,int thickness)605 void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness)
606 {
607     // assert w % 2 == 0
608     // assert h % 2 == 0
609     // assert rx % 2 == 0
610     // assert ry % 2 == 0
611     // assert rw % 2 == 0
612     // assert rh % 2 == 0
613     // assert thickness % 2 == 0
614 
615     const unsigned char* pen_color = (const unsigned char*)&color;
616 
617     unsigned int v_y;
618     unsigned int v_uv;
619     unsigned char* pen_color_y = (unsigned char*)&v_y;
620     unsigned char* pen_color_uv = (unsigned char*)&v_uv;
621     pen_color_y[0] = pen_color[0];
622     pen_color_uv[0] = pen_color[1];
623     pen_color_uv[1] = pen_color[2];
624 
625     unsigned char* Y = yuv420sp;
626     draw_rectangle_c1(Y, w, h, rx, ry, rw, rh, v_y, thickness);
627 
628     unsigned char* UV = yuv420sp + w * h;
629     int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
630     draw_rectangle_c2(UV, w / 2, h / 2, rx / 2, ry / 2, rw / 2, rh / 2, v_uv, thickness_uv);
631 }
632 
distance_lessequal(int x0,int y0,int x1,int y1,float r)633 static inline bool distance_lessequal(int x0, int y0, int x1, int y1, float r)
634 {
635     int dx = x0 - x1;
636     int dy = y0 - y1;
637     int q = dx * dx + dy * dy;
638     return q <= r * r;
639 }
640 
distance_inrange(int x0,int y0,int x1,int y1,float r0,float r1)641 static inline bool distance_inrange(int x0, int y0, int x1, int y1, float r0, float r1)
642 {
643     int dx = x0 - x1;
644     int dy = y0 - y1;
645     int q = dx * dx + dy * dy;
646     return q >= r0 * r0 && q < r1 * r1;
647 }
648 
draw_circle_c1(unsigned char * pixels,int w,int h,int cx,int cy,int radius,unsigned int color,int thickness)649 void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
650 {
651     return draw_circle_c1(pixels, w, h, w, cx, cy, radius, color, thickness);
652 }
653 
draw_circle_c2(unsigned char * pixels,int w,int h,int cx,int cy,int radius,unsigned int color,int thickness)654 void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
655 {
656     return draw_circle_c2(pixels, w, h, w * 2, cx, cy, radius, color, thickness);
657 }
658 
draw_circle_c3(unsigned char * pixels,int w,int h,int cx,int cy,int radius,unsigned int color,int thickness)659 void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
660 {
661     return draw_circle_c3(pixels, w, h, w * 3, cx, cy, radius, color, thickness);
662 }
663 
draw_circle_c4(unsigned char * pixels,int w,int h,int cx,int cy,int radius,unsigned int color,int thickness)664 void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
665 {
666     return draw_circle_c4(pixels, w, h, w * 4, cx, cy, radius, color, thickness);
667 }
668 
draw_circle_c1(unsigned char * pixels,int w,int h,int stride,int cx,int cy,int radius,unsigned int color,int thickness)669 void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
670 {
671     const unsigned char* pen_color = (const unsigned char*)&color;
672 
673     if (thickness == -1)
674     {
675         // filled
676         for (int y = cy - (radius - 1); y < cy + radius; y++)
677         {
678             if (y < 0)
679                 continue;
680 
681             if (y >= h)
682                 break;
683 
684             unsigned char* p = pixels + stride * y;
685 
686             for (int x = cx - (radius - 1); x < cx + radius; x++)
687             {
688                 if (x < 0)
689                     continue;
690 
691                 if (x >= w)
692                     break;
693 
694                 // distance from cx cy
695                 if (distance_lessequal(x, y, cx, cy, radius))
696                 {
697                     p[x] = pen_color[0];
698                 }
699             }
700         }
701 
702         return;
703     }
704 
705     const float t0 = thickness / 2.f;
706     const float t1 = thickness - t0;
707 
708     for (int y = cy - (radius - 1) - t0; y < cy + radius + t1; y++)
709     {
710         if (y < 0)
711             continue;
712 
713         if (y >= h)
714             break;
715 
716         unsigned char* p = pixels + stride * y;
717 
718         for (int x = cx - (radius - 1) - t0; x < cx + radius + t1; x++)
719         {
720             if (x < 0)
721                 continue;
722 
723             if (x >= w)
724                 break;
725 
726             // distance from cx cy
727             if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
728             {
729                 p[x] = pen_color[0];
730             }
731         }
732     }
733 }
734 
draw_circle_c2(unsigned char * pixels,int w,int h,int stride,int cx,int cy,int radius,unsigned int color,int thickness)735 void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
736 {
737     const unsigned char* pen_color = (const unsigned char*)&color;
738 
739     if (thickness == -1)
740     {
741         // filled
742         for (int y = cy - (radius - 1); y < cy + radius; y++)
743         {
744             if (y < 0)
745                 continue;
746 
747             if (y >= h)
748                 break;
749 
750             unsigned char* p = pixels + stride * y;
751 
752             for (int x = cx - (radius - 1); x < cx + radius; x++)
753             {
754                 if (x < 0)
755                     continue;
756 
757                 if (x >= w)
758                     break;
759 
760                 // distance from cx cy
761                 if (distance_lessequal(x, y, cx, cy, radius))
762                 {
763                     p[x * 2 + 0] = pen_color[0];
764                     p[x * 2 + 1] = pen_color[1];
765                 }
766             }
767         }
768 
769         return;
770     }
771 
772     const float t0 = thickness / 2.f;
773     const float t1 = thickness - t0;
774 
775     for (int y = cy - radius - t0; y < cy + radius + t1; y++)
776     {
777         if (y < 0)
778             continue;
779 
780         if (y >= h)
781             break;
782 
783         unsigned char* p = pixels + stride * y;
784 
785         for (int x = cx - radius - t0; x < cx + radius + t1; x++)
786         {
787             if (x < 0)
788                 continue;
789 
790             if (x >= w)
791                 break;
792 
793             // distance from cx cy
794             if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
795             {
796                 p[x * 2 + 0] = pen_color[0];
797                 p[x * 2 + 1] = pen_color[1];
798             }
799         }
800     }
801 }
802 
draw_circle_c3(unsigned char * pixels,int w,int h,int stride,int cx,int cy,int radius,unsigned int color,int thickness)803 void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
804 {
805     const unsigned char* pen_color = (const unsigned char*)&color;
806 
807     if (thickness == -1)
808     {
809         // filled
810         for (int y = cy - (radius - 1); y < cy + radius; y++)
811         {
812             if (y < 0)
813                 continue;
814 
815             if (y >= h)
816                 break;
817 
818             unsigned char* p = pixels + stride * y;
819 
820             for (int x = cx - (radius - 1); x < cx + radius; x++)
821             {
822                 if (x < 0)
823                     continue;
824 
825                 if (x >= w)
826                     break;
827 
828                 // distance from cx cy
829                 if (distance_lessequal(x, y, cx, cy, radius))
830                 {
831                     p[x * 3 + 0] = pen_color[0];
832                     p[x * 3 + 1] = pen_color[1];
833                     p[x * 3 + 2] = pen_color[2];
834                 }
835             }
836         }
837 
838         return;
839     }
840 
841     const float t0 = thickness / 2.f;
842     const float t1 = thickness - t0;
843 
844     for (int y = cy - radius - t0; y < cy + radius + t1; y++)
845     {
846         if (y < 0)
847             continue;
848 
849         if (y >= h)
850             break;
851 
852         unsigned char* p = pixels + stride * y;
853 
854         for (int x = cx - radius - t0; x < cx + radius + t1; x++)
855         {
856             if (x < 0)
857                 continue;
858 
859             if (x >= w)
860                 break;
861 
862             // distance from cx cy
863             if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
864             {
865                 p[x * 3 + 0] = pen_color[0];
866                 p[x * 3 + 1] = pen_color[1];
867                 p[x * 3 + 2] = pen_color[2];
868             }
869         }
870     }
871 }
872 
draw_circle_c4(unsigned char * pixels,int w,int h,int stride,int cx,int cy,int radius,unsigned int color,int thickness)873 void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness)
874 {
875     const unsigned char* pen_color = (const unsigned char*)&color;
876 
877     if (thickness == -1)
878     {
879         // filled
880         for (int y = cy - (radius - 1); y < cy + radius; y++)
881         {
882             if (y < 0)
883                 continue;
884 
885             if (y >= h)
886                 break;
887 
888             unsigned char* p = pixels + stride * y;
889 
890             for (int x = cx - (radius - 1); x < cx + radius; x++)
891             {
892                 if (x < 0)
893                     continue;
894 
895                 if (x >= w)
896                     break;
897 
898                 // distance from cx cy
899                 if (distance_lessequal(x, y, cx, cy, radius))
900                 {
901                     p[x * 4 + 0] = pen_color[0];
902                     p[x * 4 + 1] = pen_color[1];
903                     p[x * 4 + 2] = pen_color[2];
904                     p[x * 4 + 3] = pen_color[3];
905                 }
906             }
907         }
908 
909         return;
910     }
911 
912     const float t0 = thickness / 2.f;
913     const float t1 = thickness - t0;
914 
915     for (int y = cy - (radius - 1) - t0; y < cy + radius + t1; y++)
916     {
917         if (y < 0)
918             continue;
919 
920         if (y >= h)
921             break;
922 
923         unsigned char* p = pixels + stride * y;
924 
925         for (int x = cx - (radius - 1) - t0; x < cx + radius + t1; x++)
926         {
927             if (x < 0)
928                 continue;
929 
930             if (x >= w)
931                 break;
932 
933             // distance from cx cy
934             if (distance_inrange(x, y, cx, cy, radius - t0, radius + t1))
935             {
936                 p[x * 4 + 0] = pen_color[0];
937                 p[x * 4 + 1] = pen_color[1];
938                 p[x * 4 + 2] = pen_color[2];
939                 p[x * 4 + 3] = pen_color[3];
940             }
941         }
942     }
943 }
944 
draw_circle_yuv420sp(unsigned char * yuv420sp,int w,int h,int cx,int cy,int radius,unsigned int color,int thickness)945 void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness)
946 {
947     // assert w % 2 == 0
948     // assert h % 2 == 0
949     // assert cx % 2 == 0
950     // assert cy % 2 == 0
951     // assert radius % 2 == 0
952     // assert thickness % 2 == 0
953 
954     const unsigned char* pen_color = (const unsigned char*)&color;
955 
956     unsigned int v_y;
957     unsigned int v_uv;
958     unsigned char* pen_color_y = (unsigned char*)&v_y;
959     unsigned char* pen_color_uv = (unsigned char*)&v_uv;
960     pen_color_y[0] = pen_color[0];
961     pen_color_uv[0] = pen_color[1];
962     pen_color_uv[1] = pen_color[2];
963 
964     unsigned char* Y = yuv420sp;
965     draw_circle_c1(Y, w, h, cx, cy, radius, v_y, thickness);
966 
967     unsigned char* UV = yuv420sp + w * h;
968     int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
969     draw_circle_c2(UV, w / 2, h / 2, cx / 2, cy / 2, radius / 2, v_uv, thickness_uv);
970 }
971 
distance_lessthan(int x,int y,int x0,int y0,int x1,int y1,float t)972 static inline bool distance_lessthan(int x, int y, int x0, int y0, int x1, int y1, float t)
973 {
974     int dx01 = x1 - x0;
975     int dy01 = y1 - y0;
976     int dx0 = x - x0;
977     int dy0 = y - y0;
978 
979     float r = (float)(dx0 * dx01 + dy0 * dy01) / (dx01 * dx01 + dy01 * dy01);
980 
981     if (r < 0 || r > 1)
982         return false;
983 
984     float px = x0 + dx01 * r;
985     float py = y0 + dy01 * r;
986     float dx = x - px;
987     float dy = y - py;
988     float p = dx * dx + dy * dy;
989     return p < t;
990 }
991 
draw_line_c1(unsigned char * pixels,int w,int h,int x0,int y0,int x1,int y1,unsigned int color,int thickness)992 void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
993 {
994     draw_line_c1(pixels, w, h, w, x0, y0, x1, y1, color, thickness);
995 }
996 
draw_line_c2(unsigned char * pixels,int w,int h,int x0,int y0,int x1,int y1,unsigned int color,int thickness)997 void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
998 {
999     draw_line_c2(pixels, w, h, w * 2, x0, y0, x1, y1, color, thickness);
1000 }
1001 
draw_line_c3(unsigned char * pixels,int w,int h,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1002 void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1003 {
1004     draw_line_c3(pixels, w, h, w * 3, x0, y0, x1, y1, color, thickness);
1005 }
1006 
draw_line_c4(unsigned char * pixels,int w,int h,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1007 void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1008 {
1009     draw_line_c4(pixels, w, h, w * 4, x0, y0, x1, y1, color, thickness);
1010 }
1011 
draw_line_c1(unsigned char * pixels,int w,int h,int stride,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1012 void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1013 {
1014     const unsigned char* pen_color = (const unsigned char*)&color;
1015 
1016     const float t0 = thickness / 2.f;
1017     const float t1 = thickness - t0;
1018 
1019     int x_min = std::min(x0, x1);
1020     int x_max = std::max(x0, x1);
1021     int y_min = std::min(y0, y1);
1022     int y_max = std::max(y0, y1);
1023 
1024     for (int y = y_min - t0; y < y_max + t1; y++)
1025     {
1026         if (y < 0)
1027             continue;
1028 
1029         if (y >= h)
1030             break;
1031 
1032         unsigned char* p = pixels + stride * y;
1033 
1034         for (int x = x_min - t0; x < x_max + t1; x++)
1035         {
1036             if (x < 0)
1037                 continue;
1038 
1039             if (x >= w)
1040                 break;
1041 
1042             // distance from line
1043             if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
1044             {
1045                 p[x] = pen_color[0];
1046             }
1047         }
1048     }
1049 }
1050 
draw_line_c2(unsigned char * pixels,int w,int h,int stride,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1051 void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1052 {
1053     const unsigned char* pen_color = (const unsigned char*)&color;
1054 
1055     const float t0 = thickness / 2.f;
1056     const float t1 = thickness - t0;
1057 
1058     int x_min = std::min(x0, x1);
1059     int x_max = std::max(x0, x1);
1060     int y_min = std::min(y0, y1);
1061     int y_max = std::max(y0, y1);
1062 
1063     for (int y = y_min - t0; y < y_max + t1; y++)
1064     {
1065         if (y < 0)
1066             continue;
1067 
1068         if (y >= h)
1069             break;
1070 
1071         unsigned char* p = pixels + stride * y;
1072 
1073         for (int x = x_min - t0; x < x_max + t1; x++)
1074         {
1075             if (x < 0)
1076                 continue;
1077 
1078             if (x >= w)
1079                 break;
1080 
1081             // distance from line
1082             if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
1083             {
1084                 p[x * 2 + 0] = pen_color[0];
1085                 p[x * 2 + 1] = pen_color[1];
1086             }
1087         }
1088     }
1089 }
1090 
draw_line_c3(unsigned char * pixels,int w,int h,int stride,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1091 void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1092 {
1093     const unsigned char* pen_color = (const unsigned char*)&color;
1094 
1095     const float t0 = thickness / 2.f;
1096     const float t1 = thickness - t0;
1097 
1098     int x_min = std::min(x0, x1);
1099     int x_max = std::max(x0, x1);
1100     int y_min = std::min(y0, y1);
1101     int y_max = std::max(y0, y1);
1102 
1103     for (int y = y_min - t0; y < y_max + t1; y++)
1104     {
1105         if (y < 0)
1106             continue;
1107 
1108         if (y >= h)
1109             break;
1110 
1111         unsigned char* p = pixels + stride * y;
1112 
1113         for (int x = x_min - t0; x < x_max + t1; x++)
1114         {
1115             if (x < 0)
1116                 continue;
1117 
1118             if (x >= w)
1119                 break;
1120 
1121             // distance from line
1122             if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
1123             {
1124                 p[x * 3 + 0] = pen_color[0];
1125                 p[x * 3 + 1] = pen_color[1];
1126                 p[x * 3 + 2] = pen_color[2];
1127             }
1128         }
1129     }
1130 }
1131 
draw_line_c4(unsigned char * pixels,int w,int h,int stride,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1132 void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1133 {
1134     const unsigned char* pen_color = (const unsigned char*)&color;
1135 
1136     const float t0 = thickness / 2.f;
1137     const float t1 = thickness - t0;
1138 
1139     int x_min = std::min(x0, x1);
1140     int x_max = std::max(x0, x1);
1141     int y_min = std::min(y0, y1);
1142     int y_max = std::max(y0, y1);
1143 
1144     for (int y = y_min - t0; y < y_max + t1; y++)
1145     {
1146         if (y < 0)
1147             continue;
1148 
1149         if (y >= h)
1150             break;
1151 
1152         unsigned char* p = pixels + stride * y;
1153 
1154         for (int x = x_min - t0; x < x_max + t1; x++)
1155         {
1156             if (x < 0)
1157                 continue;
1158 
1159             if (x >= w)
1160                 break;
1161 
1162             // distance from line
1163             if (distance_lessthan(x, y, x0, y0, x1, y1, t1))
1164             {
1165                 p[x * 4 + 0] = pen_color[0];
1166                 p[x * 4 + 1] = pen_color[1];
1167                 p[x * 4 + 2] = pen_color[2];
1168                 p[x * 4 + 3] = pen_color[3];
1169             }
1170         }
1171     }
1172 }
1173 
draw_line_yuv420sp(unsigned char * yuv420sp,int w,int h,int x0,int y0,int x1,int y1,unsigned int color,int thickness)1174 void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness)
1175 {
1176     // assert w % 2 == 0
1177     // assert h % 2 == 0
1178     // assert x0 % 2 == 0
1179     // assert y0 % 2 == 0
1180     // assert x1 % 2 == 0
1181     // assert y1 % 2 == 0
1182     // assert thickness % 2 == 0
1183 
1184     const unsigned char* pen_color = (const unsigned char*)&color;
1185 
1186     unsigned int v_y;
1187     unsigned int v_uv;
1188     unsigned char* pen_color_y = (unsigned char*)&v_y;
1189     unsigned char* pen_color_uv = (unsigned char*)&v_uv;
1190     pen_color_y[0] = pen_color[0];
1191     pen_color_uv[0] = pen_color[1];
1192     pen_color_uv[1] = pen_color[2];
1193 
1194     unsigned char* Y = yuv420sp;
1195     draw_line_c1(Y, w, h, x0, y0, x1, y1, v_y, thickness);
1196 
1197     unsigned char* UV = yuv420sp + w * h;
1198     int thickness_uv = thickness == -1 ? thickness : std::max(thickness / 2, 1);
1199     draw_line_c2(UV, w / 2, h / 2, x0 / 2, y0 / 2, x1 / 2, y1 / 2, v_uv, thickness_uv);
1200 }
1201 
get_text_drawing_size(const char * text,int fontpixelsize,int * w,int * h)1202 void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h)
1203 {
1204     *w = 0;
1205     *h = 0;
1206 
1207     const int n = strlen(text);
1208 
1209     int line_w = 0;
1210     for (int i = 0; i < n; i++)
1211     {
1212         char ch = text[i];
1213 
1214         if (ch == '\n')
1215         {
1216             // newline
1217             *w = std::max(*w, line_w);
1218             *h += fontpixelsize * 2;
1219             line_w = 0;
1220         }
1221 
1222         if (isprint(ch) != 0)
1223         {
1224             line_w += fontpixelsize;
1225         }
1226     }
1227 
1228     *w = std::max(*w, line_w);
1229     *h += fontpixelsize * 2;
1230 }
1231 
draw_text_c1(unsigned char * pixels,int w,int h,const char * text,int x,int y,int fontpixelsize,unsigned int color)1232 void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1233 {
1234     return draw_text_c1(pixels, w, h, w, text, x, y, fontpixelsize, color);
1235 }
1236 
draw_text_c2(unsigned char * pixels,int w,int h,const char * text,int x,int y,int fontpixelsize,unsigned int color)1237 void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1238 {
1239     return draw_text_c2(pixels, w, h, w * 2, text, x, y, fontpixelsize, color);
1240 }
1241 
draw_text_c3(unsigned char * pixels,int w,int h,const char * text,int x,int y,int fontpixelsize,unsigned int color)1242 void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1243 {
1244     return draw_text_c3(pixels, w, h, w * 3, text, x, y, fontpixelsize, color);
1245 }
1246 
draw_text_c4(unsigned char * pixels,int w,int h,const char * text,int x,int y,int fontpixelsize,unsigned int color)1247 void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1248 {
1249     return draw_text_c4(pixels, w, h, w * 4, text, x, y, fontpixelsize, color);
1250 }
1251 
draw_text_c1(unsigned char * pixels,int w,int h,int stride,const char * text,int x,int y,int fontpixelsize,unsigned int color)1252 void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1253 {
1254     const unsigned char* pen_color = (const unsigned char*)&color;
1255 
1256     unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
1257 
1258     const int n = strlen(text);
1259 
1260     int cursor_x = x;
1261     int cursor_y = y;
1262     for (int i = 0; i < n; i++)
1263     {
1264         char ch = text[i];
1265 
1266         if (ch == '\n')
1267         {
1268             // newline
1269             cursor_x = x;
1270             cursor_y += fontpixelsize * 2;
1271         }
1272 
1273         if (isprint(ch) != 0)
1274         {
1275             const unsigned char* font_bitmap = mono_font_data[ch - ' '];
1276 
1277             // draw resized character
1278             resize_bilinear_c1(font_bitmap, 20, 40, resized_font_bitmap, fontpixelsize, fontpixelsize * 2);
1279 
1280             for (int j = cursor_y; j < cursor_y + fontpixelsize * 2; j++)
1281             {
1282                 if (j < 0)
1283                     continue;
1284 
1285                 if (j >= h)
1286                     break;
1287 
1288                 const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize;
1289                 unsigned char* p = pixels + stride * j;
1290 
1291                 for (int k = cursor_x; k < cursor_x + fontpixelsize; k++)
1292                 {
1293                     if (k < 0)
1294                         continue;
1295 
1296                     if (k >= w)
1297                         break;
1298 
1299                     unsigned char alpha = palpha[k - cursor_x];
1300 
1301                     p[k] = (p[k] * (255 - alpha) + pen_color[0] * alpha) / 255;
1302                 }
1303             }
1304 
1305             cursor_x += fontpixelsize;
1306         }
1307     }
1308 
1309     delete[] resized_font_bitmap;
1310 }
1311 
draw_text_c2(unsigned char * pixels,int w,int h,int stride,const char * text,int x,int y,int fontpixelsize,unsigned int color)1312 void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1313 {
1314     const unsigned char* pen_color = (const unsigned char*)&color;
1315 
1316     unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
1317 
1318     const int n = strlen(text);
1319 
1320     int cursor_x = x;
1321     int cursor_y = y;
1322     for (int i = 0; i < n; i++)
1323     {
1324         char ch = text[i];
1325 
1326         if (ch == '\n')
1327         {
1328             // newline
1329             cursor_x = x;
1330             cursor_y += fontpixelsize * 2;
1331         }
1332 
1333         if (isprint(ch) != 0)
1334         {
1335             int font_bitmap_index = ch - ' ';
1336             const unsigned char* font_bitmap = mono_font_data[font_bitmap_index];
1337 
1338             // draw resized character
1339             resize_bilinear_c1(font_bitmap, 20, 40, resized_font_bitmap, fontpixelsize, fontpixelsize * 2);
1340 
1341             for (int j = cursor_y; j < cursor_y + fontpixelsize * 2; j++)
1342             {
1343                 if (j < 0)
1344                     continue;
1345 
1346                 if (j >= h)
1347                     break;
1348 
1349                 const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize;
1350                 unsigned char* p = pixels + stride * j;
1351 
1352                 for (int k = cursor_x; k < cursor_x + fontpixelsize; k++)
1353                 {
1354                     if (k < 0)
1355                         continue;
1356 
1357                     if (k >= w)
1358                         break;
1359 
1360                     unsigned char alpha = palpha[k - cursor_x];
1361 
1362                     p[k * 2 + 0] = (p[k * 2 + 0] * (255 - alpha) + pen_color[0] * alpha) / 255;
1363                     p[k * 2 + 1] = (p[k * 2 + 1] * (255 - alpha) + pen_color[1] * alpha) / 255;
1364                 }
1365             }
1366 
1367             cursor_x += fontpixelsize;
1368         }
1369     }
1370 
1371     delete[] resized_font_bitmap;
1372 }
1373 
draw_text_c3(unsigned char * pixels,int w,int h,int stride,const char * text,int x,int y,int fontpixelsize,unsigned int color)1374 void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1375 {
1376     const unsigned char* pen_color = (const unsigned char*)&color;
1377 
1378     unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
1379 
1380     const int n = strlen(text);
1381 
1382     int cursor_x = x;
1383     int cursor_y = y;
1384     for (int i = 0; i < n; i++)
1385     {
1386         char ch = text[i];
1387 
1388         if (ch == '\n')
1389         {
1390             // newline
1391             cursor_x = x;
1392             cursor_y += fontpixelsize * 2;
1393         }
1394 
1395         if (isprint(ch) != 0)
1396         {
1397             int font_bitmap_index = ch - ' ';
1398             const unsigned char* font_bitmap = mono_font_data[font_bitmap_index];
1399 
1400             // draw resized character
1401             resize_bilinear_c1(font_bitmap, 20, 40, resized_font_bitmap, fontpixelsize, fontpixelsize * 2);
1402 
1403             for (int j = cursor_y; j < cursor_y + fontpixelsize * 2; j++)
1404             {
1405                 if (j < 0)
1406                     continue;
1407 
1408                 if (j >= h)
1409                     break;
1410 
1411                 const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize;
1412                 unsigned char* p = pixels + stride * j;
1413 
1414                 for (int k = cursor_x; k < cursor_x + fontpixelsize; k++)
1415                 {
1416                     if (k < 0)
1417                         continue;
1418 
1419                     if (k >= w)
1420                         break;
1421 
1422                     unsigned char alpha = palpha[k - cursor_x];
1423 
1424                     p[k * 3 + 0] = (p[k * 3 + 0] * (255 - alpha) + pen_color[0] * alpha) / 255;
1425                     p[k * 3 + 1] = (p[k * 3 + 1] * (255 - alpha) + pen_color[1] * alpha) / 255;
1426                     p[k * 3 + 2] = (p[k * 3 + 2] * (255 - alpha) + pen_color[2] * alpha) / 255;
1427                 }
1428             }
1429 
1430             cursor_x += fontpixelsize;
1431         }
1432     }
1433 
1434     delete[] resized_font_bitmap;
1435 }
1436 
draw_text_c4(unsigned char * pixels,int w,int h,int stride,const char * text,int x,int y,int fontpixelsize,unsigned int color)1437 void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1438 {
1439     const unsigned char* pen_color = (const unsigned char*)&color;
1440 
1441     unsigned char* resized_font_bitmap = new unsigned char[fontpixelsize * fontpixelsize * 2];
1442 
1443     const int n = strlen(text);
1444 
1445     int cursor_x = x;
1446     int cursor_y = y;
1447     for (int i = 0; i < n; i++)
1448     {
1449         char ch = text[i];
1450 
1451         if (ch == '\n')
1452         {
1453             // newline
1454             cursor_x = x;
1455             cursor_y += fontpixelsize * 2;
1456         }
1457 
1458         if (isprint(ch) != 0)
1459         {
1460             const unsigned char* font_bitmap = mono_font_data[ch - ' '];
1461 
1462             // draw resized character
1463             resize_bilinear_c1(font_bitmap, 20, 40, resized_font_bitmap, fontpixelsize, fontpixelsize * 2);
1464 
1465             for (int j = cursor_y; j < cursor_y + fontpixelsize * 2; j++)
1466             {
1467                 if (j < 0)
1468                     continue;
1469 
1470                 if (j >= h)
1471                     break;
1472 
1473                 const unsigned char* palpha = resized_font_bitmap + (j - cursor_y) * fontpixelsize;
1474                 unsigned char* p = pixels + stride * j;
1475 
1476                 for (int k = cursor_x; k < cursor_x + fontpixelsize; k++)
1477                 {
1478                     if (k < 0)
1479                         continue;
1480 
1481                     if (k >= w)
1482                         break;
1483 
1484                     unsigned char alpha = palpha[k - cursor_x];
1485 
1486                     p[k * 4 + 0] = (p[k * 4 + 0] * (255 - alpha) + pen_color[0] * alpha) / 255;
1487                     p[k * 4 + 1] = (p[k * 4 + 1] * (255 - alpha) + pen_color[1] * alpha) / 255;
1488                     p[k * 4 + 2] = (p[k * 4 + 2] * (255 - alpha) + pen_color[2] * alpha) / 255;
1489                     p[k * 4 + 3] = (p[k * 4 + 3] * (255 - alpha) + pen_color[3] * alpha) / 255;
1490                 }
1491             }
1492 
1493             cursor_x += fontpixelsize;
1494         }
1495     }
1496 
1497     delete[] resized_font_bitmap;
1498 }
1499 
draw_text_yuv420sp(unsigned char * yuv420sp,int w,int h,const char * text,int x,int y,int fontpixelsize,unsigned int color)1500 void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color)
1501 {
1502     // assert w % 2 == 0
1503     // assert h % 2 == 0
1504     // assert x % 2 == 0
1505     // assert y % 2 == 0
1506     // assert fontpixelsize % 2 == 0
1507 
1508     const unsigned char* pen_color = (const unsigned char*)&color;
1509 
1510     unsigned int v_y;
1511     unsigned int v_uv;
1512     unsigned char* pen_color_y = (unsigned char*)&v_y;
1513     unsigned char* pen_color_uv = (unsigned char*)&v_uv;
1514     pen_color_y[0] = pen_color[0];
1515     pen_color_uv[0] = pen_color[1];
1516     pen_color_uv[1] = pen_color[2];
1517 
1518     unsigned char* Y = yuv420sp;
1519     draw_text_c1(Y, w, h, text, x, y, fontpixelsize, v_y);
1520 
1521     unsigned char* UV = yuv420sp + w * h;
1522     draw_text_c2(UV, w / 2, h / 2, text, x / 2, y / 2, std::max(fontpixelsize / 2, 1), v_uv);
1523 }
1524 
1525 #endif // NCNN_PIXEL_DRAWING
1526 
1527 } // namespace ncnn
1528