# HG changeset patch # User Matti Hamalainen # Date 1503010995 -10800 # Node ID 0d3f5f44c0c4168d672a72cd461e795f111689fa # Parent 5206e3d4e6b7b8ab6f242f5d0748f35bde1539bc Somewhat improve PCX read support in libgfx. diff -r 5206e3d4e6b7 -r 0d3f5f44c0c4 src/libgfx.c --- a/src/libgfx.c Fri Aug 18 00:43:48 2017 +0300 +++ b/src/libgfx.c Fri Aug 18 02:03:15 2017 +0300 @@ -681,6 +681,8 @@ #endif +#define DMPCX_PAL_COLORS 16 // Number of internal palette colors + typedef struct { Uint8 r,g,b; @@ -689,18 +691,21 @@ typedef struct { - Uint8 manufacturer, - version, - encoding, - bpp; + Uint8 manufacturer, // always 0x0a + version, // Z-Soft PCX Paintbrush version: + // 0 = v2.5, 2 = v2.8 with palette, 3 = v2.8 without palette, 5 = v3.0 or better + encoding, // usually 0x01 = RLE, 0x00 = uncompressed + bitsPerPlane; // bits per pixel per plane + Uint16 xmin, ymin, xmax, ymax; - Uint16 hres, vres; - DMPCXColor colormap[16]; - Uint8 reserved; - Uint8 nplanes; - Uint16 bpl; - Uint16 palinfo; - Uint8 filler[58]; + Uint16 hres, vres; // resolution in DPI, can be image dimensions as well. + DMPCXColor colorMap[DMPCX_PAL_COLORS]; + Uint8 reserved; // should be set to 0 + Uint8 nplanes; // number of planes + Uint16 bpl; // bytes per plane LINE + Uint16 palInfo; // 1 = color/BW, 2 = grayscale + Uint16 hScreenSize, vScreenSize; + Uint8 filler[54]; } DMPCXHeader; @@ -742,14 +747,13 @@ static int dmWritePCXRow(void *cbdata, Uint8 *row, size_t len) { DMPCXData *pcx = (DMPCXData *) cbdata; - int plane; size_t soffs = 0; // fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl); pcx->bufOffs = 0; - for (plane = 0; plane < pcx->header->nplanes; plane++) + for (int plane = 0; plane < pcx->header->nplanes; plane++) { Uint8 data = dmPCXGetByte(row, len, soffs++), count = 1; @@ -814,25 +818,24 @@ dmMemset(&hdr, 0, sizeof(hdr)); if (spec->paletted) { - int i; - for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++) + for (int i = 0; i < (img->ncolors > DMPCX_PAL_COLORS ? DMPCX_PAL_COLORS : img->ncolors); i++) { - hdr.colormap[i].r = img->pal[i].r; - hdr.colormap[i].g = img->pal[i].g; - hdr.colormap[i].b = img->pal[i].b; + hdr.colorMap[i].r = img->pal[i].r; + hdr.colorMap[i].g = img->pal[i].g; + hdr.colorMap[i].b = img->pal[i].b; } } hdr.manufacturer = 10; hdr.version = 5; hdr.encoding = 1; - hdr.bpp = 8; + hdr.bitsPerPlane = 8; hdr.hres = img->width * spec->scaleX; hdr.vres = img->height * spec->scaleY; hdr.xmin = hdr.ymin = 0; hdr.xmax = hdr.hres - 1; hdr.ymax = hdr.vres - 1; hdr.nplanes = dmImageGetBytesPerPixel(pcx.format); - hdr.palinfo = 1; + hdr.palInfo = 1; res = (img->width * spec->scaleX); hdr.bpl = res / 2; @@ -840,7 +843,7 @@ hdr.bpl *= 2; dmMsg(3, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n", - spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl); + spec->paletted, hdr.nplanes, hdr.bitsPerPlane, hdr.bpl); pcx.bufLen = hdr.bpl * 4; if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) @@ -855,7 +858,7 @@ if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) || !dm_fwrite_byte(pcx.fp, hdr.version) || !dm_fwrite_byte(pcx.fp, hdr.encoding) || - !dm_fwrite_byte(pcx.fp, hdr.bpp)) + !dm_fwrite_byte(pcx.fp, hdr.bitsPerPlane)) { res = dmError(DMERR_FWRITE, "PCX: Could not write basic header data.\n"); @@ -874,7 +877,7 @@ goto error; } - if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) + if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colorMap, sizeof(hdr.colorMap))) { res = dmError(DMERR_FWRITE, "PCX: Could not write colormap.\n"); @@ -884,7 +887,7 @@ if (!dm_fwrite_byte(pcx.fp, hdr.reserved) || !dm_fwrite_byte(pcx.fp, hdr.nplanes) || !dm_fwrite_le16(pcx.fp, hdr.bpl) || - !dm_fwrite_le16(pcx.fp, hdr.palinfo) || + !dm_fwrite_le16(pcx.fp, hdr.palInfo) || !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) { res = dmError(DMERR_FWRITE, @@ -977,9 +980,7 @@ DMImage *img; DMPCXData pcx; DMPCXHeader hdr; - BOOL paletted; - int res = 0, yc, xc; - Uint8 *dp; + int res = 0; pcx.buf = NULL; @@ -987,7 +988,7 @@ if (!dm_fread_byte(fp, &hdr.manufacturer) || !dm_fread_byte(fp, &hdr.version) || !dm_fread_byte(fp, &hdr.encoding) || - !dm_fread_byte(fp, &hdr.bpp)) + !dm_fread_byte(fp, &hdr.bitsPerPlane)) { res = dmError(DMERR_FREAD, "PCX: Could not read basic header data.\n"); @@ -996,8 +997,7 @@ if (hdr.manufacturer != 10 || hdr.version != 5 || - hdr.encoding != 1 || - hdr.bpp != 8) + hdr.encoding != 1) { res = dmError(DMERR_NOT_SUPPORTED, "PCX: Not a PCX file, or unsupported variant.\n"); @@ -1016,7 +1016,7 @@ goto error; } - if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) + if (!dm_fread_str(fp, (Uint8 *) &hdr.colorMap, sizeof(hdr.colorMap))) { res = dmError(DMERR_FREAD, "PCX: Could not read colormap.\n"); @@ -1026,7 +1026,7 @@ if (!dm_fread_byte(fp, &hdr.reserved) || !dm_fread_byte(fp, &hdr.nplanes) || !dm_fread_le16(fp, &hdr.bpl) || - !dm_fread_le16(fp, &hdr.palinfo) || + !dm_fread_le16(fp, &hdr.palInfo) || !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) { res = dmError(DMERR_FREAD, @@ -1034,9 +1034,9 @@ goto error; } - if (hdr.nplanes != 3 && hdr.nplanes != 1) + if (hdr.nplanes < 1 || hdr.nplanes > 8) { - res = dmError(DMERR_FREAD, + res = dmError(DMERR_NOT_SUPPORTED, "PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes); goto error; @@ -1050,7 +1050,14 @@ goto error; } - paletted = hdr.nplanes == 1; + if (hdr.bpl < (img->width * hdr.bitsPerPlane) / 8) + { + res = dmError(DMERR_MALLOC, + "PCX: The bytes per plane line value %d is smaller than width*bpp/8 = %d!\n", + hdr.bpl, (img->width * hdr.bitsPerPlane) / 8); + goto error; + } + pcx.bufLen = hdr.nplanes * hdr.bpl; if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) { @@ -1060,48 +1067,44 @@ } // Read image data - dp = img->data; - for (yc = 0; yc < img->height; yc++) + Uint8 *dp = img->data; + for (int yc = 0; yc < img->height; yc++) { // Decode row of RLE'd data if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen)) { res = dmError(DMERR_INVALID_DATA, - "PCX: Error decoding RLE data.\n"); + "PCX: Error decoding RLE compressed data.\n"); goto error; } // Decode bitplanes - switch (hdr.nplanes) + switch (hdr.bitsPerPlane) { - case 1: - memcpy(dp, pcx.buf, img->width); + case 8: + for (int nplane = 0; nplane < hdr.nplanes; nplane++) + { + Uint8 *dptr = dp + nplane, + *sptr = pcx.buf + (hdr.bpl * nplane); + + for (int xc = 0; xc < img->width; xc += hdr.nplanes, dptr += hdr.nplanes, sptr++) + *dptr = *sptr; + } break; - case 3: - { - Uint8 *dptr = dp, - *sptr1 = pcx.buf, - *sptr2 = sptr1 + hdr.bpl, - *sptr3 = sptr2 + hdr.bpl; - - for (xc = 0; xc < img->width; xc++) - { - *dptr++ = *sptr1++; - *dptr++ = *sptr2++; - *dptr++ = *sptr3++; - } - } - break; + default: + res = dmError(DMERR_INVALID_DATA, + "PCX: Unsupported number of bits per plane %d.\n", + hdr.bitsPerPlane); + goto error; } dp += img->pitch; } - // Read VGA palette - if (paletted) + // Read additional VGA palette, if available { - int i, ncolors; + int ncolors; Uint8 tmpb; BOOL read; @@ -1125,6 +1128,7 @@ if (read) { + // Okay, attempt to read the palette data if (!dmReadPaletteData(fp, img->pal, ncolors)) { res = dmError(DMERR_FREAD, @@ -1134,14 +1138,13 @@ } else { - for (i = 0; i < img->ncolors; i++) + // If the extra palette is not available, copy the colors from + // the header palette to our internal palette structure. + for (int i = 0; i < (img->ncolors > DMPCX_PAL_COLORS ? DMPCX_PAL_COLORS : img->ncolors); i++) { - if (i < 16) - { - img->pal[i].r = hdr.colormap[i].r; - img->pal[i].g = hdr.colormap[i].g; - img->pal[i].b = hdr.colormap[i].b; - } + img->pal[i].r = hdr.colorMap[i].r; + img->pal[i].g = hdr.colorMap[i].g; + img->pal[i].b = hdr.colorMap[i].b; } } }