给位图文件添加文字水印
来源:互联网 发布:高等数学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. 设置memDC的TextColor(文字颜色),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"); }
目前,该类只能处理位图图片
- 给位图文件添加文字水印
- 给位图文件添加文字水印
- 给图片添加文字水印
- 给图片添加文字水印
- JAVA给图片上添加水印文字
- java给图片添加水印文字
- Java给图片添加图片、文字水印
- php给图片添加文字水印
- java给图片添加水印文字
- IOS给图片添加文字水印
- java给图片添加水印文字
- Java给图片添加文字水印
- 用canvas给界面添加文字水印
- 给图片添加水印图片文字
- JAVA给图片添加图片水印或文字水印
- java给图片添加图片水印,文字水印,马赛克
- C# 给PDF文件添加水印
- Java给图片添加水印(图标和文字)
- 安装在Windows Azure上的程序集
- 怎样显示Jpg,bmp,Gif图像文件
- 开始学习ASP.NET了
- getServletContext.getRealPath()问题
- Ubuntu不能上网@litsoft
- 给位图文件添加文字水印
- 媒体称乌克兰帮中国建风洞研制重型军事运输机
- No Interfaces Available In Wireshark Mac OS X
- Android开发环境配置
- 6.8_install.txt
- SQL Server 格式化数值
- 命令详解:tee
- 抽象类与接口的区别
- PhpMyAdmin 不能导出数据的一种解决