给位图文件添加文字水印

来源:互联网 发布:高等数学c1网络课程 编辑:程序博客网 时间:2024/06/10 20:32

转自:http://hi.baidu.com/cwcblog/blog/item/02f426509555e70f377abe31.html

  这里所说的水印,就是在图片内部添加文字标记,通常用于标明版权。为了提高重用性,我把这个功能的实现封装成了一个类。

        实现原理:

1.       加载一个位图到内存

2.       创建一个与屏幕内存设备兼容的内存设备上下文memDC

3.       把位图选进memDC

4.       设置自定义字体font

5.       font选进memDC

6.       设置memDCTextColor(文字颜色),BkColor(文字背景色),Transparent(文字背景是否透明)

7.       自动或手动设置文字在图片的位置

8.       使用TextOut函数将水印文字输出到内存设备memDC

9.       memDC中的内容保存到位图文件

 

代码实现:-CWaterMark

头文件

/* Copyright (C) wuchen 2011 ALL RIGHTS RESERVED.

* Author:niewucai

* Email:niewucai@126.com

* Last Update:2011/05/11

实现对位图图片添加文字水印功能 -- 头文件

*/

#pragmaonce

#include<string>

usingnamespace std;

 

class CWaterMark{

public:

     /*构造方法

     * @lpszImgFile:要添加水印的位图图片文件

     */

     CWaterMark(LPCTSTR lpszImgFile);

     /*构造方法

     * @nIDResource:位图资源标识

     */

     CWaterMark(UINT nIDResource);

     ~CWaterMark();

 

     //水印文字位置枚举

     typedefenum

     {

         /* 表示左上位置。

         */

         LeftTop = 1,

 

         /* 表示中上位置。

         */

         CenterTop,

 

         /* 表示右上位置。

         */

         RightTop,

 

         /* 表示左中位置。

         */

         LeftMiddle,

 

         /* 表示中心位置。

         */

         CenterMiddle,

 

         /* 表示右中位置。

         */

         RightMiddle,

 

         /* 表示左下位置。

         */

         LeftBottom,

 

         /* 表示中下位置。

         */

         CenterBottom,

 

         /* 表示右下位置。

         */

         RightBottom

     }Location;

 

public:

     int m_topSpacing;  //水印文字与图片顶部的间距(像素)

     int m_rightSpacing;    //水印文字与图片右端的间距(像素)

     int m_bottomSpacing;//水印文字与图片底部的间距(像素)

     int m_leftSpacing; //水印文字与图片左端的间距(像素)

public:

     /*更换当前操作位图

     * @nIDResouce:位图资源标识

     * return:是否更换成功

     */

     bool ChangeBitmap(UINT nIDResource);

     /*更换当前操作位图

     * @lpszImgFile:位图文件路径

     * return:是否更换成功

     */

     bool ChangeBitmap(LPCTSTR lpszImgFile);

     /*获取与设备无关的内存设备上下文*/

     inline HDC GetMemoryDC()

     {

         return m_hMemDC;

     }

     /*获取当前处理位图的BITMAP结构*/

     int GetBitmap(BITMAP* pBitMap);

     /*获取水印文字的前景色*/

     COLORREF GetForeColor();

     /*设置水印文字的前景色*/

     void SetForeColor(COLORREF foreColor = 0);

     /*获取水印文字的背景色*/

     COLORREF GetBkColor();

     /*设置水印文字的背景色*/

     void SetBkColor(COLORREF bkColor = RGB(255, 255, 255));

     /*获取当前是否设置水印文字为透明背景*/

     bool IsTransparent();

     /*设置当前是否设置水印文字为透明背景*/

     void SetTransparent(bool transparent = true);

     /*获取当前用于输出水印文字的字体*/

     HFONT GetTextFont();

     /*设置当前用于输出水印文字的字体,返回上一次设置的字体*/

     HFONT SetTextFont(HFONT hFont);

     /*添加水印文字

     * @lpszText:水印文本

     * @x:水印文本相对图片左上角的水平位置(像素)

     * @y:水印文本相对图片左上角的垂直位置(像素)

     */

     void AddWaterMark(LPCTSTR lpszText, int x, int y);

     /*根据选择的方式和上下左右的间距,自动添加水印文本到合适的位置,默认添加到图片右下角*/

     void AddWaterMark(LPCTSTR lpszText, Location type = Location::RightBottom);

     /*保存到当前操作位图文件,返回是否保存成功-  只针对以位图文件加载的情况*/

     bool Save();

     /*保存到指定位图文件,返回是否保存成功*/

     bool Save(LPCTSTR lpszFile);

private:

     /*初始化工作*/

     void Init();

     /*根据BITMAP句柄创建位图文件信息*/

     PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);

     /*创建位图文件*/

     void CreateBMPFile(HWND hwnd, LPCTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);

private:

     string m_imgFile;      //要添加水印的图片文件

     HFONT m_hFont;              //水印文字的当前字体

     HFONT m_hOldFont;      

     HFONT m_hInitFont;     //水印文字的初始字体

     COLORREF m_foreColor;  //水印文字的文本颜色

     COLORREF m_bkColor;         //水印文字的背景颜色

     bool m_isTransparant;  //水印文字是否透明

     HBITMAP m_hBmp;             //HBITMAP对象

     HBITMAP  m_hOldBmp;

     HDC  m_hMemDC;          //内存设备句柄

};

 

实现文件:

/* Copyright (C) wuchen 2011 ALL RIGHTS RESERVED.

* Author:niewucai

* Email:niewucai@126.com

* Last Update:2011/05/11

实现对位图图片添加文字水印功能-- 实现文件

*/

#include<stdafx.h>

#include"WaterMark.h"

 

CWaterMark::CWaterMark(LPCTSTR lpszImgFile)

: m_topSpacing(10),

m_rightSpacing(10),

m_bottomSpacing(10),

m_leftSpacing(10),

m_isTransparant(true),

m_foreColor(0),

m_bkColor(RGB(255, 255, 255))

{

     this->m_imgFile = lpszImgFile;

     //创建默认字体

     m_hFont = CreateFontA(0, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("宋体"));

     m_hInitFont = m_hFont;

 

     m_hBmp = (HBITMAP)LoadImage(AfxGetInstanceHandle(), lpszImgFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

 

     Init();

}

CWaterMark::CWaterMark(UINT nIDResource)

: m_topSpacing(10),

m_rightSpacing(10),

m_bottomSpacing(10),

m_leftSpacing(10),

m_isTransparant(true),

m_foreColor(0),

m_bkColor(RGB(255, 255, 255))

{

     //创建默认字体

     m_hFont = CreateFontA(0, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("宋体"));

     m_hInitFont = m_hFont;

 

     m_hBmp = (HBITMAP)LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource));

 

     Init();

}

CWaterMark::~CWaterMark()

{

     SelectObject(m_hMemDC, m_hOldBmp);

     SelectObject(m_hMemDC, m_hOldFont);

     DeleteObject(m_hInitFont);

}

void CWaterMark::Init()

{

     m_hMemDC = CreateCompatibleDC(NULL); //创建一个与屏幕内存设备兼容的内存设备

     m_hOldFont = (HFONT)SelectObject(m_hMemDC, (HFONT)m_hFont);//选择默认字体

     m_hOldBmp = (HBITMAP)SelectObject(m_hMemDC, m_hBmp);//选择位图到内存设备

     SetBkMode(m_hMemDC, m_isTransparant ? TRANSPARENT : OPAQUE);//是否背景透明

     SetTextColor(m_hMemDC, m_foreColor);//前景色

     ::SetBkColor(m_hMemDC, m_bkColor);//背景色

}

/*更换当前操作位图

* @nIDResouce:位图资源标识

* return:是否更换成功

*/

bool CWaterMark::ChangeBitmap(UINT nIDResource)

{

     m_hBmp = (HBITMAP)LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource));

     if(!m_hBmp)

     {

         returnfalse;

     }

     m_imgFile.clear();

     m_hOldBmp = (HBITMAP)SelectObject(m_hMemDC, m_hBmp);//选择位图到内存设备

     returntrue;

}

/*更换当前操作位图

* @lpszImgFile:位图文件路径

* return:是否更换成功

*/

bool CWaterMark::ChangeBitmap(LPCTSTR lpszImgFile)

{                  

     m_hBmp = (HBITMAP)LoadImage(AfxGetInstanceHandle(), lpszImgFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

     if(!m_hBmp)

     {

         returnfalse;

     }

     this->m_imgFile = lpszImgFile;

     m_hOldBmp = (HBITMAP)SelectObject(m_hMemDC, m_hBmp);//选择位图到内存设备

     returntrue;

}

/*获取当前处理位图的BITMAP结构*/

int CWaterMark::GetBitmap(BITMAP* pBitMap)

{

     if(!m_hBmp)

     {

         return 0;

     }

     return CBitmap::FromHandle(m_hBmp)->GetBitmap(pBitMap);

}

/*获取水印文字的前景色*/

COLORREF CWaterMark::GetForeColor()

{

     return m_foreColor;

}

/*设置水印文字的前景色*/

void CWaterMark::SetForeColor(COLORREF foreColor/* = 0*/)

{

     m_foreColor = foreColor;

     SetTextColor(m_hMemDC, m_foreColor);//设置前景色

}

/*获取水印文字的背景色*/

COLORREF CWaterMark::GetBkColor()

{

     return m_bkColor;

}

/*设置水印文字的背景色*/

void CWaterMark::SetBkColor(COLORREF bkColor/* = RGB(255, 255, 255)*/)

{

     m_bkColor = bkColor;

     ::SetBkColor(m_hMemDC, m_bkColor);//背景色

}

/*获取当前是否设置水印文字为透明背景*/

bool CWaterMark::IsTransparent()

{

     return m_isTransparant;

}

/*设置当前是否设置水印文字为透明背景*/

void CWaterMark::SetTransparent(bool transparent/* = true*/)

{

     m_isTransparant = transparent;

     SetBkMode(m_hMemDC, m_isTransparant ? TRANSPARENT : OPAQUE);//是否背景透明

}

/*获取当前用于输出水印文字的字体*/

HFONT CWaterMark::GetTextFont()

{

     return m_hFont;

}

/*设置当前用于输出水印文字的字体,返回上一次设置的字体*/

HFONT CWaterMark::SetTextFont(HFONT hFont)

{

     m_hFont = hFont;

     m_hOldFont = (HFONT)SelectObject(m_hMemDC, (HFONT)m_hFont);//设置水印文字字体

     return m_hOldFont;

}

/*添加水印文字

* @lpszText:水印文本

* @x:水印文本相对图片左上角的水平位置(像素)

* @y:水印文本相对图片左上角的垂直位置(像素)

*/

void CWaterMark::AddWaterMark(LPCTSTR lpszText, int x, int y)

{

     TextOut(m_hMemDC, x, y, lpszText, strlen(lpszText));

}

/*根据选择的方式和上下左右的间距,自动添加水印文本到合适的位置,默认添加到图片右下角*/

void CWaterMark::AddWaterMark(LPCTSTR lpszText, Location type/* = Location::RightBottom*/)

{

     //获取字体宽度

     TEXTMETRIC txtMetric = {0};

     ::GetTextMetrics(m_hMemDC, &txtMetric);

     //水印文字的总高度和宽度

     SIZE size;

     ::GetTextExtentPoint(m_hMemDC, lpszText, strlen(lpszText), &size);

     int height = size.cy;

     int width = size.cx;

     //水印文本相对图片左上角的水平位置(像素)

     int x = 0;

     //水印文本相对图片左上角的垂直位置(像素)

     int y = 0;

     BITMAP bmp;

     this->GetBitmap(&bmp);

     //位图的高度和宽度

     int nBmpWidth = bmp.bmWidth;

     int nBmpHeight = bmp.bmHeight;

     switch(type)

     {

     case Location::LeftTop:

         x = m_leftSpacing;

         y = m_topSpacing;

         break;

     case Location::CenterTop:

         x = (nBmpWidth - width) / 2;

         y = m_topSpacing;

         break;

     case Location::RightTop:

         x = nBmpWidth - width - m_rightSpacing;

         y = m_topSpacing;

         break;

     case Location::LeftMiddle:

         x = m_leftSpacing;

         y = (nBmpHeight - height) / 2;

         break;

     case Location::CenterMiddle:

         x = (nBmpWidth - width) / 2;

         y = (nBmpHeight - height) / 2;

         break;

     case Location::RightMiddle:

         x = nBmpWidth - width - m_rightSpacing;

         y = (nBmpHeight - height) / 2;

         break;

     case Location::LeftBottom:

         x = m_leftSpacing;

         y = nBmpHeight - height - m_bottomSpacing;

         break;

     case Location::CenterBottom:

         x = (nBmpWidth - width) / 2;

         y = nBmpHeight - height - m_bottomSpacing;

         break;

     case Location::RightBottom:

         x = nBmpWidth - width - m_rightSpacing;

         y = nBmpHeight - height - m_bottomSpacing;

         break;

     default:

         break;

     }

     TextOut(m_hMemDC, x, y, lpszText, strlen(lpszText));

}

/*保存到当前操作位图文件,返回是否保存成功-  只针对以位图文件加载的情况*/

bool CWaterMark::Save()

{

     if(m_imgFile.empty())

     {

         returnfalse;

     }

     if(m_hBmp)

     {

         PBITMAPINFO bmpInfo = CreateBitmapInfoStruct(NULL, m_hBmp);

         CreateBMPFile(NULL, m_imgFile.c_str(), bmpInfo, m_hBmp, m_hMemDC);

         returntrue;

     }

     else

     {

         returnfalse;

     }

}

/*保存到指定位图文件,返回是否保存成功*/

bool CWaterMark::Save(LPCTSTR lpszFile)

{

     if(m_hBmp)

     {

         PBITMAPINFO bmpInfo = CreateBitmapInfoStruct(NULL, m_hBmp);

         CreateBMPFile(NULL, lpszFile, bmpInfo, m_hBmp, m_hMemDC);

         returntrue;

     }

     else

     {

         returnfalse;

     }

}

PBITMAPINFO CWaterMark::CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)

     BITMAP bmp; 

     PBITMAPINFO pbmi; 

     WORD    cClrBits; 

 

     // Retrieve the bitmap color format, width, and height.  

     if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) 

         return NULL; 

 

     // Convert the color format to a count of bits.  

     cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 

     if (cClrBits == 1) 

         cClrBits = 1; 

     elseif (cClrBits <= 4) 

         cClrBits = 4; 

     elseif (cClrBits <= 8) 

         cClrBits = 8; 

     elseif (cClrBits <= 16) 

         cClrBits = 16; 

     elseif (cClrBits <= 24) 

         cClrBits = 24; 

     else cClrBits = 32; 

 

     // Allocate memory for the BITMAPINFO structure. (This structure  

     // contains a BITMAPINFOHEADER structure and an array of RGBQUAD  

     // data structures.)  

 

     if (cClrBits < 24) 

         pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 

         sizeof(BITMAPINFOHEADER) + 

         sizeof(RGBQUAD) * (1<< cClrBits)); 

 

     // There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel 

 

     else 

         pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 

         sizeof(BITMAPINFOHEADER)); 

 

     // Initialize the fields in the BITMAPINFO structure.  

 

     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 

     pbmi->bmiHeader.biWidth = bmp.bmWidth; 

     pbmi->bmiHeader.biHeight = bmp.bmHeight; 

     pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 

     pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 

     if (cClrBits < 24) 

         pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

 

     // If the bitmap is not compressed, set the BI_RGB flag.  

     pbmi->bmiHeader.biCompression = BI_RGB; 

 

     // Compute the number of bytes in the array of color  

     // indices and store the result in biSizeImage.  

     // The width must be DWORD aligned unless the bitmap is RLE 

     // compressed. 

     pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8

         * pbmi->bmiHeader.biHeight; 

     // Set biClrImportant to 0, indicating that all of the  

     // device colors are important.  

     pbmi->bmiHeader.biClrImportant = 0; 

     return pbmi; 

}

void CWaterMark::CreateBMPFile(HWND hwnd, LPCTSTR pszFile, PBITMAPINFO pbi, 

                                    HBITMAP hBMP, HDC hDC) 

     HANDLE hf;                 // file handle  

     BITMAPFILEHEADER hdr;       // bitmap file-header  

     PBITMAPINFOHEADER pbih;     // bitmap info-header  

     LPBYTE lpBits;              // memory pointer  

     DWORD dwTotal;              // total count of bytes  

     DWORD cb;                   // incremental count of bytes  

     BYTE *hp;                   // byte pointer  

     DWORD dwTmp; 

 

     pbih = (PBITMAPINFOHEADER) pbi; 

     lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

 

     if (!lpBits) 

         return

 

     // Retrieve the color table (RGBQUAD array) and the bits  

     // (array of palette indices) from the DIB.  

     if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, 

         DIB_RGB_COLORS)) 

     {

         return

     }

 

     // Create the .BMP file.  

     hf = CreateFile(pszFile, 

         GENERIC_READ | GENERIC_WRITE, 

         FILE_SHARE_READ, 

         NULL, 

         CREATE_ALWAYS, 

         FILE_ATTRIBUTE_NORMAL, 

         NULL); 

     if (hf == INVALID_HANDLE_VALUE) 

         return

     hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"  

     // Compute the size of the entire file.  

     hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 

         pbih->biSize + pbih->biClrUsed 

         * sizeof(RGBQUAD) + pbih->biSizeImage); 

     hdr.bfReserved1 = 0; 

     hdr.bfReserved2 = 0; 

 

     // Compute the offset to the array of color indices.  

     hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 

         pbih->biSize + pbih->biClrUsed 

         * sizeof (RGBQUAD); 

 

     // Copy the BITMAPFILEHEADER into the .BMP file.  

     if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 

         (LPDWORD) &dwTmp,  NULL)) 

     {

         return

     }

 

     // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.  

     if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) 

         + pbih->biClrUsed * sizeof (RGBQUAD), 

         (LPDWORD) &dwTmp, ( NULL)))

         return

 

     // Copy the array of color indices into the .BMP file.  

     dwTotal = cb = pbih->biSizeImage; 

     hp = lpBits; 

     if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 

         return

 

     // Close the .BMP file.  

     if (!CloseHandle(hf)) 

         return

 

     // Free memory.  

     GlobalFree((HGLOBAL)lpBits);

}

测试代码:新建一个单文档,新建一个测试菜单项

void CBasicCGView::OnTestMenu()

{

     //构造一个水印操作类对象

     CWaterMark mark(IDB_BITMAP1);

     //创建一个字体GDI对象

     HFONT hFont = CreateFontA(28, 0, 0, 0, FW_BOLD, 1, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("华文楷体"));

     //设置水印文字文本字体

     mark.SetTextFont(hFont);

     //设置水印文字文本颜色

     mark.SetForeColor(RGB(255, 128, 0));

     //添加一条水印文本到位图的右下角,也可以添加多条

     //自动添加水印时,文字与图片上下左右顶端的间距由

     //mark.m_leftSpacing, mark.m_rightSpacing, mark.m_topSpacing, mark.m_bottomSpacing控制

     mark.AddWaterMark("Hello World", CWaterMark::Location::RightBottom);

     BITMAP bmp;

     mark.GetBitmap(&bmp);

     CDC* pDC = GetDC();

     //拷贝结果到客户区视图DC

     pDC->BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, CDC::FromHandle(mark.GetMemoryDC()), 0, 0, SRCCOPY);

     ReleaseDC(pDC);

     //保存结果到指定位图文件

     mark.Save("C://1.bmp");

}

目前,该类只能处理位图图片