# HG changeset patch # User Matti Hamalainen # Date 1551349821 -7200 # Node ID 614b161c0aa5f48809a435952ed27b3756754d0c # Parent 3b3acb6b4ba03beb8452e6595fe2ab263f461490 Initial support for reading PPM/PGM. diff -r 3b3acb6b4ba0 -r 614b161c0aa5 tools/libgfx.c --- a/tools/libgfx.c Thu Feb 28 12:18:27 2019 +0200 +++ b/tools/libgfx.c Thu Feb 28 12:30:21 2019 +0200 @@ -106,6 +106,7 @@ { switch (format) { + case DM_COLFMT_GRAYSCALE : return 1; case DM_COLFMT_PALETTE : return 1; case DM_COLFMT_RGB : return 3; case DM_COLFMT_RGBA : return 4; @@ -243,6 +244,7 @@ switch (spec->format) { case DM_COLFMT_PALETTE: + case DM_COLFMT_GRAYSCALE: for (xscale = 0; xscale < spec->scaleX; xscale++) *ptr1++ = c; break; @@ -511,10 +513,32 @@ int dmWritePPMImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *spec) { DMImageConvSpec tmpSpec; + char *tmpFmt; + + memcpy(&tmpSpec, spec, sizeof(DMImageConvSpec)); + + switch (spec->format) + { + case DM_COLFMT_RGB: + case DM_COLFMT_RGBA: + case DM_COLFMT_PALETTE: + tmpSpec.format = DM_COLFMT_RGB; + tmpFmt = "6"; + break; + + case DM_COLFMT_GRAYSCALE: + tmpFmt = "5"; + break; + + default: + return dmError(DMERR_NOT_SUPPORTED, + "PPM: Not a supported color format for PPM/PGM format image.\n"); + } // Write PPM header char *tmp = dm_strdup_printf( - "P6\n%d %d\n255\n", + "P%s\n%d %d\n255\n", + tmpFmt, img->width * spec->scaleX, img->height * spec->scaleY); @@ -525,12 +549,84 @@ dmFree(tmp); // Write image data - memcpy(&tmpSpec, spec, sizeof(DMImageConvSpec)); - tmpSpec.format = DM_COLFMT_RGB; return dmWriteImageData(img, (void *) fp, dmWritePPMRow, &tmpSpec); } +int dmReadPPMImage(DMResource *fp, DMImage **pimg) +{ + DMImage *img = NULL; + unsigned int width, height; + int itype, res = DMERR_OK; + char hdr1[8], hdr2[32], hdr3[16]; + + // Read PPM header + if (dmfgets(hdr1, sizeof(hdr1), fp) == NULL || + dmfgets(hdr2, sizeof(hdr2), fp) == NULL || + dmfgets(hdr3, sizeof(hdr3), fp) == NULL) + { + res = dmError(DMERR_FREAD, + "PPM: Could not read image header data.\n"); + goto error; + } + + if (hdr1[0] != 'P' || !isdigit(hdr1[1]) || + !isdigit(hdr2[0]) || !isdigit(hdr3[0])) + { + res = dmError(DMERR_NOT_SUPPORTED, + "PPM: Not a supported PPM/PGM format image.\n"); + goto error; + } + + switch (hdr1[1]) + { + case '6': itype = DM_COLFMT_RGB; break; + case '5': itype = DM_COLFMT_GRAYSCALE; break; + default: + res = dmError(DMERR_NOT_SUPPORTED, + "PPM: Unsupported PPM/PGM subtype.\n"); + goto error; + } + + if (sscanf(hdr2, "%u %u", &width, &height) != 2) + { + res = dmError(DMERR_INVALID_DATA, + "PPM: Invalid PPM/PGM image dimensions.\n"); + goto error; + } + + if ((*pimg = img = dmImageAlloc(width, height, itype, -1)) == NULL) + { + res = dmError(DMERR_MALLOC, + "PPM: Could not allocate image data.\n"); + goto error; + } + + if (dmf_read_str(fp, img->data, img->size)) + { + res = dmError(DMERR_FREAD, + "PPM: Could not read image data.\n"); + goto error; + } + +error: + + return res; +} + + +static int fmtProbePPM(const Uint8 *buf, const size_t len) +{ + if (len > 32 && + buf[0] == 'P' && + buf[1] == '5' && + buf[2] == 0x0a && isdigit(buf[3])) + return DM_PROBE_SCORE_MAX; + + return DM_PROBE_SCORE_FALSE; +} + + #ifdef DM_USE_LIBPNG static int fmtProbePNG(const Uint8 *buf, const size_t len) { @@ -2518,8 +2614,8 @@ #endif { "ppm", "Portable PixMap", - DM_IMGFMT_PPM, DM_FMT_WR, - NULL, NULL, dmWritePPMImage, + DM_IMGFMT_PPM, DM_FMT_RDWR, + fmtProbePPM, dmReadPPMImage, dmWritePPMImage, }, { "pcx", "Z-Soft Paintbrush", diff -r 3b3acb6b4ba0 -r 614b161c0aa5 tools/libgfx.h --- a/tools/libgfx.h Thu Feb 28 12:18:27 2019 +0200 +++ b/tools/libgfx.h Thu Feb 28 12:30:21 2019 +0200 @@ -34,6 +34,7 @@ enum { DM_COLFMT_PALETTE, + DM_COLFMT_GRAYSCALE, DM_COLFMT_RGB, DM_COLFMT_RGBA, }; @@ -135,6 +136,7 @@ int dmWriteRAWImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *spec); int dmWritePPMImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *spec); +int dmReadPPMImage(DMResource *fp, DMImage **pimg); #ifdef DM_USE_LIBPNG int dmWritePNGImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *spec);