cvxFont.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "cvxFont.h"
  2. #include <cassert>
  3. #include <clocale>
  4. #include <utility>
  5. #include <sstream>
  6. #include <cstdlib>
  7. cvx::CvxFont::CvxFont(const cv::String& fontType)
  8. {
  9. assert(!fontType.empty());
  10. m_error = FT_Init_FreeType(&m_library);
  11. if (m_error){
  12. std::cerr << "library initial error!" << std::endl;
  13. return;
  14. }
  15. m_error = FT_New_Face(m_library, fontType.c_str(), 0, &m_face);
  16. if (m_error == FT_Err_Unknown_File_Format){
  17. std::cerr << "unsupported font format!" << std::endl;
  18. return;
  19. }
  20. else if (m_error){
  21. std::cerr << " can not open font files" << std::endl;
  22. return;
  23. }
  24. // use default parameters
  25. m_font = new FontProperty;
  26. initFont();
  27. setlocale(LC_ALL, "");
  28. }
  29. // release freetype resource
  30. cvx::CvxFont::~CvxFont()
  31. {
  32. delete m_font;
  33. FT_Done_Face(m_face);
  34. FT_Done_FreeType(m_library);
  35. }
  36. void cvx::CvxFont::setFontSize(const int fontSize)
  37. {
  38. m_font->fontSize = fontSize;
  39. FT_Set_Pixel_Sizes(m_face, fontSize, 0);
  40. }
  41. // initial font
  42. void cvx::CvxFont::initFont()
  43. {
  44. setFontSize(16);
  45. setSpaceRatio(0.5);
  46. setFontRatio(0);
  47. setRotateAngle(0);
  48. setDiaphaneity(1);
  49. setUnderline(false);
  50. setVertical(false);
  51. // set font
  52. FT_Set_Pixel_Sizes(m_face, getFontSize(), 0);
  53. }
  54. void cvx::CvxFont::rotateFont(double angle) {
  55. angle = (angle / 360) * 3.14159 * 2;
  56. /* set up matrix */
  57. m_matrix.xx = static_cast<FT_Fixed>(cos(angle) * 0x10000L);
  58. m_matrix.xy = static_cast<FT_Fixed>(-sin(angle) * 0x10000L);
  59. m_matrix.yx = static_cast<FT_Fixed>(sin(angle) * 0x10000L);
  60. m_matrix.yy = static_cast<FT_Fixed>(cos(angle) * 0x10000L);
  61. FT_Set_Transform(m_face, &m_matrix, nullptr);
  62. }
  63. void cvx::CvxFont::putTextStr(cv::Mat& img, const cv::String& text, cv::Point pos, const cv::Scalar& color)
  64. {
  65. CV_Assert(!img.empty());
  66. CV_Assert(!text.empty());
  67. int xStart = pos.x;
  68. int yStart = pos.y;
  69. m_maxDiffHeight = 0;
  70. const char* ptr = text.c_str();
  71. std::mbtowc(nullptr, nullptr, 0); // reset the conversion state
  72. const char* end = ptr + std::strlen(ptr);
  73. int ret;
  74. for (wchar_t wc; (ret = std::mbtowc(&wc, ptr, end - ptr)) > 0; ptr += ret) {
  75. putWChar(img, (wc & 0xffffffff), pos, color);
  76. }
  77. int xEnd = pos.x;
  78. int yEnd = pos.y;
  79. if (getUnderline()) {
  80. if (getVertical()) {
  81. cv::line(img, cv::Point(xStart + m_maxDiffHeight, yStart), cv::Point(xStart + m_maxDiffHeight, yEnd), color, 2);
  82. }
  83. else {
  84. cv::line(img, cv::Point(xStart, yStart + m_maxDiffHeight), cv::Point(xEnd, yStart + m_maxDiffHeight), color, 2);
  85. }
  86. }
  87. }
  88. void cvx::CvxFont::putWChar(cv::Mat& img, uint32_t wc, cv::Point& pos, const cv::Scalar& color)
  89. {
  90. rotateFont(getAngle());
  91. const auto vertical = getVertical();
  92. const auto size = getFontSize();
  93. // Converting a Character Code Into a Glyph Index
  94. FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc);
  95. FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT);
  96. FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_MONO);
  97. FT_GlyphSlot slot = m_face->glyph;
  98. FT_Bitmap bitmap = slot->bitmap;
  99. bool isSpace = wc == ' ';
  100. // get rows and cols of current wide char
  101. auto rows = bitmap.rows;
  102. auto cols = bitmap.width;
  103. cv::Point gPos = pos;
  104. //gPos.y += m_font->fontSize;
  105. if (vertical)
  106. {
  107. gPos.x += (slot->metrics.vertBearingX >> 6);
  108. gPos.y += (slot->metrics.vertBearingY >> 6);
  109. m_maxDiffHeight = std::max(m_maxDiffHeight, rows - (slot->metrics.vertBearingY >> 6));
  110. }
  111. else
  112. {
  113. gPos.x += (slot->metrics.horiBearingX >> 6);
  114. gPos.y -= (slot->metrics.horiBearingY >> 6);
  115. m_maxDiffHeight = std::max(m_maxDiffHeight, rows - (slot->metrics.horiBearingY >> 6));
  116. }
  117. // https://stackoverflow.com/questions/52254639/how-to-access-pixels-state-in-monochrome-bitmap-using-freetype2
  118. for (auto i = 0; i < rows; ++i)
  119. {
  120. for (auto j = 0; j < cols; ++j)
  121. {
  122. int off = i * slot->bitmap.pitch + j / 8;
  123. if (slot->bitmap.buffer[off] & (0x80 >> (j % 8)))
  124. {
  125. const auto r = gPos.y + i; //vertical ? pos.y + i : pos.y + i + (size - rows); // to make align to bottom
  126. const auto c = gPos.x + j;
  127. if (r >= 0 && r < img.rows && c >= 0 && c < img.cols)
  128. {
  129. cv::Vec3b scalar = img.at<cv::Vec3b>(cv::Point(c, r));
  130. // merge set color with origin color
  131. double p = getDiaphaneity();
  132. for (int k = 0; k < 3; ++k)
  133. {
  134. scalar.val[k] = static_cast<uchar>(scalar.val[k] * (1 - p) + color.val[k] * p);
  135. }
  136. img.at<cv::Vec3b>(cv::Point(c, r)) = cv::Vec3b(scalar[0], scalar[1], scalar[2]);
  137. }
  138. }
  139. }
  140. }
  141. // modify position to next character
  142. const auto space = static_cast<int>(size * getSpaceRatio());
  143. const auto sep = static_cast<int>(size * getFontRatio());
  144. // vertical string or not, default not vertical
  145. if (vertical){
  146. const auto moveX = (static_cast<int>(getAngle()) == 0) ? (slot->metrics.vertAdvance >> 6) : rows + 1;
  147. pos.y += isSpace ? space : moveX + sep;
  148. }else{
  149. const auto moveY = (static_cast<int>(getAngle()) == 0) ? (slot->metrics.horiAdvance >> 6) : cols + 1;
  150. pos.x += isSpace ? space : moveY + sep;
  151. }
  152. }
  153. void cvx::putText(cv::Mat& img, const std::string& text, cv::Point pos, cvx::CvxFont& fontFace, int fontSize, const cv::Scalar& color) {
  154. fontFace.setFontSize(fontSize);
  155. fontFace.putTextStr(img, text, std::move(pos), color);
  156. fontFace.initFont();
  157. }