gooodboooy 发表于 2015-5-30 14:54:40

MFC操作BMP写字的方法

   //一下程序来源于网上,拿来分享下
1 //单击一个Button,保存位图
2 void CDlgDlg::OnButton1()
3 {
4   // TODO: Add your control notification handler code here   
5   HDC hDC = ::GetDC(GetSafeHwnd());
6   HDC hMemDC = CreateCompatibleDC(hDC);
7   //打开位图文件
8   HBITMAP hBmp = OpenBmpFile(hDC, "Splash.bmp");
9   SelectObject(hMemDC, hBmp);
10   //在位图上写字
11   RECT rect = {50, 50, 200, 200};
12   SetBkMode(hMemDC, TRANSPARENT);
13   DrawText(hMemDC, "你好", -1, &rect, DT_VCENTER);
14
15   //保存位图到文件
16   PBITMAPINFO pBmpInfo = CreateBitmapInfoStruct(GetSafeHwnd(), hBmp);
17   CreateBMPFile(GetSafeHwnd(), "Test.bmp", pBmpInfo, hBmp, hDC);
18
19   DeleteDC(hMemDC);
20   DeleteObject(hBmp);
21 }
22
23 //打开位图文件,得到位图句柄
24 HBITMAP CDlgDlg::OpenBmpFile(HDC hDC, LPSTR lpszFileName)
25 {
26   HBITMAP hBmp = NULL;
27   //读位图文件,得到位图句柄
28   HANDLE hFile = CreateFile(
29         lpszFileName,
30         GENERIC_READ,
31         FILE_SHARE_READ,
32         NULL,
33         OPEN_EXISTING,
34         FILE_ATTRIBUTE_NORMAL,
35         NULL);
36   if(hFile == INVALID_HANDLE_VALUE)
37         return NULL;
38   //读位图文件头
39   BITMAPFILEHEADER bmpFileHeader;
40   DWORD dwNumberOfBytesRead;
41   if(ReadFile(hFile, (LPVOID)&bmpFileHeader, sizeof(BITMAPFILEHEADER), &dwNumberOfBytesRead, NULL) == 0)
42   {   
43         CloseHandle(hFile);
44         return NULL;
45   }
46   //读位图信息
47   BITMAPINFO *pBmpInfo = new BITMAPINFO;
48   if(ReadFile(hFile, pBmpInfo, sizeof(BITMAPINFOHEADER), &dwNumberOfBytesRead, NULL) == 0)
49   {   
50         CloseHandle(hFile);
51         return NULL;
52   }
53   //读位图数据
54   LPVOID pBmpData;
55   //创建DIB位图句柄
56   hBmp = CreateDIBSection(hDC, pBmpInfo, DIB_PAL_COLORS, &pBmpData, NULL, 0);
57   if(hBmp == NULL)
58   {
59         DWORD dwErr = GetLastError();
60         return NULL;
61   }
62   else//读位图数据
63         if(ReadFile(hFile, pBmpData, pBmpInfo->bmiHeader.biSizeImage, &dwNumberOfBytesRead, NULL) == 0)
64         {   
65             CloseHandle(hFile);
66             return NULL;
67         }      
68   CloseHandle(hFile);
69   return hBmp;
70 }
71
72 //下面的代码是把一张位图保存于文件中,参考MSDN
73 PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
74 {
75   BITMAP bmp;
76   PBITMAPINFO pbmi;
77   WORD    cClrBits;
78
79   // Retrieve the bitmap's color format, width, and height.
80   if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
81         return NULL;
82
83   // Convert the color format to a count of bits.
84   cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
85   if (cClrBits == 1)
86         cClrBits = 1;
87   else if (cClrBits <= 4)
88         cClrBits = 4;
89   else if (cClrBits <= 8)
90         cClrBits = 8;
91   else if (cClrBits <= 16)
92         cClrBits = 16;
93   else if (cClrBits <= 24)
94         cClrBits = 24;
95   else cClrBits = 32;
96
97   // Allocate memory for the BITMAPINFO structure. (This structure
98   // contains a BITMAPINFOHEADER structure and an array of RGBQUAD
99   // data structures.)
100
101      if (cClrBits != 24)
102          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
103                     sizeof(BITMAPINFOHEADER) +
104                     sizeof(RGBQUAD) * (1<< cClrBits));
105
106      // There is no RGBQUAD array for the 24-bit-per-pixel format.
107
108      else
109          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
110                     sizeof(BITMAPINFOHEADER));
111
112   // Initialize the fields in the BITMAPINFO structure.
113
114   pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
115   pbmi->bmiHeader.biWidth = bmp.bmWidth;
116   pbmi->bmiHeader.biHeight = bmp.bmHeight;
117   pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
118   pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
119   if (cClrBits < 24)
120         pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
121
122   // If the bitmap is not compressed, set the BI_RGB flag.
123   pbmi->bmiHeader.biCompression = BI_RGB;
124
125   // Compute the number of bytes in the array of color
126   // indices and store the result in biSizeImage.
127   // For Windows NT/2000, the width must be DWORD aligned unless
128   // the bitmap is RLE compressed. This example shows this.
129   // For Windows 95/98, the width must be WORD aligned unless the
130   // bitmap is RLE compressed.
131   pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
132                                 * pbmi->bmiHeader.biHeight;
133   // Set biClrImportant to 0, indicating that all of the
134   // device colors are important.
135      pbmi->bmiHeader.biClrImportant = 0;
136      return pbmi;
137}
138
139 void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,
140                   HBITMAP hBMP, HDC hDC)
141{
142      HANDLE hf;               // file handle
143   BITMAPFILEHEADER hdr;       // bitmap file-header
144   PBITMAPINFOHEADER pbih;   // bitmap info-header
145   LPBYTE lpBits;            // memory pointer
146   DWORD dwTotal;            // total count of bytes
147   DWORD cb;                   // incremental count of bytes
148   BYTE *hp;                   // byte pointer
149   DWORD dwTmp;
150
151   pbih = (PBITMAPINFOHEADER) pbi;
152   lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
153
154   if (!lpBits)
155          return ;
156
157   // Retrieve the color table (RGBQUAD array) and the bits
158   // (array of palette indices) from the DIB.
159   if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
160         DIB_RGB_COLORS))
161   {
162         return ;
163   }
164
165   // Create the .BMP file.
166   hf = CreateFile(pszFile,
167                  GENERIC_READ | GENERIC_WRITE,
168                  (DWORD) 0,
169                     NULL,
170                  CREATE_ALWAYS,
171                  FILE_ATTRIBUTE_NORMAL,
172                  (HANDLE) NULL);
173   if (hf == INVALID_HANDLE_VALUE)
174         return ;
175   hdr.bfType = 0x4d42;      // 0x42 = "B" 0x4d = "M"
176   // Compute the size of the entire file.
177   hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
178                  pbih->biSize + pbih->biClrUsed
179                  * sizeof(RGBQUAD) + pbih->biSizeImage);
180   hdr.bfReserved1 = 0;
181   hdr.bfReserved2 = 0;
182
183   // Compute the offset to the array of color indices.
184   hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
185                     pbih->biSize + pbih->biClrUsed
186                     * sizeof (RGBQUAD);
187
188   // Copy the BITMAPFILEHEADER into the .BMP file.
189   if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
190         (LPDWORD) &dwTmp,NULL))
191   {
192      return ;
193   }
194
195   // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
196   if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
197                   + pbih->biClrUsed * sizeof (RGBQUAD),
198                   (LPDWORD) &dwTmp, ( NULL)))
199         return ;
200
201   // Copy the array of color indices into the .BMP file.
202   dwTotal = cb = pbih->biSizeImage;
203   hp = lpBits;
204   if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
205            return ;
206
207   // Close the .BMP file.
208      if (!CloseHandle(hf))
209            return ;
210
211   // Free memory.
212   GlobalFree((HGLOBAL)lpBits);
213 }

另一种实现:
1 FILE *fp=fopen("back.bmp", "rb");
2 if(fp == 0)
3   return 1;
4
5 fseek(fp, sizeof(BITMAPFILEHEADER), 0);
6 BITMAPINFOHEADER head;
7 fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
8 int bmpHeight = head.biHeight;
9 int bmpWidth = head.biWidth;
10 int biBitCount = head.biBitCount;
11 int lineByte = (bmpWidth*biBitCount/8+3)/4*4;
12 RGBQUAD *pColorTable;
13 if(biBitCount == 8)
14 {
15   pColorTable = new RGBQUAD;
16   fread(pColorTable, sizeof(RGBQUAD), 256, fp);
17 }
18 unsigned char *pBmpBuf = new unsigned char;
19 fread(pBmpBuf, 1, lineByte*bmpHeight, fp);
20
21 CDC *m_pMemDC;
22 m_pMemDC = new CDC();
23 CDC *pDC;
24 pDC = GetDC();
25 m_pMemDC->CreateCompatibleDC(pDC);
26 CBitmap *m_pOldBmp = NULL;
27 CBitmap *m_pMemBmp = new CBitmap();       //根据图片的大小创建一个兼容位图
28 m_pMemBmp->CreateCompatibleBitmap(pDC, bmpWidth, bmpHeight);
29 m_pOldBmp = m_pMemDC->SelectObject(m_pMemBmp);
30
31 // 把图像的数据绘制到兼容位图上
32
33 SetDIBits(m_pMemDC->GetSafeHdc(), (HBITMAP)m_pMemBmp->m_hObject,
34   0, bmpHeight, (LPVOID)pBmpBuf, (BITMAPINFO*)&head, DIB_RGB_COLORS);
35 m_pMemDC->SetBkMode(TRANSPARENT);
36 m_pMemDC->SetTextColor(RGB(255, 0, 0));
37
38 //设置字体
39 CFont font;
40 font.CreateFont(10,10,0,0,10,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,OUT_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_SWISS,"宋体");
41 SelectObject(hMemDC, font);
42 // 添加文字到指定位置
43 m_pMemDC->TextOut(17, 10, "hello");
44
45 unsigned char *pTemp = new unsigned char;
46 GetDIBits(m_pMemDC->GetSafeHdc(), (HBITMAP)m_pMemBmp->m_hObject, 0, bmpHeight,
47   (LPVOID)pTemp, (BITMAPINFO*)&head, DIB_RGB_COLORS);
48 fclose(fp);
49
50 char bmpwrite[] = "c:\\2.bmp";
51 fp = fopen(bmpwrite,"wb");
52 BITMAPFILEHEADER fileHead;
53 fileHead.bfType = 0x4D42;
54 fileHead.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+lineByte*bmpHeight;
55 fileHead.bfReserved1 = 0;
56 fileHead.bfReserved2 = 0;
57 fileHead.bfOffBits = 54;
58 fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
59
60 fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
61 fwrite(pTemp, lineByte*bmpHeight, 1, fp);
62 fclose(fp);
63
64 delete m_pMemBmp;
65 delete m_pMemDC;
66 delete[] pBmpBuf;
67 delete[] pTemp;

armstrong 发表于 2015-6-15 21:18:19

用MFC还真是麻烦啊!在.net平台上,几句代码轻松就实现了的。

chxaitz 发表于 2015-6-15 22:27:24

C++选啥都行就是别选MFC,后来你就知道了,框架烂的一比,别的我也不知道谁更好,但是他是最烂的~

hmd420304805 发表于 2015-6-20 11:37:58

用过qt以后,发誓再也不用mfc!

wenshiguang 发表于 2015-6-20 12:02:03

MFC只是难用,并没有那么烂吧,当年C++还没有那么多特性支持的时候搞出来的框架,只是现在更优秀的东西出现了,看着有点过时而已

armstrong 发表于 2015-6-20 22:53:50

关于界面设计,我知道一个比较好用:fltk。它是开源的跨平台界面库,是DirectUI型的,完全面向对象的设计思想。下面是Windows和linux下的示例截图,编译很简单:
Windows下效果:

Linux下效果:
页: [1]
查看完整版本: MFC操作BMP写字的方法