vc下打印透明背景圖片


一、前言

  剛接到個任務,要把帶有透明背景的章子圖片打印出來,開始覺得不是很簡單嗎,直接用vc自動生成的打印功能不就ok了。不過問題卻不是想像的那么簡單!

二、窗口中顯示透明圖片

  在窗口中顯示圖片,可以用強大的CImage類,這個類能加載很多常見格式的圖像文件,當然對於我要加載的png格式的透明圖片也是可以的。具體的代碼如下:

1 CImage m_image; 2  
3 m_image.Load(_T("picture.png")); 4 if (m_image.IsNull()) 5 { 6     MessageBox(_T("圖片沒加載成功")); 7     return; 8 }

  加載png圖片到CImage對象后,CImage提供了一個函數Draw,可以直接將圖片畫到窗口上下文中,在CDrawView類的OnDraw加入下面的代碼:

  m_Image.Draw(pDC->m_hDC,0,0);

  就這幾行代碼就可以了,直接點運行,圖片確實畫到了窗口上,不過卻不是透明顯示的。透明圖片中每個像素都有一個ALPHA(0-255)值來表示透明的程度,如果某個像素不是透明的,那么它的ALPHA為0。一般在已有像素上畫帶有ALPHA值的像素,可以用下面的方法實現:假設源像素的RGB分別為srcR,srcG,srcB,要畫的帶有ALPHA值的像素的RGB和ALPHA為desR,desG,desB和desA,新像素的RGB為newR,newG,newB。具體計算方法為:

  newR = srcR * (1-desA) / 255 + desR * desA / 255

  newG = srcR * (1-desA) / 255 + desG * desA / 255

  newB = srcB * (1-desA) / 255 + desB * desA / 255

  CImage類中的Draw函數的實現確實根據下面實現的:

     newR = srcR * (1-desA) / 255 + desR 

  newG = srcR * (1-desA) / 255 + desG 

  newB = srcB * (1-desA) / 255 + desB 

  對於超過255的,都按255處理,顯然,如果desR,desG,desB比較大的話,最終得到的newR,newG,newB都將會是255,導致圖片的背景都是白色。所以在調用Draw函數之前必須先對desR,desG,desB進行下面的處理:

  desR = desR * desA / 255

  desG = desG * desA / 255

  desG = desG * desA / 255

  具體的實現代碼如下:

 1 for(int i = 0; i < m_image.GetWidth(); i++)  2 {  3     for(int j = 0; j < m_image.GetHeight(); j++)  4  {  5         unsigned char* pucColor = reinterpret_cast<unsigned char *>(m_image.GetPixelAddress(i , j));  6         pucColor[0] = pucColor[0] * pucColor[3] / 255; //pucColor[3]為ALPHA值  7         pucColor[1] = pucColor[1] * pucColor[3] / 255;  8         pucColor[2] = pucColor[2] * pucColor[3] / 255;  9  } 10 } 

三、放大打印預覽中圖片的大小

  直接點打印預覽的時候,發現圖片顯示的很小。這是由於顯示器設備每英寸的像素是96,而打印機每英寸的像素是600,也就是說打印機預覽顯示的圖像的大小只有顯示器顯示圖像的1/6。必須要放大打印機顯示視口的比例,使得其顯示的圖像和顯示器中顯示的圖像大小一致。辦法是在CDrawView類中重載OnPrepareDC函數,具體代碼如下:

 1 void CDrawView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)  2 {  3     // TODO: 在此添加專用代碼和/或調用基類
 4  CView::OnPrepareDC(pDC, pInfo);  5     pDC->SetMapMode(MM_ANISOTROPIC);//轉換坐標映射方式
 6     CSize size=CSize(1024,768);  7     pDC->SetWindowExt(size);  8     //得到實際設備每邏輯英寸的象素數量
 9     int xLogPixPerInch=pDC->GetDeviceCaps(LOGPIXELSX); 10     int yLogPixPerInch=pDC->GetDeviceCaps(LOGPIXELSY); 11     long xExt=(long)size.cx*xLogPixPerInch/96; 12     long yExt=(long)size.cy*yLogPixPerInch/96; 13     //確定視口大小
14     pDC->SetViewportExt((int)xExt,(int)yExt); 15 } 16     

  這樣使用打印預覽的時候,圖像的大小就恢復正常了。本以為到這里就大功告成了,沒想到點打印的時候,居然打出的是白紙(汗!!)。

四、打印出透明圖片

  打印預覽能顯示出來,卻打印不出來,這讓我百思不得其解啊!后來想想也許是Draw函數與打印機設備不兼容,然后換做CDC的SetPixel來畫圖像,結果還是打印不出來,就這樣白白浪費了一天的時間啊!過了一天突然想到是不是打印機的問題或者是打印程序的問題,於是在窗口上打印幾個字來顯示看看,發現可以打印出來,說明不是打印機和打印程序的問題。然后我試着畫個矩形,看看能不能打印出來,最終發現還是可以打印出來的。既然可以打印出矩形來,那么打印出圖像來也應該不是問題,把圖像中的每個像素用一個長和高為1的矩形畫出來不就行了嗎。根據這個思想,稍微改了下代碼,點打印終於可以了,具體代碼如下:

 1   int i;  2     int j;  3     for (i=0; i<m_image.GetWidth(); i++)  4  {  5         for (j=0; j<m_image.GetHeight(); j++)  6  {  7             byte *pByte = (byte *)m_image.GetPixelAddress(i, j);  8             
 9             if (m_image.GetBPP() == 32) //確認該圖像包含Alpha通道
10  { 11                 if (pByte[3])//確保透明背景不被畫出 12  { 13                     pDC->FillSolidRect(i,j,1,1,m_image.GetPixel(i,j)); 14  } 15                 
16  } 17             else
18  { 19                 pDC->FillSolidRect(i,j,1,1,m_image.GetPixel(i,j)); 20  } 21  } 22     }

五、總結

  從這個小任務的完成,很多事情其實就是那么一點的思想,如果你對問題轉變個思路,而不是一條道走到黑,問題也許一下就解決了。某個問題的解決方法不止一種,特別在計算機軟件開發中。即使但你嘗試了所有方法都解決不了一個問題的時候,也不要放棄,或許過片刻,或許過一天,一個新的idea就突然出現在你腦子里,把這個問題解決了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM