@@ -66,7 +66,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2
6666public:
6767 FreeType2Impl ();
6868 ~FreeType2Impl ();
69- void loadFontData (String fontFileName, int id ) CV_OVERRIDE;
69+ void loadFontData (String fontFileName, int idx ) CV_OVERRIDE;
7070 void setSplitNumber ( int num ) CV_OVERRIDE;
7171 void putText (
7272 InputOutputArray img, const String& text, Point org,
@@ -92,17 +92,28 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2
9292 int fontHeight, Scalar color,
9393 int thickness, int line_type, bool bottomLeftOrigin
9494 );
95+
9596 void putTextBitmapBlend (
9697 InputOutputArray img, const String& text, Point org,
9798 int fontHeight, Scalar color,
9899 int thickness, int line_type, bool bottomLeftOrigin
99100 );
101+
100102 void putTextOutline (
101103 InputOutputArray img, const String& text, Point org,
102104 int fontHeight, Scalar color,
103105 int thickness, int line_type, bool bottomLeftOrigin
104106 );
105107
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;
106117
107118 static int mvFn ( const FT_Vector *to, void * user);
108119 static int lnFn ( const FT_Vector *to, void * user);
@@ -158,7 +169,8 @@ FreeType2Impl::FreeType2Impl()
158169
159170FreeType2Impl::~FreeType2Impl ()
160171{
161- if ( mIsFaceAvailable == true ){
172+ if ( mIsFaceAvailable == true )
173+ {
162174 hb_font_destroy (mHb_font );
163175 CV_Assert (!FT_Done_Face (mFace ));
164176 mIsFaceAvailable = false ;
@@ -168,12 +180,22 @@ FreeType2Impl::~FreeType2Impl()
168180
169181void FreeType2Impl::loadFontData (String fontFileName, int idx)
170182{
171- if ( mIsFaceAvailable == true ){
183+ CV_Assert ( idx >= 0 );
184+ if ( mIsFaceAvailable == true )
185+ {
172186 hb_font_destroy (mHb_font );
173187 CV_Assert (!FT_Done_Face (mFace ));
174188 }
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+
176193 mHb_font = hb_ft_font_create (mFace , NULL );
194+ if ( mHb_font == NULL )
195+ {
196+ CV_Assert (!FT_Done_Face (mFace ));
197+ return ;
198+ }
177199 CV_Assert ( mHb_font != NULL );
178200 mIsFaceAvailable = true ;
179201}
@@ -189,16 +211,17 @@ void FreeType2Impl::putText(
189211 int _thickness, int _line_type, bool _bottomLeftOrigin
190212)
191213{
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 );
202225
203226 if ( _text.empty () )
204227 {
@@ -209,15 +232,11 @@ void FreeType2Impl::putText(
209232 return ;
210233 }
211234
212- if ( _line_type == CV_AA && _img.depth () != CV_8U ){
213- _line_type = 8 ;
214- }
215-
216235 CV_Assert (!FT_Set_Pixel_Sizes ( mFace , _fontHeight, _fontHeight ));
217236
218237 if ( _thickness < 0 ) // CV_FILLED
219238 {
220- if ( _line_type == CV_AA ) {
239+ if ( _line_type == LINE_AA ) {
221240 putTextBitmapBlend ( _img, _text, _org, _fontHeight, _color,
222241 _thickness, _line_type, _bottomLeftOrigin );
223242 }else {
@@ -292,13 +311,36 @@ void FreeType2Impl::putTextOutline(
292311 hb_buffer_destroy (hb_buffer);
293312}
294313
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+
295337void FreeType2Impl::putTextBitmapMono (
296338 InputOutputArray _img, const String& _text, Point _org,
297339 int _fontHeight, Scalar _color,
298340 int _thickness, int _line_type, bool _bottomLeftOrigin )
299341{
300342 CV_Assert ( _thickness < 0 );
301- CV_Assert ( _line_type == 4 || _line_type == 8 );
343+ CV_Assert ( _line_type == LINE_4 || _line_type == LINE_8 );
302344
303345 Mat dst = _img.getMat ();
304346 hb_buffer_t *hb_buffer = hb_buffer_create ();
@@ -318,6 +360,17 @@ void FreeType2Impl::putTextBitmapMono(
318360 _org.y -= _fontHeight;
319361 }
320362
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+
321374 for ( unsigned int i = 0 ; i < textLen ; i ++ ){
322375 CV_Assert ( !FT_Load_Glyph (mFace , info[i].codepoint , 0 ) );
323376 CV_Assert ( !FT_Render_Glyph ( mFace ->glyph , FT_RENDER_MODE_MONO ) );
@@ -351,10 +404,7 @@ void FreeType2Impl::putTextBitmapMono(
351404 }
352405
353406 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 );
358408 }
359409 }
360410 }
@@ -366,14 +416,88 @@ void FreeType2Impl::putTextBitmapMono(
366416 hb_buffer_destroy (hb_buffer);
367417}
368418
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+
369493void FreeType2Impl::putTextBitmapBlend (
370494 InputOutputArray _img, const String& _text, Point _org,
371495 int _fontHeight, Scalar _color,
372496 int _thickness, int _line_type, bool _bottomLeftOrigin )
373497{
374498
375499 CV_Assert ( _thickness < 0 );
376- CV_Assert ( _line_type == 16 );
500+ CV_Assert ( _line_type == LINE_AA );
377501
378502 Mat dst = _img.getMat ();
379503 hb_buffer_t *hb_buffer = hb_buffer_create ();
@@ -393,6 +517,17 @@ void FreeType2Impl::putTextBitmapBlend(
393517 _org.y -= _fontHeight;
394518 }
395519
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+
396531 for ( unsigned int i = 0 ; i < textLen ; i ++ ){
397532 CV_Assert ( !FT_Load_Glyph (mFace , info[i].codepoint , 0 ) );
398533 CV_Assert ( !FT_Render_Glyph ( mFace ->glyph , FT_RENDER_MODE_NORMAL ) );
@@ -411,7 +546,7 @@ void FreeType2Impl::putTextBitmapBlend(
411546 }
412547
413548 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 ];
415550 if ( cl == 0 ) {
416551 continue ;
417552 }
@@ -424,12 +559,7 @@ void FreeType2Impl::putTextBitmapBlend(
424559 break ;
425560 }
426561
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 );
433563 }
434564 }
435565 _org.x += ( mFace ->glyph ->advance .x ) >> 6 ;
0 commit comments