- (NSBitmapImageRep*) imageRepFromPCXFile: (NSString*) filePath {
typedef struct PaletteEntry {
unsigned char red;
unsigned char green;
unsigned char blue;
} PaletteEntry;
NSData* pcxData = [NSData dataWithContentsOfFile: filePath];
const unsigned char* pcxBytes = [pcxData bytes];
if (pcxBytes[1] != 0x05) { NSLog (@"ERROR: PCX is not version 3"); return nil; }
// version 3 - check for a palette
PaletteEntry* palettePtr = (PaletteEntry*) (pcxBytes + [pcxData length]-768);
if ( *((unsigned char*)palettePtr - 1) != 0x0c) { NSLog (@"ERROR: PCX has no palette"); return nil; }
// found the palette pointer
// now get the image dimensions
unsigned bitsPerPixel = pcxBytes[3];
if (bitsPerPixel != 8) { NSLog (@"ERROR; Invalid PCX pixel size"); return nil; }
unsigned numPlanes = pcxBytes[65];
if (numPlanes != 1) { NSLog (@"ERROR: Invalid PCX number of planes"); return nil; }
unsigned bytesPerLine = pcxBytes[66] + (pcxBytes[67] << 8);
unsigned pcxWidth = pcxBytes[8] + (pcxBytes[9] << 8) - pcxBytes[4] + (pcxBytes[5] << 8) +1;
unsigned pcxHeight = pcxBytes[10] + (pcxBytes[11] << 8) - pcxBytes[6] + (pcxBytes[7] << 8) +1;
unsigned pcxRowBytes = bytesPerLine * numPlanes;
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
pixelsWide: pcxWidth
pixelsHigh: pcxHeight
bitsPerSample: 8
samplesPerPixel: 4
hasAlpha:true
isPlanar: NO
colorSpaceName: NSDeviceRGBColorSpace
bytesPerRow: 0
bitsPerPixel: 0];
// populate the pixel map
const unsigned char* pcxByte = pcxBytes + 128;
unsigned char* bmpByte = [imageRep bitmapData];
int y; for (y = 0; y < pcxHeight; y++) {
// decode a pcx line
int repeat = 0;
int inX = pcxRowBytes;
int outX = pcxWidth;
while (inX--) {
unsigned char c;
if (repeat == 0) { // next byte
c = *(pcxByte++);
if (c >= 0xc0) { // start repeating next byte
repeat = c - 0xc0 - 1;
c = *(pcxByte++);
}
} else
repeat --;
if (outX-- > 0) {
// write out the color elements
PaletteEntry* color = palettePtr + c;
if ((color->red == 255 && color->green == 0 && color->blue == 255) ||
(color->red == 0 && color->green == 255 && color->blue == 0)) {
// magenta and green are transparent
*(bmpByte++) = 0;
*(bmpByte++) = 0;
*(bmpByte++) = 0;
*(bmpByte++) = 0;
} else {
*(bmpByte++) = color->red;
*(bmpByte++) = color->green;
*(bmpByte++) = color->blue;
*(bmpByte++) = 255;
}
}
}
}
return imageRep;
}