#include "CvxText.hpp" #include "../base/HGDef.h" #include "../base/HGInc.h" #include CvxText::CvxText() { m_library = NULL; m_face = NULL; } CvxText::~CvxText() { Destroy(); } HGResult CvxText::Create(const HGChar* fontPath) { if (NULL != m_face) { return HGBASE_ERR_FAIL; } FT_Init_FreeType(&m_library); if (NULL == m_library) { return HGBASE_ERR_FAIL; } FT_New_Face(m_library, fontPath, 0, &m_face); if (NULL == m_face) { FT_Done_FreeType(m_library); m_library = NULL; return HGBASE_ERR_FAIL; } return HGBASE_ERR_OK; } HGResult CvxText::Destroy() { if (NULL == m_face) { return HGBASE_ERR_FAIL; } FT_Done_Face(m_face); m_face = NULL; FT_Done_FreeType(m_library); m_library = NULL; return HGBASE_ERR_OK; } #if defined(HG_CMP_MSC) static WCHAR *GetUnicodeStr(const char *text) { int len = ::MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0); WCHAR *pUnicode = new WCHAR [len]; ::MultiByteToWideChar(CP_ACP, 0, text, -1, pUnicode, len); return pUnicode; } #else static uint16_t *GetUnicodeStr(const char *text) { if (0 == *text) { uint16_t *pUnicode = new uint16_t [1]; *pUnicode = 0; return pUnicode; } uint16_t *pUnicode = new uint16_t [strlen(text) + 2]; memset(pUnicode, 0, sizeof(uint16_t) * (strlen(text) + 2)); iconv_t cd = iconv_open("UNICODE//IGNORE", "UTF-8"); if ((iconv_t)-1 != cd) { char *inbuf = (char *)text; size_t inbytes = strlen(text); char *outbuf = (char *)pUnicode; size_t outsize = sizeof(uint16_t) * (strlen(text) + 1); iconv(cd, &inbuf, &inbytes, &outbuf, &outsize); iconv_close(cd); } return pUnicode; } #endif HGResult CvxText::DrawString(HGImage image, const HGChar* text, HGColor color, HGUInt posType, HGInt locationX, HGInt locationY, HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout) { if (NULL == m_face) { return HGBASE_ERR_FAIL; } assert(NULL != image); assert(NULL != text && '\0' != *text); assert(posType >= HGIMGPROC_WMPOSTYPE_LEFT && posType <= HGIMGPROC_WMPOSTYPE_LOCATION); assert(0 != fontSize); HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); if (HGBASE_IMGTYPE_BINARY == imgInfo.type) { HGImage imageTmp = NULL; HGResult ret = HGBase_CloneImage(image, HGBASE_IMGTYPE_GRAY, 0, &imageTmp); if (HGBASE_ERR_OK == ret) { ret = DrawString(imageTmp, text, color, posType, locationX, locationY, fontSize, bold, underline, italic, strikeout); HGBase_DestroyImage(imageTmp); } return ret; } HGUInt width, height; std::vector vPos; GetStringLocation(text, fontSize, bold, underline, italic, strikeout, width, height, vPos); if (HGIMGPROC_WMPOSTYPE_LOCATION == posType) { #if defined(HG_CMP_MSC) WCHAR* pUnicode = GetUnicodeStr(text); #else uint16_t* pUnicode = GetUnicodeStr(text); uint16_t* pUnicodeEx = pUnicode + 1; #endif int i = 0; #if defined(HG_CMP_MSC) while ('\0' != pUnicode[i]) #else while ('\0' != pUnicodeEx[i]) #endif { #if defined(HG_CMP_MSC) DrawChar(image, pUnicode[i], color, locationX + vPos[i].left, locationY + vPos[i].top, fontSize, bold, italic); #else DrawChar(image, pUnicodeEx[i], color, locationX + vPos[i].left, locationY + vPos[i].top, fontSize, bold, italic); #endif ++i; } delete[] pUnicode; if (underline) { HGImgProc_ImageDrawLine(image, locationX, locationY + height - 1, locationX + width, locationY + height - 1, color, 1, HGIMGPROC_LINETYPE_SOLID); } if (strikeout) { if (underline) HGImgProc_ImageDrawLine(image, locationX, locationY + (height - 1) / 2, locationX + width, locationY + (height - 1) / 2, color, 1, HGIMGPROC_LINETYPE_SOLID); else HGImgProc_ImageDrawLine(image, locationX, locationY + height / 2, locationX + width, locationY + height / 2, color, 1, HGIMGPROC_LINETYPE_SOLID); } return HGBASE_ERR_OK; } HGImageRoi imgRoi; HGBase_GetImageROI(image, &imgRoi); HGInt roiWidth = imgRoi.right - imgRoi.left; HGInt roiHeight = imgRoi.bottom - imgRoi.top; HGInt x, y; if (HGIMGPROC_WMPOSTYPE_LEFT == posType) { x = 0; y = (roiHeight - height) / 2; } else if (HGIMGPROC_WMPOSTYPE_TOP == posType) { x = (roiWidth - width) / 2; y = 0; } else if (HGIMGPROC_WMPOSTYPE_RIGHT == posType) { x = roiWidth - width; y = (roiHeight - height) / 2; } else if (HGIMGPROC_WMPOSTYPE_BOTTOM == posType) { x = (roiWidth - width) / 2; y = roiHeight - height; } else if (HGIMGPROC_WMPOSTYPE_LEFTTOP == posType) { x = 0; y = 0; } else if (HGIMGPROC_WMPOSTYPE_RIGHTTOP == posType) { x = roiWidth - width; y = 0; } else if (HGIMGPROC_WMPOSTYPE_LEFTBOTTOM == posType) { x = 0; y = roiHeight - height; } else if (HGIMGPROC_WMPOSTYPE_RIGHTBOTTOM == posType) { x = roiWidth - width; y = roiHeight - height; } else { x = (roiWidth - width) / 2; y = (roiHeight - height) / 2; } return DrawString(image, text, color, HGIMGPROC_WMPOSTYPE_LOCATION, x, y, fontSize, bold, underline, italic, strikeout); } void CvxText::MeasureChar(HGUInt wc, HGUInt fontSize, HGBool bold, HGBool italic, FT_BBox& acbox) { assert(NULL != m_face); assert(0 != fontSize); FT_Set_Pixel_Sizes(m_face, fontSize, fontSize); FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc); FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT); if (bold) { if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Outline_Embolden(&m_face->glyph->outline, fontSize * 2); } } if (italic) { if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Matrix matrix; matrix.xx = 0x10000L; matrix.xy = 0.4f * 0x10000L; matrix.yx = 0; matrix.yy = 0x10000L; FT_Outline_Transform(&m_face->glyph->outline, &matrix); } } if (m_face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL); } FT_Glyph glyph; FT_Get_Glyph(m_face->glyph, &glyph); FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &acbox); } void CvxText::GetStringLocation(const HGChar* text, HGUInt fontSize, HGBool bold, HGBool underline, HGBool italic, HGBool strikeout, HGUInt& width, HGUInt& height, std::vector &vPos) { assert(NULL != text && '\0' != *text); assert(0 != fontSize); width = 0; height = 0; vPos.clear(); #if defined(HG_CMP_MSC) WCHAR* pUnicode = GetUnicodeStr(text); #else uint16_t* pUnicode = GetUnicodeStr(text); uint16_t* pUnicodeEx = pUnicode + 1; #endif HGInt origin = 0; HGInt minY = INT_MAX, maxY = INT_MIN; int i = 0; #if defined(HG_CMP_MSC) while ('\0' != pUnicode[i]) #else while ('\0' != pUnicodeEx[i]) #endif { FT_BBox acbox; #if defined(HG_CMP_MSC) MeasureChar(pUnicode[i], fontSize, bold, italic, acbox); #else MeasureChar(pUnicodeEx[i], fontSize, bold, italic, acbox); #endif HGRect pos; pos.left = origin + acbox.xMin; pos.right = origin + acbox.xMax; pos.top = -acbox.yMax; pos.bottom = -acbox.yMin; vPos.push_back(pos); #if defined(HG_CMP_MSC) if (pUnicode[i] < 255 && (!isprint((int)pUnicode[i]) || isspace((int)pUnicode[i]))) #else if (pUnicodeEx[i] < 255 && (!isprint((int)pUnicodeEx[i]) || isspace((int)pUnicodeEx[i]))) #endif { origin += fontSize / 2; } else { origin += (acbox.xMax + acbox.xMin); } if (acbox.yMin < minY) minY = acbox.yMin; if (acbox.yMax > maxY) maxY = acbox.yMax; ++i; } delete[] pUnicode; width = origin; height = (maxY - minY); if (underline) ++height; for (int i = 0; i < (int)vPos.size(); ++i) { vPos[i].top += maxY; vPos[i].bottom += maxY; } } void CvxText::DrawChar(HGImage image, HGUInt wc, HGColor color, HGInt x, HGInt y, HGUInt fontSize, HGBool bold, HGBool italic) { assert(NULL != m_face); assert(NULL != image); assert(0 != fontSize); FT_Set_Pixel_Sizes(m_face, fontSize, fontSize); FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc); FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT); if (bold) { if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Outline_Embolden(&m_face->glyph->outline, fontSize * 2); } } if (italic) { if (m_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Matrix matrix; matrix.xx = 0x10000L; matrix.xy = 0.4f * 0x10000L; matrix.yx = 0; matrix.yy = 0x10000L; FT_Outline_Transform(&m_face->glyph->outline, &matrix); } } if (m_face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL); } HGImageInfo imgInfo; HGBase_GetImageInfo(image, &imgInfo); uint32_t imgWidth = imgInfo.width; uint32_t imgHeight = imgInfo.height; uint32_t imgWidthStep = imgInfo.widthStep; uint32_t imgType = imgInfo.type; uint8_t *imgData; HGBase_GetImageData(image, &imgData); int32_t imgChannel = 0; if (HGBASE_IMGTYPE_GRAY == imgType) imgChannel = 1; else if (HGBASE_IMGTYPE_RGB == imgType || HGBASE_IMGTYPE_BGR == imgType) imgChannel = 3; else if (HGBASE_IMGTYPE_RGBA == imgType || HGBASE_IMGTYPE_BGRA == imgType) imgChannel = 4; assert(0 != imgChannel); HGImageRoi imgRoi; HGBase_GetImageROI(image, &imgRoi); uint32_t imgLeft = imgRoi.left; uint32_t imgTop = imgRoi.top; uint32_t imgRight = imgRoi.right; uint32_t imgBottom = imgRoi.bottom; for (unsigned int i = 0; i < m_face->glyph->bitmap.rows; ++i) { for (unsigned int j = 0; j < m_face->glyph->bitmap.width; ++j) { int32_t xOffset = (int32_t)imgLeft + x + (int32_t)j; int32_t yOffset = (int32_t)imgTop + y + (int32_t)i; if (xOffset >= (int32_t)imgLeft && xOffset < (int32_t)imgRight && yOffset >= (int32_t)imgTop && yOffset < (int32_t)imgBottom) { uint8_t *p = m_face->glyph->bitmap.buffer + m_face->glyph->bitmap.pitch * i + j; int32_t opacity = HG_GETCOLOR_A(color) * (*p) / 255; uint8_t *pEx = imgData + yOffset * imgWidthStep + xOffset * imgChannel; if (HGBASE_IMGORIGIN_BOTTOM == imgInfo.origin) pEx = imgData + (imgHeight - yOffset - 1) * imgWidthStep + xOffset * imgChannel; if (HGBASE_IMGTYPE_RGB == imgType || HGBASE_IMGTYPE_RGBA == imgType) { int32_t v0 = HG_GETCOLOR_R(color); int32_t vDest0 = pEx[0]; int32_t value0 = (v0 - vDest0) * opacity; pEx[0] = (uint8_t)(vDest0 + (((value0 << 8) + value0) >> 16)); int32_t v1 = HG_GETCOLOR_G(color); int32_t vDest1 = pEx[1]; int32_t value1 = (v1 - vDest1) * opacity; pEx[1] = (uint8_t)(vDest1 + (((value1 << 8) + value1) >> 16)); int32_t v2 = HG_GETCOLOR_B(color); int32_t vDest2 = pEx[2]; int32_t value2 = (v2 - vDest2) * opacity; pEx[2] = (uint8_t)(vDest2 + (((value2 << 8) + value2) >> 16)); } else if (HGBASE_IMGTYPE_BGR == imgType || HGBASE_IMGTYPE_BGRA == imgType) { int32_t v0 = HG_GETCOLOR_B(color); int32_t vDest0 = pEx[0]; int32_t value0 = (v0 - vDest0) * opacity; pEx[0] = (uint8_t)(vDest0 + (((value0 << 8) + value0) >> 16)); int32_t v1 = HG_GETCOLOR_G(color); int32_t vDest1 = pEx[1]; int32_t value1 = (v1 - vDest1) * opacity; pEx[1] = (uint8_t)(vDest1 + (((value1 << 8) + value1) >> 16)); int32_t v2 = HG_GETCOLOR_R(color); int32_t vDest2 = pEx[2]; int32_t value2 = (v2 - vDest2) * opacity; pEx[2] = (uint8_t)(vDest2 + (((value2 << 8) + value2) >> 16)); } else { int32_t v = (HG_GETCOLOR_R(color) * 76 + HG_GETCOLOR_G(color) * 150 + HG_GETCOLOR_B(color) * 30) >> 8; int32_t vDest = *pEx; int32_t value = (v - vDest) * opacity; *pEx = (uint8_t)(vDest + (((value << 8) + value) >> 16)); } } } } }