Bmpfile.cpp
上传用户:qiutianh
上传日期:2022-08-08
资源大小:939k
文件大小:14k
源码类别:

图形图象

开发平台:

Visual C++

  1. // bmpops.cpp : implementation of the BMPFile class
  2. //
  3. // This handles the reading and writing of BMP files.
  4. //
  5. //
  6. #include "stdafx.h"
  7. #include "bmpfile.h"
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. BMPFile::BMPFile()
  14. {
  15. m_errorText="OK";
  16. }
  17. ////////////////////////////////////////////////////////////////////////////
  18. // load a .BMP file - 1,4,8,24 bit
  19. //
  20. // allocates and returns an RGB buffer containing the image.
  21. // modifies width and height accordingly - NULL, 0, 0 on error
  22. BYTE * BMPFile::LoadBMP(CString fileName, 
  23. UINT *width, 
  24. UINT *height)
  25. {
  26. BITMAP inBM;
  27. BYTE m1,m2;
  28.     long filesize;
  29.     short res1,res2;
  30.     long pixoff;
  31.     long bmisize;                    
  32.     long compression;
  33.     unsigned long sizeimage;
  34.     long xscale, yscale;
  35.     long colors;
  36.     long impcol;
  37.     
  38. BYTE *outBuf=NULL;
  39. // for safety
  40. *width=0; *height=0;
  41. // init
  42. m_errorText="OK";
  43. m_bytesRead=0;
  44. FILE *fp;
  45. fp=fopen(fileName,"rb");
  46. if (fp==NULL) {
  47. CString msg;                    
  48. msg="Can't open file for reading :n"+fileName;
  49. m_errorText=msg;
  50. return NULL;
  51. } else {
  52.     long rc;
  53. rc=fread((BYTE  *)&(m1),1,1,fp); m_bytesRead+=1;
  54. if (rc==-1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  55. rc=fread((BYTE  *)&(m2),1,1,fp); m_bytesRead+=1;
  56. if (rc==-1) m_errorText="Read Error!";
  57. if ((m1!='B') || (m2!='M')) {
  58. m_errorText="Not a valid BMP File";
  59. fclose(fp);
  60. return NULL;
  61.         }
  62.         
  63. ////////////////////////////////////////////////////////////////////////////
  64. //
  65. // read a ton of header stuff
  66. rc=fread((long  *)&(filesize),4,1,fp); m_bytesRead+=4;
  67. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  68. rc=fread((int  *)&(res1),2,1,fp); m_bytesRead+=2;
  69. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  70. rc=fread((int  *)&(res2),2,1,fp); m_bytesRead+=2;
  71. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  72. rc=fread((long  *)&(pixoff),4,1,fp); m_bytesRead+=4;
  73. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  74. rc=fread((long  *)&(bmisize),4,1,fp); m_bytesRead+=4;
  75. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  76. rc=fread((long  *)&(inBM.bmWidth),4,1,fp);  m_bytesRead+=4;
  77. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  78. rc=fread((long  *)&(inBM.bmHeight),4,1,fp); m_bytesRead+=4;
  79. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  80. rc=fread((int  *)&(inBM.bmPlanes),2,1,fp); m_bytesRead+=2;
  81. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  82. rc=fread((int  *)&(inBM.bmBitsPixel),2,1,fp); m_bytesRead+=2;
  83. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  84. rc=fread((long  *)&(compression),4,1,fp); m_bytesRead+=4;
  85. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  86. rc=fread((long  *)&(sizeimage),4,1,fp); m_bytesRead+=4;
  87. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  88. rc=fread((long  *)&(xscale),4,1,fp); m_bytesRead+=4;
  89. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  90. rc=fread((long  *)&(yscale),4,1,fp); m_bytesRead+=4;
  91. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  92. rc=fread((long  *)&(colors),4,1,fp); m_bytesRead+=4;
  93. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  94. rc=fread((long  *)&(impcol),4,1,fp); m_bytesRead+=4;
  95. if (rc!=1) {m_errorText="Read Error!"; fclose(fp); return NULL;}
  96. ////////////////////////////////////////////////////////////////////////////
  97. // i don't do RLE files
  98. if (compression!=BI_RGB) {
  99.      m_errorText="This is a compressed file.";
  100.      fclose(fp);
  101.      return NULL;
  102.     }
  103. if (colors == 0) {
  104. colors = 1 << inBM.bmBitsPixel;
  105. }
  106. ////////////////////////////////////////////////////////////////////////////
  107. // read colormap
  108. RGBQUAD *colormap = NULL;
  109. switch (inBM.bmBitsPixel) {
  110. case 24:
  111. break;
  112. // read pallete 
  113. case 1:
  114. case 4:
  115. case 8:
  116. colormap = new RGBQUAD[colors];
  117. if (colormap==NULL) {
  118. fclose(fp);
  119. m_errorText="Out of memory";
  120. return NULL;
  121. }
  122. int i;
  123. for (i=0;i<colors;i++) {
  124. BYTE r,g,b, dummy;
  125. rc=fread((BYTE *)&(b),1,1,fp);
  126. m_bytesRead++;
  127. if (rc!=1) {
  128. m_errorText="Read Error!";
  129. delete [] colormap;
  130. fclose(fp);
  131. return NULL;
  132. }
  133. rc=fread((BYTE  *)&(g),1,1,fp); 
  134. m_bytesRead++;
  135. if (rc!=1) {
  136. m_errorText="Read Error!";
  137. delete [] colormap;
  138. fclose(fp);
  139. return NULL;
  140. }
  141. rc=fread((BYTE  *)&(r),1,1,fp); 
  142. m_bytesRead++;
  143. if (rc!=1) {
  144. m_errorText="Read Error!";
  145. delete [] colormap;
  146. fclose(fp);
  147. return NULL;
  148. }
  149. rc=fread((BYTE  *)&(dummy),1,1,fp); 
  150. m_bytesRead++;
  151. if (rc!=1) {
  152. m_errorText="Read Error!";
  153. delete [] colormap;
  154. fclose(fp);
  155. return NULL;
  156. }
  157. colormap[i].rgbRed=r;
  158. colormap[i].rgbGreen=g;
  159. colormap[i].rgbBlue=b;
  160. }
  161. break;
  162. }
  163. if ((long)m_bytesRead>pixoff) {
  164. fclose(fp);
  165. m_errorText="Corrupt palette";
  166. delete [] colormap;
  167. fclose(fp);
  168. return NULL;
  169. }
  170. while ((long)m_bytesRead<pixoff) {
  171. char dummy;
  172. fread(&dummy,1,1,fp);
  173. m_bytesRead++;
  174. }
  175. int w=inBM.bmWidth;
  176. int h=inBM.bmHeight;
  177. // set the output params
  178. *width=w;
  179. *height=h;
  180. long row_size = w * 3;
  181. long bufsize = (long)w * 3 * (long)h;
  182. ////////////////////////////////////////////////////////////////////////////
  183. // alloc our buffer
  184. outBuf=(BYTE *) new BYTE [bufsize];
  185. if (outBuf==NULL) {
  186. m_errorText="Memory alloc Failed";
  187. } else {
  188. ////////////////////////////////////////////////////////////////////////////
  189. // read it
  190. long row=0;
  191. long rowOffset=0;
  192. // read rows in reverse order
  193. for (row=inBM.bmHeight-1;row>=0;row--) {
  194. // which row are we working on?
  195. rowOffset=(long unsigned)row*row_size;       
  196. if (inBM.bmBitsPixel==24) {
  197. for (int col=0;col<w;col++) {
  198. long offset = col * 3;
  199. char pixel[3];
  200. if (fread((void  *)(pixel),1,3,fp)==3) {
  201. // we swap red and blue here
  202. *(outBuf + rowOffset + offset + 0)=pixel[2]; // r
  203. *(outBuf + rowOffset + offset + 1)=pixel[1]; // g
  204. *(outBuf + rowOffset + offset + 2)=pixel[0]; // b
  205. }
  206. }
  207. m_bytesRead+=row_size;
  208. // read DWORD padding
  209. while ((m_bytesRead-pixoff)&3) {
  210. char dummy;
  211. if (fread(&dummy,1,1,fp)!=1) {
  212. m_errorText="Read Error";
  213. delete [] outBuf;
  214. fclose(fp);
  215. return NULL;
  216. }
  217. m_bytesRead++;
  218. }
  219.  
  220. } else { // 1, 4, or 8 bit image
  221. ////////////////////////////////////////////////////////////////
  222. // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
  223. int bit_count = 0;
  224. UINT mask = (1 << inBM.bmBitsPixel) - 1;
  225. BYTE inbyte=0;
  226. for (int col=0;col<w;col++) {
  227. int pix=0;
  228. // if we need another byte
  229. if (bit_count <= 0) {
  230. bit_count = 8;
  231. if (fread(&inbyte,1,1,fp)!=1) {
  232. m_errorText="Read Error";
  233. delete [] outBuf;
  234. delete [] colormap;
  235. fclose(fp);
  236. return NULL;
  237. }
  238. m_bytesRead++;
  239. }
  240. // keep track of where we are in the bytes
  241. bit_count -= inBM.bmBitsPixel;
  242. pix = ( inbyte >> bit_count) & mask;
  243. // lookup the color from the colormap - stuff it in our buffer
  244. // swap red and blue
  245. *(outBuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue;
  246. *(outBuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen;
  247. *(outBuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed;
  248. }
  249. // read DWORD padding
  250. while ((m_bytesRead-pixoff)&3) {
  251. char dummy;
  252. if (fread(&dummy,1,1,fp)!=1) {
  253. m_errorText="Read Error";
  254. delete [] outBuf;
  255. if (colormap)
  256. delete [] colormap;
  257. fclose(fp);
  258. return NULL;
  259. }
  260. m_bytesRead++;
  261. }
  262. }
  263. }
  264. }
  265. if (colormap) {
  266. delete [] colormap;
  267. }
  268. fclose(fp);
  269.     }
  270. return outBuf;
  271. }
  272. ////////////////////////////////////////////////////////////////////////////
  273. // write a 24-bit BMP file
  274. //
  275. // image MUST be a packed buffer (not DWORD-aligned)
  276. // image MUST be vertically flipped !
  277. // image MUST be BGR, not RGB !
  278. //
  279. void BMPFile::SaveBMP(CString fileName, // output path
  280. BYTE * buf, // BGR buffer
  281. UINT width, // pixels
  282. UINT height)
  283. {
  284. short res1=0;
  285.     short res2=0;
  286.     long pixoff=54;
  287.     long compression=0;
  288.     long cmpsize=0;
  289.     long colors=0;
  290.     long impcol=0;
  291. char m1='B';
  292. char m2='M';
  293. m_errorText="OK";
  294. DWORD widthDW = WIDTHBYTES(width * 24);
  295. long bmfsize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  296.    widthDW * height;
  297. long byteswritten=0;
  298. BITMAPINFOHEADER header;
  299.    header.biSize=40;  // header size
  300. header.biWidth=width;
  301. header.biHeight=height;
  302. header.biPlanes=1;
  303. header.biBitCount=24; // RGB encoded, 24 bit
  304. header.biCompression=BI_RGB; // no compression
  305. header.biSizeImage=0;
  306. header.biXPelsPerMeter=0;
  307. header.biYPelsPerMeter=0;
  308. header.biClrUsed=0;
  309. header.biClrImportant=0;
  310. FILE *fp;
  311. fp=fopen(fileName,"wb");
  312. if (fp==NULL) {
  313. m_errorText="Can't open file for writing";
  314. return;
  315. }
  316. // should probably check for write errors here...
  317. fwrite((BYTE  *)&(m1),1,1,fp); byteswritten+=1;
  318. fwrite((BYTE  *)&(m2),1,1,fp); byteswritten+=1;
  319. fwrite((long  *)&(bmfsize),4,1,fp); byteswritten+=4;
  320. fwrite((int  *)&(res1),2,1,fp); byteswritten+=2;
  321. fwrite((int  *)&(res2),2,1,fp); byteswritten+=2;
  322. fwrite((long  *)&(pixoff),4,1,fp); byteswritten+=4;
  323. fwrite((BITMAPINFOHEADER *)&header,sizeof(BITMAPINFOHEADER),1,fp);
  324. byteswritten+=sizeof(BITMAPINFOHEADER);
  325. long row=0;
  326. long rowidx;
  327. long row_size;
  328. row_size=header.biWidth*3;
  329.     long rc;
  330. for (row=0;row<header.biHeight;row++) {
  331. rowidx=(long unsigned)row*row_size;       
  332. // write a row
  333. rc=fwrite((void  *)(buf+rowidx),row_size,1,fp);
  334. if (rc!=1) {
  335. m_errorText="fwrite errornGiving up";
  336. break;
  337. }
  338. byteswritten+=row_size;
  339. // pad to DWORD
  340. for (DWORD count=row_size;count<widthDW;count++) {
  341. char dummy=0;
  342. fwrite(&dummy,1,1,fp);
  343. byteswritten++;   
  344. }
  345. }
  346.            
  347. fclose(fp);
  348. }
  349. ////////////////////////////////////////////////////////////////////////////////////
  350. //
  351. // 1,4,8 bit BMP stuff
  352. //
  353. // if you have a color-mapped image and a color map...
  354. //
  355. // the BMP saving code in SaveColorMappedBMP modified from Programming 
  356. // for Graphics Files in C and C++, by John Levine.
  357. void BMPFile::SaveBMP(CString fileName,  // output path
  358.  BYTE * colormappedbuffer, // one BYTE per pixel colomapped image
  359.  UINT width,
  360.  UINT height,
  361.    int bitsperpixel, // 1, 4, 8
  362.  int colors, // number of colors (number of RGBQUADs)
  363.  RGBQUAD *colormap) // array of RGBQUADs 
  364. {
  365. int datasize, cmapsize, byteswritten, row, col;
  366. m_errorText="OK";
  367. if (bitsperpixel == 24) {
  368. // the routines could be combined, but i don't feel like it
  369. m_errorText="We don't do 24-bit files in here, sorry";
  370. return;
  371. } else
  372. cmapsize = colors * 4;
  373. datasize = BMP_PIXELSIZE(width, height, bitsperpixel);
  374. long filesize = BMP_HEADERSIZE + cmapsize + datasize;
  375. int res1, res2;
  376. res1 = res2 = 0;
  377. long pixeloffset = BMP_HEADERSIZE + cmapsize;
  378. int bmisize = 40;
  379. long cols = width;
  380. long rows = height;
  381. WORD planes = 1;
  382. long compression =0;
  383. long cmpsize = datasize;
  384. long xscale = 0;
  385. long yscale = 0;
  386. long impcolors = colors;
  387. FILE *fp;
  388. fp = fopen(fileName, "wb");
  389. if (fp==NULL) {
  390. m_errorText="Can't Open";
  391. return;
  392. }
  393. char bm[2];
  394. bm[0]='B';
  395. bm[1]='M';
  396. // header stuff
  397. BITMAPFILEHEADER bmfh;
  398. bmfh.bfType=*(WORD *)&bm; 
  399.     bmfh.bfSize= filesize; 
  400.     bmfh.bfReserved1=0; 
  401.     bmfh.bfReserved2=0; 
  402.     bmfh.bfOffBits=pixeloffset; 
  403. fwrite(&bmfh, sizeof (BITMAPFILEHEADER), 1, fp);
  404. BITMAPINFOHEADER bmih;
  405. bmih.biSize = bmisize; 
  406. bmih.biWidth = cols; 
  407. bmih.biHeight = rows; 
  408. bmih.biPlanes = planes; 
  409. bmih.biBitCount =bitsperpixel;
  410. bmih.biCompression = compression; 
  411. bmih.biSizeImage = cmpsize; 
  412. bmih.biXPelsPerMeter = xscale; 
  413. bmih.biYPelsPerMeter = yscale; 
  414. bmih.biClrUsed = colors;
  415. bmih.biClrImportant = impcolors;
  416. fwrite(&bmih, sizeof (BITMAPINFOHEADER), 1, fp);
  417. if (cmapsize) {
  418. int i;
  419. for (i = 0; i< colors; i++) {
  420. putc(colormap[i].rgbRed, fp);
  421. putc(colormap[i].rgbGreen, fp);
  422. putc(colormap[i].rgbBlue, fp);
  423. putc(0, fp); // dummy
  424. }
  425. }
  426. byteswritten = BMP_HEADERSIZE + cmapsize;
  427. for (row = 0; row< (int)height; row++) {
  428. int pixbuf;
  429. int nbits = 0;
  430. for (col =0 ; col < (int)width; col++) {
  431. int offset = row * width + col; // offset into our color-mapped RGB buffer
  432. BYTE pval = *(colormappedbuffer + offset);
  433. pixbuf = (pixbuf << bitsperpixel) | pval;
  434. nbits += bitsperpixel;
  435. if (nbits > 8) {
  436. m_errorText="Error : nBits > 8????";
  437. fclose(fp);
  438. return;
  439. }
  440. if (nbits == 8) {
  441. putc(pixbuf, fp);
  442. pixbuf=0;
  443. nbits=0;
  444. byteswritten++;
  445. }
  446. } // cols
  447. if (nbits > 0) {
  448. putc(pixbuf, fp); // write partially filled byte
  449. byteswritten++;
  450. }
  451. // DWORD align
  452. while ((byteswritten -pixeloffset) & 3) {
  453. putc(0, fp);
  454. byteswritten++;
  455. }
  456. } //rows
  457. if (byteswritten!=filesize) {
  458. m_errorText="byteswritten != filesize";
  459. }
  460. fclose(fp);
  461. }