Newer
Older
lynxi-plugin / src / osd / osdPlugin.cpp

#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;
}