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

图形图象

开发平台:

Visual C++

  1. ////////////////////////////////////////////////////////////////////////////
  2. // mfcappView.cpp : implementation of the CMfcappView class
  3. //
  4. //
  5. // Note  : GIF code removed 9/23/97 pending Unisys licensing. 
  6. //
  7. //
  8. // This code copyright 1997 Chris Losinger, unless otherwise noted
  9. //
  10. // CHRISDL@PAGESZ.NET
  11. //
  12. // PLEASE!!! Tell me of any bugs you find!!!
  13. //
  14. // This code contains examples of using my JpegFile class, how to
  15. // read and write 1,4,8 and 24-bit BMPs 
  16. //
  17. // I find that this code works well for my purposes. Feel free to 
  18. // use it in your own code, but I can't assume any responsibility
  19. // if this code fails to do what you expect.
  20. //
  21. // If you find any problems with this code, feel free to contact 
  22. // me for help.
  23. //
  24. // 24-bit to 8-bit color quantization code modified from Dennis Lee's
  25. // DL1Quant. His source is available at ...
  26. //
  27. // MfcAppView.cpp : implementation of the CMfcAppView class
  28. //
  29. #include "stdafx.h"
  30. #include "MfcApp.h"
  31. #include <math.h>
  32. #include "MfcAppDoc.h"
  33. #include "MfcAppView.h"
  34. #include "JpegFile.h"
  35. #include "BMPDlg.h"
  36. #include "BMPFile.h"
  37. #include "QuantDlg.h"
  38. #include "dl1quant.h"
  39. #ifdef _DEBUG
  40. #define new DEBUG_NEW
  41. #undef THIS_FILE
  42. static char THIS_FILE[] = __FILE__;
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CMfcAppView
  46. IMPLEMENT_DYNCREATE(CMfcAppView, CView)
  47. BEGIN_MESSAGE_MAP(CMfcAppView, CView)
  48. //{{AFX_MSG_MAP(CMfcAppView)
  49. ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
  50. ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
  51. ON_COMMAND(ID_FILE_SAVECOLORMAPPEDBMP, OnFileSavecolormappedbmp)
  52. ON_COMMAND(ID_FILE_SAVEGRAYAS, OnFileSavegrayas)
  53. ON_COMMAND(ID_FILE_GETDIMENSIONSJPG, OnFileGetdimensionsjpg)
  54. //}}AFX_MSG_MAP
  55. END_MESSAGE_MAP()
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CMfcAppView construction/destruction
  58. CMfcAppView::CMfcAppView()
  59. {
  60. // we keep a single global image in memory
  61. m_buf=NULL; // where we keep our image data
  62. m_width=0; // image dimensions
  63. m_height=0;
  64. m_widthDW=0;
  65. }
  66. CMfcAppView::~CMfcAppView()
  67. {
  68. // clean up
  69. if (m_buf!=NULL) {
  70. delete [] m_buf;
  71. m_buf=NULL;
  72. }
  73. }
  74. BOOL CMfcAppView::PreCreateWindow(CREATESTRUCT& cs)
  75. {
  76. // TODO: Modify the Window class or styles here by modifying
  77. //  the CREATESTRUCT cs
  78. return CView::PreCreateWindow(cs);
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. // CMfcAppView drawing
  82. void CMfcAppView::OnDraw(CDC* pDC)
  83. {
  84. CMfcAppDoc* pDoc = GetDocument();
  85. ASSERT_VALID(pDoc);
  86. // draw the BMP we have in memory
  87. DrawBMP();
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CMfcAppView diagnostics
  91. #ifdef _DEBUG
  92. void CMfcAppView::AssertValid() const
  93. {
  94. CView::AssertValid();
  95. }
  96. void CMfcAppView::Dump(CDumpContext& dc) const
  97. {
  98. CView::Dump(dc);
  99. }
  100. CMfcAppDoc* CMfcAppView::GetDocument() // non-debug version is inline
  101. {
  102. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMfcAppDoc)));
  103. return (CMfcAppDoc*)m_pDocument;
  104. }
  105. #endif //_DEBUG
  106. /////////////////////////////////////////////////////////////////////////////
  107. // CMfcAppView message handlers
  108. void CMfcAppView::OnFileOpen() 
  109. {
  110. CString fileName;
  111. CString filt="JPG File (*.JPG)|*.JPG|BMP (*.BMP)|*.BMP|All files (*.*)|*.*||";
  112.     
  113.     // OPENFILENAME - so i can get to its Help page easily
  114. CFileDialog fileDlg(TRUE,"*.JPG","*.JPG",NULL,filt,this);
  115. fileDlg.m_ofn.Flags|=OFN_FILEMUSTEXIST;
  116. fileDlg.m_ofn.lpstrTitle="File to load";
  117. if (fileDlg.DoModal()==IDOK) {
  118. AfxGetApp()->DoWaitCursor(1);
  119. fileName=fileDlg.GetPathName();
  120. CString ext=fileName.Right(4);
  121. if (!ext.CompareNoCase(".JPG"))
  122. LoadJPG(fileName);
  123. if (!ext.CompareNoCase(".BMP"))
  124. LoadBMP(fileName);
  125. AfxGetApp()->DoWaitCursor(-1);
  126. }            
  127. // force a redraw
  128. Invalidate(TRUE);
  129. }
  130. void CMfcAppView::OnFileSaveAs() 
  131. {
  132. CString fileName;
  133. CString filt="JPG File (*.JPG)|*.JPG|BMP (*.BMP)|*.BMP|All files (*.*)|*.*||";
  134.     
  135.     // OPENFILENAME - so i can get to its Help page easily
  136. CFileDialog fileDlg(FALSE,"*.JPG","*.JPG",NULL,filt,this);
  137. fileDlg.m_ofn.Flags|=OFN_FILEMUSTEXIST;
  138. fileDlg.m_ofn.lpstrTitle="File to save as";
  139. if (fileDlg.DoModal()==IDOK) {
  140. AfxGetApp()->DoWaitCursor(1);
  141. fileName=fileDlg.GetPathName();
  142. CString ext=fileName.Right(4);
  143. if (!ext.CompareNoCase(".JPG"))
  144. SaveJPG(fileName,TRUE);
  145. if (!ext.CompareNoCase(".BMP"))
  146. SaveBMP24(fileName);
  147. AfxGetApp()->DoWaitCursor(-1);
  148. }      
  149. }
  150. void CMfcAppView::OnFileSavecolormappedbmp() 
  151. {
  152. if (m_buf==NULL) {
  153. AfxMessageBox("No Image!");
  154. return;
  155. }
  156. ////////////////////////////////////////////////////////////////////////
  157. // get the filename
  158. CString fileName;
  159. CString filt="BMP (*.BMP)|*.BMP|All files (*.*)|*.*||";
  160.     
  161.     // OPENFILENAME - so i can get to its Help page easily
  162. CFileDialog fileDlg(FALSE,"*.BMP","*.BMP",NULL,filt,this);
  163. fileDlg.m_ofn.Flags|=OFN_FILEMUSTEXIST;
  164. fileDlg.m_ofn.lpstrTitle="File to save as";
  165. if (fileDlg.DoModal()!=IDOK)
  166. return;
  167. fileName=fileDlg.GetPathName();
  168. ////////////////////////////////////////////////////////////////////////
  169. // fetch bits per pixel
  170. CBMPDlg theDlg;
  171. if (theDlg.DoModal()!=IDOK)
  172. return;
  173. int bitsperpixel = theDlg.m_bits;
  174. AfxGetApp()->DoWaitCursor(1);
  175. ////////////////////////////////////////////////////////////////////////
  176. // prepare for color-mapping
  177. // our palette
  178. RGBQUAD colormap[256];
  179. // num colors
  180. int colors = (int)pow(2,bitsperpixel);
  181. BYTE *colorMappedBuffer = NULL;
  182. // if we can use the color quantizer, we will
  183. if (bitsperpixel==8) {
  184. CQuantDlg theDlg;
  185. if (theDlg.DoModal()!=IDOK) {
  186. return;
  187. }
  188. // color or grayscale?
  189. if (theDlg.m_color) {
  190. // color !
  191. // allocate a buffer to colormap to
  192. colorMappedBuffer = (BYTE *)  new BYTE[m_width* m_height];
  193. if (colorMappedBuffer==NULL) {
  194. AfxMessageBox("Memory Error in OnSaveColormappedbmp!");
  195. return;
  196. }
  197. BYTE tmpPal[3][256];
  198. // colormap it 
  199. // generates an 8-bit color-mapped image into colorMappedBuffer
  200. if (!dl1quant(m_buf, 
  201. colorMappedBuffer, // buffers
  202. m_width,
  203. m_height,
  204. theDlg.m_quantColors,
  205. TRUE,
  206. tmpPal)) { // palette
  207. AfxMessageBox("Quantization error");
  208. delete [] colorMappedBuffer;
  209. return;
  210. }
  211. // copy our palette
  212. for (UINT col=0;col<256;col++) {
  213. if (col>theDlg.m_quantColors) {
  214. colormap[col].rgbRed=0;
  215. colormap[col].rgbBlue=0;
  216. colormap[col].rgbGreen=0;
  217. } else {
  218. colormap[col].rgbRed=tmpPal[0][col];
  219. colormap[col].rgbGreen=tmpPal[1][col];
  220. colormap[col].rgbBlue=tmpPal[2][col];
  221. }
  222. }
  223. } else {
  224. // gray :(
  225. // convert to 8-bit colormapped grayscale
  226. colorMappedBuffer = MakeColormappedGrayscale(m_buf, // RGB
  227. (UINT)m_width, // pixels
  228. (UINT)m_height, 
  229. (UINT)m_width * 3, // bytes
  230. (UINT)colors, // colors
  231. colormap); // palette
  232. }
  233. } else { // bitsperpixel!=8
  234. // based on bitsperpixel, create a colormapped image
  235. colorMappedBuffer = MakeColormappedGrayscale(m_buf, 
  236. (UINT)m_width, 
  237. (UINT)m_height, 
  238. (UINT)m_width * 3, 
  239. (UINT)colors,
  240. colormap);
  241. }
  242. ////////////////////////////////////////////////////////////////////////
  243. // finally, save the thing
  244. if (colorMappedBuffer!=NULL) {
  245. // write the BMP using our colormapped image (one byte per pixel, packed),
  246. // number of bits, number of total colors and a colormap
  247. // pixel values must be in the range [0...colors-1]
  248. BMPFile theBmpFile;
  249. theBmpFile.SaveBMP(fileName, // path
  250. colorMappedBuffer, // image
  251. m_width, // pixels
  252. m_height,
  253. bitsperpixel, // 1,4,8
  254. colors, // num colors
  255. colormap); // palette
  256. if (theBmpFile.m_errorText!="OK") {
  257. AfxMessageBox(theBmpFile.m_errorText, MB_ICONSTOP);
  258. }else {
  259. // load what we just saved
  260. LoadBMP(fileName);
  261. Invalidate(TRUE);
  262. }
  263. // toss our buffer...
  264. delete [] colorMappedBuffer;
  265. } else {
  266. AfxMessageBox("Failed to allocate space for RGB buffer");
  267. }
  268. AfxGetApp()->DoWaitCursor(-1);
  269. }
  270. void CMfcAppView::OnFileSavegrayas() 
  271. {
  272. // note, because i'm lazy, most image data in this app
  273. // is handled as 24-bit images. this makes the DIB
  274. // conversion easier. 1,4,8, 15/16 and 32 bit DIBs are
  275. // significantly more difficult to handle.
  276. CString fileName;
  277. CString filt="JPG File (*.JPG)|*.JPG|All files (*.*)|*.*||";
  278.     
  279.     // OPENFILENAME - so i can get to its Help page easily
  280. CFileDialog fileDlg(FALSE,"*.JPG","*.JPG",NULL,filt,this);
  281. fileDlg.m_ofn.Flags|=OFN_FILEMUSTEXIST;
  282. fileDlg.m_ofn.lpstrTitle="File to save as grayscale";
  283. if (fileDlg.DoModal()==IDOK) {
  284. fileName=fileDlg.GetPathName();
  285. AfxGetApp()->DoWaitCursor(1);
  286. CString ext;
  287. ext=fileName.Right(4);
  288. if (!ext.CompareNoCase(".JPG"))
  289. SaveJPG(fileName,FALSE);
  290. AfxGetApp()->DoWaitCursor(-1);
  291. }
  292. }
  293. void CMfcAppView::DrawBMP()
  294. {
  295. // if we don't have an image, get out of here
  296. if (m_buf==NULL) return;
  297. CDC *theDC = GetDC();
  298. if (theDC!=NULL) {
  299. CRect clientRect;
  300. GetClientRect(clientRect);
  301. // Center It
  302. int left = max(clientRect.left, ((clientRect.Width() - (int)m_width) / 2));
  303. int top = max(clientRect.top, ((clientRect.Height() - (int)m_height) / 2));
  304. // a 24-bit DIB is DWORD-aligned, vertically flipped and 
  305. // has Red and Blue bytes swapped. we already did the 
  306. // RGB->BGR and the flip when we read the images, now do
  307. // the DWORD-align
  308. BYTE *tmp;
  309. // DWORD-align for display
  310. tmp = JpegFile::MakeDwordAlignedBuf(m_buf,
  311.  m_width,
  312.  m_height,
  313.  &m_widthDW);
  314. // set up a DIB 
  315. BITMAPINFOHEADER bmiHeader;
  316. bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  317. bmiHeader.biWidth = m_width;
  318. bmiHeader.biHeight = m_height;
  319. bmiHeader.biPlanes = 1;
  320. bmiHeader.biBitCount = 24;
  321. bmiHeader.biCompression = BI_RGB;
  322. bmiHeader.biSizeImage = 0;
  323. bmiHeader.biXPelsPerMeter = 0;
  324. bmiHeader.biYPelsPerMeter = 0;
  325. bmiHeader.biClrUsed = 0;
  326. bmiHeader.biClrImportant = 0;
  327. // now blast it to the CDC passed in.
  328. // lines returns the number of lines actually displayed
  329. int lines = StretchDIBits(theDC->m_hDC,
  330. left, top,
  331. bmiHeader.biWidth,
  332. bmiHeader.biHeight,
  333. 0,0,
  334. bmiHeader.biWidth,
  335. bmiHeader.biHeight,
  336. tmp,
  337. (LPBITMAPINFO)&bmiHeader,
  338. DIB_RGB_COLORS,
  339. SRCCOPY);
  340. delete [] tmp;
  341. CString info;
  342. info.Format("(%d x %d)", m_width, m_height);
  343. theDC->SetBkMode(TRANSPARENT);
  344. theDC->SetTextColor(RGB(0,0,0));
  345. theDC->TextOut(10,5, info);
  346. ReleaseDC(theDC);
  347. }
  348. }
  349. ////////////////////////////////////////////////////////////////////////////
  350. // read a JPG to our global buffer
  351. //
  352. void CMfcAppView::LoadJPG(CString fileName)
  353. {
  354. // m_buf is the global buffer
  355. if (m_buf!=NULL) {
  356. delete [] m_buf;
  357. m_buf=NULL;
  358. }
  359. // read to buffer tmp
  360. m_buf=JpegFile::JpegFileToRGB(fileName, &m_width, &m_height);
  361. //////////////////////
  362. // set up for display
  363. // do this before DWORD-alignment!!!
  364. // this works on packed (not DWORD-aligned) buffers
  365. // swap red and blue for display
  366. JpegFile::BGRFromRGB(m_buf, m_width, m_height);
  367. // vertical flip for display
  368. JpegFile::VertFlipBuf(m_buf, m_width * 3, m_height);
  369. }
  370. ////////////////////////////////////////////////////////////////////////////
  371. // read a BMP to our global buffer
  372. //
  373. void CMfcAppView::LoadBMP(CString fileName)
  374. {
  375. if (m_buf!=NULL) {
  376. delete [] m_buf;
  377. }
  378. BMPFile theBmpFile;
  379. m_buf=theBmpFile.LoadBMP(fileName, &m_width, &m_height);
  380. if ((m_buf==NULL) || (theBmpFile.m_errorText!="OK")) 
  381. {
  382. AfxMessageBox(theBmpFile.m_errorText);
  383. m_buf=NULL;
  384. return;
  385. }
  386. //////////////////////
  387. // set up for display
  388. // do this before DWORD-alignment!!!
  389. // this works on packed (not DWORD-aligned) buffers
  390. // swap red and blue for display
  391. JpegFile::BGRFromRGB(m_buf, m_width, m_height);
  392. // vertical flip for display
  393. JpegFile::VertFlipBuf(m_buf, m_width * 3, m_height);
  394. }
  395. ////////////////////////////////////////////////////////////////////////////
  396. // save functions are generally more complex than reading functions.
  397. // there are many more decisions to be made for writing than for reading.
  398. ////////////////////////////////////////////////////////////////////////////
  399. // save a JPG
  400. void CMfcAppView::SaveJPG(CString fileName, BOOL color)
  401. {
  402. // note, because i'm lazy, most image data in this app
  403. // is handled as 24-bit images. this makes the DIB
  404. // conversion easier. 1,4,8, 15/16 and 32 bit DIBs are
  405. // significantly more difficult to handle.
  406. if (m_buf==NULL) {
  407. AfxMessageBox("No Image!");
  408. return;
  409. }
  410. // we vertical flip for display. undo that.
  411. JpegFile::VertFlipBuf(m_buf, m_width * 3, m_height);
  412. // we swap red and blue for display, undo that.
  413. JpegFile::BGRFromRGB(m_buf, m_width, m_height);
  414. // save RGB packed buffer to JPG
  415. BOOL ok=JpegFile::RGBToJpegFile(fileName, 
  416. m_buf,
  417. m_width,
  418. m_height,
  419. color, 
  420. 75); // quality value 1-100.
  421. if (!ok) {
  422. AfxMessageBox("Write Error");
  423. } else {
  424. // load what we just saved
  425. LoadJPG(fileName);
  426. Invalidate(TRUE);
  427. }
  428. }
  429. ////////////////////////////////////////////////////////////////////////////
  430. //
  431. // use the BMPFile class to write a 24-bit BMP file
  432. //
  433. void CMfcAppView::SaveBMP24(CString filename)
  434. {
  435. // note, because i'm lazy, most image data in this app
  436. // is handled as 24-bit images. this makes the DIB
  437. // conversion easier. 1,4,8, 15/16 and 32 bit DIBs are
  438. // significantly more difficult to handle.
  439. if (m_buf==NULL) {
  440. AfxMessageBox("No Image!");
  441. return;
  442. }
  443. // image in m_buf is already BGR and vertically flipped, so we don't need
  444. // to do that for this function.
  445. // i really should make an RGB to BMP fn.
  446. BMPFile theBmpFile;
  447. theBmpFile.SaveBMP(filename,
  448. m_buf,
  449. m_width,
  450. m_height);
  451. if (theBmpFile.m_errorText!="OK") 
  452. AfxMessageBox(theBmpFile.m_errorText, MB_ICONSTOP);
  453. else {
  454. // load what we just saved
  455. LoadBMP(filename);
  456. Invalidate(TRUE);
  457. }
  458. }
  459. // get JPG dimensions
  460. void CMfcAppView::OnFileGetdimensionsjpg() 
  461. {
  462. CString fileName;
  463. CString filt="JPG File (*.JPG)|*.JPG|All files (*.*)|*.*||";
  464.     
  465.     // OPENFILENAME - so i can get to its Help page easily
  466. CFileDialog fileDlg(TRUE,"*.JPG","*.JPG",NULL,filt,this);
  467. fileDlg.m_ofn.Flags|=OFN_FILEMUSTEXIST;
  468. fileDlg.m_ofn.lpstrTitle="File to examine";
  469. if (fileDlg.DoModal()==IDOK) {
  470. fileName=fileDlg.GetPathName();
  471. UINT width, height;
  472. if (JpegFile::GetJPGDimensions(fileName,
  473. &width,
  474. &height)) {
  475. char buf[200];
  476. sprintf(buf,"%d %d",width,height);
  477. AfxMessageBox(buf);
  478. } else
  479. AfxMessageBox("JPEG Error");
  480. }            
  481. }
  482. ////////////////////////////////////////////////////////////////////////
  483. // instead of creating a good palette for the colormapped images
  484. // this just graymaps them.
  485. //
  486. BYTE * CMfcAppView::MakeColormappedGrayscale(BYTE *inBuf,
  487.   UINT inWidth,
  488.   UINT inHeight,
  489.   UINT inWidthBytes,
  490.   UINT colors,
  491.   RGBQUAD* colormap)
  492. {
  493. ////////////////////////////////////////////////////////////////////////
  494. // allocate a buffer to colormap
  495. BYTE *tmp = (BYTE *)  new BYTE[inWidth * inHeight];
  496. if (tmp==NULL)
  497. return NULL;
  498. // force our image to use a stupid gray scale
  499. UINT color;
  500. for (color = 0;color < colors; color++) {
  501. colormap[color].rgbRed = color * 256 / colors;
  502. colormap[color].rgbGreen = color * 256 / colors;
  503. colormap[color].rgbBlue = color * 256 / colors;
  504. }
  505. UINT col, row;
  506. for (row =0; row < inHeight; row++) {
  507. for (col=0;col <inWidth; col++) {
  508. BYTE inRed, inBlue, inGreen;
  509. // src pixel
  510. long in_offset = row * inWidthBytes + col * 3;
  511. inRed = *(inBuf + in_offset + 0);
  512. inGreen = *(inBuf + in_offset + 1);
  513. inBlue = *(inBuf + in_offset + 2);
  514. // luminance
  515. int lum = (int)(.299 * (double)(inRed) + 
  516. .587 * (double)(inGreen) + 
  517. .114 * (double)(inBlue));
  518. // force luminance value into our range of colors
  519. lum = colors * lum / 256;
  520. // dest pixel
  521. long out_offset = row * inWidth + col;
  522. *(tmp+out_offset) = (BYTE)lum;
  523. }
  524. }
  525. return tmp;
  526. }