C++图像处理 -- PCX格式图像(上) (四)

2014-11-24 08:19:01 · 作者: · 浏览: 4
if (header->flag != 0x0a) return NULL;
PRGBTriple ppal = NULL;
PixelFormat format = PixelFormatUndefined;
if (header->bitsPrePixel == 1)
{
if (header->planes == 4)
{
format = PixelFormat4bppIndexed;
ppal = (PRGBTriple)header->palette;
}
else format = PixelFormat1bppIndexed;
}
else
{
if (header->planes == 3)
format = PixelFormat24bppRGB;
else if (header->planes == 1)
{
ppal = (PRGBTriple)(imageMem + imageBytes - 256 * 3);
if (*((LPBYTE)ppal - 1) == 0x0c)
format = PixelFormat8bppIndexed;
}
}
if (format == PixelFormatUndefined) return NULL;
Bitmap *bmp = new Bitmap(header->xMax - header->xMin + 1,
header->yMax - header->yMin + 1, format);
if (ppal)
{
INT count = 1 << (header->bitsPrePixel * header->planes);
ColorPalette *pal = (ColorPalette*)new BYTE[count * sizeof(ARGB) + sizeof(ColorPalette)];
PRGBQuad pp = (PRGBQuad)pal->Entries;
for (INT i = 0; i < count; i ++)
{
pp[i].rgbBlue = ppal[i].rgbtRed;
pp[i].rgbGreen = ppal[i].rgbtGreen;
pp[i].rgbRed = ppal[i].rgbtBlue;
pp[i].rgbReserved = 255;
}
pal->Flags = 0;
pal->Count = count;
bmp->SetPalette(pal);
delete[] pal;
}
LPBYTE bitsMem = imageMem + sizeof(PcxFileHeader);
BitmapData data;
Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());
bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, format, &data);
switch (format)
{
case PixelFormat4bppIndexed:
UnpackPck4(&data, bitsMem, header->bytesPreLine);
break;
case PixelFormat24bppRGB:
UnpackPck24(&data, bitsMem, header->bytesPreLine);
break;
default:
UnpackPck(&data, bitsMem, header->bytesPreLine);
}
bmp->
UnlockBits(&data);
return bmp;
}
//---------------------------------------------------------------------------
Bitmap *LoadPcxImageFromStream(IStream *stream)
{
LARGE_INTEGER move;
ULARGE_INTEGER size;
move.QuadPart = 0;
if (stream->Seek(move, STREAM_SEEK_END, &size) != S_OK)
return NULL;
stream->Seek(move, STREAM_SEEK_SET, NULL);
LPBYTE imageMem = new BYTE[size.LowPart];
Bitmap *bmp = NULL;
if (stream->Read(imageMem, size.LowPart, NULL) == S_OK)
bmp = UnpackPckImage(imageMem, size.LowPart);
delete[] imageMem;
return bmp;
}
//---------------------------------------------------------------------------
上面代码中,UnpackPckImage函数是核心代码,负责对PCX格式图像内存映像进行解析并转换。现在版本的PCX格式图像主要是单色、16色、256色和24位真彩色,本文代码能准确的解析这几种图像。但有时也可能有些不规范图像,如16色图像,规范的格式应该是像素位数bitsPrePixel=1,像素平面planes=4,同时调色板数据在文件头的palette中,这是从EGA显示卡遗留下来的格式,但如bitsPrePixel=4,像素平面planes=1的格式描述,也同样是16色格式,而且是符合现代16色格式的,我用Photoshop对这种格式描述做过实验,但会显示文件不完整的错误,既然是“不完整”而不是非法错误,证明这种16色格式描述也应该是正确的,因此我尝试将调色板从文件头移到文件尾,结果Photoshop果然将图像读出来了,但只显示了一半的宽度,由此,我得知这是Photoshop的容错读取,即它忽略了bitsPrePixel=4这个描述,而是把它当256色图像处理的,事实上,在Photoshop中是没法正确保存16色图像的,它总是将16色用256色方式保存的,我在UnpackPckImage函数中也采用了这种容错方式,只要图像尾部有调色板,就可以当256色处理;只要planes=3,就当24位真彩色读取,而不再管其它描述。
LoadPcxImageFromStream函数只是简单的从流读取PCX格式图像到内存映像而已,之所以选择从流读取,主要是考虑通用性。为了能从文件读取PCX图像,我也写了一个不完整的文件流类,只需要前面6个接口函数能用就行了(事实上,只要Read、Write和Seek3个函数能用即可)。下面是这个文件流类和LoadPcxImageFromFile函数代码:
[cpp]
class FileStream : public IStream
{
HANDLE handle;
INT refCount;
public:
HRESULT STDMET