Project

General

Profile

BitmapToolkit Scol plugin
freetypeFont.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25#include <scolPlugin.h>
26
27#include "freetypeFont.h"
28
29namespace cv {
30 namespace freetype {
31
32 using namespace std;
33
34 class FreeTypeFontImpl CV_FINAL : public FreeTypeFont
35 {
36 public:
37 FreeTypeFontImpl();
38 ~FreeTypeFontImpl();
39
40 bool loadFontData(String fontFileName, int idx) CV_OVERRIDE;
41 bool loadFontData(const FT_Byte* fontData, FT_Long fontDataSize, int idx) CV_OVERRIDE;
42
43 void setSplitNumber(int num) CV_OVERRIDE;
44
45 void putText(
46 InputOutputArray img, const String& text, Point org,
47 int fontHeight, Scalar color,
48 int thickness, int line_type, bool bottomLeftOrigin
49 ) CV_OVERRIDE;
50
51 Size getTextSize(
52 const String& text, int fontHeight, int thickness,
53 CV_OUT int* baseLine
54 ) CV_OVERRIDE;
55
56 private:
57 FT_Library mLibrary;
58 FTC_Manager mFtcManager;
59 FTC_ImageCache mImageCache;
60 FTC_ImageTypeRec mImageType;
61 FT_Face mFace;
62 FT_Outline_Funcs mFn;
63 hb_buffer_t* mHbBuffer;
64 bool mIsFaceAvailable;
65 int mCtoL;
66 hb_font_t *mHb_font;
67 char* mFontData;
68
69 static FT_Error Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer req_data, FT_Face *aface);
70
71 void putTextBitmapMono(
72 InputOutputArray img, const String& text, Point org,
73 int fontHeight, Scalar color,
74 int thickness, int line_type, bool bottomLeftOrigin
75 );
76
77 void putTextBitmapBlend(
78 InputOutputArray img, const String& text, Point org,
79 int fontHeight, Scalar color,
80 int thickness, int line_type, bool bottomLeftOrigin
81 );
82
83 void putTextOutline(
84 InputOutputArray img, const String& text, Point org,
85 int fontHeight, Scalar color,
86 int thickness, int line_type, bool bottomLeftOrigin
87 );
88
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);
93
94 // Offset value to handle the position less than 0.
95 static const unsigned int cOutlineOffset = 0x80000000;
96
100 static int ftd(unsigned int fixedInt)
101 {
102 unsigned int ret = ((fixedInt + (1 << 5)) >> 6);
103 return (int)ret - (cOutlineOffset >> 6);
104 }
105
106 class PathUserData
107 {
108 private:
109 public:
110 PathUserData(InputOutputArray _img) : mImg(_img) {};
111
112 InputOutputArray mImg;
113 Scalar mColor;
114 int mThickness;
115 int mLine_type;
116 FT_Vector mOldP;
117 int mCtoL;
118 std::vector < Point > mPts;
119 };
120 };
121
122 class drawGlyph
123 {
124 public:
125 drawGlyph(cv::Point _pos, FTC_Manager* _manager) : pos(_pos), manager(_manager){};
126 FT_Glyph glyph;
127 cv::Point pos;
128 FTC_Node anode;
129 FTC_Manager* manager;
130 };
131
132 class blitBuffer
133 {
134 public:
135 blitBuffer(InputOutputArray img, std::vector<drawGlyph> lGlyph, cv::Scalar color) : mImg(img), mLglyph(lGlyph), mColor(color) {};
136
137 InputOutputArray mImg;
138 std::vector<drawGlyph> mLglyph;
139 cv::Scalar mColor;
140 };
141
142 class blitMono : public cv::ParallelLoopBody
143 {
144 public:
145 blitMono(const blitBuffer _conv)
146 : conv(_conv)
147 {}
148
149 void operator()(const cv::Range& range) const
150 {
151 const int start = range.start;
152 const int end = range.end;
153 cv::Mat dst = conv.mImg.getMat();
154
155 for (unsigned int t = start; t < end; t++)
156 {
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))
159 continue;
160
161 FT_BitmapGlyph gbmp = (FT_BitmapGlyph)dGlyph.glyph;
162 FT_Bitmap* bmp = &gbmp->bitmap;
163
164 dGlyph.pos.y -= gbmp->top;
165 dGlyph.pos.x += gbmp->left;
166
167 if (!bmp || !bmp->buffer)
168 continue;
169
170 for (int row = 0; row < bmp->rows; row++)
171 {
172 if (dGlyph.pos.y + row < 0)
173 continue;
174
175 if (dGlyph.pos.y + row >= dst.rows)
176 break;
177
178 for (int col = 0; col < bmp->pitch; col++)
179 {
180 int cl = bmp->buffer[row * bmp->pitch + col];
181 if (cl == 0)
182 continue;
183
184 for (int bit = 7; bit >= 0; bit--)
185 {
186 if (dGlyph.pos.x + col * 8 + (7 - bit) < 0)
187 continue;
188
189 if (dGlyph.pos.x + col * 8 + (7 - bit) >= dst.cols)
190 break;
191
192 if (((cl >> bit) & 0x01) == 1)
193 {
194 if (conv.mImg.channels() == 3)
195 {
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];
200 }
201 else
202 {
203 uint8_t* ptr = dst.ptr<uint8_t>(dGlyph.pos.y + row, dGlyph.pos.x + col * 8 + (7 - bit));
204 (*ptr) = conv.mColor[0];
205 }
206 }
207 }
208 }
209 }
210 FTC_Node_Unref(dGlyph.anode, *dGlyph.manager);
211 }
212 }
213
214 private:
215 blitMono& operator=(const blitMono&);
216 const blitBuffer conv;
217 };
218
219 class blitBlend : public cv::ParallelLoopBody
220 {
221 public:
222 blitBlend(const blitBuffer _conv)
223 : conv(_conv)
224 {}
225
226 void operator()(const cv::Range& range) const
227 {
228 const int start = range.start;
229 const int end = range.end;
230 cv::Mat dst = conv.mImg.getMat();
231
232 for (unsigned int t = start; t < end; t++)
233 {
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))
236 continue;
237
238 FT_BitmapGlyph gbmp = (FT_BitmapGlyph)dGlyph.glyph;
239 FT_Bitmap* bmp = &gbmp->bitmap;
240
241 dGlyph.pos.y -= gbmp->top;
242 dGlyph.pos.x += gbmp->left;
243
244 if (!bmp || !bmp->buffer)
245 continue;
246
247 for (int row = 0; row < bmp->rows; row++)
248 {
249 if (dGlyph.pos.y + row < 0)
250 continue;
251
252 if (dGlyph.pos.y + row >= dst.rows)
253 break;
254
255 for (int col = 0; col < bmp->pitch; col++)
256 {
257 int cl = bmp->buffer[row * bmp->pitch + col];
258 if (cl == 0)
259 continue;
260
261 if (dGlyph.pos.x + col < 0)
262 continue;
263
264 if (dGlyph.pos.x + col >= dst.cols)
265 break;
266
267 double blendAlpha = (double)cl / 255.0;
268 if (conv.mImg.channels() == 3)
269 {
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);
274 }
275 else
276 {
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);
279 }
280 }
281 }
282 FTC_Node_Unref(dGlyph.anode, *dGlyph.manager);
283 }
284 }
285
286 private:
287 blitBlend& operator=(const blitBlend&);
288 const blitBuffer conv;
289 };
290
291 FreeTypeFontImpl::FreeTypeFontImpl()
292 {
293 FT_Init_FreeType(&(this->mLibrary));
294 mHbBuffer = hb_buffer_create();
295
296 mCtoL = 16;
297 mFn.shift = 0;
298 mFn.delta = 0;
299 mFn.move_to = FreeTypeFontImpl::mvFn;
300 mFn.line_to = FreeTypeFontImpl::lnFn;
301 mFn.cubic_to = FreeTypeFontImpl::cuFn;
302 mFn.conic_to = FreeTypeFontImpl::coFn;
303 mHb_font = NULL;
304 mFontData = NULL;
305
306 FTC_Manager_New(mLibrary, 1, 0, 0 /*1024 * 1024*/, Face_Requester, this, &mFtcManager);
307 FTC_ImageCache_New(mFtcManager, &mImageCache);
308
309 mIsFaceAvailable = false;
310 }
311
312 FreeTypeFontImpl::~FreeTypeFontImpl()
313 {
314 hb_buffer_destroy(mHbBuffer);
315 if (mIsFaceAvailable == true)
316 {
317 hb_font_destroy(mHb_font);
318 // Do not use FT_Done_Face(mFace) here, the following FTC_Manager_Done will delete the font and may crash if the font is already deleted
319 mIsFaceAvailable = false;
320 }
321 FTC_Manager_Done(mFtcManager);
322 CV_Assert(!FT_Done_FreeType(mLibrary));
323
324 if (mFontData != 0)
325 delete[] mFontData;
326 }
327
328 FT_Error FreeTypeFontImpl::Face_Requester(FTC_FaceID face_id, FT_Library library, FT_Pointer req_data, FT_Face *aface)
329 {
330 FreeTypeFontImpl *impl = static_cast<FreeTypeFontImpl *>(req_data);
331 *aface = impl->mFace;
332 return 0;
333 }
334
335 bool FreeTypeFontImpl::loadFontData(String fontFileName, int idx)
336 {
337 if (mIsFaceAvailable == true)
338 {
339 hb_font_destroy(mHb_font);
340 CV_Assert(!FT_Done_Face(mFace));
341
342 if (mFontData != NULL)
343 {
344 delete[] mFontData;
345 mFontData = NULL;
346 }
347 mIsFaceAvailable = false;
348 }
349#ifdef ANDROID
350 std::stringstream stream(std::stringstream::in|std::stringstream::out|std::stringstream::binary);
351 if (!SCfopenStream(fontFileName.c_str(), stream))
352 return false;
353
354 // get length of file:
355 stream.seekg(0, stream.end);
356 int length = stream.tellg();
357 stream.seekg(0, stream.beg);
358
359 mFontData = new char[length];
360 stream.read(mFontData, length);
361
362 if (!loadFontData((FT_Byte*)mFontData, (FT_Long)length, 0))
363 {
364 if (mFontData != NULL)
365 {
366 delete[] mFontData;
367 mFontData = NULL;
368 }
369 return false;
370 }
371 else
372 return true;
373#else
374 if (FT_New_Face(mLibrary, fontFileName.c_str(), idx, &(mFace)) != 0)
375 {
376 mIsFaceAvailable = false;
377 mHb_font = NULL;
378 return false;
379 }
380
381 mHb_font = hb_ft_font_create(mFace, NULL);
382 if (mHb_font == NULL)
383 {
384 mIsFaceAvailable = false;
385 return false;
386 }
387
388 mIsFaceAvailable = true;
389 return true;
390#endif
391 }
392
393 bool FreeTypeFontImpl::loadFontData(const FT_Byte* fontData, FT_Long fontDataSize, int idx)
394 {
395 if (mIsFaceAvailable == true)
396 {
397 hb_font_destroy(mHb_font);
398 CV_Assert(!FT_Done_Face(mFace));
399
400 if (mFontData != NULL)
401 {
402 delete[] mFontData;
403 mFontData = NULL;
404 }
405 }
406
407 if (FT_New_Memory_Face(mLibrary, fontData, fontDataSize, idx, &(mFace)) != 0)
408 {
409 mIsFaceAvailable = false;
410 mHb_font = NULL;
411 return false;
412 }
413
414 mHb_font = hb_ft_font_create(mFace, NULL);
415 if (mHb_font == NULL)
416 {
417 mIsFaceAvailable = false;
418 return false;
419 }
420
421 mIsFaceAvailable = true;
422 return true;
423 }
424
425 void FreeTypeFontImpl::setSplitNumber(int num)
426 {
427 CV_Assert(num > 0);
428 mCtoL = num;
429 }
430
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
435 )
436 {
437 CV_Assert(mIsFaceAvailable == true);
438 CV_Assert((_img.empty() == false) &&
439 (_img.isMat() == true) &&
440 (_img.depth() == CV_8U) &&
441 (_img.dims() == 2));
442 CV_Assert((_line_type == CV_AA) ||
443 (_line_type == 4) ||
444 (_line_type == 8));
445 CV_Assert(_fontHeight >= 0);
446
447 if (_text.empty())
448 return;
449
450 std::string text = to_utf8(_text);
451
452 if (_fontHeight == 0)
453 return;
454
455 if (_line_type == CV_AA && _img.depth() != CV_8U)
456 {
457 _line_type = 8;
458 }
459
460 CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
461
462 if (_thickness < 0) // CV_FILLED
463 {
464 if (_line_type == CV_AA)
465 {
466 putTextBitmapBlend(_img, text, _org, _fontHeight, _color,
467 _thickness, _line_type, _bottomLeftOrigin);
468 }
469 else
470 {
471 putTextBitmapMono(_img, text, _org, _fontHeight, _color,
472 _thickness, _line_type, _bottomLeftOrigin);
473 }
474 }
475 else
476 {
477 putTextOutline(_img, text, _org, _fontHeight, _color,
478 _thickness, _line_type, _bottomLeftOrigin);
479 }
480 }
481
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)
486 {
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);
491
492 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(mHbBuffer, &textLen);
493 CV_Assert(info != NULL);
494
495 hb_shape(mHb_font, mHbBuffer, NULL, 0);
496
497 if (_bottomLeftOrigin == true)
498 _org.y -= _fontHeight;
499
500 PathUserData *userData = new PathUserData(_img);
501 userData->mColor = _color;
502 userData->mCtoL = mCtoL;
503 userData->mThickness = _thickness;
504 userData->mLine_type = _line_type;
505
506 mImageType.face_id = (FTC_FaceID)1;
507 mImageType.width = _fontHeight;
508 mImageType.height = _fontHeight;
509 mImageType.flags = FT_LOAD_DEFAULT;
510
511 for (unsigned int i = 0; i < textLen; i++)
512 {
513 FT_Glyph glyph;
514 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &glyph, nullptr));
515
516 FT_OutlineGlyph outlineglyph = (FT_OutlineGlyph)glyph;
517 FT_Outline outline;
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));
520
521 // Flip
522 FT_Matrix mtx = { 1 << 16 , 0 , 0 , -(1 << 16) };
523 FT_Outline_Transform(&outline, &mtx);
524
525 // Move
526 FT_Outline_Translate(&outline,
527 cOutlineOffset,
528 cOutlineOffset);
529
530 // Move
531 FT_Outline_Translate(&outline,
532 (FT_Pos)(_org.x << 6),
533 (FT_Pos)((_org.y + _fontHeight) << 6));
534
535 // Draw
536 CV_Assert(!FT_Outline_Decompose(&outline, &mFn, (void*)userData));
537
538 // Draw (Last Path)
539 mvFn(NULL, (void*)userData);
540
541 _org.x += (glyph->advance.x) >> 16;
542 _org.y += (glyph->advance.y) >> 16;
543
544 FT_Outline_Done(mLibrary, &outline);
545 }
546 delete userData;
547 }
548
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)
553 {
554 CV_Assert(_thickness < 0);
555
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);
562
563 hb_shape(mHb_font, mHbBuffer, NULL, 0);
564
565 _org.y += _fontHeight;
566 if (_bottomLeftOrigin == true)
567 _org.y -= _fontHeight;
568
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;
573
574 std::vector<drawGlyph> lGlyph;
575 for (unsigned int i = 0; i < textLen; i++)
576 {
577 drawGlyph dGlyph(_org, &mFtcManager);
578
579 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &dGlyph.glyph, &dGlyph.anode));
580 lGlyph.push_back(dGlyph);
581
582 _org.x += (dGlyph.glyph->advance.x) >> 16;
583 _org.y += (dGlyph.glyph->advance.y) >> 16;
584 }
585
586 blitBuffer conv(_img, lGlyph, _color);
587 cv::parallel_for_(cv::Range(0, lGlyph.size()), blitMono(conv));
588 }
589
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)
594 {
595 CV_Assert(_thickness < 0);
596
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);
603
604 hb_shape(mHb_font, mHbBuffer, NULL, 0);
605
606 _org.y += _fontHeight;
607 if (_bottomLeftOrigin == true)
608 _org.y -= _fontHeight;
609
610 mImageType.face_id = (FTC_FaceID)1;
611 mImageType.width = _fontHeight;
612 mImageType.height = _fontHeight;
613 mImageType.flags = FT_LOAD_RENDER;
614
615 std::vector<drawGlyph> lGlyph;
616 for (unsigned int i = 0; i < textLen; i++)
617 {
618 drawGlyph dGlyph(_org, &mFtcManager);
619
620 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &dGlyph.glyph, &dGlyph.anode));
621 lGlyph.push_back(dGlyph);
622
623 _org.x += (dGlyph.glyph->advance.x) >> 16;
624 _org.y += (dGlyph.glyph->advance.y) >> 16;
625 }
626
627 blitBuffer conv(_img, lGlyph, _color);
628 cv::parallel_for_(cv::Range(0, lGlyph.size()), blitBlend(conv));
629 }
630
631 Size FreeTypeFontImpl::getTextSize(
632 const String& _text,
633 int _fontHeight,
634 int _thickness,
635 CV_OUT int* _baseLine)
636 {
637 if (_text.empty())
638 return Size(0, 0);
639
640 CV_Assert(_fontHeight >= 0);
641 if (_fontHeight == 0)
642 return Size(0, 0);
643
644 CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
645
646 Point _org(0, 0);
647
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);
655
656 _org.y -= _fontHeight;
657 int xMin = INT_MAX, xMax = INT_MIN;
658 int yMin = INT_MAX, yMax = INT_MIN;
659
660 mImageType.face_id = (FTC_FaceID)1;
661 mImageType.width = _fontHeight;
662 mImageType.height = _fontHeight;
663 mImageType.flags = FT_LOAD_RENDER;
664
665 for (unsigned int i = 0; i < textLen; i++)
666 {
667 FT_Glyph glyph;
668 CV_Assert(!FTC_ImageCache_Lookup(mImageCache, &mImageType, info[i].codepoint, &glyph, nullptr));
669
670 if (glyph->format != FT_GLYPH_FORMAT_BITMAP)
671 FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
672
673 FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)glyph;
674
675 FT_Bitmap *bmp = &(glyph_bitmap->bitmap);
676
677 Point gPos = _org;
678
679 gPos.y -= glyph_bitmap->top;
680 gPos.x += glyph_bitmap->left;
681 int rows = bmp->rows;
682 int cols = bmp->pitch;
683
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);
688
689 _org.x += (glyph->advance.x) >> 16;
690 _org.y += (glyph->advance.y) >> 16;
691 }
692
693 int width = xMax - xMin;
694 int height = yMax - yMin;
695
696 if (_thickness > 0)
697 {
698 width = cvRound(width + _thickness * 2);
699 height = cvRound(height + _thickness * 1);
700 }
701 else
702 {
703 width = cvRound(width + 1);
704 height = cvRound(height + 1);
705 }
706
707 if (_baseLine)
708 *_baseLine = yMin;
709
710 return Size(width, height);
711 }
712
713 int FreeTypeFontImpl::mvFn(const FT_Vector *to, void * user)
714 {
715 if (user == NULL)
716 return 1;
717
718 PathUserData *p = (PathUserData*)user;
719
720 if (p->mPts.size() > 0)
721 {
722 Mat dst = p->mImg.getMat();
723 const Point *ptsList[] = { &(p->mPts[0]) };
724 int npt[1]; npt[0] = p->mPts.size();
725 polylines(
726 dst,
727 ptsList,
728 npt,
729 1,
730 false,
731 p->mColor,
732 p->mThickness,
733 p->mLine_type,
734 0
735 );
736 }
737
738 p->mPts.clear();
739
740 if (to == NULL)
741 return 1;
742
743 p->mPts.push_back(Point(ftd(to->x), ftd(to->y)));
744 p->mOldP = *to;
745 return 0;
746 }
747
748 int FreeTypeFontImpl::lnFn(const FT_Vector *to, void * user)
749 {
750 if (to == NULL)
751 return 1;
752 if (user == NULL)
753 return 1;
754
755 PathUserData *p = (PathUserData *)user;
756 p->mPts.push_back(Point(ftd(to->x), ftd(to->y)));
757 p->mOldP = *to;
758 return 0;
759 }
760
761 int FreeTypeFontImpl::coFn(const FT_Vector *cnt,
762 const FT_Vector *to,
763 void * user)
764 {
765 if (cnt == NULL)
766 return 1;
767
768 if (to == NULL)
769 return 1;
770
771 if (user == NULL)
772 return 1;
773
774 PathUserData *p = (PathUserData *)user;
775
776 // Bezier to Line
777 for (int i = 0; i <= p->mCtoL; i++)
778 {
779 double u = (double)i * 1.0 / (p->mCtoL);
780 double nu = 1.0 - u;
781 double p0 = nu * nu;
782 double p1 = 2.0 * u * nu;
783 double p2 = u * u;
784
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)));
788 }
789 p->mOldP = *to;
790 return 0;
791 }
792
793 int FreeTypeFontImpl::cuFn(const FT_Vector *cnt1,
794 const FT_Vector *cnt2,
795 const FT_Vector *to,
796 void * user)
797 {
798 if (cnt1 == NULL)
799 return 1;
800
801 if (cnt2 == NULL)
802 return 1;
803
804 if (to == NULL)
805 return 1;
806
807 if (user == NULL)
808 return 1;
809
810 PathUserData *p = (PathUserData *)user;
811
812 // Bezier to Line
813 for (int i = 0; i <= p->mCtoL; i++)
814 {
815 double u = (double)i * 1.0 / (p->mCtoL);
816 double nu = 1.0 - u;
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;
821
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;
826
827 p->mPts.push_back(Point(ftd(X), ftd(Y)));
828 }
829 p->mOldP = *to;
830 return 0;
831 }
832
833 Ptr<FreeTypeFont> createFreeTypeFont()
834 {
835 return Ptr<FreeTypeFontImpl>(new FreeTypeFontImpl());
836 }
837
838 }
839} // namespace freetype2
Ptr< FreeTypeFont > createFreeTypeFont()
Create FreeType2 Instance.