Mercurial > hg > dmlib
diff libgfx.c @ 435:e4a3f183e463
Modularize some more.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 03 Nov 2012 16:08:30 +0200 |
parents | |
children | 86f956e4580f |
line wrap: on
line diff
--- /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 <png.h> +#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; +}