PCX是一个比较早的图像文件格式,它也有过一段时间的辉煌,但随着计算机硬、软件的发展,该图像格式基本已成过去时,主要是因为早期PCX格式图像是配合当时显卡硬件而设计的,如CGA/EGA/VGA等,现在显然已经过时了,虽然后来的版本增加了对256色和24位真彩色的支持,但仍然因其文件格式的先天不足,导致操作很不方便,如256色图像调色板就是以“补丁”形式追加到文件最后面的,24位真彩色用以前EGA图像卡按行以彩色面形式存放等;另外PCX的RLE编码对6位以下像素格式是比较有效的,对目前8位为主的像素格式压缩也不尽人意,如24位像素格式压缩后,有时比不压缩空间占用还大。
虽然PCX格式图像目前使用不多,但还是有很多软件是支持这种格式的,如Photoshop。在图像处理编程时,偶尔也会遇到这种格式的图像,但不象BMP、JPEG、GIF等图像格式容易找到现存的库函数或组件,所以本文提供了PCX格式图像与GDI+位图的相互转换的代码,本文分上下两篇,上篇将PCX格式图像转换为GDI+位图,下篇将GDI+位图转换为PCX格式图像。下面是转换源码:
[cpp]
typedef struct // pcx文件头
{
BYTE flag; // 标记
BYTE version; // 版本号
BYTE encodeing; // 编码方式
BYTE bitsPrePixel; // 平面像素位数
WORD xMin; // 最小X
WORD yMin; // 最小Y
WORD xMax; // 最大X
WORD yMax; // 最大Y
WORD hRes; // 水平分辨率
WORD vRes; // 垂直分辨率
BYTE palette[48]; // 16色调色板
BYTE reserved; // 保留
BYTE planes; // 平面数
WORD bytesPreLine; // 每行字节数
WORD paletteType; // 调色板类型。1:彩色或黑白,2:灰度
BYTE filler[58];
}PcxFileHeader, *PPcxFileHeader;
//---------------------------------------------------------------------------
FORCEINLINE
LPBYTE UnpackPckLine(LPBYTE dest, LPBYTE source, INT bytes)
{
while (bytes > 0)
{
if (*source > 0xc0)
{
INT count = *source ++ & 0x3f;
BYTE c = *source ++;
bytes -= count;
for (; count > 0; *dest ++ = c, count --);
}
else
{
*dest ++ = *source ++;
bytes --;
}
}
return source;
}
//---------------------------------------------------------------------------
// 单色或256色
VOID UnpackPck(BitmapData *data, LPBYTE bitsMem, INT bytesPreLine)
{
LPBYTE p = (LPBYTE)data->Scan0;
LPBYTE m = bitsMem;
for (UINT y = 0; y < data->Height; y ++, p += data->Stride)
{
m = UnpackPckLine(p, m, bytesPreLine);
}
}
//---------------------------------------------------------------------------
// 16色
VOID UnpackPck4(BitmapData *data, LPBYTE bitsMem, INT bytesPreLine)
{
LPBYTE p = (LPBYTE)data->Scan0;
LPBYTE m = bitsMem;
INT datOffset = data->Stride -
((GetPixelFormatSize(data->PixelFormat) * data->Width + 7) >> 3);
if (data->Width & 1) datOffset ++;
INT bytes1 = bytesPreLine;
INT bytes2 = bytes1 << 1;
INT bytes3 = bytes2 + bytes1;
INT bytes = bytes1 << 2;
LPBYTE buffer = new BYTE[bytes];
for (UINT y = 0; y < data->Height; y ++, p += datOffset)
{
m = UnpackPckLine(buffer, m, bytes);
LPBYTE b = buffer;
BYTE mask = 0x80;
for (UINT x = 0; x < data->Width; x ++)
{
if (*b & mask) *p |= 1;
if (*(b + bytes1) & mask) *p |= 2;
if (*(b + bytes2) & mask) *p |= 4;
if (*(b + bytes3) & mask) *p |= 8;
if (x & 1) p ++;
else *p <<= 4;
mask >>= 1;
if (!mask)
{
mask = 0x80;
b ++;
}
}
}
delete[] buffer;
}
//---------------------------------------------------------------------------
// 24位真彩色
VOID UnpackPck24(BitmapData *data, LPBYTE bitsMem, INT bytesPreLine)
{
INT bytes1 = bytesPreLine;
INT bytes2 = bytes1 << 1;
INT bytes = bytes2 + bytes1;
INT width = (INT)data->Width > bytesPreLine? bytesPreLine : data->Width;
INT datOffset = data->Stride - width * 3;
PRGBTriple p = (PRGBTriple)data->Scan0;