25#include <scolPlugin.h>
34 class FreeTypeFontImpl CV_FINAL :
public FreeTypeFont
40 bool loadFontData(String fontFileName,
int idx) CV_OVERRIDE;
41 bool loadFontData(
const FT_Byte* fontData, FT_Long fontDataSize,
int idx) CV_OVERRIDE;
43 void setSplitNumber(
int num) CV_OVERRIDE;
46 InputOutputArray img,
const String& text, Point org,
47 int fontHeight, Scalar color,
48 int thickness,
int line_type,
bool bottomLeftOrigin
52 const String& text,
int fontHeight,
int thickness,
58 FTC_Manager mFtcManager;
59 FTC_ImageCache mImageCache;
60 FTC_ImageTypeRec mImageType;
63 hb_buffer_t* mHbBuffer;
64 bool mIsFaceAvailable;
69 static FT_Error Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer req_data, FT_Face *aface);
71 void putTextBitmapMono(
72 InputOutputArray img,
const String& text, Point org,
73 int fontHeight, Scalar color,
74 int thickness,
int line_type,
bool bottomLeftOrigin
77 void putTextBitmapBlend(
78 InputOutputArray img,
const String& text, Point org,
79 int fontHeight, Scalar color,
80 int thickness,
int line_type,
bool bottomLeftOrigin
84 InputOutputArray img,
const String& text, Point org,
85 int fontHeight, Scalar color,
86 int thickness,
int line_type,
bool bottomLeftOrigin
89 static int mvFn(
const FT_Vector *to,
void * user);
90 static int lnFn(
const FT_Vector *to,
void * user);
91 static int coFn(
const FT_Vector *cnt,
const FT_Vector *to,
void * user);
92 static int cuFn(
const FT_Vector *cnt1,
const FT_Vector *cnt2,
const FT_Vector *to,
void * user);
95 static const unsigned int cOutlineOffset = 0x80000000;
100 static int ftd(
unsigned int fixedInt)
102 unsigned int ret = ((fixedInt + (1 << 5)) >> 6);
103 return (
int)ret - (cOutlineOffset >> 6);
110 PathUserData(InputOutputArray _img) : mImg(_img) {};
112 InputOutputArray mImg;
118 std::vector < Point > mPts;
125 drawGlyph(cv::Point _pos, FTC_Manager* _manager) : pos(_pos), manager(_manager){};
129 FTC_Manager* manager;
135 blitBuffer(InputOutputArray img, std::vector<drawGlyph> lGlyph, cv::Scalar color) : mImg(img), mLglyph(lGlyph), mColor(color) {};
137 InputOutputArray mImg;
138 std::vector<drawGlyph> mLglyph;
142 class blitMono :
public cv::ParallelLoopBody
145 blitMono(
const blitBuffer _conv)
149 void operator()(
const cv::Range& range)
const
151 const int start = range.start;
152 const int end = range.end;
153 cv::Mat dst = conv.mImg.getMat();
155 for (
unsigned int t = start; t < end; t++)
157 drawGlyph dGlyph = conv.mLglyph[t];
158 if (dGlyph.glyph->format != FT_GLYPH_FORMAT_BITMAP && FT_Glyph_To_Bitmap(&dGlyph.glyph, FT_RENDER_MODE_MONO, 0, 1))
161 FT_BitmapGlyph gbmp = (FT_BitmapGlyph)dGlyph.glyph;
162 FT_Bitmap* bmp = &gbmp->bitmap;
164 dGlyph.pos.y -= gbmp->top;
165 dGlyph.pos.x += gbmp->left;
167 if (!bmp || !bmp->buffer)
170 for (
int row = 0; row < bmp->rows; row++)
172 if (dGlyph.pos.y + row < 0)
175 if (dGlyph.pos.y + row >= dst.rows)
178 for (
int col = 0; col < bmp->pitch; col++)
180 int cl = bmp->buffer[row * bmp->pitch + col];
184 for (
int bit = 7; bit >= 0; bit--)
186 if (dGlyph.pos.x + col * 8 + (7 - bit) < 0)
189 if (dGlyph.pos.x + col * 8 + (7 - bit) >= dst.cols)
192 if (((cl >> bit) & 0x01) == 1)
194 if (conv.mImg.channels() == 3)
196 cv::Vec3b* ptr = dst.ptr<cv::Vec3b>(dGlyph.pos.y + row, dGlyph.pos.x + col * 8 + (7 - bit));
197 (*ptr)[0] = conv.mColor[0];
198 (*ptr)[1] = conv.mColor[1];
199 (*ptr)[2] = conv.mColor[2];
203 uint8_t* ptr = dst.ptr<uint8_t>(dGlyph.pos.y + row, dGlyph.pos.x + col * 8 + (7 - bit));
204 (*ptr) = conv.mColor[0];
210 FTC_Node_Unref(dGlyph.anode, *dGlyph.manager);
215 blitMono& operator=(
const blitMono&);
216 const blitBuffer conv;
219 class blitBlend :
public cv::ParallelLoopBody
222 blitBlend(
const blitBuffer _conv)
226 void operator()(
const cv::Range& range)
const
228 const int start = range.start;
229 const int end = range.end;
230 cv::Mat dst = conv.mImg.getMat();
232 for (
unsigned int t = start; t < end; t++)
234 drawGlyph dGlyph = conv.mLglyph[t];
235 if (dGlyph.glyph->format != FT_GLYPH_FORMAT_BITMAP && FT_Glyph_To_Bitmap(&dGlyph.glyph, FT_RENDER_MODE_NORMAL, 0, 1))
238 FT_BitmapGlyph gbmp = (FT_BitmapGlyph)dGlyph.glyph;
239 FT_Bitmap* bmp = &gbmp->bitmap;
241 dGlyph.pos.y -= gbmp->top;
242 dGlyph.pos.x += gbmp->left;
244 if (!bmp || !bmp->buffer)
247 for (
int row = 0; row < bmp->rows; row++)
249 if (dGlyph.pos.y + row < 0)
252 if (dGlyph.pos.y + row >= dst.rows)
255 for (
int col = 0; col < bmp->pitch; col++)
257 int cl = bmp->buffer[row * bmp->pitch + col];
261 if (dGlyph.pos.x + col < 0)
264 if (dGlyph.pos.x + col >= dst.cols)
267 double blendAlpha = (double)cl / 255.0;
268 if (conv.mImg.channels() == 3)
270 cv::Vec3b* ptr = dst.ptr<cv::Vec3b>(dGlyph.pos.y + row, dGlyph.pos.x + col);
271 (*ptr)[0] = (double)conv.mColor[0] * blendAlpha + (*ptr)[0] * (1.0 - blendAlpha);
272 (*ptr)[1] = (double)conv.mColor[1] * blendAlpha + (*ptr)[1] * (1.0 - blendAlpha);
273 (*ptr)[2] = (double)conv.mColor[2] * blendAlpha + (*ptr)[2] * (1.0 - blendAlpha);
277 uchar* ptr = dst.ptr<uchar>(dGlyph.pos.y + row, dGlyph.pos.x + col);
278 (*ptr) = (double)conv.mColor[0] * blendAlpha + (*ptr) * (1.0 - blendAlpha);
282 FTC_Node_Unref(dGlyph.anode, *dGlyph.manager);
287 blitBlend& operator=(
const blitBlend&);
288 const blitBuffer conv;
291 FreeTypeFontImpl::FreeTypeFontImpl()
293 FT_Init_FreeType(&(this->mLibrary));
294 mHbBuffer = hb_buffer_create();
299 mFn.move_to = FreeTypeFontImpl::mvFn;
300 mFn.line_to = FreeTypeFontImpl::lnFn;
301 mFn.cubic_to = FreeTypeFontImpl::cuFn;
302 mFn.conic_to = FreeTypeFontImpl::coFn;
306 FTC_Manager_New(mLibrary, 1, 0, 0 , Face_Requester,
this, &mFtcManager);
307 FTC_ImageCache_New(mFtcManager, &mImageCache);
309 mIsFaceAvailable =
false;
312 FreeTypeFontImpl::~FreeTypeFontImpl()
314 hb_buffer_destroy(mHbBuffer);
315 if (mIsFaceAvailable ==
true)
317 hb_font_destroy(mHb_font);
319 mIsFaceAvailable =
false;
321 FTC_Manager_Done(mFtcManager);
322 CV_Assert(!FT_Done_FreeType(mLibrary));
328 FT_Error FreeTypeFontImpl::Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer req_data, FT_Face *aface)
330 FreeTypeFontImpl *impl =
static_cast<FreeTypeFontImpl *
>(req_data);
331 *aface = impl->mFace;
335 bool FreeTypeFontImpl::loadFontData(String fontFileName,
int idx)
337 if (mIsFaceAvailable ==
true)
339 hb_font_destroy(mHb_font);
340 CV_Assert(!FT_Done_Face(mFace));
342 if (mFontData != NULL)
347 mIsFaceAvailable =
false;
350 std::stringstream stream(std::stringstream::in|std::stringstream::out|std::stringstream::binary);
351 if (!SCfopenStream(fontFileName.c_str(), stream))
355 stream.seekg(0, stream.end);
356 int length = stream.tellg();
357 stream.seekg(0, stream.beg);
359 mFontData =
new char[length];
360 stream.read(mFontData, length);
362 if (!loadFontData((FT_Byte*)mFontData, (FT_Long)length, 0))
364 if (mFontData != NULL)
374 if (FT_New_Face(mLibrary, fontFileName.c_str(), idx, &(mFace)) != 0)
376 mIsFaceAvailable =
false;
381 mHb_font = hb_ft_font_create(mFace, NULL);
382 if (mHb_font == NULL)
384 mIsFaceAvailable =
false;
388 mIsFaceAvailable =
true;
393 bool FreeTypeFontImpl::loadFontData(
const FT_Byte* fontData, FT_Long fontDataSize,
int idx)
395 if (mIsFaceAvailable ==
true)
397 hb_font_destroy(mHb_font);
398 CV_Assert(!FT_Done_Face(mFace));
400 if (mFontData != NULL)
407 if (FT_New_Memory_Face(mLibrary, fontData, fontDataSize, idx, &(mFace)) != 0)
409 mIsFaceAvailable =
false;
414 mHb_font = hb_ft_font_create(mFace, NULL);
415 if (mHb_font == NULL)
417 mIsFaceAvailable =
false;
421 mIsFaceAvailable =
true;
425 void FreeTypeFontImpl::setSplitNumber(
int num)
431 void FreeTypeFontImpl::putText(
432 InputOutputArray _img,
const String& _text, Point _org,
433 int _fontHeight, Scalar _color,
434 int _thickness,
int _line_type,
bool _bottomLeftOrigin
437 CV_Assert(mIsFaceAvailable ==
true);
438 CV_Assert((_img.empty() ==
false) &&
439 (_img.isMat() ==
true) &&
440 (_img.depth() == CV_8U) &&
442 CV_Assert((_line_type == CV_AA) ||
445 CV_Assert(_fontHeight >= 0);
450 std::string text = to_utf8(_text);
452 if (_fontHeight == 0)
455 if (_line_type == CV_AA && _img.depth() != CV_8U)
460 CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
464 if (_line_type == CV_AA)
466 putTextBitmapBlend(_img, text, _org, _fontHeight, _color,
467 _thickness, _line_type, _bottomLeftOrigin);
471 putTextBitmapMono(_img, text, _org, _fontHeight, _color,
472 _thickness, _line_type, _bottomLeftOrigin);
477 putTextOutline(_img, text, _org, _fontHeight, _color,
478 _thickness, _line_type, _bottomLeftOrigin);
482 void FreeTypeFontImpl::putTextOutline(
483 InputOutputArray _img,
const String& _text, Point _org,
484 int _fontHeight, Scalar _color,
485 int _thickness,
int _line_type,
bool _bottomLeftOrigin)
487 unsigned int textLen;
488 hb_buffer_reset(mHbBuffer);
489 hb_buffer_guess_segment_properties(mHbBuffer);
490 hb_buffer_add_utf8(mHbBuffer, _text.c_str(), -1, 0, -1);
492 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(mHbBuffer, &textLen);
493 CV_Assert(info != NULL);
495 hb_shape(mHb_font, mHbBuffer, NULL, 0);
497 if (_bottomLeftOrigin ==
true)
498 _org.y -= _fontHeight;
500 PathUserData *userData =
new PathUserData(_img);
501 userData->mColor = _color;
502 userData->mCtoL = mCtoL;
503 userData->mThickness = _thickness;
504 userData->mLine_type = _line_type;
506 mImageType.face_id = (FTC_FaceID)1;
507 mImageType.width = _fontHeight;
508 mImageType.height = _fontHeight;
509 mImageType.flags = FT_LOAD_DEFAULT;
511 for (
unsigned int i = 0; i < textLen; i++)
514 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &glyph,
nullptr));
516 FT_OutlineGlyph outlineglyph = (FT_OutlineGlyph)glyph;
518 CV_Assert(!FT_Outline_New(mLibrary, outlineglyph->outline.n_points, outlineglyph->outline.n_contours, &outline));
519 CV_Assert(!FT_Outline_Copy(&outlineglyph->outline, &outline));
522 FT_Matrix mtx = { 1 << 16 , 0 , 0 , -(1 << 16) };
523 FT_Outline_Transform(&outline, &mtx);
526 FT_Outline_Translate(&outline,
531 FT_Outline_Translate(&outline,
532 (FT_Pos)(_org.x << 6),
533 (FT_Pos)((_org.y + _fontHeight) << 6));
536 CV_Assert(!FT_Outline_Decompose(&outline, &mFn, (
void*)userData));
539 mvFn(NULL, (
void*)userData);
541 _org.x += (glyph->advance.x) >> 16;
542 _org.y += (glyph->advance.y) >> 16;
544 FT_Outline_Done(mLibrary, &outline);
549 void FreeTypeFontImpl::putTextBitmapMono(
550 InputOutputArray _img,
const String& _text, Point _org,
551 int _fontHeight, Scalar _color,
552 int _thickness,
int _line_type,
bool _bottomLeftOrigin)
554 CV_Assert(_thickness < 0);
556 unsigned int textLen;
557 hb_buffer_reset(mHbBuffer);
558 hb_buffer_guess_segment_properties(mHbBuffer);
559 hb_buffer_add_utf8(mHbBuffer, _text.c_str(), -1, 0, -1);
560 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(mHbBuffer, &textLen);
561 CV_Assert(info != NULL);
563 hb_shape(mHb_font, mHbBuffer, NULL, 0);
565 _org.y += _fontHeight;
566 if (_bottomLeftOrigin ==
true)
567 _org.y -= _fontHeight;
569 mImageType.face_id = (FTC_FaceID) 1;
570 mImageType.width = _fontHeight;
571 mImageType.height = _fontHeight;
572 mImageType.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_MONO;
574 std::vector<drawGlyph> lGlyph;
575 for (
unsigned int i = 0; i < textLen; i++)
577 drawGlyph dGlyph(_org, &mFtcManager);
579 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &dGlyph.glyph, &dGlyph.anode));
580 lGlyph.push_back(dGlyph);
582 _org.x += (dGlyph.glyph->advance.x) >> 16;
583 _org.y += (dGlyph.glyph->advance.y) >> 16;
586 blitBuffer conv(_img, lGlyph, _color);
587 cv::parallel_for_(cv::Range(0, lGlyph.size()), blitMono(conv));
590 void FreeTypeFontImpl::putTextBitmapBlend(
591 InputOutputArray _img,
const String& _text, Point _org,
592 int _fontHeight, Scalar _color,
593 int _thickness,
int _line_type,
bool _bottomLeftOrigin)
595 CV_Assert(_thickness < 0);
597 unsigned int textLen;
598 hb_buffer_reset(mHbBuffer);
599 hb_buffer_guess_segment_properties(mHbBuffer);
600 hb_buffer_add_utf8(mHbBuffer, _text.c_str(), -1, 0, -1);
601 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(mHbBuffer, &textLen);
602 CV_Assert(info != NULL);
604 hb_shape(mHb_font, mHbBuffer, NULL, 0);
606 _org.y += _fontHeight;
607 if (_bottomLeftOrigin ==
true)
608 _org.y -= _fontHeight;
610 mImageType.face_id = (FTC_FaceID)1;
611 mImageType.width = _fontHeight;
612 mImageType.height = _fontHeight;
613 mImageType.flags = FT_LOAD_RENDER;
615 std::vector<drawGlyph> lGlyph;
616 for (
unsigned int i = 0; i < textLen; i++)
618 drawGlyph dGlyph(_org, &mFtcManager);
620 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &dGlyph.glyph, &dGlyph.anode));
621 lGlyph.push_back(dGlyph);
623 _org.x += (dGlyph.glyph->advance.x) >> 16;
624 _org.y += (dGlyph.glyph->advance.y) >> 16;
627 blitBuffer conv(_img, lGlyph, _color);
628 cv::parallel_for_(cv::Range(0, lGlyph.size()), blitBlend(conv));
631 Size FreeTypeFontImpl::getTextSize(
635 CV_OUT
int* _baseLine)
640 CV_Assert(_fontHeight >= 0);
641 if (_fontHeight == 0)
644 CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
648 unsigned int textLen;
649 hb_buffer_reset(mHbBuffer);
650 hb_buffer_guess_segment_properties(mHbBuffer);
651 hb_buffer_add_utf8(mHbBuffer, _text.c_str(), -1, 0, -1);
652 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(mHbBuffer, &textLen);
653 CV_Assert(info != NULL);
654 hb_shape(mHb_font, mHbBuffer, NULL, 0);
656 _org.y -= _fontHeight;
657 int xMin = INT_MAX, xMax = INT_MIN;
658 int yMin = INT_MAX, yMax = INT_MIN;
660 mImageType.face_id = (FTC_FaceID)1;
661 mImageType.width = _fontHeight;
662 mImageType.height = _fontHeight;
663 mImageType.flags = FT_LOAD_RENDER;
665 for (
unsigned int i = 0; i < textLen; i++)
668 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &glyph,
nullptr));
670 if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
671 FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
673 FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)glyph;
675 FT_Bitmap *bmp = &(glyph_bitmap->bitmap);
679 gPos.y -= glyph_bitmap->top;
680 gPos.x += glyph_bitmap->left;
681 int rows = bmp->rows;
682 int cols = bmp->pitch;
684 yMin = cv::min(yMin, gPos.y);
685 yMax = cv::max(yMax, gPos.y + rows);
686 xMin = cv::min(xMin, gPos.x);
687 xMax = cv::max(xMax, gPos.x + cols);
689 _org.x += (glyph->advance.x) >> 16;
690 _org.y += (glyph->advance.y) >> 16;
693 int width = xMax - xMin;
694 int height = yMax - yMin;
698 width = cvRound(width + _thickness * 2);
699 height = cvRound(height + _thickness * 1);
703 width = cvRound(width + 1);
704 height = cvRound(height + 1);
710 return Size(width, height);
713 int FreeTypeFontImpl::mvFn(
const FT_Vector *to,
void * user)
718 PathUserData *p = (PathUserData*)user;
720 if (p->mPts.size() > 0)
722 Mat dst = p->mImg.getMat();
723 const Point *ptsList[] = { &(p->mPts[0]) };
724 int npt[1]; npt[0] = p->mPts.size();
743 p->mPts.push_back(Point(ftd(to->x), ftd(to->y)));
748 int FreeTypeFontImpl::lnFn(
const FT_Vector *to,
void * user)
755 PathUserData *p = (PathUserData *)user;
756 p->mPts.push_back(Point(ftd(to->x), ftd(to->y)));
761 int FreeTypeFontImpl::coFn(
const FT_Vector *cnt,
774 PathUserData *p = (PathUserData *)user;
777 for (
int i = 0; i <= p->mCtoL; i++)
779 double u = (double)i * 1.0 / (p->mCtoL);
782 double p1 = 2.0 * u * nu;
785 double X = (p->mOldP.x) * p0 + cnt->x * p1 + to->x * p2;
786 double Y = (p->mOldP.y) * p0 + cnt->y * p1 + to->y * p2;
787 p->mPts.push_back(Point(ftd(X), ftd(Y)));
793 int FreeTypeFontImpl::cuFn(
const FT_Vector *cnt1,
794 const FT_Vector *cnt2,
810 PathUserData *p = (PathUserData *)user;
813 for (
int i = 0; i <= p->mCtoL; i++)
815 double u = (double)i * 1.0 / (p->mCtoL);
817 double p0 = nu * nu * nu;
818 double p1 = 3.0 * u * nu * nu;
819 double p2 = 3.0 * u * u * nu;
820 double p3 = u * u * u;
822 double X = (p->mOldP.x) * p0 + (cnt1->x) * p1 +
823 (cnt2->x) * p2 + (to->x) * p3;
824 double Y = (p->mOldP.y) * p0 + (cnt1->y) * p1 +
825 (cnt2->y) * p2 + (to->y) * p3;
827 p->mPts.push_back(Point(ftd(X), ftd(Y)));
835 return Ptr<FreeTypeFontImpl>(
new FreeTypeFontImpl());
Ptr< FreeTypeFont > createFreeTypeFont()
Create FreeType2 Instance.