给位图文件添加文字水印

转自: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对象

HBITMAPm_hOldBmp;

HDCm_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;

WORDcClrBits;

// 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");

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值