C++图像处理 -- PCX格式图像(下) (二)

2014-11-24 08:19:01 · 作者: · 浏览: 1
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;