@@ -66,7 +66,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2
66
66
public:
67
67
FreeType2Impl ();
68
68
~FreeType2Impl ();
69
- void loadFontData (String fontFileName, int id ) CV_OVERRIDE;
69
+ void loadFontData (String fontFileName, int idx ) CV_OVERRIDE;
70
70
void setSplitNumber ( int num ) CV_OVERRIDE;
71
71
void putText (
72
72
InputOutputArray img, const String& text, Point org,
@@ -92,17 +92,28 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2
92
92
int fontHeight, Scalar color,
93
93
int thickness, int line_type, bool bottomLeftOrigin
94
94
);
95
+
95
96
void putTextBitmapBlend (
96
97
InputOutputArray img, const String& text, Point org,
97
98
int fontHeight, Scalar color,
98
99
int thickness, int line_type, bool bottomLeftOrigin
99
100
);
101
+
100
102
void putTextOutline (
101
103
InputOutputArray img, const String& text, Point org,
102
104
int fontHeight, Scalar color,
103
105
int thickness, int line_type, bool bottomLeftOrigin
104
106
);
105
107
108
+ typedef void (putPixel_mono_fn)( Mat& _dst, const int _py, const int _px, const uint8_t *_col);
109
+ putPixel_mono_fn putPixel_8UC1_mono;
110
+ putPixel_mono_fn putPixel_8UC3_mono;
111
+ putPixel_mono_fn putPixel_8UC4_mono;
112
+
113
+ typedef void (putPixel_blend_fn)( Mat& _dst, const int _py, const int _px, const uint8_t *_col, const uint8_t alpha);
114
+ putPixel_blend_fn putPixel_8UC1_blend;
115
+ putPixel_blend_fn putPixel_8UC3_blend;
116
+ putPixel_blend_fn putPixel_8UC4_blend;
106
117
107
118
static int mvFn ( const FT_Vector *to, void * user);
108
119
static int lnFn ( const FT_Vector *to, void * user);
@@ -158,7 +169,8 @@ FreeType2Impl::FreeType2Impl()
158
169
159
170
FreeType2Impl::~FreeType2Impl ()
160
171
{
161
- if ( mIsFaceAvailable == true ){
172
+ if ( mIsFaceAvailable == true )
173
+ {
162
174
hb_font_destroy (mHb_font );
163
175
CV_Assert (!FT_Done_Face (mFace ));
164
176
mIsFaceAvailable = false ;
@@ -168,12 +180,22 @@ FreeType2Impl::~FreeType2Impl()
168
180
169
181
void FreeType2Impl::loadFontData (String fontFileName, int idx)
170
182
{
171
- if ( mIsFaceAvailable == true ){
183
+ CV_Assert ( idx >= 0 );
184
+ if ( mIsFaceAvailable == true )
185
+ {
172
186
hb_font_destroy (mHb_font );
173
187
CV_Assert (!FT_Done_Face (mFace ));
174
188
}
175
- CV_Assert (!FT_New_Face ( mLibrary , fontFileName.c_str (), idx, &(mFace ) ) );
189
+
190
+ mIsFaceAvailable = false ;
191
+ CV_Assert ( !FT_New_Face ( mLibrary , fontFileName.c_str (), static_cast <FT_Long>(idx), &(mFace ) ) );
192
+
176
193
mHb_font = hb_ft_font_create (mFace , NULL );
194
+ if ( mHb_font == NULL )
195
+ {
196
+ CV_Assert (!FT_Done_Face (mFace ));
197
+ return ;
198
+ }
177
199
CV_Assert ( mHb_font != NULL );
178
200
mIsFaceAvailable = true ;
179
201
}
@@ -189,16 +211,17 @@ void FreeType2Impl::putText(
189
211
int _thickness, int _line_type, bool _bottomLeftOrigin
190
212
)
191
213
{
192
- CV_Assert ( mIsFaceAvailable == true );
193
- CV_Assert ( ( _img.empty () == false ) &&
194
- ( _img.isMat () == true ) &&
195
- ( _img.depth () == CV_8U ) &&
196
- ( _img.dims () == 2 ) &&
197
- ( _img.channels () == 3 ) );
198
- CV_Assert ( ( _line_type == CV_AA) ||
199
- ( _line_type == 4 ) ||
200
- ( _line_type == 8 ) );
201
- CV_Assert ( _fontHeight >= 0 );
214
+ CV_Assert ( mIsFaceAvailable == true );
215
+ CV_Assert ( _img.empty () == false );
216
+ CV_Assert ( _img.isMat () == true );
217
+ CV_Assert ( _img.dims () == 2 );
218
+ CV_Assert ( ( _img.type () == CV_8UC1 ) ||
219
+ ( _img.type () == CV_8UC3 ) ||
220
+ ( _img.type () == CV_8UC4 ) );
221
+ CV_Assert ( ( _line_type == LINE_AA) ||
222
+ ( _line_type == LINE_4 ) ||
223
+ ( _line_type == LINE_8 ) );
224
+ CV_Assert ( _fontHeight >= 0 );
202
225
203
226
if ( _text.empty () )
204
227
{
@@ -209,15 +232,11 @@ void FreeType2Impl::putText(
209
232
return ;
210
233
}
211
234
212
- if ( _line_type == CV_AA && _img.depth () != CV_8U ){
213
- _line_type = 8 ;
214
- }
215
-
216
235
CV_Assert (!FT_Set_Pixel_Sizes ( mFace , _fontHeight, _fontHeight ));
217
236
218
237
if ( _thickness < 0 ) // CV_FILLED
219
238
{
220
- if ( _line_type == CV_AA ) {
239
+ if ( _line_type == LINE_AA ) {
221
240
putTextBitmapBlend ( _img, _text, _org, _fontHeight, _color,
222
241
_thickness, _line_type, _bottomLeftOrigin );
223
242
}else {
@@ -292,13 +311,36 @@ void FreeType2Impl::putTextOutline(
292
311
hb_buffer_destroy (hb_buffer);
293
312
}
294
313
314
+ void FreeType2Impl::putPixel_8UC1_mono ( Mat& _dst, const int _py, const int _px, const uint8_t *_col)
315
+ {
316
+ uint8_t * ptr = _dst.ptr <uint8_t >( _py, _px );
317
+ (*ptr) = _col[0 ];
318
+ }
319
+
320
+ void FreeType2Impl::putPixel_8UC3_mono ( Mat& _dst, const int _py, const int _px, const uint8_t *_col)
321
+ {
322
+ cv::Vec3b* ptr = _dst.ptr <cv::Vec3b>( _py, _px );
323
+ (*ptr)[0 ] = _col[0 ];
324
+ (*ptr)[1 ] = _col[1 ];
325
+ (*ptr)[2 ] = _col[2 ];
326
+ }
327
+
328
+ void FreeType2Impl::putPixel_8UC4_mono ( Mat& _dst, const int _py, const int _px, const uint8_t *_col)
329
+ {
330
+ cv::Vec4b* ptr = _dst.ptr <cv::Vec4b>( _py, _px );
331
+ (*ptr)[0 ] = _col[0 ];
332
+ (*ptr)[1 ] = _col[1 ];
333
+ (*ptr)[2 ] = _col[2 ];
334
+ (*ptr)[3 ] = _col[3 ];
335
+ }
336
+
295
337
void FreeType2Impl::putTextBitmapMono (
296
338
InputOutputArray _img, const String& _text, Point _org,
297
339
int _fontHeight, Scalar _color,
298
340
int _thickness, int _line_type, bool _bottomLeftOrigin )
299
341
{
300
342
CV_Assert ( _thickness < 0 );
301
- CV_Assert ( _line_type == 4 || _line_type == 8 );
343
+ CV_Assert ( _line_type == LINE_4 || _line_type == LINE_8 );
302
344
303
345
Mat dst = _img.getMat ();
304
346
hb_buffer_t *hb_buffer = hb_buffer_create ();
@@ -318,6 +360,17 @@ void FreeType2Impl::putTextBitmapMono(
318
360
_org.y -= _fontHeight;
319
361
}
320
362
363
+ const uint8_t _colorUC8n[4 ] = {
364
+ static_cast <uint8_t >(_color[0 ]),
365
+ static_cast <uint8_t >(_color[1 ]),
366
+ static_cast <uint8_t >(_color[2 ]),
367
+ static_cast <uint8_t >(_color[3 ]) };
368
+
369
+ void (cv::freetype::FreeType2Impl::*putPixel)( Mat&, const int , const int , const uint8_t *) =
370
+ (_img.type () == CV_8UC4)?(&FreeType2Impl::putPixel_8UC4_mono):
371
+ (_img.type () == CV_8UC3)?(&FreeType2Impl::putPixel_8UC3_mono):
372
+ (&FreeType2Impl::putPixel_8UC1_mono);
373
+
321
374
for ( unsigned int i = 0 ; i < textLen ; i ++ ){
322
375
CV_Assert ( !FT_Load_Glyph (mFace , info[i].codepoint , 0 ) );
323
376
CV_Assert ( !FT_Render_Glyph ( mFace ->glyph , FT_RENDER_MODE_MONO ) );
@@ -351,10 +404,7 @@ void FreeType2Impl::putTextBitmapMono(
351
404
}
352
405
353
406
if ( ( (cl >> bit) & 0x01 ) == 1 ) {
354
- cv::Vec3b* ptr = dst.ptr <cv::Vec3b>( gPos .y + row, gPos .x + col * 8 + (7 - bit) );
355
- (*ptr)[0 ] = _color[0 ];
356
- (*ptr)[1 ] = _color[1 ];
357
- (*ptr)[2 ] = _color[2 ];
407
+ (this ->*putPixel)( dst, gPos .y + row, gPos .x + col * 8 + (7 - bit), _colorUC8n );
358
408
}
359
409
}
360
410
}
@@ -366,14 +416,88 @@ void FreeType2Impl::putTextBitmapMono(
366
416
hb_buffer_destroy (hb_buffer);
367
417
}
368
418
419
+ // Alpha composite algorithm is porting from imgproc.
420
+ // See https://github.com/opencv/opencv/blob/4.6.0/modules/imgproc/src/drawing.cpp
421
+ // static void LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color )
422
+ // ICV_PUT_POINT Macro.
423
+
424
+ void FreeType2Impl::putPixel_8UC1_blend ( Mat& _dst, const int _py, const int _px, const uint8_t *_col, const uint8_t alpha)
425
+ {
426
+ const int a = alpha;
427
+ const int cb = _col[0 ];
428
+ uint8_t * tptr = _dst.ptr <uint8_t >( _py, _px );
429
+
430
+ int _cb = static_cast <int >(tptr[0 ]);
431
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
432
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
433
+
434
+ tptr[0 ] = static_cast <uint8_t >(_cb);
435
+ }
436
+
437
+ void FreeType2Impl::putPixel_8UC3_blend ( Mat& _dst, const int _py, const int _px, const uint8_t *_col, const uint8_t alpha)
438
+ {
439
+ const int a = alpha;
440
+ const int cb = _col[0 ];
441
+ const int cg = _col[1 ];
442
+ const int cr = _col[2 ];
443
+ uint8_t * tptr = _dst.ptr <uint8_t >( _py, _px );
444
+
445
+ int _cb = static_cast <int >(tptr[0 ]);
446
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
447
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
448
+
449
+ int _cg = static_cast <int >(tptr[1 ]);
450
+ _cg += ((cg - _cg)*a + 127 )>> 8 ;
451
+ _cg += ((cg - _cg)*a + 127 )>> 8 ;
452
+
453
+ int _cr = static_cast <int >(tptr[2 ]);
454
+ _cr += ((cr - _cr)*a + 127 )>> 8 ;
455
+ _cr += ((cr - _cr)*a + 127 )>> 8 ;
456
+
457
+ tptr[0 ] = static_cast <uint8_t >(_cb);
458
+ tptr[1 ] = static_cast <uint8_t >(_cg);
459
+ tptr[2 ] = static_cast <uint8_t >(_cr);
460
+ }
461
+
462
+ void FreeType2Impl::putPixel_8UC4_blend ( Mat& _dst, const int _py, const int _px, const uint8_t *_col, const uint8_t alpha)
463
+ {
464
+ const uint8_t a = alpha;
465
+ const int cb = _col[0 ];
466
+ const int cg = _col[1 ];
467
+ const int cr = _col[2 ];
468
+ const int ca = _col[3 ];
469
+ uint8_t * tptr = _dst.ptr <uint8_t >( _py, _px );
470
+
471
+ int _cb = static_cast <int >(tptr[0 ]);
472
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
473
+ _cb += ((cb - _cb)*a + 127 )>> 8 ;
474
+
475
+ int _cg = static_cast <int >(tptr[1 ]);
476
+ _cg += ((cg - _cg)*a + 127 )>> 8 ;
477
+ _cg += ((cg - _cg)*a + 127 )>> 8 ;
478
+
479
+ int _cr = static_cast <int >(tptr[2 ]);
480
+ _cr += ((cr - _cr)*a + 127 )>> 8 ;
481
+ _cr += ((cr - _cr)*a + 127 )>> 8 ;
482
+
483
+ int _ca = static_cast <int >(tptr[3 ]);
484
+ _ca += ((ca - _ca)*a + 127 )>> 8 ;
485
+ _ca += ((ca - _ca)*a + 127 )>> 8 ;
486
+
487
+ tptr[0 ] = static_cast <uint8_t >(_cb);
488
+ tptr[1 ] = static_cast <uint8_t >(_cg);
489
+ tptr[2 ] = static_cast <uint8_t >(_cr);
490
+ tptr[3 ] = static_cast <uint8_t >(_ca);
491
+ }
492
+
369
493
void FreeType2Impl::putTextBitmapBlend (
370
494
InputOutputArray _img, const String& _text, Point _org,
371
495
int _fontHeight, Scalar _color,
372
496
int _thickness, int _line_type, bool _bottomLeftOrigin )
373
497
{
374
498
375
499
CV_Assert ( _thickness < 0 );
376
- CV_Assert ( _line_type == 16 );
500
+ CV_Assert ( _line_type == LINE_AA );
377
501
378
502
Mat dst = _img.getMat ();
379
503
hb_buffer_t *hb_buffer = hb_buffer_create ();
@@ -393,6 +517,17 @@ void FreeType2Impl::putTextBitmapBlend(
393
517
_org.y -= _fontHeight;
394
518
}
395
519
520
+ const uint8_t _colorUC8n[4 ] = {
521
+ static_cast <uint8_t >(_color[0 ]),
522
+ static_cast <uint8_t >(_color[1 ]),
523
+ static_cast <uint8_t >(_color[2 ]),
524
+ static_cast <uint8_t >(_color[3 ]) };
525
+
526
+ void (cv::freetype::FreeType2Impl::*putPixel)( Mat&, const int , const int , const uint8_t *, const uint8_t ) =
527
+ (_img.type () == CV_8UC4)?(&FreeType2Impl::putPixel_8UC4_blend):
528
+ (_img.type () == CV_8UC3)?(&FreeType2Impl::putPixel_8UC3_blend):
529
+ (&FreeType2Impl::putPixel_8UC1_blend);
530
+
396
531
for ( unsigned int i = 0 ; i < textLen ; i ++ ){
397
532
CV_Assert ( !FT_Load_Glyph (mFace , info[i].codepoint , 0 ) );
398
533
CV_Assert ( !FT_Render_Glyph ( mFace ->glyph , FT_RENDER_MODE_NORMAL ) );
@@ -411,7 +546,7 @@ void FreeType2Impl::putTextBitmapBlend(
411
546
}
412
547
413
548
for (int col = 0 ; col < bmp->pitch ; col ++) {
414
- int cl = bmp->buffer [ row * bmp->pitch + col ];
549
+ uint8_t cl = bmp->buffer [ row * bmp->pitch + col ];
415
550
if ( cl == 0 ) {
416
551
continue ;
417
552
}
@@ -424,12 +559,7 @@ void FreeType2Impl::putTextBitmapBlend(
424
559
break ;
425
560
}
426
561
427
- cv::Vec3b* ptr = dst.ptr <cv::Vec3b>( gPos .y + row , gPos .x + col);
428
- double blendAlpha = (double ) cl / 255.0 ;
429
-
430
- (*ptr)[0 ] = (double ) _color[0 ] * blendAlpha + (*ptr)[0 ] * (1.0 - blendAlpha );
431
- (*ptr)[1 ] = (double ) _color[1 ] * blendAlpha + (*ptr)[1 ] * (1.0 - blendAlpha );
432
- (*ptr)[2 ] = (double ) _color[2 ] * blendAlpha + (*ptr)[2 ] * (1.0 - blendAlpha );
562
+ (this ->*putPixel)( dst, gPos .y + row, gPos .x + col, _colorUC8n, cl );
433
563
}
434
564
}
435
565
_org.x += ( mFace ->glyph ->advance .x ) >> 6 ;
0 commit comments