|
|
|
@ -397,12 +397,13 @@ namespace cv {
|
|
|
|
|
int offsetY = 0;
|
|
|
|
|
int imgHeight = mat.rows;
|
|
|
|
|
// Initilize currentPosition ( in FreeType coordinates)
|
|
|
|
|
FT_Vector currentPos = { 0,0 };
|
|
|
|
|
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) {
|
|
|
|
|
if (_bottomLeftOrigin != true)
|
|
|
|
|
{
|
|
|
|
|
currentPos.y += _fontHeight * 64;
|
|
|
|
|
currentPos.y = imgHeight * 64 - currentPos.y;
|
|
|
|
|
}
|
|
|
|
@ -468,11 +469,9 @@ namespace cv {
|
|
|
|
|
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;
|
|
|
|
@ -531,8 +530,8 @@ namespace cv {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float bearingX = slot->metrics.horiBearingX >> 6;
|
|
|
|
|
float bearingY = slot->metrics.horiBearingY >> 6;
|
|
|
|
|
float advance = slot->advance.x >> 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];
|
|
|
|
@ -543,14 +542,18 @@ namespace cv {
|
|
|
|
|
// 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;
|
|
|
|
|
if (row < 0 || row >= imgHeight)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (int w = 0; w < s->width; ++w)
|
|
|
|
|
{
|
|
|
|
|
int col = s->x - rect.xmin + w + _org.x + bearingX;
|
|
|
|
|
if (row < 0 || col < 0 || row >= imgHeight || col >= imgWidth)
|
|
|
|
|
if (col < 0 || col >= imgWidth)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
@ -571,18 +574,23 @@ namespace cv {
|
|
|
|
|
// 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;
|
|
|
|
|
if (row < 0 || row >= imgHeight)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (int w = 0; w < s->width; ++w)
|
|
|
|
|
{
|
|
|
|
|
// int col = s->x - rect.xmin + w + _org.x + bearingX;
|
|
|
|
|
int col = s->x - rect.xmin + w + _org.x + bearingX;
|
|
|
|
|
if (row < 0 || col < 0 || row >= imgHeight || col >= imgWidth)
|
|
|
|
|
if (col < 0 || col >= imgWidth)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 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>(row, col) = fontColor;
|
|
|
|
|
// mat.at<Vec3b>(-(s->y - rect.ymin), s->x - rect.xmin + w) = fontColor;
|
|
|
|
|
#if 0
|
|
|
|
|
Pixel32 &dst =
|
|
|
|
@ -612,15 +620,15 @@ namespace cv {
|
|
|
|
|
// 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->advance.x + mFace->glyph->bitmap_left;
|
|
|
|
|
currentPos.y += mFace->glyph->advance.y;
|
|
|
|
|
// 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.x += (mFace->glyph->advance.x + mFace->glyph->bitmap_left) >> 6;
|
|
|
|
|
_org.y += mFace->glyph->advance.y >> 6;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
@ -630,6 +638,124 @@ namespace cv {
|
|
|
|
|
#endif 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Size FreeType2Impl::getTextSize(
|
|
|
|
|
const String& _text,
|
|
|
|
|
int _fontHeight,
|
|
|
|
|
int _thickness,
|
|
|
|
|
CV_OUT int* _baseLine)
|
|
|
|
|
{
|
|
|
|
|
if (_text.empty())
|
|
|
|
|
{
|
|
|
|
|
return Size(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CV_Assert(_fontHeight >= 0);
|
|
|
|
|
if (_fontHeight == 0)
|
|
|
|
|
{
|
|
|
|
|
return Size(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
|
|
|
|
|
|
|
|
|
|
FT_Vector currentPos = { 0,0 };
|
|
|
|
|
FT_Set_Transform(mFace, 0, ¤tPos);
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
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
|
|
|
|
|
// Initilize BoundaryBox ( in OpenCV coordinates )
|
|
|
|
|
int xMin = INT_MAX, yMin = INT_MAX;
|
|
|
|
|
int xMax = INT_MIN, yMax = INT_MIN;
|
|
|
|
|
|
|
|
|
|
#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 (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;
|
|
|
|
|
FT_Outline outline = slot->outline;
|
|
|
|
|
FT_BBox bbox;
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
// Get BoundaryBox ( in FreeType coordinatrs )
|
|
|
|
|
CV_Assert(!FT_Outline_Get_BBox(&outline, &bbox));
|
|
|
|
|
|
|
|
|
|
// If codepoint is space(0x20), it has no glyph.
|
|
|
|
|
// A dummy boundary box is needed when last code is space.
|
|
|
|
|
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;
|
|
|
|
|
bbox.yMax = yMax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update current position ( in FreeType coordinates )
|
|
|
|
|
currentPos.x += mFace->glyph->advance.x + mFace->glyph->bitmap_left;
|
|
|
|
|
currentPos.y += mFace->glyph->advance.y;
|
|
|
|
|
|
|
|
|
|
// Update BoundaryBox ( in OpenCV coordinates )
|
|
|
|
|
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, ftd(bbox.yMax));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
hb_buffer_destroy(hb_buffer);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Calcurate width/height/baseline ( in OpenCV coordinates )
|
|
|
|
|
int width = xMax - xMin;
|
|
|
|
|
int height = -yMin;
|
|
|
|
|
|
|
|
|
|
if (_thickness > 0) {
|
|
|
|
|
width = cvRound(width + _thickness * 2);
|
|
|
|
|
height = cvRound(height + _thickness * 1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
width = cvRound(width + 1);
|
|
|
|
|
height = cvRound(height + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_baseLine) {
|
|
|
|
|
*_baseLine = yMax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Size(width, height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FreeType2Impl::putPixel_8UC1_mono(Mat& _dst, const int _py, const int _px, const uint8_t *_col)
|
|
|
|
|
{
|
|
|
|
|
uint8_t* ptr = _dst.ptr<uint8_t>(_py, _px);
|
|
|
|
@ -912,124 +1038,6 @@ namespace cv {
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Size FreeType2Impl::getTextSize(
|
|
|
|
|
const String& _text,
|
|
|
|
|
int _fontHeight,
|
|
|
|
|
int _thickness,
|
|
|
|
|
CV_OUT int* _baseLine)
|
|
|
|
|
{
|
|
|
|
|
if (_text.empty())
|
|
|
|
|
{
|
|
|
|
|
return Size(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CV_Assert(_fontHeight >= 0);
|
|
|
|
|
if (_fontHeight == 0)
|
|
|
|
|
{
|
|
|
|
|
return Size(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CV_Assert(!FT_Set_Pixel_Sizes(mFace, _fontHeight, _fontHeight));
|
|
|
|
|
|
|
|
|
|
FT_Vector currentPos = { 0,0 };
|
|
|
|
|
FT_Set_Transform(mFace, 0, ¤tPos);
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
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
|
|
|
|
|
// Initilize BoundaryBox ( in OpenCV coordinates )
|
|
|
|
|
int xMin = INT_MAX, yMin = INT_MAX;
|
|
|
|
|
int xMax = INT_MIN, yMax = INT_MIN;
|
|
|
|
|
|
|
|
|
|
#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 (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;
|
|
|
|
|
FT_Outline outline = slot->outline;
|
|
|
|
|
FT_BBox bbox;
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
// Get BoundaryBox ( in FreeType coordinatrs )
|
|
|
|
|
CV_Assert(!FT_Outline_Get_BBox(&outline, &bbox));
|
|
|
|
|
|
|
|
|
|
// If codepoint is space(0x20), it has no glyph.
|
|
|
|
|
// A dummy boundary box is needed when last code is space.
|
|
|
|
|
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;
|
|
|
|
|
bbox.yMax = yMax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update current position ( in FreeType coordinates )
|
|
|
|
|
currentPos.x += mFace->glyph->advance.x;
|
|
|
|
|
currentPos.y += mFace->glyph->advance.y;
|
|
|
|
|
|
|
|
|
|
// Update BoundaryBox ( in OpenCV coordinates )
|
|
|
|
|
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, ftd(bbox.yMax));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USING_HB)
|
|
|
|
|
hb_buffer_destroy(hb_buffer);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Calcurate width/height/baseline ( in OpenCV coordinates )
|
|
|
|
|
int width = xMax - xMin;
|
|
|
|
|
int height = -yMin;
|
|
|
|
|
|
|
|
|
|
if (_thickness > 0) {
|
|
|
|
|
width = cvRound(width + _thickness * 2);
|
|
|
|
|
height = cvRound(height + _thickness * 1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
width = cvRound(width + 1);
|
|
|
|
|
height = cvRound(height + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_baseLine) {
|
|
|
|
|
*_baseLine = yMax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Size(width, height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FreeType2Impl::mvFn(const FT_Vector *to, void * user)
|
|
|
|
|
{
|
|
|
|
|
if (user == NULL) { return 1; }
|
|
|
|
|