PCX 圖象檔案格式的讀寫 (轉)

worldblog發表於2007-12-13
PCX 圖象檔案格式的讀寫 (轉)[@more@]

PCX 圖象格式的讀寫

PCX圖象檔案格式最早出現於Zsoft公司開發的PC Paintbrush繪圖,由於該繪圖軟體功能強大併成功移植到操作,
加上PCX是最早支援彩色的圖象格式之一,PCX成為目前比較流行的圖象格式。

對於開發圖象瀏覽、處理軟體的員來講,如何讀取、儲存PCX圖象格式是最為基本的話題,作者根據自己對PCX圖象格式理解,
開發了相應的程式碼,希望對讀者有用,由於篇幅限制,在此對檔案格式不予介紹,讀者可以參考相關數目。

程式碼如下,方法程式段之後簡單講解,水平有限,還請包涵;我的電子信箱是:to:cadinfo@263">cadinfo@263.net,歡迎探討。

========================================================
/****************************************************************************
* 名稱:LoadPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
*
* 引數:PPCXHEAD ppcxHdr -指向PCXHEAD結構的指標!NULL,匯入BitPlane,Byteine,=>clScanLineSize
* LPBYTE ppcxImg -指向PCX圖象區指標!NULL,RLE編碼,位置遞增+=rec。
* 呼叫之前獲得首地址指標:
* LPBYTE ppcxBits -指向DIB資料區的指標,按掃描行(scanline)長度遞增
*
* 返回:UINT rec -返回每行解壓以後的位元組數目
*
* 說明:根據PCX圖象資料指標,對RLE進行解碼
****************************************************************************/
UINT CPcxImage::LoadPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
{
 ASSERT(ppcxHdr!=NULL&&ppcxImg!=NULL&&ppcxBits!=NULL);

 // because in bitmap bits order, it's blue=>green=>red
 // however pcx is red=>green=>blue so use decrease order
 //-----------------------------------------
 UINT lPos(0), // 記錄存入ppcxBits的總數
  iX(0), // 記錄每個位平面位元組序號
  rec(0); // 讀取_ppcxImg_ 位元組序號
 for ( int bp=ppcxHdr->BitPlane-1; bp >= 0;  bp-- )
 {
 // RLE 解碼=======
 iX=0;
 
 while ( iXBytePerLine )
 {
 BYTE uiValue = ppcxImg[rec++];
 if ( (uiValue & 0xc0) == 0xc0 ) // 判斷高位位元組是否設定 0xc0
 {
 uiValue = uiValue & 0x3f ; // 計算重複
 BYTE Color = ppcxImg[rec++]; // 提取顏色
 
 // 存放到DIB
 for ( BYTE bRepeat=0; bRepeat < uiValue; bRepeat++ )
 {
 ppcxBits[(iX++)*ppcxHdr->BitPlane+bp] = Color;
 lPos++;
 }
 }
 else
 {
 ppcxBits[(iX++)*ppcxHdr->BitPlane+bp] = uiValue;
 lPos++;
 }
 }
 
 }

 return rec;
}


/****************************************************************************
* 函式名稱:PackPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
*
* 引數:PPCXHEAD ppcxHdr -指向PCXHEAD結構的指標!NULL,匯入BitPlane,BytePerLine,=>clScanLineSize
* LPBYTE ppcxBits -指向DIB資料區的指標,按掃描行(scanline)長度遞增
* LPBYTE ppcxImg -指向PCX圖象區指標!NULL,RLE壓縮編碼。
* 呼叫之前宣告: LPBYTE ppcxImg=new BYTE[2*BitPlane*BytePerLine]
*
* 返回:UINT rec -返回每行壓縮以後的位元組數目
*
* 說明:根據DIB圖象資料指標,進行RLE編碼(經過測試演算法很完善,支援256和24bit真彩色)
****************************************************************************/
UINT CPcxImage::PackPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxBits, LPBYTE ppcxImg) const
{
 //----------------------------------------
 // RLE壓縮
 ASSERT(ppcxHdr!=NULL && ppcxBits!=NULL && ppcxImg!=NULL);

 BYTE i(1);
 UINT lPos(0), rec(0);

 // ☆RLE編碼,最大重複<=63☆
 for(int bp=ppcxHdr->BitPlane-1; bp>=0; bp--)
 {
 lPos=0; // 處理到的RGB序列

 while(lPosBytePerLine) // 等價小於圖象寬度
 {
 i=1; // 重置步長-1
 
 //-----------------&gt以下程式碼檢查
 while((ppcxBits[(i-1+lPos)*ppcxHdr->BitPlane+bp]==ppcxBits[(i+lPos)*ppcxHdr->BitPlane+bp])
 &&((lPos+i)BytePerLine)&&(i<63)) i++;
 if(i>1 && i<64)
 {
 // 表明當前象素位置開始存在i個重複象素值,依次寫入PCX圖象資料Buffer
 // 1.重複次數
 ppcxImg[rec++]=i|0xc0;
 // 2.象素值
 ppcxImg[rec++]=ppcxBits[lPos*ppcxHdr->BitPlane+bp];
 
 lPos+=i; // lPos-記錄當前掃描行中已經處理的位元組數
 // rec -記錄當前已經寫入PCX檔案的位元組數
 }
 else
 {
 // 表明當前象素位置開始不存在重複象素值
 // 象素值大於0xc0(192),寫標誌0xc1
 if((ppcxBits[lPos*ppcxHdr->BitPlane+bp]&0xc0)==0xc0) ppcxImg[rec++]=0xc1;
 ppcxImg[rec++]=ppcxBits[lPos*ppcxHdr->BitPlane+bp]; lPos++;
 }
 }
 }
 
 // 寫圖象資料結束
 return rec;
}

===========================================================
呼叫如下:
 1.// RLE解碼-------------> 已經包含8、24bit圖象
 for( int iY=0; iY<=ppcxHdr->YMax; iY++ )
 {
 ZeroMemory(ppcxBits, clScanLineSize);
 ppcxImg+=LoadPCXLine(ppcxHdr, ppcxImg, ppcxBits); // 讀取掃描行資料
 ppcxBits+=clScanLineSize;
 }
 ppcxHdr是指向PCXHEAD結構(128BYTE)的指標,ppcxBits是存放解碼後圖象資料的buffer,ppcxImg是指向pcx圖象檔案
中圖象資料的指標,此處隨掃描行遞增。完成功能是從pcx檔案中解碼圖象資料到windows點陣圖格式的圖象資料。

 2.// RLE壓縮-------------> 已經包含8、24bit圖象
 // 最壞情況下申請2倍的緩衝,相鄰都不重複,並且都大於0xc0
 LPBYTE ppcxImg=new BYTE[2*pcxHdr.BitPlane*pcxHdr.BytePerLine]; // 存放臨時掃描行
 UINT rec(0); // 計數器,寫如PCX檔案位元組數
 for( int iY=0; iY<=pcxHdr.YMax; iY++ )
 {
 ZeroMemory(ppcxImg,2*pcxHdr.BitPlane*pcxHdr.BytePerLine);
 rec=PackPCXLine(&pcxHdr, ppcxBits, ppcxImg);
 
 // DIB 掃描行遞增
 ppcxBits+=clScanLineSize;
 
 pFile->Write(ppcxImg,rec);
 }
 delete []ppcxImg;
 具體引數大致同1.ppcxImg為臨時RLE壓縮後的buffer。
------【OVER】------


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992665/,如需轉載,請註明出處,否則將追究法律責任。

相關文章