|
|
|
@ -18,6 +18,77 @@ namespace cv {
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if (('1234' >> 24) == '1')
|
|
|
|
|
#elif (('4321' >> 24) == '1')
|
|
|
|
|
#define BIG_ENDIAN
|
|
|
|
|
#else
|
|
|
|
|
#error "Couldn't determine the endianness!"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct Vec2
|
|
|
|
|
{
|
|
|
|
|
Vec2() { }
|
|
|
|
|
Vec2(float a, float b)
|
|
|
|
|
: x(a), y(b) { }
|
|
|
|
|
|
|
|
|
|
float x, y;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Rect
|
|
|
|
|
{
|
|
|
|
|
Rect() { }
|
|
|
|
|
Rect(float left, float top, float right, float bottom)
|
|
|
|
|
: xmin(left), xmax(right), ymin(top), ymax(bottom) { }
|
|
|
|
|
|
|
|
|
|
void Include(const Vec2 &r)
|
|
|
|
|
{
|
|
|
|
|
xmin = MIN(xmin, r.x);
|
|
|
|
|
ymin = MIN(ymin, r.y);
|
|
|
|
|
xmax = MAX(xmax, r.x);
|
|
|
|
|
ymax = MAX(ymax, r.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float Width() const { return xmax - xmin + 1; }
|
|
|
|
|
float Height() const { return ymax - ymin + 1; }
|
|
|
|
|
|
|
|
|
|
float xmin, xmax, ymin, ymax;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A horizontal pixel span generated by the FreeType renderer.
|
|
|
|
|
|
|
|
|
|
struct Span
|
|
|
|
|
{
|
|
|
|
|
Span() { }
|
|
|
|
|
Span(int _x, int _y, int _width, int _coverage)
|
|
|
|
|
: x(_x), y(_y), width(_width), coverage(_coverage) { }
|
|
|
|
|
|
|
|
|
|
int x, y, width, coverage;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef std::vector<Span> Spans;
|
|
|
|
|
|
|
|
|
|
// Each time the renderer calls us back we just push another span entry on
|
|
|
|
|
// our list.
|
|
|
|
|
void RasterCallback(const int y, const int count, const FT_Span * const spans, void * const user)
|
|
|
|
|
{
|
|
|
|
|
Spans *sptr = (Spans *)user;
|
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
|
sptr->push_back(Span(spans[i].x, y, spans[i].len, spans[i].coverage));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set up the raster parameters and render the outline.
|
|
|
|
|
void RenderSpans(FT_Library &library, FT_Outline * const outline, Spans *spans)
|
|
|
|
|
{
|
|
|
|
|
FT_Raster_Params params;
|
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
|
|
|
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
|
|
|
|
|
params.gray_spans = RasterCallback;
|
|
|
|
|
params.user = spans;
|
|
|
|
|
|
|
|
|
|
FT_Outline_Render(library, outline, ¶ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FreeType2Impl : public FreeType2
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
@ -30,10 +101,7 @@ namespace cv {
|
|
|
|
|
int fontHeight, Scalar color,
|
|
|
|
|
int thickness, int line_type, bool bottomLeftOrigin
|
|
|
|
|
);
|
|
|
|
|
Size getTextSize(
|
|
|
|
|
const String& text, int fontHeight, int thickness,
|
|
|
|
|
CV_OUT int* baseLine
|
|
|
|
|
);
|
|
|
|
|
Size getTextSize(const String& text, int fontHeight, int thickness, CV_OUT int* baseLine);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
FT_Library mLibrary;
|
|
|
|
@ -61,6 +129,12 @@ namespace cv {
|
|
|
|
|
int thickness, int line_type, bool bottomLeftOrigin
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
void putTextStroker(
|
|
|
|
|
InputOutputArray img, const String& text, Point org,
|
|
|
|
|
int fontHeight, Scalar color,
|
|
|
|
|
int thickness, int line_type, bool bottomLeftOrigin
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
typedef void (putPixel_mono_fn)(Mat& _dst, const int _py, const int _px, const uint8_t *_col);
|
|
|
|
|
putPixel_mono_fn putPixel_8UC1_mono;
|
|
|
|
|
putPixel_mono_fn putPixel_8UC3_mono;
|
|
|
|
@ -73,13 +147,8 @@ namespace cv {
|
|
|
|
|
|
|
|
|
|
static int mvFn(const FT_Vector *to, void * user);
|
|
|
|
|
static int lnFn(const FT_Vector *to, void * user);
|
|
|
|
|
static int coFn(const FT_Vector *cnt,
|
|
|
|
|
const FT_Vector *to,
|
|
|
|
|
void * user);
|
|
|
|
|
static int cuFn(const FT_Vector *cnt1,
|
|
|
|
|
const FT_Vector *cnt2,
|
|
|
|
|
const FT_Vector *to,
|
|
|
|
|
void * user);
|
|
|
|
|
static int coFn(const FT_Vector *cnt, const FT_Vector *to, void * user);
|
|
|
|
|
static int cuFn(const FT_Vector *cnt1, const FT_Vector *cnt2, const FT_Vector *to, void * user);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert from FT_F26Dot6 to int(coodinate of OpenCV)
|
|
|
|
@ -160,6 +229,7 @@ namespace cv {
|
|
|
|
|
}
|
|
|
|
|
CV_Assert(mHb_font != NULL);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
mIsFaceAvailable = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -209,8 +279,8 @@ namespace cv {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
putTextOutline(_img, _text, _org, _fontHeight, _color,
|
|
|
|
|
_thickness, _line_type, _bottomLeftOrigin);
|
|
|
|
|
// putTextOutline(_img, _text, _org, _fontHeight, _color, _thickness, _line_type, _bottomLeftOrigin);
|
|
|
|
|
putTextStroker(_img, _text, _org, _fontHeight, _color, _thickness, _line_type, _bottomLeftOrigin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -267,9 +337,7 @@ namespace cv {
|
|
|
|
|
FT_Outline_Transform(&outline, &mtx);
|
|
|
|
|
|
|
|
|
|
// Move to current position ( in FreeType coordinates )
|
|
|
|
|
FT_Outline_Translate(&outline,
|
|
|
|
|
currentPos.x,
|
|
|
|
|
currentPos.y);
|
|
|
|
|
FT_Outline_Translate(&outline, currentPos.x, currentPos.y);
|
|
|
|
|
|
|
|
|
|
// Draw ( in FreeType coordinates )
|
|
|
|
|
CV_Assert(!FT_Outline_Decompose(&outline, &mFn, (void*)userData));
|
|
|
|
@ -282,6 +350,262 @@ namespace cv {
|
|
|
|
|
currentPos.y += mFace->glyph->advance.y;
|
|
|
|
|
}
|
|
|
|
|
delete userData;
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
hb_buffer_destroy(hb_buffer);
|
|
|
|
|
#endif 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FreeType2Impl::putTextStroker(
|
|
|
|
|
InputOutputArray _img, const String& _text, Point _org,
|
|
|
|
|
int _fontHeight, Scalar _color,
|
|
|
|
|
int _thickness, int _line_type, bool _bottomLeftOrigin)
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
hb_buffer_t *hb_buffer = hb_buffer_create();
|
|
|
|
|
CV_Assert(hb_buffer != NULL);
|
|
|
|
|
|
|
|
|
|
hb_buffer_add_utf8(hb_buffer, _text.c_str(), -1, 0, -1);
|
|
|
|
|
hb_buffer_guess_segment_properties(hb_buffer);
|
|
|
|
|
hb_shape(mHb_font, hb_buffer, NULL, 0);
|
|
|
|
|
|
|
|
|
|
unsigned int textLen = 0;
|
|
|
|
|
hb_glyph_info_t *info =
|
|
|
|
|
hb_buffer_get_glyph_infos(hb_buffer, &textLen);
|
|
|
|
|
CV_Assert(info != NULL);
|
|
|
|
|
#else
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
|
|
|
|
wstring wstr = converter.from_bytes(_text);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Mat& mat = _img.getMatRef();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
PathUserData *userData = new PathUserData(_img);
|
|
|
|
|
userData->mColor = _color;
|
|
|
|
|
userData->mCtoL = mCtoL;
|
|
|
|
|
userData->mThickness = _thickness;
|
|
|
|
|
userData->mLine_type = _line_type;
|
|
|
|
|
*/
|
|
|
|
|
int offsetY = 0;
|
|
|
|
|
int imgHeight = mat.rows;
|
|
|
|
|
// Initilize currentPosition ( in FreeType coordinates)
|
|
|
|
|
FT_Vector currentPos = { 0,0 };
|
|
|
|
|
currentPos.x = _org.x * 64;
|
|
|
|
|
currentPos.y = _org.y * 64;
|
|
|
|
|
|
|
|
|
|
// Update currentPosition with bottomLeftOrigin ( in FreeType coordinates)
|
|
|
|
|
if (_bottomLeftOrigin != true) {
|
|
|
|
|
currentPos.y += _fontHeight * 64;
|
|
|
|
|
currentPos.y = imgHeight * 64 - currentPos.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// To Freetype coordinates
|
|
|
|
|
|
|
|
|
|
FT_BBox bbox, glyph_bbox;
|
|
|
|
|
|
|
|
|
|
FT_Vector pen{ 0, 0 };
|
|
|
|
|
bbox.xMin = bbox.yMin = 32000;
|
|
|
|
|
bbox.xMax = bbox.yMax = -32000;
|
|
|
|
|
|
|
|
|
|
// Get some metrics of our image.
|
|
|
|
|
// int imgWidth = mat.cols;
|
|
|
|
|
|
|
|
|
|
cv::Vec3b outlineColor = cv::Vec3b(255 - (uchar)_color[0], 255 - (uchar)_color[1], 255 - (uchar)_color[2]);
|
|
|
|
|
cv::Vec3b fontColor = cv::Vec3b((uchar)_color[0], (uchar)_color[1], (uchar)_color[2]);
|
|
|
|
|
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
for (unsigned int i = 0; i < textLen; i++)
|
|
|
|
|
{
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, info[i].codepoint, 0));
|
|
|
|
|
#else
|
|
|
|
|
for (unsigned int i = 0; i < wstr.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
FT_Set_Transform(mFace, 0, &pen);
|
|
|
|
|
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, FT_Get_Char_Index(mFace, wstr[i]), FT_LOAD_RENDER));
|
|
|
|
|
#endif
|
|
|
|
|
FT_GlyphSlot slot = mFace->glyph;
|
|
|
|
|
|
|
|
|
|
FT_Glyph glyph = NULL;
|
|
|
|
|
int error = FT_Get_Glyph(mFace->glyph, &glyph);
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
printf("FT_Get_Glyph error!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
|
|
|
|
|
|
|
|
|
|
if (glyph_bbox.xMin < bbox.xMin)
|
|
|
|
|
bbox.xMin = glyph_bbox.xMin;
|
|
|
|
|
if (glyph_bbox.yMin < bbox.yMin)
|
|
|
|
|
bbox.yMin = glyph_bbox.yMin;
|
|
|
|
|
if (glyph_bbox.xMax > bbox.xMax)
|
|
|
|
|
bbox.xMax = glyph_bbox.xMax;
|
|
|
|
|
if (glyph_bbox.yMax > bbox.yMax)
|
|
|
|
|
bbox.yMax = glyph_bbox.yMax;
|
|
|
|
|
|
|
|
|
|
pen.x += slot->advance.x;
|
|
|
|
|
pen.y += slot->advance.y;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentPos.x -= bbox.xMin * 64;
|
|
|
|
|
currentPos.y -= bbox.yMax * 64;
|
|
|
|
|
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
for (unsigned int i = 0; i < textLen; i++)
|
|
|
|
|
{
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, info[i].codepoint, 0));
|
|
|
|
|
#else
|
|
|
|
|
for (unsigned int i = 0; i < wstr.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
// if (_bottomLeftOrigin != true)
|
|
|
|
|
{
|
|
|
|
|
FT_Set_Transform(mFace, 0, ¤tPos);
|
|
|
|
|
}
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, FT_Get_Char_Index(mFace, wstr[i]), FT_LOAD_NO_BITMAP));
|
|
|
|
|
#endif
|
|
|
|
|
FT_GlyphSlot slot = mFace->glyph;
|
|
|
|
|
FT_Outline outline = slot->outline;
|
|
|
|
|
|
|
|
|
|
// Flip ( in FreeType coordinates )
|
|
|
|
|
FT_Matrix mtx = { 1 << 16 , 0 , 0 , -(1 << 16) };
|
|
|
|
|
// FT_Outline_Transform(&outline, &mtx);
|
|
|
|
|
|
|
|
|
|
// Move to current position ( in FreeType coordinates )
|
|
|
|
|
FT_Outline_Translate(&outline, currentPos.x, currentPos.y);
|
|
|
|
|
|
|
|
|
|
Spans spans;
|
|
|
|
|
RenderSpans(mLibrary, &outline, &spans);
|
|
|
|
|
|
|
|
|
|
// Next we need the spans for the outline.
|
|
|
|
|
Spans outlineSpans;
|
|
|
|
|
|
|
|
|
|
// Set up a stroker.
|
|
|
|
|
FT_Stroker stroker = NULL;
|
|
|
|
|
FT_Stroker_New(mLibrary, &stroker);
|
|
|
|
|
FT_Stroker_Set(stroker, (int)(_thickness * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
|
|
|
|
|
|
|
|
|
|
FT_Glyph glyph = NULL;
|
|
|
|
|
if (FT_Get_Glyph(slot, &glyph) == 0)
|
|
|
|
|
{
|
|
|
|
|
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);
|
|
|
|
|
|
|
|
|
|
FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
|
|
|
|
|
// Again, this needs to be an outline to work.
|
|
|
|
|
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
|
|
|
{
|
|
|
|
|
// Render the outline spans to the span list
|
|
|
|
|
FT_Outline *o = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
|
|
|
RenderSpans(mLibrary, o, &outlineSpans);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up afterwards.
|
|
|
|
|
FT_Stroker_Done(stroker);
|
|
|
|
|
FT_Done_Glyph(glyph);
|
|
|
|
|
|
|
|
|
|
// Now we need to put it all together.
|
|
|
|
|
if (!spans.empty())
|
|
|
|
|
{
|
|
|
|
|
// Figure out what the bounding rect is for both the span lists.
|
|
|
|
|
Rect rect(spans.front().x, spans.front().y, spans.front().x, spans.front().y);
|
|
|
|
|
for (Spans::iterator s = spans.begin(); s != spans.end(); ++s)
|
|
|
|
|
{
|
|
|
|
|
rect.Include(Vec2(s->x, s->y));
|
|
|
|
|
rect.Include(Vec2(s->x + s->width - 1, s->y));
|
|
|
|
|
}
|
|
|
|
|
for (Spans::iterator s = outlineSpans.begin(); s != outlineSpans.end(); ++s)
|
|
|
|
|
{
|
|
|
|
|
rect.Include(Vec2(s->x, s->y));
|
|
|
|
|
rect.Include(Vec2(s->x + s->width - 1, s->y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float bearingX = slot->metrics.horiBearingX >> 6;
|
|
|
|
|
float bearingY = slot->metrics.horiBearingY >> 6;
|
|
|
|
|
float advance = slot->advance.x >> 6;
|
|
|
|
|
|
|
|
|
|
// Allocate data for our image and clear it out to transparent.
|
|
|
|
|
// Pixel32 *pxl = new Pixel32[imgSize];
|
|
|
|
|
// memset(pxl, 0, sizeof(Pixel32) * imgSize);
|
|
|
|
|
|
|
|
|
|
offsetY = ((bbox.yMax - bbox.yMin) - ((glyph_bbox.yMax - glyph_bbox.yMin))) / 2;
|
|
|
|
|
// offsetY = ((bbox.yMax) - (glyph_bbox.yMax >> 6)) / 2;
|
|
|
|
|
// Loop over the outline spans and just draw them into the
|
|
|
|
|
// image.
|
|
|
|
|
for (Spans::iterator s = outlineSpans.begin(); s != outlineSpans.end(); ++s)
|
|
|
|
|
{
|
|
|
|
|
for (int w = 0; w < s->width; ++w)
|
|
|
|
|
{
|
|
|
|
|
// int row = (imgHeight - 1 - (s->y - rect.ymin)) - imgHeight + (rect.ymax - rect.ymin);
|
|
|
|
|
// int row = (imgHeight - 1 - (s->y - rect.ymin));
|
|
|
|
|
int row = (bbox.yMax - bbox.yMin) - (s->y - rect.ymin) + _org.y - offsetY;
|
|
|
|
|
// int row = ((bbox.yMax - bbox.yMin) - (glyph_bbox.yMax - glyph_bbox.yMin)) / 2 - (s->y - rect.ymin) + _org.y;
|
|
|
|
|
// mat.at<Vec3b>((imgHeight - 1 - (s->y - rect.ymin)), s->x - rect.xmin + w) = outlineColor;
|
|
|
|
|
mat.at<Vec3b>(row, s->x - rect.xmin + w + _org.x + bearingX) = outlineColor;
|
|
|
|
|
// mat.at<Vec3b>(-(s->y - rect.ymin), s->x - rect.xmin + w) = outlineColor;
|
|
|
|
|
// vec3b.
|
|
|
|
|
/*
|
|
|
|
|
pxl[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth
|
|
|
|
|
+ s->x - rect.xmin + w)] =
|
|
|
|
|
Pixel32(outlineCol.r, outlineCol.g, outlineCol.b,
|
|
|
|
|
s->coverage);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Then loop over the regular glyph spans and blend them into
|
|
|
|
|
// the image.
|
|
|
|
|
for (Spans::iterator s = spans.begin(); s != spans.end(); ++s)
|
|
|
|
|
{
|
|
|
|
|
for (int w = 0; w < s->width; ++w)
|
|
|
|
|
{
|
|
|
|
|
// int row = (imgHeight - 1 - (s->y - rect.ymin)) - imgHeight + (rect.ymax - rect.ymin);
|
|
|
|
|
int row = (bbox.yMax - bbox.yMin) - (s->y - rect.ymin) + _org.y - offsetY;
|
|
|
|
|
// int row = ((bbox.yMax - bbox.yMin) - (glyph_bbox.yMax - glyph_bbox.yMin)) / 2 - (s->y - rect.ymin) + _org.y;
|
|
|
|
|
mat.at<Vec3b>(row, s->x - rect.xmin + w + _org.x + bearingX) = fontColor;
|
|
|
|
|
// mat.at<Vec3b>(-(s->y - rect.ymin), s->x - rect.xmin + w) = fontColor;
|
|
|
|
|
#if 0
|
|
|
|
|
Pixel32 &dst =
|
|
|
|
|
pxl[(int)(
|
|
|
|
|
(imgHeight - 1 - (s->y - rect.ymin)) * imgWidth
|
|
|
|
|
+ s->x - rect.xmin + w)];
|
|
|
|
|
Pixel32 src = Pixel32(fontCol.r, fontCol.g, fontCol.b,
|
|
|
|
|
s->coverage);
|
|
|
|
|
dst.r = (int)(dst.r + ((src.r - dst.r) * src.a) / 255.0f);
|
|
|
|
|
dst.g = (int)(dst.g + ((src.g - dst.g) * src.a) / 255.0f);
|
|
|
|
|
dst.b = (int)(dst.b + ((src.b - dst.b) * src.a) / 255.0f);
|
|
|
|
|
dst.a = MIN(255, dst.a + src.a);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// This is unused in this test but you would need this to draw
|
|
|
|
|
// more than one glyph.
|
|
|
|
|
float bearingX = face->glyph->metrics.horiBearingX >> 6;
|
|
|
|
|
float bearingY = face->glyph->metrics.horiBearingY >> 6;
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
// Update current position ( in FreeType coordinates )
|
|
|
|
|
|
|
|
|
|
float advance = mFace->glyph->advance.x >> 6;
|
|
|
|
|
currentPos.x += mFace->glyph->advance.x >> 6;
|
|
|
|
|
currentPos.y += mFace->glyph->advance.y >> 6;
|
|
|
|
|
// currentPos.x += mFace->glyph->metrics.horiBearingX >> 6;
|
|
|
|
|
// currentPos.y += mFace->glyph->metrics.horiBearingY >> 6;
|
|
|
|
|
|
|
|
|
|
// currentPos.x += mFace->glyph->metrics.horiBearingX;
|
|
|
|
|
// currentPos.y += mFace->glyph->metrics.horiBearingY;
|
|
|
|
|
// break;
|
|
|
|
|
_org.x += mFace->glyph->advance.x >> 6;
|
|
|
|
|
_org.y += mFace->glyph->advance.y >> 6;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
hb_buffer_destroy(hb_buffer);
|
|
|
|
|
#endif 0
|
|
|
|
@ -614,6 +938,14 @@ namespace cv {
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, info[i].codepoint, 0));
|
|
|
|
|
#else
|
|
|
|
|
for (unsigned int i = 0; i < wstr.size(); i++) {
|
|
|
|
|
if (wstr[i] == '\r' || wstr[i] == '\n')
|
|
|
|
|
{
|
|
|
|
|
// xMin = cv::min(xMin, ftd(bbox.xMin));
|
|
|
|
|
// xMax = cv::max(xMax, ftd(bbox.xMax));
|
|
|
|
|
// yMin = cv::min(yMin, ftd(bbox.yMin));
|
|
|
|
|
// yMax = cv::max(yMax, currentPos.y + (mFace->glyph->advance.y));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
CV_Assert(!FT_Load_Glyph(mFace, FT_Get_Char_Index(mFace, wstr[i]), 0));
|
|
|
|
|
#endif
|
|
|
|
|
FT_GlyphSlot slot = mFace->glyph;
|
|
|
|
@ -625,9 +957,7 @@ namespace cv {
|
|
|
|
|
FT_Outline_Transform(&outline, &mtx);
|
|
|
|
|
|
|
|
|
|
// Move to current position ( in FreeType coordinates )
|
|
|
|
|
FT_Outline_Translate(&outline,
|
|
|
|
|
currentPos.x,
|
|
|
|
|
currentPos.y);
|
|
|
|
|
FT_Outline_Translate(&outline, currentPos.x, currentPos.y);
|
|
|
|
|
|
|
|
|
|
// Get BoundaryBox ( in FreeType coordinatrs )
|
|
|
|
|
CV_Assert(!FT_Outline_Get_BBox(&outline, &bbox));
|
|
|
|
@ -637,7 +967,8 @@ namespace cv {
|
|
|
|
|
if (
|
|
|
|
|
(bbox.xMin == 0) && (bbox.xMax == 0) &&
|
|
|
|
|
(bbox.yMin == 0) && (bbox.yMax == 0)
|
|
|
|
|
) {
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
bbox.xMin = currentPos.x;
|
|
|
|
|
bbox.xMax = currentPos.x + (mFace->glyph->advance.x);
|
|
|
|
|
bbox.yMin = yMin;
|
|
|
|
|