MFC中,在图片上添加汉字(c++实现)

本程序是写在水星相机里的代码片,主要实现在图片上写汉字。因为字符宽度的问题,OpenCV自带的cvInitFont和cvPutText函数不支持向图像中写入中文,所以用GDI+和位图操作实现。

void GetStringSize(HDC hDC, const char* str, int* w, int* h)
{
    SIZE size;//分cx和cy
    GetTextExtentPoint32A(hDC, str, strlen(str), &size);
    if (w != 0) *w = size.cx;
    if (h != 0) *h = size.cy;
}

void paDrawString(Mat& dst, const char* str, Point org, Scalar color, int fontSize, bool italic, bool underline)
{
    char *p = NULL;
    //CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));//

    int x, y, r, b;
    if (org.x > dst.cols || org.y > dst.rows) return;
    x = org.x < 0 ? -org.x : 0;
    y = org.y < 0 ? -org.y : 0;

    LOGFONTA lf;//字体设置
    lf.lfHeight = -fontSize;//字高
    lf.lfWidth = 0;//字宽
    lf.lfEscapement = 0;//字体旋转角度
    lf.lfOrientation = 0;//字体方向
    lf.lfWeight = 5;//字体轻重
    lf.lfItalic = italic;  //斜体  
    lf.lfUnderline = underline;   //下划线  
    lf.lfStrikeOut = 0;//是否有强调线
    lf.lfCharSet = DEFAULT_CHARSET;//字符集
    lf.lfOutPrecision = 0;//输出精度
    lf.lfClipPrecision = 0;//裁剪精度
    lf.lfQuality = PROOF_QUALITY;//输出质量
    lf.lfPitchAndFamily = 0;//间隔和字体系列
    strcpy_s(lf.lfFaceName,"宋体");//字体名

    HFONT hf = CreateFontIndirectA(&lf);//创建字体
    HDC hDC = CreateCompatibleDC(0);//创建一个內存设备上下文环境的DC
    HFONT hOldFont = (HFONT)SelectObject(hDC, hf);//hdc:上下文环境句柄,被选择的对象句柄

    int strBaseW = 0, strBaseH = 0;
    int singleRow = 0;
    char buf[1 << 12];
    strcpy_s(buf, str);//把汉字写进buf里

    //处理多行  
    {
        int nnh = 0;//计算一共有几个字符
        int cw, ch;//字体的长宽

        const char* ln = strtok_s(buf, "\n", &p);//把buf数据按照换行给分割开
        while (ln != 0)
        {
            GetStringSize(hDC, ln, &cw, &ch);//获得字体的大小(长宽cw ch表示)
            strBaseW = max(strBaseW, cw);//字体的最大长度
            strBaseH = max(strBaseH, ch);//字体的最大宽度

            ln = strtok_s(0, "\n",&p);
            nnh++;
        }
        singleRow = strBaseH;//每一个字符的长度
        strBaseH *= nnh;//
    }

    if (org.x + strBaseW < 0 || org.y + strBaseH < 0)//如果输入的数字不合适,就释放画图画笔
    {
        SelectObject(hDC, hOldFont);//函数功能:该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
        DeleteObject(hf);//DeleteObject,该函数删除一个逻辑笔、画笔、字体、位图、区域或者调色板,释放所有与该对象有关的系统资源,在对象被删除之后,指定的句柄也就失效了。
        DeleteObject(hDC);
        return;
    }

    r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
    b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
    org.x = org.x < 0 ? 0 : org.x;
    org.y = org.y < 0 ? 0 : org.y;//判断字符是否溢出边界

    BITMAPINFO bmp = { 0 };//BITMAPINFO结构定义了Windows设备无关位图(DIB)的度量和颜色信息
    BITMAPINFOHEADER& bih = bmp.bmiHeader;//位图信息头BITMAPINFOHEADER
    int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4));

    bih.biSize = sizeof(BITMAPINFOHEADER);
    bih.biWidth = strBaseW;
    bih.biHeight = strBaseH;
    bih.biPlanes = 1;
    bih.biBitCount = 24;
    bih.biCompression = BI_RGB;
    bih.biSizeImage = strBaseH * strDrawLineStep;
    bih.biClrUsed = 0;
    bih.biClrImportant = 0;

    void* pDibData = 0;
    HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0);//创建应用程序可以直接写入的、与设备无关的位图(DIB)的函数;HBITMAP是句柄;  BITMAP是实例:

    CV_Assert(pDibData != 0);
    HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);

    //color.val[2], color.val[1], color.val[0]  
    SetTextColor(hDC, RGB(255, 255, 255));//功能:设置指定设备环境(HDC)的字体颜色
    SetBkColor(hDC, 0);//该函数用指定的颜色值来设置当前的背景色,如果指定的颜色值超出了当前设备的表示范围,则设置为最近似的、设备可以表示的颜色。
    //SetStretchBltMode(hDC, COLORONCOLOR);  

    strcpy_s(buf, str);
    const char* ln = strtok_s(buf, "\n",&p);
    int outTextY = 0;
    while (ln != 0)
    {
        TextOutA(hDC, 0, outTextY, ln, strlen(ln));
        outTextY += singleRow;
        ln = strtok_s(0, "\n",&p);
    }
    uchar* dstData = (uchar*)dst.data;
    int dstStep = dst.step / sizeof(dstData[0]);
    unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep;
    unsigned char* pStr = (unsigned char*)pDibData + x * 3;
    for (int tty = y; tty <= b; ++tty)
    {
        unsigned char* subImg = pImg + (tty - y) * dstStep;
        unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep;
        for (int ttx = x; ttx <= r; ++ttx)
        {
            for (int n = 0; n < dst.channels(); ++n){
                double vtxt = subStr[n] / 255.0;
                int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n];
                subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv);
            }

            subStr += 3;
            subImg += dst.channels();
        }
    }

    SelectObject(hDC, hOldBmp);
    SelectObject(hDC, hOldFont);
    DeleteObject(hf);
    DeleteObject(hBmp);
    DeleteDC(hDC);
}

在主程序中,添加代码(由于直接从相机中得到的BAYE是上下颠倒的,因此,需要一步Flip翻转)

    RECT objRect;
    m_pWnd->GetClientRect(&objRect);    
    nWndWidth  = objRect.right  - objRect.left;
    nWndHeight = objRect.bottom - objRect.top;


    IplImage * frame;
    ch = (LPSTR)(LPCTSTR)sum4;
    frame = cvCreateImageHeader(cvSize(m_nImageWidth, m_nImageHeight), IPL_DEPTH_8U, 3);//添加画布

    cvSetData(frame, m_pImgBuffer, m_nImageWidth * 3);
    Mat img(frame,0);
    paDrawString(img, ch, Point(20, 20), Scalar(0, 0, 255), 50, false, false);
    frame = &IplImage(img);

    for (int i = 0; i<(m_nFrameSize); i++)
        m_pImgBuffer[i] = (frame->imageDataOrigin)[i];//IplImage转BAYE
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值