程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++圖像處理 -- PCX格式圖像(下)

C++圖像處理 -- PCX格式圖像(下)

編輯:C++入門知識

本文則介紹將GDI+位圖轉換為PCX格式圖像。       下面是GDI+位圖轉換為PCX格式圖像代碼:   [cpp]   INT PackPcxLine(LPBYTE dest, LPBYTE source, INT bytesPreLine, INT planes)   {       LPBYTE pd = dest;       INT delta = planes --;       LPBYTE ps = source + planes;       INT bytes = bytesPreLine;       while(planes >= 0)       {           INT count = 0;           BYTE c = *ps;           do           {               count ++;               if (-- bytes == 0)               {                   if (-- planes < 0) break;                   bytes = bytesPreLine;                   ps = source + planes;               }               else ps += delta;           } while(c == *ps && count < 0x3f);           if (c >= 0xc0 || count > 1)               *pd ++ = count | 0xc0;           *pd ++ = c;       }       return pd - dest;   }   //---------------------------------------------------------------------------       typedef union   {       WORD value;       struct       {           BYTE low;           BYTE high;       };   }testMask;      INT PackPcx4Line(LPBYTE dest, LPBYTE source, INT bytesPreLine, INT width)   {       INT bytes = bytesPreLine << 2;       LPBYTE buf = dest + bytes;       testMask mask;       mask.value = 0x1001;       width = (width + 1) >> 1;       while(mask.high)       {           BYTE c = 0;           BYTE bit = 0x80;           LPBYTE pb = buf;           for (INT i = 0; i < width; i ++)           {               if (source[i] & mask.high) c |= bit;               bit >>= 1;               if (source[i] & mask.low) c |= bit;               bit >>= 1;               if (bit == 0)               {                   *pb ++ = c;                   c = 0;                   bit = 0x80;               }           }           buf += bytesPreLine;           mask.value <<= 1;       }       return PackPcxLine(dest, dest + bytes, bytes, 1);   }   //---------------------------------------------------------------------------       VOID ARGBQuadToRGBTriple(PRGBTriple dest, PRGBQuad source, INT count)   {       for (INT i = 0; i < count; i++)       {           dest[i].rgbtBlue = source[i].rgbRed;           dest[i].rgbtGreen = source[i].rgbGreen;           dest[i].rgbtRed = source[i].rgbBlue;       }   }   //---------------------------------------------------------------------------       BOOL SavePcxImageToStream(IStream *stream, Bitmap *bmp)   {       PixelFormat format = bmp->GetPixelFormat();       if (format == PixelFormatUndefined)           return FALSE;       PcxFileHeader header;       ColorPalette *pal = NULL;       BYTE palette[256 * 3 + 1];       ZeroMemory(&header, sizeof(PcxFileHeader));       header.bitsPrePixel = GetPixelFormatSize(format);       header.planes = 1;       if (header.bitsPrePixel > 8)       {           format = PixelFormat24bppRGB;           header.planes = 3;           header.bitsPrePixel = 8;       }       else //if (header.bitsPrePixel > 1)        {           pal = (ColorPalette*)new BYTE[256 * sizeof(ARGB) + sizeof(ColorPalette)];           bmp->GetPalette(pal, bmp->GetPaletteSize());           PRGBTriple ppal = (PRGBTriple)&palette[1];           // 如果是16色位圖,調色板保存到文件頭            if (format == PixelFormat4bppIndexed)           {               header.planes = header.bitsPrePixel;               header.bitsPrePixel = 1;               ppal = (PRGBTriple)header.palette;           }           ARGBQuadToRGBTriple(ppal, (PRGBQuad)pal->Entries, pal->Count);           delete[] pal;       }       Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());       header.flag = 0x0A;       header.version = 5;       header.encodeing = 1;       header.xMax = r.Width - 1;       header.yMax = r.Height - 1;       header.hRes = 96;       header.vRes = 96;       header.paletteType = 1;       header.bytesPreLine = (r.Width * header.bitsPrePixel + 7) >> 3;       if (header.bytesPreLine & 1)           header.bytesPreLine ++;       // 保存PCX文件頭        if (stream->Write(&header, sizeof(PcxFileHeader), NULL) != S_OK)           return FALSE;       // 獲取GDI+位圖數據到位圖數據結構        BitmapData data;       data.Stride = ((r.Width * GetPixelFormatSize(format) + 31) & -32) >> 3;       INT size = r.Height * data.Stride;       // size為位圖數據字節數,header.bytesPreLine*header.planes*2為編碼緩沖區字節數        data.Scan0 = (LPVOID)new BYTE[size + header.bytesPreLine * header.planes * 2];       bmp->LockBits(&r, ImageLockModeRead | ImageLockModeUserInputBuf, format, &data);       bmp->UnlockBits(&data);       // 如果單色位圖調色板首項不為0,位圖數據反向        if (format == PixelFormat1bppIndexed && (*(ARGB*)&palette[1] & 0xffffff))       {           INT count = data.Height * (data.Stride >> 2);           LPDWORD pd = (LPDWORD)data.Scan0;           for (INT i = 0; i < count; pd[i] ^= (DWORD)(-1), i ++);       }       LPBYTE p = (LPBYTE)data.Scan0;       LPBYTE buffer = p + size;       INT bytes;       // 逐行進行RLE編碼並保存到流        for (UINT y = 0; y < data.Height; y ++, p += data.Stride)       {           if (format == PixelFormat4bppIndexed)               bytes = PackPcx4Line(buffer, p, header.bytesPreLine, data.Width);           else               bytes = PackPcxLine(buffer, p, header.bytesPreLine, header.planes);           stream->Write(buffer, bytes, NULL);       }       delete[] data.Scan0;       // 如果是256色位圖,調色板保存到流的尾部        if (format == PixelFormat8bppIndexed)       {           palette[0] = 0x0c;           stream->Write(palette, 256 * 3 + 1, NULL);       }       return TRUE;   }   //---------------------------------------------------------------------------       BOOL SavePcxImageToFile(LPTSTR fileName, Bitmap *bmp)   {       IStream *stream = new FileStream(fileName, FALSE);       stream->AddRef();       BOOL result = SavePcxImageToStream(stream, bmp);       stream->Release();       return result;   }   //---------------------------------------------------------------------------     INT PackPcxLine(LPBYTE dest, LPBYTE source, INT bytesPreLine, INT planes) { LPBYTE pd = dest; INT delta = planes --; LPBYTE ps = source + planes; INT bytes = bytesPreLine; while(planes >= 0) { INT count = 0; BYTE c = *ps; do { count ++; if (-- bytes == 0) { if (-- planes < 0) break; bytes = bytesPreLine; ps = source + planes; } else ps += delta; } while(c == *ps && count < 0x3f); if (c >= 0xc0 || count > 1) *pd ++ = count | 0xc0; *pd ++ = c; } return pd - dest; } //---------------------------------------------------------------------------   typedef union { WORD value; struct { BYTE low; BYTE high;     }; }testMask;   INT PackPcx4Line(LPBYTE dest, LPBYTE source, INT bytesPreLine, INT width) { INT bytes = bytesPreLine << 2; LPBYTE buf = dest + bytes; testMask mask; mask.value = 0x1001; width = (width + 1) >> 1; while(mask.high) { BYTE c = 0; BYTE bit = 0x80; LPBYTE pb = buf; for (INT i = 0; i < width; i ++) { if (source[i] & mask.high) c |= bit; bit >>= 1; if (source[i] & mask.low) c |= bit; bit >>= 1; if (bit == 0) { *pb ++ = c; c = 0; bit = 0x80; } } buf += bytesPreLine; mask.value <<= 1; } return PackPcxLine(dest, dest + bytes, bytes, 1); } //---------------------------------------------------------------------------   VOID ARGBQuadToRGBTriple(PRGBTriple dest, PRGBQuad source, INT count) { for (INT i = 0; i < count; i++) { dest[i].rgbtBlue = source[i].rgbRed; dest[i].rgbtGreen = source[i].rgbGreen; dest[i].rgbtRed = source[i].rgbBlue;     } } //---------------------------------------------------------------------------   BOOL SavePcxImageToStream(IStream *stream, Bitmap *bmp) { PixelFormat format = bmp->GetPixelFormat(); if (format == PixelFormatUndefined) return FALSE; PcxFileHeader header; ColorPalette *pal = NULL; BYTE palette[256 * 3 + 1]; ZeroMemory(&header, sizeof(PcxFileHeader)); header.bitsPrePixel = GetPixelFormatSize(format); header.planes = 1; if (header.bitsPrePixel > 8) { format = PixelFormat24bppRGB; header.planes = 3; header.bitsPrePixel = 8; } else //if (header.bitsPrePixel > 1) { pal = (ColorPalette*)new BYTE[256 * sizeof(ARGB) + sizeof(ColorPalette)]; bmp->GetPalette(pal, bmp->GetPaletteSize()); PRGBTriple ppal = (PRGBTriple)&palette[1]; // 如果是16色位圖,調色板保存到文件頭 if (format == PixelFormat4bppIndexed) { header.planes = header.bitsPrePixel; header.bitsPrePixel = 1; ppal = (PRGBTriple)header.palette; } ARGBQuadToRGBTriple(ppal, (PRGBQuad)pal->Entries, pal->Count); delete[] pal; } Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight()); header.flag = 0x0A; header.version = 5; header.encodeing = 1; header.xMax = r.Width - 1; header.yMax = r.Height - 1; header.hRes = 96; header.vRes = 96; header.paletteType = 1; header.bytesPreLine = (r.Width * header.bitsPrePixel + 7) >> 3; if (header.bytesPreLine & 1) header.bytesPreLine ++; // 保存PCX文件頭 if (stream->Write(&header, sizeof(PcxFileHeader), NULL) != S_OK) return FALSE; // 獲取GDI+位圖數據到位圖數據結構 BitmapData data; data.Stride = ((r.Width * GetPixelFormatSize(format) + 31) & -32) >> 3; INT size = r.Height * data.Stride; // size為位圖數據字節數,header.bytesPreLine*header.planes*2為編碼緩沖區字節數 data.Scan0 = (LPVOID)new BYTE[size + header.bytesPreLine * header.planes * 2]; bmp->LockBits(&r, ImageLockModeRead | ImageLockModeUserInputBuf, format, &data); bmp->UnlockBits(&data); // 如果單色位圖調色板首項不為0,位圖數據反向 if (format == PixelFormat1bppIndexed && (*(ARGB*)&palette[1] & 0xffffff)) { INT count = data.Height * (data.Stride >> 2); LPDWORD pd = (LPDWORD)data.Scan0; for (INT i = 0; i < count; pd[i] ^= (DWORD)(-1), i ++); } LPBYTE p = (LPBYTE)data.Scan0; LPBYTE buffer = p + size; INT bytes; // 逐行進行RLE編碼並保存到流 for (UINT y = 0; y < data.Height; y ++, p += data.Stride) { if (format == PixelFormat4bppIndexed) bytes = PackPcx4Line(buffer, p, header.bytesPreLine, data.Width); else bytes = PackPcxLine(buffer, p, header.bytesPreLine, header.planes); stream->Write(buffer, bytes, NULL); } delete[] data.Scan0; // 如果是256色位圖,調色板保存到流的尾部 if (format == PixelFormat8bppIndexed) { palette[0] = 0x0c; stream->Write(palette, 256 * 3 + 1, NULL); } return TRUE; } //---------------------------------------------------------------------------   BOOL SavePcxImageToFile(LPTSTR fileName, Bitmap *bmp) { IStream *stream = new FileStream(fileName, FALSE); stream->AddRef(); BOOL result = SavePcxImageToStream(stream, bmp); stream->Release(); return result; } //---------------------------------------------------------------------------     代碼中SavePcxImageToStream函數已經將大致的轉換流程作了注釋,本文不再羅嗦,而SavePcxImageToFile函數仍然是利用我寫的簡易文件流將轉換後的PCX格式圖像保存到文件,        下面是個GDI+位圖轉換為PCX格式圖像例子(BCB2010):   [cpp]   void __fastcall TForm1::Button3Click(TObject *Sender)   {       Gdiplus::Bitmap *bmp = new Gdiplus::Bitmap(L"d:\\1-4.bmp");       if (bmp->GetLastStatus() != Ok)           throw new Exception("Load Image fail");       Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle);       g->DrawImage(bmp, 0, 0);       delete g;       SavePcxImageToFile("d:\\1-4.pcx", bmp);       delete bmp;   }    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved