#include <freetype/freetype.h> #include <ft2build.h> #include <mutex> #include <vector> #include "fontdata.h" #include "lyn_plugin_dev.h" #include "detect.h" #include "osdPlugin.h" struct TextBitMap { uint8_t *buffer = nullptr; int w = 0; int h = 0; // char ch; // lynFontSize fontSize; }; void setFontSize(FT_Face *ftFace, int fontSize) { FT_Set_Char_Size(*ftFace, 0, fontSize * 64, 0, 96); FT_Set_Pixel_Sizes(*ftFace, 0, fontSize); } int drawText(uint32_t startX, uint32_t startY, uint32_t imgW, uint32_t imgH, lynPixelFormat_t imgFmt, unsigned char *imgData, char vIndexs[20]) { static bool s_init = false; // static int s_fontSize = 0; static std::mutex s_drawTextMux; static FT_Library ftLib; static FT_Face ftFace; static std::vector<TextBitMap> s_textVec; int ret; if (imgData == nullptr) { return -1; } if (!s_init) { std::unique_lock<std::mutex> lock(s_drawTextMux); ret = FT_Init_FreeType(&ftLib); ret = FT_New_Memory_Face(ftLib, (const unsigned char *)fontData, sizeof(fontData), 0, &ftFace); if (ret != 0) { return -2; } FT_Select_Charmap(ftFace, FT_ENCODING_UNICODE); setFontSize(&ftFace, FONT_SIZE_18); for (size_t i = 0; i < PLATE_DATA.length(); i++) { if (i == 31) { setFontSize(&ftFace, 30); } else if (i == 65) { setFontSize(&ftFace, FONT_SIZE_18); } wchar_t ch = PLATE_DATA.at(i); auto index = FT_Get_Char_Index(ftFace, ch); FT_Load_Glyph(ftFace, index, FT_LOAD_DEFAULT); // FT_Render_Glyph(ftFace->glyph, FT_RENDER_MODE_NORMAL); TextBitMap bitMap; bitMap.w = ftFace->glyph->bitmap.width; bitMap.h = ftFace->glyph->bitmap.rows; bitMap.buffer = (uint8_t *)malloc(bitMap.w * bitMap.h); // bitMap.fontSize = fontSize; memcpy(bitMap.buffer, ftFace->glyph->bitmap.buffer, bitMap.w * bitMap.h); s_textVec.emplace_back(bitMap); } s_init = true; } unsigned char *data_y = imgData; int pix_x_base = startX; int pix_y_base = startY; for (uint8_t k = 0; k < 20; ++k) { uint8_t idx = vIndexs[k]; if (idx >= PLATE_DATA.length()) { continue; } uint32_t w = s_textVec[idx].w; uint32_t h = s_textVec[idx].h; pix_y_base = startY - h; unsigned char *data = s_textVec[idx].buffer; for (uint32_t j = 0; j < h; ++j) { for (uint32_t i = 0; i < w; ++i) { uint32_t pix_x = pix_x_base + i; uint32_t pix_y = pix_y_base + j; if (pix_y < 0 || pix_y >= imgH || pix_x >= imgW || pix_x < 0) { continue; } int a = data[j * w + i] >> 5; data_y[pix_y * imgW + pix_x] = data_y[pix_y * imgW + pix_x] * (8 - a) / 8 + (255 >> 3) * a; } } pix_x_base += (w + 2); } return 0; } int osdDraw(int width, int height, void* data, std::vector<TARGET_INFO>& targets) { if (targets.empty()) { return 0; } void *imgData = lynPluginGetVirtAddr(data); if (imgData == nullptr) { LOG_PLUGIN_E("get imgData addr error"); return -1; } lynDrawBoxAttr boxAttr; boxAttr.imgW = width; boxAttr.imgH = height; for (auto& target : targets) { if (target.width <= DRAW_THICK_2 * 2 || target.height <= DRAW_THICK_2 * 2) { LOG_PLUGIN_E("invalid draw thickness!\n"); continue; } boxAttr.startX = target.left; boxAttr.startY = target.top; boxAttr.boxW = target.width; boxAttr.boxH = target.height; boxAttr.thickness = DRAW_THICK_2; boxAttr.color = DRAW_COLOR_YELLOW; boxAttr.imgFmt = LYN_PIX_FMT_NV12; boxAttr.imgData = (unsigned char *)imgData; // 绘制车牌的方框 int ret = lynPluginDrawBox(&boxAttr); { // 绘制车牌号的背景方框 int backGroundWidth = 140; int xOffset = (backGroundWidth - target.width) / 2; if (xOffset < 0) xOffset = 0; int startX = target.left - xOffset; int startYBase = target.top; boxAttr.color = DRAW_COLOR_BLACK; boxAttr.startX = startX; boxAttr.startY = startYBase - 16; boxAttr.boxW = backGroundWidth; boxAttr.boxH = 16; boxAttr.thickness = DRAW_THICK_8; ret = lynPluginDrawBox(&boxAttr); boxAttr.startX = startX; boxAttr.startY = startYBase - 32; boxAttr.boxW = backGroundWidth; boxAttr.boxH = 16; boxAttr.thickness = DRAW_THICK_8; ret = lynPluginDrawBox(&boxAttr); // 叠加文字 drawText(startX + 8, startYBase - 8, width, height, LYN_PIX_FMT_NV12, (unsigned char *)imgData, target.info); } if (ret != 0) { continue; } } return 0; }