From: David Maciejak <[email protected]> According to that checks I was able to see that some netpbm support type are missing (exactly: ascii graymap (PGM files) and pixmap (PPM) and ascii/binary bitmap (PBM)).
To identify the file format, I based the checks on what is provided by mime package. See the link below for more details. http://en.wikipedia.org/wiki/Netpbm_format --- wrlib/load.c | 14 ++- wrlib/load_ppm.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 274 insertions(+), 53 deletions(-) diff --git a/wrlib/load.c b/wrlib/load.c index 94ef564..0f6b268 100644 --- a/wrlib/load.c +++ b/wrlib/load.c @@ -73,12 +73,18 @@ static WRImgFormat identFile(const char *path); char **RSupportedFileFormats(void) { - static char *tmp[IM_TYPES + 1]; + static char *tmp[IM_TYPES + 2]; int i = 0; /* built-in */ tmp[i++] = "XPM"; - /* built-in */ + /* built-in PNM here refers to anymap format: PPM, PGM, PBM */ + tmp[i++] = "PNM"; + /* + * PPM is a just a sub-type of PNM, but it has to be in the list + * for compatibility with legacy programs that may expect it but + * not the new PNM type + */ tmp[i++] = "PPM"; #ifdef USE_TIFF tmp[i++] = "TIFF"; @@ -309,8 +315,8 @@ static WRImgFormat identFile(const char *path) return IM_PNG; #endif - /* check for raw PPM or PGM */ - if (buffer[0] == 'P' && (buffer[1] == '5' || buffer[1] == '6')) + /* check for PBM or PGM or PPM */ + if (buffer[0] == 'P' && (buffer[1] > '0' && buffer[1] < '7') && (buffer[2] == 0x0a || buffer[2] == 0x20 || buffer[2] == 0x09 || buffer[2] == 0x0d)) return IM_PPM; /* check for JPEG */ diff --git a/wrlib/load_ppm.c b/wrlib/load_ppm.c index 49c10db..8d1ab72 100644 --- a/wrlib/load_ppm.c +++ b/wrlib/load_ppm.c @@ -3,6 +3,7 @@ * Raster graphics library * * Copyright (c) 1997-2003 Alfredo K. Kojima + * Copyright (c) 2014 Window Maker Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,79 +27,283 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <limits.h> #include "wraster.h" #include "imgformat.h" -static RImage *load_graymap(FILE *file, int w, int h, int max, int raw) +/* + * fileio.c - routines to read elements based on Netpbm + * + * Copyright (C) 1988 by Jef Poskanzer. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +char pm_getc(FILE * const fileP) +{ + int ich; + char ch; + + ich = getc(fileP); + if (ich == EOF) + fprintf(stderr, "EOF / read error reading a byte\n"); + ch = (char)ich; + + if (ch == '#') { + do { + ich = getc(fileP); + if (ich == EOF) + fprintf(stderr, "EOF / read error reading a byte\n"); + ch = (char)ich; + } while (ch != '\n' && ch != '\r'); + } + return ch; +} + +unsigned char pm_getrawbyte(FILE * const file) +{ + int iby; + + iby = getc(file); + if (iby == EOF) + fprintf(stderr, "EOF / read error reading a one-byte sample\n"); + return (unsigned char)iby; +} + +int pm_getuint(FILE * const ifP) +{ + char ch; + unsigned int i; + + do { + ch = pm_getc(ifP); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + fprintf(stderr, "junk in file where an unsigned integer should be\n"); + + i = 0; + do { + unsigned int const digitVal = ch - '0'; + + if (i > INT_MAX / 10) { + fprintf(stderr, "ASCII decimal integer in file is too large to be processed\n"); + return -1; + } + + i *= 10; + + if (i > INT_MAX - digitVal) { + fprintf(stderr, "ASCII decimal integer in file is too large to be processed\n"); + return -1; + } + + i += digitVal; + + ch = pm_getc(ifP); + } while (ch >= '0' && ch <= '9'); + + return i; +} +/* end of fileio.c re-used code */ +/******************************************************************************************/ + +/* PGM: support for portable graymap ascii and binary encoding */ +static RImage *load_graymap(FILE * file, int w, int h, int max, int raw) { RImage *image; unsigned char *ptr; - char *buf; int x, y; - image = RCreateImage(w, h, 0); - if (!image) + if (raw != '2' && raw != '5') { + RErrorCode = RERR_BADFORMAT; return NULL; + } - if (!raw) - return image; + image = RCreateImage(w, h, 0); + if (!image) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } if (max < 256) { - buf = malloc(w + 1); - if (!buf) - return NULL; - ptr = image->data; - for (y = 0; y < h; y++) { - if (!fread(buf, w, 1, file)) { - free(buf); - RErrorCode = RERR_BADIMAGEFILE; - return NULL; + if (raw == '2') { + int val; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + val = pm_getuint(file); + + if (val > max || val < 0) { + RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); + return NULL; + } + + val = val * 255 / max; + *(ptr++) = val; + *(ptr++) = val; + *(ptr++) = val; + } } + } else { + if (raw == '5') { + char *buf; + + buf = malloc(w + 1); + if (!buf) { + RErrorCode = RERR_NOMEMORY; + RReleaseImage(image); + return NULL; + } + for (y = 0; y < h; y++) { + if (!fread(buf, w, 1, file)) { + free(buf); + RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); + return NULL; + } - for (x = 0; x < w; x++) { - *(ptr++) = buf[x]; - *(ptr++) = buf[x]; - *(ptr++) = buf[x]; + for (x = 0; x < w; x++) { + *(ptr++) = buf[x]; + *(ptr++) = buf[x]; + *(ptr++) = buf[x]; + } + } + free(buf); } } - free(buf); } - return image; } -static RImage *load_pixmap(FILE *file, int w, int h, int max, int raw) +/* PPM: support for portable pixmap ascii and binary encoding */ +static RImage *load_pixmap(FILE * file, int w, int h, int max, int raw) { RImage *image; int i; - char buf[3]; unsigned char *ptr; - image = RCreateImage(w, h, 0); - if (!image) + if (raw != '3' && raw != '6') { + RErrorCode = RERR_BADFORMAT; return NULL; + } - if (!raw) - return image; + image = RCreateImage(w, h, 0); + if (!image) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } ptr = image->data; if (max < 256) { - i = 0; + if (raw == '3') { + int x, y, val; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + for (i = 0; i < 3; i++) { + val = pm_getuint(file); + + if (val > max || val < 0) { + RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); + return NULL; + } + + val = val * 255 / max; + *(ptr++) = val; + } + } + } + } else if (raw == '6') { + char buf[3]; + + i = 0; + while (i < w * h) { + if (fread(buf, 1, 3, file) != 3) { + RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); + return NULL; + } + + *(ptr++) = buf[0]; + *(ptr++) = buf[1]; + *(ptr++) = buf[2]; + i++; + } + } + } + return image; +} + +/* PBM: support for portable bitmap ascii and binary encoding */ +static RImage *load_bitmap(FILE * file, int w, int h, int max, int raw) +{ + RImage *image; + int val; + unsigned char *ptr; + + if (raw != '1' && raw != '4') { + RErrorCode = RERR_BADFORMAT; + return NULL; + } + + image = RCreateImage(w, h, 0); + if (!image) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + + ptr = image->data; + if (raw == '1') { + int i = 0; + while (i < w * h) { - if (fread(buf, 1, 3, file) != 3) { + val = pm_getuint(file); + + if (val > max || val < 0) { RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); return NULL; } - *(ptr++) = buf[0]; - *(ptr++) = buf[1]; - *(ptr++) = buf[2]; + val = (val == 0) ? 255 : 0; + *(ptr++) = val; + *(ptr++) = val; + *(ptr++) = val; i++; } - } + } else { + if (raw == '4') { + unsigned char buf; + int bitshift; + int x, y; + for (y = 0; y < h; y++) { + bitshift = -1; + for (x = 0; x < w; x++) { + if (bitshift == -1) { + buf = pm_getrawbyte(file); + bitshift = 7; + } + val = (buf >> bitshift) & 1; + val = (val == 0) ? 255 : 0; + --bitshift; + *(ptr++) = val; + *(ptr++) = val; + *(ptr++) = val; + } + } + } + } return image; } @@ -123,8 +328,8 @@ RImage *RLoadPPM(const char *file_name) return NULL; } - /* only accept raw pixmaps or graymaps */ - if (buffer[0] != 'P' || (buffer[1] != '5' && buffer[1] != '6')) { + /* accept bitmaps, pixmaps or graymaps */ + if (buffer[0] != 'P' || (buffer[1] < '1' || buffer[1] > '6')) { RErrorCode = RERR_BADFORMAT; fclose(file); return NULL; @@ -152,24 +357,34 @@ RImage *RLoadPPM(const char *file_name) return NULL; } - if (!fgets(buffer, 255, file)) { - RErrorCode = RERR_BADIMAGEFILE; - fclose(file); - return NULL; + if (type != '1' && type != '4') { + if (!fgets(buffer, 255, file)) { + RErrorCode = RERR_BADIMAGEFILE; + fclose(file); + return NULL; + } + /* get max value */ + if (sscanf(buffer, "%i", &m) != 1 || m < 1) { + /* Short file */ + RErrorCode = RERR_BADIMAGEFILE; + fclose(file); + return NULL; + } + } else { + m = 1; } - if (sscanf(buffer, "%i", &m) != 1 || m < 1) { - /* Short file */ - RErrorCode = RERR_BADIMAGEFILE; - fclose(file); - return NULL; + if (type == '1' || type == '4') { + /* Portable Bit Map: P1 is for 'plain' (ascii, rare), P4 for 'regular' (binary) */ + image = load_bitmap(file, w, h, m, type); + } else if (type == '2' || type == '5') { + /* Portable Gray Map: P2 is for 'plain' (ascii, rare), P5 for 'regular' (binary) */ + image = load_graymap(file, w, h, m, type); + } else if (type == '3' || type == '6') { + /* Portable Pix Map: P3 is for 'plain' (ascii, rare), P6 for 'regular' (binary) */ + image = load_pixmap(file, w, h, m, type); } - if (type == '5') - image = load_graymap(file, w, h, m, type == '5'); - else if (type == '6') - image = load_pixmap(file, w, h, m, type == '6'); - fclose(file); return image; } -- 1.8.5.3 -- To unsubscribe, send mail to [email protected].
