bool CxImagePCX::Decode(CxFile *hFile) { if (hFile == NULL) return false; PCXHEADER pcxHeader; int i, x, y, y2, nbytes, count, Height, Width; BYTE c, ColorMap[PCX_MAXCOLORS][3]; BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL; BYTE *pcxplanes, *pcxpixels; try { if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) throw "Can't read PCX image"; if (pcxHeader.Manufacturer != PCX_MAGIC) throw "Error: Not a PCX file"; // Check for PCX run length encoding if (pcxHeader.Encoding != 1) throw "PCX file has unknown encoding scheme"; Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1; Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1; info.xDPI = pcxHeader.Hres; info.yDPI = pcxHeader.Vres; // Check that we can handle this image format if (pcxHeader.ColorPlanes > 4) throw "Can't handle image with more than 4 planes"; // Create the image if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){ Create (Width, Height, 24, CXIMAGE_FORMAT_PCX); #if CXIMAGE_SUPPORT_ALPHA if (pcxHeader.ColorPlanes==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1) Create (Width, Height, 4, CXIMAGE_FORMAT_PCX); else Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX); if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding //Read the image and check if it's ok nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height; lpHead1 = pcximage = (BYTE*)malloc(nbytes); while (nbytes > 0){ if (hFile == NULL || hFile->Eof()) throw "corrupted PCX"; hFile->Read(&c,1,1); if ((c & 0XC0) != 0XC0){ // Repeated group *pcximage++ = c; --nbytes; continue; } count = c & 0X3F; // extract count hFile->Read(&c,1,1); if (count > nbytes) throw "repeat count spans end of image"; nbytes -= count; while (--count >=0) *pcximage++ = c; } pcximage = lpHead1; //store the palette for (i = 0; i < 16; i++){ ColorMap[i][0] = pcxHeader.ColorMap[i][0]; ColorMap[i][1] = pcxHeader.ColorMap[i][1]; ColorMap[i][2] = pcxHeader.ColorMap[i][2]; } if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){ hFile->Read(&c,1,1); if (c != PCX_256_COLORS) throw "bad color map signature"; for (i = 0; i < PCX_MAXCOLORS; i++){ hFile->Read(&ColorMap[i][0],1,1); hFile->Read(&ColorMap[i][1],1,1); hFile->Read(&ColorMap[i][2],1,1); } } if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0; ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255; } for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]); lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8); // Convert the image for (y = 0; y < Height; y++){ if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding y2=Height-1-y; pcxpixels = lpHead2; pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes); if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){ // Deal with 24 bit color image for (x = 0; x < Width; x++){ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); } continue; #if CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){ for (x = 0; x < Width; x++){ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]); } continue; #endif //CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 1) { PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel); } else { PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel); } for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]); } } catch (char *message) { strncpy(info.szLastError,message,255); if (lpHead1){ free(lpHead1); lpHead1 = NULL; } if (lpHead2){ free(lpHead2); lpHead2 = NULL; } return false; } if (lpHead1){ free(lpHead1); lpHead1 = NULL; } if (lpHead2){ free(lpHead2); lpHead2 = NULL; } return true; }
void PLPCXDecoder::GetImage (PLBmpBase & Bmp) { int i, x, y; PLBYTE ColorMap[PCX_MAXCOLORS][3]; PLBYTE * pcximage = NULL; PLBYTE * lpHead1 = NULL; PLBYTE * lpHead2 = NULL; PLBYTE * pcxplanes; PLBYTE * pcxpixels; PLBYTE c; int nbytes, count; Trace (2, "PCX getimage.\n"); try { nbytes = m_PcxHeader.BytesPerLine * m_PcxHeader.ColorPlanes * GetHeight(); lpHead1 = pcximage = (PLBYTE *)malloc(nbytes); try { while (nbytes > 0) { c = ReadByte(m_pDataSrc); if ((c & 0XC0) != 0XC0) // Repeated group { *pcximage++ = c; --nbytes; continue; } count = c & 0X3F; // extract count c = ReadByte(m_pDataSrc); if (count > nbytes) { raiseError(PL_ERRINTERNAL, "repeat count spans end of image."); } nbytes -= count; while (--count >=0) *pcximage++ = c; } } catch (PLTextException e) { // Just in case BytesPerLine is bogus. // This will fall apart for images that have a palette after the // image data, however. if (e.GetCode() != PL_ERREND_OF_FILE) throw; } pcximage = lpHead1; for (i = 0; i < 16; i++) { ColorMap[i][0] = m_PcxHeader.ColorMap[i][0]; ColorMap[i][1] = m_PcxHeader.ColorMap[i][1]; ColorMap[i][2] = m_PcxHeader.ColorMap[i][2]; } if (m_PcxHeader.BitsPerPixel == 8 && m_PcxHeader.ColorPlanes == 1) { /* It seems like valid PCXs exist with a bad color map signature... PLBYTE colsig = ReadByte(m_pDataSrc); if (colsig != PCX_256_COLORS) { raiseError(PL_ERRINTERNAL, "bad color map signature."); } */ for (i = 0; i < PCX_MAXCOLORS; i++) { ColorMap[i][0] = ReadByte(m_pDataSrc); ColorMap[i][1] = ReadByte(m_pDataSrc); ColorMap[i][2] = ReadByte(m_pDataSrc); } } if (m_PcxHeader.BitsPerPixel == 1 && m_PcxHeader.ColorPlanes == 1) { ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0; ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255; } lpHead2 = pcxpixels = (PLBYTE *)malloc(GetWidth() + m_PcxHeader.BytesPerLine * 8); // Convert the image PLPixel32 ** pLineArray = Bmp.GetLineArray32(); for (y = 0; y < GetHeight(); y++) { pcxpixels = lpHead2; pcxplanes = pcximage + (y * m_PcxHeader.BytesPerLine * m_PcxHeader.ColorPlanes); if (m_PcxHeader.ColorPlanes == 3 && m_PcxHeader.BitsPerPixel == 8) { // Deal with 24 bit color image for (x = 0; x < GetWidth(); x++) { PLPixel32 * pPixel = pLineArray[y]; pPixel[x].Set (pcxplanes[x], pcxplanes[m_PcxHeader.BytesPerLine + x], pcxplanes[2*m_PcxHeader.BytesPerLine + x], 0xFF); } continue; } else if (m_PcxHeader.ColorPlanes == 1) { PCX_UnpackPixels(pcxpixels, pcxplanes, m_PcxHeader.BytesPerLine, m_PcxHeader.ColorPlanes, m_PcxHeader.BitsPerPixel); } else { PCX_PlanesToPixels(pcxpixels, pcxplanes, m_PcxHeader.BytesPerLine, m_PcxHeader.ColorPlanes, m_PcxHeader.BitsPerPixel); } for (x = 0; x < GetWidth(); x++) { i = pcxpixels[x]; PLPixel32 * pPixel = pLineArray[y]; pPixel[x].Set (ColorMap[i][0], ColorMap[i][1], ColorMap[i][2], 0xFF); } } } catch (PLTextException) { if (lpHead1) { free(lpHead1); lpHead1 = NULL; } if (lpHead2) { free(lpHead2); lpHead2 = NULL; } throw; } if (lpHead1) { free(lpHead1); lpHead1 = NULL; } if (lpHead2) { free(lpHead2); lpHead2 = NULL; } }