# HG changeset patch # User Matti Hamalainen # Date 1351951710 -7200 # Node ID e4a3f183e463b6aee95d6b8bc5736b61a12fb656 # Parent 380c226c75af336c6ef059306ec968a8a5907ccb Modularize some more. diff -r 380c226c75af -r e4a3f183e463 Makefile.gen --- a/Makefile.gen Sat Nov 03 14:52:52 2012 +0200 +++ b/Makefile.gen Sat Nov 03 16:08:30 2012 +0200 @@ -189,7 +189,7 @@ ### Dependancies ifeq ($(DM_BUILD_TOOLS),yes) -DMLIB_OBJS += lib64gfx.o +DMLIB_OBJS += libgfx.o lib64gfx.o ifeq ($(DM_USE_STDIO),yes) BINARIES+= objlink data2inc gfxconv ifeq ($(SUP_MODLOAD),yes) @@ -310,6 +310,10 @@ @echo " CC $+" @$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) +$(OBJPATH)libgfx.o: $(DMLIB)libgfx.c $(DMLIB)libgfx.h + @echo " CC $+" + @$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) $(LIBPNG_CFLAGS) + $(DMLIB_A): $(addprefix $(OBJPATH),$(DMLIB_OBJS)) $(DMLIB)Makefile.gen config.mak @echo " AR $@ $(addprefix $(OBJPATH),$(DMLIB_OBJS))" diff -r 380c226c75af -r e4a3f183e463 gfxconv.c --- a/gfxconv.c Sat Nov 03 14:52:52 2012 +0200 +++ b/gfxconv.c Sat Nov 03 16:08:30 2012 +0200 @@ -9,34 +9,12 @@ #include "dmlib.h" #include "dmargs.h" #include "dmfile.h" -#include "dmbstr.h" #include "dmmutex.h" +#include "libgfx.h" #include "lib64gfx.h" //#define UNFINISHED 1 -#ifdef DM_USE_LIBPNG -#include -#endif - -enum -{ - IMGFMT_PNG, - IMGFMT_PPM, - IMGFMT_PCX, - IMGFMT_ARAW, - - IMGFMT_LAST -}; - -static const char *imageFormatList[IMGFMT_LAST] = -{ - "PNG", - "PPM", - "PCX", - "ARAW", -}; - enum { FFMT_AUTO = 0, @@ -120,17 +98,21 @@ optInSubFormat = IMGFMT_PNG, optOutSubFormat = IMGFMT_PNG, optItemCount = -1, - optScale = 2, optPlanedWidth = 1, - optForcedFormat = -1, - optBPP = 4; + optForcedFormat = -1; int optInSkip = 0; BOOL optInMulticolor = FALSE, - optSequential = FALSE, - optPaletted = FALSE, - optInterleave = FALSE; + optSequential = FALSE; int optColors[C64_MAX_COLORS]; +DMImageSpec optSpec = +{ + .scale = 2, + .nplanes = 4, + .interleave = FALSE, + .paletted = FALSE, + .format = 0, +}; static DMOptArg optList[] = { @@ -344,7 +326,7 @@ dmError("Invalid scale value '%s'.\n", optArg); return FALSE; } - optScale = tmp; + optSpec.scale = tmp; } break; @@ -361,7 +343,7 @@ break; case 12: - optPaletted = TRUE; + optSpec.paletted = TRUE; break; case 13: @@ -372,12 +354,12 @@ dmError("Invalid bitplanes/bpp value '%s'.\n", optArg); return FALSE; } - optBPP = tmp; + optSpec.nplanes = tmp; } break; case 14: - optInterleave = TRUE; + optSpec.interleave = TRUE; break; default: @@ -489,875 +471,6 @@ } -int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), int scale, int format) -{ - int x, y, yscale, xscale, res = 0, rowSize, rowWidth; - Uint8 *row = NULL; - - // Allocate memory for row buffer - rowWidth = img->width * scale; - rowSize = rowWidth * dmImageGetBytesPerPixel(format); - - if ((row = dmMalloc(rowSize + 16)) == NULL) - { - res = DMERR_MALLOC; - goto done; - } - - // Generate the image - for (y = 0; y < img->height; y++) - { - Uint8 *ptr = row, - *ptr1 = row, - *ptr2 = ptr1 + rowWidth, - *ptr3 = ptr2 + rowWidth; - - for (x = 0; x < img->width; x++) - { - Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa; - switch (format) - { - case DM_IFMT_PALETTE: - for (xscale = 0; xscale < scale; xscale++) - *ptr++ = c; - break; - - case DM_IFMT_RGBA: - qr = img->pal[c].r; - qg = img->pal[c].g; - qb = img->pal[c].b; - qa = (c == img->ctrans) ? 0 : 255; - - for (xscale = 0; xscale < scale; xscale++) - { - *ptr++ = qr; - *ptr++ = qg; - *ptr++ = qb; - *ptr++ = qa; - } - break; - - case DM_IFMT_RGB: - qr = img->pal[c].r; - qg = img->pal[c].g; - qb = img->pal[c].b; - - for (xscale = 0; xscale < scale; xscale++) - { - *ptr++ = qr; - *ptr++ = qg; - *ptr++ = qb; - } - break; - - case DM_IFMT_RGB_PLANE: - qr = img->pal[c].r; - qg = img->pal[c].g; - qb = img->pal[c].b; - - for (xscale = 0; xscale < scale; xscale++) - { - *ptr1++ = qr; - *ptr2++ = qg; - *ptr3++ = qb; - } - break; - } - } - - for (yscale = 0; yscale < scale; yscale++) - { - if (!writeRowCB(cbdata, row, rowSize)) - { - res = DMERR_FWRITE; - goto done; - } - } - } - -done: - dmFree(row); - return res; -} - - -#define DMCOL(x) (((x) >> 4) & 0xf) - -int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors) -{ - FILE *fp; - int i; - - if ((fp = fopen(filename, "w")) == NULL) - { - dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename); - return -15; - } - - for (i = 0; i < ncolors; i++) - { - int color; - if (i < img->ncolors) - { - color = (DMCOL(img->pal[i].r) << 8) | - (DMCOL(img->pal[i].g) << 4) | - (DMCOL(img->pal[i].b)); - } - else - color = 0; - - fprintf(fp, "\tdc.w $%04X\n", color); - } - - return 0; -} - - -int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, int scale, int nplanes, BOOL interleave) -{ - int xc, yc, plane, res; - DMBitStream bs; - - if ((res = dmInitBitStream(&bs, fp)) != DMERR_OK) - return res; - - if (interleave) - { - // Output bitplanes in interleaved format (each plane of line sequentially) - for (yc = 0; yc < img->height; yc++) - { - for (plane = 0; plane < nplanes; plane++) - { - Uint8 *sp = img->data + yc * img->pitch; - for (xc = 0; xc < img->width; xc++) - { - if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1)) - return DMERR_FWRITE; - } - } - } - } - else - { - // Output each bitplane in sequence - for (plane = 0; plane < nplanes; plane++) - { - for (yc = 0; yc < img->height; yc++) - { - Uint8 *sp = img->data + yc * img->pitch; - for (xc = 0; xc < img->width; xc++) - { - if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1)) - return DMERR_FWRITE; - } - } - } - } - - return dmFlushBitStream(&bs); -} - -int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, int scale, int nplanes, BOOL interleave) -{ - FILE *fp; - int res; - - if ((fp = fopen(filename, "wb")) == NULL) - { - dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename); - return DMERR_FOPEN; - } - - res = dmWriteIFFMasterRAWImageFILE(fp, img, scale, nplanes, interleave); - - fclose(fp); - return res; -} - - -static BOOL dmWritePPMRow(void *cbdata, Uint8 *row, size_t len) -{ - return fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len; -} - - -int dmWritePPMImageFILE(FILE *fp, DMImage *img, int scale) -{ - // Write PPM header - fprintf(fp, - "P6\n%d %d\n255\n", - img->width * scale, img->height * scale); - - // Write image data - return dmWriteImageData(img, (void *) fp, dmWritePPMRow, scale, DM_IFMT_RGB); -} - - -int dmWritePPMImage(const char *filename, DMImage *img, int scale) -{ - FILE *fp; - int res; - - // Create output file - if ((fp = fopen(filename, "wb")) == NULL) - { - dmError("PPM: could not open file '%s' for writing.\n", filename); - return DMERR_FOPEN; - } - - res = dmWritePPMImageFILE(fp, img, scale); - - fclose(fp); - return res; -} - - -#ifdef DM_USE_LIBPNG -static BOOL dmWritePNGRow(void *cbdata, Uint8 *row, size_t len) -{ - png_structp png_ptr = cbdata; - (void) len; - - if (setjmp(png_jmpbuf(png_ptr))) - return FALSE; - - png_write_row(png_ptr, row); - - return TRUE; -} - - -int dmWritePNGImageFILE(FILE *fp, DMImage *img, int scale, int format) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_colorp palette = NULL; - int fmt, res = DMERR_OK; - - // Create PNG structures - png_ptr = png_create_write_struct( - PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); - - if (png_ptr == NULL) - { - dmError("PNG: png_create_write_struct() failed.\n"); - res = DMERR_MALLOC; - goto error; - } - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr); - res = DMERR_INIT_FAIL; - goto error; - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - dmError("PNG: Error during image writing..\n"); - res = DMERR_INIT_FAIL; - goto error; - } - - png_init_io(png_ptr, fp); - - // Write PNG header info - switch (format) - { - case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break; - case DM_IFMT_RGB : fmt = PNG_COLOR_TYPE_RGB; break; - case DM_IFMT_RGBA : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break; - default: - dmError("PNG: Internal error, unsupported image format %d.\n", format); - goto error; - } - - png_set_IHDR(png_ptr, info_ptr, - img->width * scale, - img->height * scale, - 8, /* bits per component */ - fmt, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - // Palette - if (format == DM_IFMT_PALETTE) - { - int i; - - palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); - if (palette == NULL) - { - dmError("PNG: Could not allocate palette structure."); - goto error; - } - - memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); - - for (i = 0; i < img->ncolors; i++) - { - palette[i].red = img->pal[i].r; - palette[i].green = img->pal[i].g; - palette[i].blue = img->pal[i].b; - } - - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - } - -// png_set_gAMA(png_ptr, info_ptr, 2.2); - - png_write_info(png_ptr, info_ptr); - - - // Write compressed image data - dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, scale, format); - - // Write footer - png_write_end(png_ptr, NULL); - -error: - png_free(png_ptr, palette); - palette = NULL; - - if (png_ptr && info_ptr) - png_destroy_write_struct(&png_ptr, &info_ptr); - - return res; -} - - -int dmWritePNGImage(const char *filename, DMImage *img, int scale, int format) -{ - int res; - FILE *fp; - - if ((fp = fopen(filename, "wb")) == NULL) - { - dmError("PNG: could not open file '%s' for writing.\n", filename); - return DMERR_FOPEN; - } - - res = dmWritePNGImageFILE(fp, img, scale, format); - - fclose(fp); - return res; -} -#endif - - -typedef struct -{ - Uint8 r,g,b; -} DMPCXColor; - - -typedef struct -{ - Uint8 manufacturer, - version, - encoding, - bpp; - Uint16 xmin, ymin, xmax, ymax; - Uint16 hres, vres; - DMPCXColor colormap[16]; - Uint8 reserved; - Uint8 nplanes; - Uint16 bpl; - Uint16 palinfo; - Uint8 filler[58]; -} DMPCXHeader; - -typedef struct -{ - DMPCXHeader *header; - Uint8 *buf; - size_t bufLen, bufOffs; - int format; - FILE *fp; -} DMPCXData; - - -static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs) -{ - return (soffs < len) ? row[soffs] : 0; -} - -static BOOL dmPCXFlush(DMPCXData *pcx) -{ - BOOL ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs; - pcx->bufOffs = 0; - return ret; -} - -static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val) -{ - if (pcx->bufOffs < pcx->bufLen) - { - pcx->buf[pcx->bufOffs++] = val; - return TRUE; - } - else - return dmPCXFlush(pcx); -} - -BOOL dmWritePCXRow(void *cbdata, Uint8 *row, size_t len) -{ - DMPCXData *pcx = (DMPCXData *) cbdata; - int plane; - - for (plane = 0; plane < pcx->header->nplanes; plane++) - { - size_t soffs = 0; - Uint8 data = dmPCXGetByte(row, len, soffs++), - count = 1; - - pcx->bufOffs = 0; - - while (soffs < pcx->header->bpl) - { - if (data == dmPCXGetByte(row, len, soffs) && count < 63) - { - count++; - soffs++; - } - else - { - if (count == 1 && (data & 0xC0) != 0xC0) - { - if (!dmPCXPutByte(pcx, data)) - return FALSE; - } - else - { - if (!dmPCXPutByte(pcx, 0xC0 | count) || - !dmPCXPutByte(pcx, data)) - return FALSE; - } - - data = dmPCXGetByte(row, len, soffs++); - count = 1; - } - } - - if (count > 1) - { - if (!dmPCXPutByte(pcx, 0xC0 | count) || - !dmPCXPutByte(pcx, data)) - return FALSE; - } - - if (!dmPCXFlush(pcx)) - return FALSE; - } - - return TRUE; -} - - -int dmWritePCXImageFILE(FILE *fp, DMImage *img, int scale, BOOL paletted) -{ - DMPCXData pcx; - DMPCXHeader hdr; - int res; - - // Create output file - pcx.buf = NULL; - pcx.format = paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE; - pcx.header = &hdr; - pcx.fp = fp; - - // Create PCX header - memset(&hdr, 0, sizeof(hdr)); - if (paletted) - { - int i; - for (i = 0; i < (img->ncolors > 16 ? 16 : 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.manufacturer = 10; - hdr.version = 5; - hdr.encoding = 1; - hdr.bpp = 8; - hdr.hres = img->width * scale; - hdr.vres = img->height * scale; - hdr.xmin = hdr.ymin = 0; - hdr.xmax = hdr.hres - 1; - hdr.ymax = hdr.vres - 1; - hdr.nplanes = dmImageGetBytesPerPixel(pcx.format); - hdr.palinfo = 1; - res = (img->width * scale); - hdr.bpl = res / 2; - if (res % 2) hdr.bpl++; - hdr.bpl *= 2; - - dmMsg(2, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n", - paletted, hdr.nplanes, hdr.bpp, hdr.bpl); - - pcx.bufLen = hdr.bpl * 4; - if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) - { - dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n", - pcx.bufLen); - res = DMERR_MALLOC; - goto error; - } - - // Write PCX header - 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)) - { - dmError("PCX: Could not write basic header data.\n"); - res = DMERR_FWRITE; - goto error; - } - - if (!dm_fwrite_le16(pcx.fp, hdr.xmin) || - !dm_fwrite_le16(pcx.fp, hdr.ymin) || - !dm_fwrite_le16(pcx.fp, hdr.xmax) || - !dm_fwrite_le16(pcx.fp, hdr.ymax) || - !dm_fwrite_le16(pcx.fp, hdr.hres) || - !dm_fwrite_le16(pcx.fp, hdr.vres)) - { - dmError("PCX: Could not write image dimensions.\n"); - res = DMERR_FWRITE; - goto error; - } - - if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) - { - dmError("PCX: Could not write colormap.\n"); - res = DMERR_FWRITE; - goto error; - } - - 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_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) - { - dmError("PCX: Could not write header remainder.\n"); - res = DMERR_FWRITE; - goto error; - } - - // Write image data - res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, scale, pcx.format); - - // Write VGA palette - if (paletted) - { - int i; - dm_fwrite_byte(pcx.fp, 0x0C); - dmMsg(2, "PCX: Writing palette of %d active entries.\n", img->ncolors); - - for (i = 0; i < img->ncolors; i++) - { - dm_fwrite_byte(pcx.fp, img->pal[i].r); - dm_fwrite_byte(pcx.fp, img->pal[i].g); - dm_fwrite_byte(pcx.fp, img->pal[i].b); - } - - // Pad the palette, if necessary - for (; i < 256; i++) - { - dm_fwrite_byte(pcx.fp, 0); - dm_fwrite_byte(pcx.fp, 0); - dm_fwrite_byte(pcx.fp, 0); - } - } - -error: - dmFree(pcx.buf); - return res; -} - - -int dmWritePCXImage(const char *filename, DMImage *img, int scale, BOOL paletted) -{ - FILE *fp; - int res; - - if ((fp = fopen(filename, "wb")) == NULL) - { - dmError("PCX: Could not open file '%s' for writing.\n", filename); - return DMERR_FOPEN; - } - - res = dmWritePCXImageFILE(fp, img, scale, paletted); - - fclose(fp); - return res; -} - - -static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen) -{ - size_t offs = 0; - do - { - int count; - Uint8 data; - - if (!dm_fread_byte(fp, &data)) - return FALSE; - - if ((data & 0xC0) == 0xC0) - { - count = data & 0x3F; - if (!dm_fread_byte(fp, &data)) - return FALSE; - } - else - count = 1; - - while (count-- && offs < bufLen) - buf[offs++] = data; - - } while (offs < bufLen); - - return TRUE; -} - - -int dmReadPCXImageFILE(FILE *fp, DMImage **pimg) -{ - DMImage *img; - DMPCXData pcx; - DMPCXHeader hdr; - BOOL paletted; - int res = 0, yc, xc; - Uint8 *dp; - - pcx.buf = NULL; - - // Read PCX header - 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)) - { - dmError("PCX: Could not read basic header data.\n"); - res = DMERR_FREAD; - goto error; - } - - if (hdr.manufacturer != 10 || - hdr.version != 5 || - hdr.encoding != 1 || - hdr.bpp != 8) - { - dmError("PCX: Not a PCX file, or unsupported variant.\n"); - res = DMERR_FREAD; - goto error; - } - - if (!dm_fread_le16(fp, &hdr.xmin) || - !dm_fread_le16(fp, &hdr.ymin) || - !dm_fread_le16(fp, &hdr.xmax) || - !dm_fread_le16(fp, &hdr.ymax) || - !dm_fread_le16(fp, &hdr.hres) || - !dm_fread_le16(fp, &hdr.vres)) - { - dmError("PCX: Could not read image dimensions.\n"); - res = DMERR_FREAD; - goto error; - } - - if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) - { - dmError("PCX: Could not read colormap.\n"); - res = DMERR_FREAD; - goto error; - } - - 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_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) - { - dmError("PCX: Could not read header remainder.\n"); - res = DMERR_FREAD; - goto error; - } - - if (hdr.nplanes != 3 && hdr.nplanes != 1) - { - dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes); - res = DMERR_FREAD; - goto error; - } - - // Allocate image - if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL) - { - dmError("PCX: Could not allocate image structure.\n"); - res = DMERR_MALLOC; - goto error; - } - - paletted = hdr.nplanes == 1; - pcx.bufLen = hdr.nplanes * hdr.bpl; - if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) - { - dmError("PCX: Could not allocate RLE buffer.\n"); - res = DMERR_MALLOC; - goto error; - } - - // Read image data - dp = img->data; - for (yc = 0; yc < img->height; yc++) - { - // Decode row of RLE'd data - if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen)) - { - dmError("PCX: Error decoding RLE data.\n"); - res = DMERR_INVALID_DATA; - goto error; - } - - // Decode bitplanes - switch (hdr.nplanes) - { - case 1: - memcpy(dp, pcx.buf, img->width); - 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; - } - - dp += img->pitch; - } - - // Read VGA palette - if (paletted) - { - int i; - Uint8 tmpb; - BOOL read; - - if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C) - { - read = FALSE; - img->ncolors = 16; - } - else - { - read = TRUE; - img->ncolors = 256; - } - - if ((img->pal = dmCalloc(img->ncolors, sizeof(DMColor))) == NULL) - { - dmError("PCX: Could not allocate palette data!\n"); - res = DMERR_MALLOC; - goto error; - } - - if (read) - { - for (i = 0; i < img->ncolors; i++) - { - Uint8 tmpR, tmpG, tmpB; - if (!dm_fread_byte(fp, &tmpR) || - !dm_fread_byte(fp, &tmpG) || - !dm_fread_byte(fp, &tmpB)) - goto error; - - img->pal[i].r = tmpR; - img->pal[i].g = tmpG; - img->pal[i].b = tmpB; - } - } - else - { - for (i = 0; i < 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; - } - } - } - - - } - -error: - dmFree(pcx.buf); - return res; -} - - -int dmReadPCXImage(const char *filename, DMImage **pimg) -{ - FILE *fp; - int res; - - if ((fp = fopen(filename, "rb")) == NULL) - { - dmError("PCX: Could not open file '%s' for reading.\n", filename); - return -15; - } - - res = dmReadPCXImageFILE(fp, pimg); - - fclose(fp); - return res; -} - - -static int fmtProbePNG(const Uint8 *buf, const size_t len) -{ - if (len > 64 && buf[0] == 0x89 && - buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' && - buf[4] == 0x0d && buf[5] == 0x0a) - return DM_PROBE_SCORE_GOOD; - - return DM_PROBE_SCORE_FALSE; -} - - -static int fmtProbePCX(const Uint8 *buf, const size_t len) -{ - if (len > 128 + 64 && - buf[0] == 10 && - buf[1] == 5 && - buf[2] == 1 && - buf[3] == 8) - return DM_PROBE_SCORE_GOOD; - - return DM_PROBE_SCORE_FALSE; -} - - #ifdef UNFINISHED int dmConvertBMP2(DMImage *screen, const DM64Image *img) { @@ -1400,43 +513,46 @@ #endif -int dmWriteImage(char *filename, DMImage *image, BOOL info) +int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) { if (info) { dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n", - imageFormatList[optOutSubFormat], + dmImageFormatList[iformat], image->width, image->height, - image->width * optScale, image->height * optScale, optScale); + image->width * spec->scale, image->height * spec->scale, + spec->scale); } - - switch (optOutSubFormat) + + switch (iformat) { #ifdef DM_USE_LIBPNG case IMGFMT_PNG: - if (info) dmMsg(2, "%s output.\n", optPaletted ? "Indexed 8bpp" : "32bit RGBA"); - return dmWritePNGImage(filename, image, optScale, optPaletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA); + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA"); + spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA; + return dmWritePNGImage(filename, image, spec); #endif case IMGFMT_PPM: if (info) dmMsg(2, "24bit RGB output.\n"); - return dmWritePPMImage(filename, image, optScale); + spec->format = DM_IFMT_RGB; + return dmWritePPMImage(filename, image, spec); case IMGFMT_PCX: - if (info) dmMsg(2, "%s output.\n", optPaletted ? "Indexed 8bpp" : "24bit RGB"); - return dmWritePCXImage(filename, image, optScale, optPaletted); + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB"); + return dmWritePCXImage(filename, image, spec); case IMGFMT_ARAW: { int res; char *palFilename = dm_strdup_printf("%s.pal", filename); - res = dmWriteIFFMasterRAWPalette(palFilename, image, 1 << optBPP); + res = dmWriteIFFMasterRAWPalette(palFilename, image, 1 << optSpec.nplanes); dmFree(palFilename); if (res != DMERR_OK) return res; - if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", optBPP, optInterleave ? "with" : "without"); - return dmWriteIFFMasterRAWImage(filename, image, optScale, optBPP, optInterleave); + if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without"); + return dmWriteIFFMasterRAWImage(filename, image, spec); } default: @@ -1544,7 +660,7 @@ dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n", optItemCount, outImage->width, outImage->height, - outImage->width * optScale, outImage->height * optScale); + outImage->width * optSpec.scale, outImage->height * optSpec.scale); } else { @@ -1595,7 +711,7 @@ goto error; } - dmWriteImage(outFilename, outImage, FALSE); + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); dmFree(outFilename); } else @@ -1612,7 +728,7 @@ if (!optSequential) { - dmWriteImage(optOutFilename, outImage, TRUE); + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); } dmImageFree(outImage); @@ -1712,17 +828,12 @@ if (optInFormat == FFMT_AUTO) { - // XXX, needs a proper probe loop - if (fmtProbePNG(dataBuf + optInSkip, dataSize - optInSkip)) + DMImageFormat *ifmt = NULL; + int index; + if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0) { optInFormat = FFMT_IMAGE; - optInSubFormat = IMGFMT_PNG; - } - else - if (fmtProbePCX(dataBuf + optInSkip, dataSize - optInSkip)) - { - optInFormat = FFMT_IMAGE; - optInSubFormat = IMGFMT_PCX; + optInSubFormat = index; } } @@ -1767,7 +878,7 @@ case FFMT_BITMAP: { - DMImage *img = NULL; + DMImage *outImage = NULL; int res = DMERR_OK; if (optOutFilename == NULL) @@ -1779,29 +890,29 @@ switch (optOutFormat) { case FFMT_IMAGE: - if ((img = dmImageAlloc(C64_SCR_WIDTH, C64_SCR_HEIGHT)) == NULL) + if ((outImage = dmImageAlloc(C64_SCR_WIDTH, C64_SCR_HEIGHT)) == NULL) { dmError("Could not allocate output image surface %d x %d.\n", C64_SCR_WIDTH, C64_SCR_HEIGHT); goto error; } - img->pal = (DMColor *) &dmC64Palette; - img->ncolors = C64_NCOLORS; - img->constpal = TRUE; + outImage->pal = (DMColor *) &dmC64Palette; + outImage->ncolors = C64_NCOLORS; + outImage->constpal = TRUE; if (cfmt->convert != NULL) - res = cfmt->convert(img, &cimage); + res = cfmt->convert(outImage, &cimage); else - res = dmC64ConvertGenericBMP2Image(img, &cimage); + res = dmC64ConvertGenericBMP2Image(outImage, &cimage); - if (res != DMERR_OK || img == NULL) + if (res != DMERR_OK || outImage == NULL) { dmError("Error in bitmap to image conversion.\n"); goto error; } - res = dmWriteImage(optOutFilename, img, TRUE); + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); break; default: @@ -1809,13 +920,13 @@ break; } - dmImageFree(img); + dmImageFree(outImage); } break; case FFMT_IMAGE: { - DMImage *img; + DMImage *outImage; int res = DMERR_OK; if (optOutFilename == NULL) @@ -1827,22 +938,22 @@ // Read input switch (optInSubFormat) { - case IMGFMT_PCX: res = dmReadPCXImageFILE(inFile, &img); break; -// case IMGFMT_PNG: res = dmReadPNGImageFILE(inFile, &img); break; -// case IMGFMT_ARAW: res = dmReadARAWImageFILE(inFile, &img, optBPP); break; + case IMGFMT_PCX: res = dmReadPCXImageFILE(inFile, &outImage); break; +// case IMGFMT_PNG: res = dmReadPNGImageFILE(inFile, &outImage); break; +// case IMGFMT_ARAW: res = dmReadARAWImageFILE(inFile, &outImage, optSpec.nplanes); break; default: dmError("Unsupported input image format for bitmap/image conversion.\n"); break; } - if (res != DMERR_OK || img == NULL) + if (res != DMERR_OK || outImage == NULL) break; switch (optOutFormat) { case FFMT_IMAGE: - res = dmWriteImage(optOutFilename, img, TRUE); + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); break; default: @@ -1850,7 +961,7 @@ break; } - dmImageFree(img); + dmImageFree(outImage); } break; } diff -r 380c226c75af -r e4a3f183e463 lib64gfx.c --- a/lib64gfx.c Sat Nov 03 14:52:52 2012 +0200 +++ b/lib64gfx.c Sat Nov 03 16:08:30 2012 +0200 @@ -7,7 +7,7 @@ * Please read file 'COPYING' for information on license and distribution. */ #include "lib64gfx.h" -#include + const char *dmC64ImageTypeNames[DM_C64IFMT_LAST_TYPE] = { @@ -53,55 +53,6 @@ -DMImage * dmImageAlloc(int width, int height) -{ - DMImage *img = dmCalloc(1, sizeof(DMImage)); - if (img == NULL) - return NULL; - - img->width = img->pitch = width; - img->height = height; - img->data = dmMalloc(width * height * sizeof(Uint8)); - if (img->data == NULL) - { - dmFree(img); - return NULL; - } - - return img; -} - - -void dmImageFree(DMImage *img) -{ - if (img != NULL) - { - if (!img->constpal) - { - dmFree(img->pal); - } - dmFree(img->data); - dmFree(img); - } -} - - -int dmImageGetBytesPerPixel(int format) -{ - switch (format) - { - case DM_IFMT_PALETTE : return 1; - - case DM_IFMT_RGB_PLANE : - case DM_IFMT_RGB : return 3; - - case DM_IFMT_RGBA : return 4; - - default: return 0; - } -} - - int dmC64ConvertCSData(DMImage *img, int xoffs, int yoffs, const Uint8 *buf, int width, int height, BOOL multicolor, int *colors) diff -r 380c226c75af -r e4a3f183e463 lib64gfx.h --- a/lib64gfx.h Sat Nov 03 14:52:52 2012 +0200 +++ b/lib64gfx.h Sat Nov 03 16:08:30 2012 +0200 @@ -9,7 +9,12 @@ #ifndef LIB64GFX_H #define LIB64GFX_H 1 -#include "dmlib.h" +#include "libgfx.h" + +#ifdef __cplusplus +extern "C" { +#endif + // Bitmap constants #define C64_SCR_WIDTH 320 @@ -45,40 +50,6 @@ #define C64_MAX_SPRITES (C64_VIDBANK_SIZE / C64_SPR_SIZE) #define C64_MAX_CHARS 256 -// Probe scores -#define DM_PROBE_SCORE_MAX 1000 -#define DM_PROBE_SCORE_GOOD 750 -#define DM_PROBE_SCORE_AVG 500 -#define DM_PROBE_SCORE_MAYBE 250 -#define DM_PROBE_SCORE_FALSE 0 - -enum -{ - DM_IFMT_PALETTE, - DM_IFMT_RGB, - DM_IFMT_RGBA, - DM_IFMT_RGB_PLANE, -}; - - -// RGBx color struct -typedef struct -{ - Uint8 r, g, b, x; -} DMColor; - - -// Bitmapped image struct (can be one of types specified by DM_IFMT_*) -typedef struct -{ - int width, height, pitch; - BOOL constpal; - int ncolors, ctrans; - DMColor *pal; - Uint8 *data; -} DMImage; - - // Different supported C64 bitmap "modes" enum { @@ -171,11 +142,6 @@ extern const char * dmC64ImageTypeNames[]; -DMImage * dmImageAlloc(int width, int height); -void dmImageFree(DMImage *img); -int dmImageGetBytesPerPixel(int format); - - int dmC64ConvertCSData(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors); int dmC64ProbeGeneric(const Uint8 *buf, const size_t len, DMC64ImageFormat **fmt); int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt); @@ -184,4 +150,9 @@ int dmReadDataFile(FILE *inFile, const char *filename, Uint8 **buf, size_t *size); + +#ifdef __cplusplus +} +#endif + #endif // LIB64GFX_H diff -r 380c226c75af -r e4a3f183e463 libgfx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgfx.c Sat Nov 03 16:08:30 2012 +0200 @@ -0,0 +1,1003 @@ +/* + * Functions for reading and converting various restricted + * C64/etc and/or indexed/paletted graphics formats. + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "libgfx.h" +#include "dmfile.h" +#include "dmbstr.h" + +#ifdef DM_USE_LIBPNG +#include +#endif + + +DMImage * dmImageAlloc(int width, int height) +{ + DMImage *img = dmCalloc(1, sizeof(DMImage)); + if (img == NULL) + return NULL; + + img->width = img->pitch = width; + img->height = height; + img->data = dmMalloc(width * height * sizeof(Uint8)); + if (img->data == NULL) + { + dmFree(img); + return NULL; + } + + return img; +} + + +void dmImageFree(DMImage *img) +{ + if (img != NULL) + { + if (!img->constpal) + { + dmFree(img->pal); + } + dmFree(img->data); + dmFree(img); + } +} + + +int dmImageGetBytesPerPixel(int format) +{ + switch (format) + { + case DM_IFMT_PALETTE : return 1; + + case DM_IFMT_RGB_PLANE : + case DM_IFMT_RGB : return 3; + + case DM_IFMT_RGBA : return 4; + + default: return 0; + } +} + + +int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec) +{ + int x, y, yscale, xscale, res = 0, rowSize, rowWidth; + Uint8 *row = NULL; + + // Allocate memory for row buffer + rowWidth = img->width * spec->scale; + rowSize = rowWidth * dmImageGetBytesPerPixel(spec->format); + + if ((row = dmMalloc(rowSize + 16)) == NULL) + { + res = DMERR_MALLOC; + goto done; + } + + // Generate the image + for (y = 0; y < img->height; y++) + { + Uint8 *ptr = row, + *ptr1 = row, + *ptr2 = ptr1 + rowWidth, + *ptr3 = ptr2 + rowWidth; + + for (x = 0; x < img->width; x++) + { + Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa; + switch (spec->format) + { + case DM_IFMT_PALETTE: + for (xscale = 0; xscale < spec->scale; xscale++) + *ptr++ = c; + break; + + case DM_IFMT_RGBA: + qr = img->pal[c].r; + qg = img->pal[c].g; + qb = img->pal[c].b; + qa = (c == img->ctrans) ? 0 : 255; + + for (xscale = 0; xscale < spec->scale; xscale++) + { + *ptr++ = qr; + *ptr++ = qg; + *ptr++ = qb; + *ptr++ = qa; + } + break; + + case DM_IFMT_RGB: + qr = img->pal[c].r; + qg = img->pal[c].g; + qb = img->pal[c].b; + + for (xscale = 0; xscale < spec->scale; xscale++) + { + *ptr++ = qr; + *ptr++ = qg; + *ptr++ = qb; + } + break; + + case DM_IFMT_RGB_PLANE: + qr = img->pal[c].r; + qg = img->pal[c].g; + qb = img->pal[c].b; + + for (xscale = 0; xscale < spec->scale; xscale++) + { + *ptr1++ = qr; + *ptr2++ = qg; + *ptr3++ = qb; + } + break; + } + } + + for (yscale = 0; yscale < spec->scale; yscale++) + { + if (!writeRowCB(cbdata, row, rowSize)) + { + res = DMERR_FWRITE; + goto done; + } + } + } + +done: + dmFree(row); + return res; +} + + +#define DMCOL(x) (((x) >> 4) & 0xf) + +int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors) +{ + FILE *fp; + int i; + + if ((fp = fopen(filename, "w")) == NULL) + { + dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename); + return -15; + } + + for (i = 0; i < ncolors; i++) + { + int color; + if (i < img->ncolors) + { + color = (DMCOL(img->pal[i].r) << 8) | + (DMCOL(img->pal[i].g) << 4) | + (DMCOL(img->pal[i].b)); + } + else + color = 0; + + fprintf(fp, "\tdc.w $%04X\n", color); + } + + return 0; +} + + +int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec) +{ + int xc, yc, plane, res; + DMBitStream bs; + + if ((res = dmInitBitStream(&bs, fp)) != DMERR_OK) + return res; + + if (spec->interleave) + { + // Output bitplanes in interleaved format (each plane of line sequentially) + for (yc = 0; yc < img->height; yc++) + { + for (plane = 0; plane < spec->nplanes; plane++) + { + Uint8 *sp = img->data + yc * img->pitch; + for (xc = 0; xc < img->width; xc++) + { + if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1)) + return DMERR_FWRITE; + } + } + } + } + else + { + // Output each bitplane in sequence + for (plane = 0; plane < spec->nplanes; plane++) + { + for (yc = 0; yc < img->height; yc++) + { + Uint8 *sp = img->data + yc * img->pitch; + for (xc = 0; xc < img->width; xc++) + { + if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1)) + return DMERR_FWRITE; + } + } + } + } + + return dmFlushBitStream(&bs); +} + +int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, DMImageSpec *spec) +{ + FILE *fp; + int res; + + if ((fp = fopen(filename, "wb")) == NULL) + { + dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename); + return DMERR_FOPEN; + } + + res = dmWriteIFFMasterRAWImageFILE(fp, img, spec); + + fclose(fp); + return res; +} + + +static BOOL dmWritePPMRow(void *cbdata, Uint8 *row, size_t len) +{ + return fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len; +} + + +int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec) +{ + // Write PPM header + fprintf(fp, + "P6\n%d %d\n255\n", + img->width * spec->scale, + img->height * spec->scale); + + // Write image data + spec->format = DM_IFMT_RGB; + return dmWriteImageData(img, (void *) fp, dmWritePPMRow, spec); +} + + +int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec) +{ + FILE *fp; + int res; + + // Create output file + if ((fp = fopen(filename, "wb")) == NULL) + { + dmError("PPM: could not open file '%s' for writing.\n", filename); + return DMERR_FOPEN; + } + + res = dmWritePPMImageFILE(fp, img, spec); + + fclose(fp); + return res; +} + + +#ifdef DM_USE_LIBPNG +static BOOL dmWritePNGRow(void *cbdata, Uint8 *row, size_t len) +{ + png_structp png_ptr = cbdata; + (void) len; + + if (setjmp(png_jmpbuf(png_ptr))) + return FALSE; + + png_write_row(png_ptr, row); + + return TRUE; +} + + +int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_colorp palette = NULL; + int fmt, res = DMERR_OK; + + // Create PNG structures + png_ptr = png_create_write_struct( + PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + if (png_ptr == NULL) + { + dmError("PNG: png_create_write_struct() failed.\n"); + res = DMERR_MALLOC; + goto error; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr); + res = DMERR_INIT_FAIL; + goto error; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + dmError("PNG: Error during image writing..\n"); + res = DMERR_INIT_FAIL; + goto error; + } + + png_init_io(png_ptr, fp); + + // Write PNG header info + switch (spec->format) + { + case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break; + case DM_IFMT_RGB : fmt = PNG_COLOR_TYPE_RGB; break; + case DM_IFMT_RGBA : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break; + default: + dmError("PNG: Internal error, unsupported image format %d.\n", spec->format); + goto error; + } + + png_set_IHDR(png_ptr, info_ptr, + img->width * spec->scale, + img->height * spec->scale, + 8, /* bits per component */ + fmt, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + // Palette + if (spec->format == DM_IFMT_PALETTE) + { + int i; + + palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); + if (palette == NULL) + { + dmError("PNG: Could not allocate palette structure."); + goto error; + } + + memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); + + for (i = 0; i < img->ncolors; i++) + { + palette[i].red = img->pal[i].r; + palette[i].green = img->pal[i].g; + palette[i].blue = img->pal[i].b; + } + + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + } + +// png_set_gAMA(png_ptr, info_ptr, 2.2); + + png_write_info(png_ptr, info_ptr); + + + // Write compressed image data + dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, spec); + + // Write footer + png_write_end(png_ptr, NULL); + +error: + png_free(png_ptr, palette); + palette = NULL; + + if (png_ptr && info_ptr) + png_destroy_write_struct(&png_ptr, &info_ptr); + + return res; +} + + +int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec) +{ + int res; + FILE *fp; + + if ((fp = fopen(filename, "wb")) == NULL) + { + dmError("PNG: could not open file '%s' for writing.\n", filename); + return DMERR_FOPEN; + } + + res = dmWritePNGImageFILE(fp, img, spec); + + fclose(fp); + return res; +} +#endif + + +typedef struct +{ + Uint8 r,g,b; +} DMPCXColor; + + +typedef struct +{ + Uint8 manufacturer, + version, + encoding, + bpp; + Uint16 xmin, ymin, xmax, ymax; + Uint16 hres, vres; + DMPCXColor colormap[16]; + Uint8 reserved; + Uint8 nplanes; + Uint16 bpl; + Uint16 palinfo; + Uint8 filler[58]; +} DMPCXHeader; + + +typedef struct +{ + DMPCXHeader *header; + Uint8 *buf; + size_t bufLen, bufOffs; + int format; + FILE *fp; +} DMPCXData; + + +static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs) +{ + return (soffs < len) ? row[soffs] : 0; +} + +static BOOL dmPCXFlush(DMPCXData *pcx) +{ + BOOL ret = TRUE; + if (pcx->bufOffs > 0) + ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs; + pcx->bufOffs = 0; + return ret; +} + +static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val) +{ + if (pcx->bufOffs < pcx->bufLen) + { + pcx->buf[pcx->bufOffs++] = val; + return TRUE; + } + else + return dmPCXFlush(pcx); +} + +static BOOL 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++) + { + Uint8 data = dmPCXGetByte(row, len, soffs++), + count = 1; + +// size_t blen = pcx->header->bpl * pcx->header->nplanes; + size_t blen = pcx->header->bpl; + while (soffs < blen) + { + if (data == dmPCXGetByte(row, len, soffs) && count < 63) + { + count++; + soffs++; + } + else + { + if (count == 1 && (data & 0xC0) != 0xC0) + { + if (!dmPCXPutByte(pcx, data)) + return FALSE; + } + else + { + if (!dmPCXPutByte(pcx, 0xC0 | count) || + !dmPCXPutByte(pcx, data)) + return FALSE; + } + + data = dmPCXGetByte(row, len, soffs++); + count = 1; + } + } + + if (count > 1) + { + if (!dmPCXPutByte(pcx, 0xC0 | count) || + !dmPCXPutByte(pcx, data)) + return FALSE; + } + + if (!dmPCXFlush(pcx)) + return FALSE; + } + + + return TRUE; +} + + +int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec) +{ + DMPCXData pcx; + DMPCXHeader hdr; + int res; + + // Create output file + pcx.buf = NULL; + pcx.format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE; + pcx.header = &hdr; + pcx.fp = fp; + + // Create PCX header + memset(&hdr, 0, sizeof(hdr)); + if (spec->paletted) + { + int i; + for (i = 0; i < (img->ncolors > 16 ? 16 : 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.manufacturer = 10; + hdr.version = 5; + hdr.encoding = 1; + hdr.bpp = 8; + hdr.hres = img->width * spec->scale; + hdr.vres = img->height * spec->scale; + hdr.xmin = hdr.ymin = 0; + hdr.xmax = hdr.hres - 1; + hdr.ymax = hdr.vres - 1; + hdr.nplanes = dmImageGetBytesPerPixel(pcx.format); + hdr.palinfo = 1; + + res = (img->width * spec->scale); + hdr.bpl = res / 2; + if (res % 2) hdr.bpl++; + hdr.bpl *= 2; + + dmMsg(2, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n", + spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl); + + pcx.bufLen = hdr.bpl * 4; + if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) + { + dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n", + pcx.bufLen); + res = DMERR_MALLOC; + goto error; + } + + // Write PCX header + 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)) + { + dmError("PCX: Could not write basic header data.\n"); + res = DMERR_FWRITE; + goto error; + } + + if (!dm_fwrite_le16(pcx.fp, hdr.xmin) || + !dm_fwrite_le16(pcx.fp, hdr.ymin) || + !dm_fwrite_le16(pcx.fp, hdr.xmax) || + !dm_fwrite_le16(pcx.fp, hdr.ymax) || + !dm_fwrite_le16(pcx.fp, hdr.hres) || + !dm_fwrite_le16(pcx.fp, hdr.vres)) + { + dmError("PCX: Could not write image dimensions.\n"); + res = DMERR_FWRITE; + goto error; + } + + if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) + { + dmError("PCX: Could not write colormap.\n"); + res = DMERR_FWRITE; + goto error; + } + + 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_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) + { + dmError("PCX: Could not write header remainder.\n"); + res = DMERR_FWRITE; + goto error; + } + + // Write image data + res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, spec); + + // Write VGA palette + if (spec->paletted) + { + int i; + dm_fwrite_byte(pcx.fp, 0x0C); + dmMsg(2, "PCX: Writing palette of %d active entries.\n", img->ncolors); + + for (i = 0; i < img->ncolors; i++) + { + dm_fwrite_byte(pcx.fp, img->pal[i].r); + dm_fwrite_byte(pcx.fp, img->pal[i].g); + dm_fwrite_byte(pcx.fp, img->pal[i].b); + } + + // Pad the palette, if necessary + for (; i < 256; i++) + { + dm_fwrite_byte(pcx.fp, 0); + dm_fwrite_byte(pcx.fp, 0); + dm_fwrite_byte(pcx.fp, 0); + } + } + +error: + dmFree(pcx.buf); + return res; +} + + +int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec) +{ + FILE *fp; + int res; + + if ((fp = fopen(filename, "wb")) == NULL) + { + dmError("PCX: Could not open file '%s' for writing.\n", filename); + return DMERR_FOPEN; + } + + res = dmWritePCXImageFILE(fp, img, spec); + + fclose(fp); + return res; +} + + +static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen) +{ + size_t offs = 0; + do + { + int count; + Uint8 data; + + if (!dm_fread_byte(fp, &data)) + return FALSE; + + if ((data & 0xC0) == 0xC0) + { + count = data & 0x3F; + if (!dm_fread_byte(fp, &data)) + return FALSE; + } + else + count = 1; + + while (count-- && offs < bufLen) + buf[offs++] = data; + + } while (offs < bufLen); + + return TRUE; +} + + +int dmReadPCXImageFILE(FILE *fp, DMImage **pimg) +{ + DMImage *img; + DMPCXData pcx; + DMPCXHeader hdr; + BOOL paletted; + int res = 0, yc, xc; + Uint8 *dp; + + pcx.buf = NULL; + + // Read PCX header + 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)) + { + dmError("PCX: Could not read basic header data.\n"); + res = DMERR_FREAD; + goto error; + } + + if (hdr.manufacturer != 10 || + hdr.version != 5 || + hdr.encoding != 1 || + hdr.bpp != 8) + { + dmError("PCX: Not a PCX file, or unsupported variant.\n"); + res = DMERR_FREAD; + goto error; + } + + if (!dm_fread_le16(fp, &hdr.xmin) || + !dm_fread_le16(fp, &hdr.ymin) || + !dm_fread_le16(fp, &hdr.xmax) || + !dm_fread_le16(fp, &hdr.ymax) || + !dm_fread_le16(fp, &hdr.hres) || + !dm_fread_le16(fp, &hdr.vres)) + { + dmError("PCX: Could not read image dimensions.\n"); + res = DMERR_FREAD; + goto error; + } + + if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) + { + dmError("PCX: Could not read colormap.\n"); + res = DMERR_FREAD; + goto error; + } + + 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_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) + { + dmError("PCX: Could not read header remainder.\n"); + res = DMERR_FREAD; + goto error; + } + + if (hdr.nplanes != 3 && hdr.nplanes != 1) + { + dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes); + res = DMERR_FREAD; + goto error; + } + + // Allocate image + if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL) + { + dmError("PCX: Could not allocate image structure.\n"); + res = DMERR_MALLOC; + goto error; + } + + paletted = hdr.nplanes == 1; + pcx.bufLen = hdr.nplanes * hdr.bpl; + if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) + { + dmError("PCX: Could not allocate RLE buffer.\n"); + res = DMERR_MALLOC; + goto error; + } + + // Read image data + dp = img->data; + for (yc = 0; yc < img->height; yc++) + { + // Decode row of RLE'd data + if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen)) + { + dmError("PCX: Error decoding RLE data.\n"); + res = DMERR_INVALID_DATA; + goto error; + } + + // Decode bitplanes + switch (hdr.nplanes) + { + case 1: + memcpy(dp, pcx.buf, img->width); + 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; + } + + dp += img->pitch; + } + + // Read VGA palette + if (paletted) + { + int i; + Uint8 tmpb; + BOOL read; + + if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C) + { + read = FALSE; + img->ncolors = 16; + } + else + { + read = TRUE; + img->ncolors = 256; + } + + if ((img->pal = dmCalloc(img->ncolors, sizeof(DMColor))) == NULL) + { + dmError("PCX: Could not allocate palette data!\n"); + res = DMERR_MALLOC; + goto error; + } + + if (read) + { + for (i = 0; i < img->ncolors; i++) + { + Uint8 tmpR, tmpG, tmpB; + if (!dm_fread_byte(fp, &tmpR) || + !dm_fread_byte(fp, &tmpG) || + !dm_fread_byte(fp, &tmpB)) + goto error; + + img->pal[i].r = tmpR; + img->pal[i].g = tmpG; + img->pal[i].b = tmpB; + } + } + else + { + for (i = 0; i < 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; + } + } + } + + + } + +error: + dmFree(pcx.buf); + return res; +} + + +int dmReadPCXImage(const char *filename, DMImage **pimg) +{ + FILE *fp; + int res; + + if ((fp = fopen(filename, "rb")) == NULL) + { + dmError("PCX: Could not open file '%s' for reading.\n", filename); + return -15; + } + + res = dmReadPCXImageFILE(fp, pimg); + + fclose(fp); + return res; +} + + +static int fmtProbePNG(const Uint8 *buf, const size_t len) +{ + if (len > 64 && buf[0] == 0x89 && + buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' && + buf[4] == 0x0d && buf[5] == 0x0a) + return DM_PROBE_SCORE_GOOD; + + return DM_PROBE_SCORE_FALSE; +} + + +static int fmtProbePCX(const Uint8 *buf, const size_t len) +{ + if (len > 128 + 64 && + buf[0] == 10 && + buf[1] == 5 && + buf[2] == 1 && + buf[3] == 8) + return DM_PROBE_SCORE_GOOD; + + return DM_PROBE_SCORE_FALSE; +} + + +DMImageFormat dmImageFormatList[IMGFMT_LAST] = +{ + { + "PNG", "Portable Network Graphics", + fmtProbePNG, + NULL, NULL, +#ifdef DM_USE_LIBPNG + dmWritePNGImage, dmWritePNGImageFILE, +#else + NULL, NULL, +#endif + }, + { + "PPM", "Portable PixMap", + NULL, + NULL, NULL, + dmWritePPMImage, dmWritePPMImageFILE, + }, + { + "PCX", "Z-Soft Paintbrush", + fmtProbePCX, + dmReadPCXImage, dmReadPCXImageFILE, + dmWritePCXImage, dmWritePCXImageFILE, + }, + { + "ARAW", "IFFMaster Amiga RAW", + NULL, + NULL, NULL, + dmWriteIFFMasterRAWImage, dmWriteIFFMasterRAWImageFILE, + } +}; + + +int dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **pfmt, int *index) +{ + int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1; + + for (i = 0; i < IMGFMT_LAST; i++) + { + DMImageFormat *fmt = &dmImageFormatList[i]; + int score = fmt->probe(buf, len); + if (score > scoreMax) + { + scoreMax = score; + scoreIndex = i; + } + } + + if (scoreIndex >= 0) + { + *pfmt = &dmImageFormatList[scoreIndex]; + *index = scoreIndex; + return scoreMax; + } + else + return DM_PROBE_SCORE_FALSE; +} diff -r 380c226c75af -r e4a3f183e463 libgfx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgfx.h Sat Nov 03 16:08:30 2012 +0200 @@ -0,0 +1,117 @@ +/* + * Functions for loading and saving bitmap images + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef LIBMGFX_H +#define LIBMGFX_H 1 + +#include "dmlib.h" +#include "dmfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +enum +{ + IMGFMT_PNG, + IMGFMT_PPM, + IMGFMT_PCX, + IMGFMT_ARAW, + + IMGFMT_LAST +}; + + +enum +{ + DM_IFMT_PALETTE, + DM_IFMT_RGB, + DM_IFMT_RGBA, + DM_IFMT_RGB_PLANE, +}; + + +// RGBx color struct +typedef struct +{ + Uint8 r, g, b, x; +} DMColor; + + +// Bitmapped image struct (can be one of types specified by DM_IFMT_*) +typedef struct +{ + int width, height, pitch; + BOOL constpal; + int ncolors, ctrans; + DMColor *pal; + Uint8 *data; +} DMImage; + + +typedef struct +{ + int scale, nplanes, format; + BOOL interleave, paletted; +} DMImageSpec; + + +typedef struct +{ + char *fext; + char *desc; + int (*probe)(const Uint8 *buf, const size_t len); + int (*read)(const char *filename, DMImage **pimg); + int (*readFILE)(FILE *fp, DMImage **pimg); + int (*write)(const char *filename, DMImage *pimg, DMImageSpec *spec); + int (*writeFILE)(FILE *fp, DMImage *pimg, DMImageSpec *spec); +} DMImageFormat; + + +// Probe scores +#define DM_PROBE_SCORE_MAX 1000 +#define DM_PROBE_SCORE_GOOD 750 +#define DM_PROBE_SCORE_AVG 500 +#define DM_PROBE_SCORE_MAYBE 250 +#define DM_PROBE_SCORE_FALSE 0 + + +extern DMImageFormat dmImageFormatList[IMGFMT_LAST]; + + +DMImage * dmImageAlloc(int width, int height); +void dmImageFree(DMImage *img); +int dmImageGetBytesPerPixel(int format); +int dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **fmt, int *index); + + +int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec); + +int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors); +int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec); +int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, DMImageSpec *spec); + +int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec); +int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec); + +#ifdef DM_USE_LIBPNG +int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec); +int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec); +#endif + +int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec); +int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec); +int dmReadPCXImageFILE(FILE *fp, DMImage **pimg); +int dmReadPCXImage(const char *filename, DMImage **pimg); + + +#ifdef __cplusplus +} +#endif + +#endif // LIBMGFX_H