diff options
Diffstat (limited to 'graphics/sam2p/input-pnm.ci')
-rw-r--r-- | graphics/sam2p/input-pnm.ci | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/graphics/sam2p/input-pnm.ci b/graphics/sam2p/input-pnm.ci new file mode 100644 index 0000000000..6f7fff469c --- /dev/null +++ b/graphics/sam2p/input-pnm.ci @@ -0,0 +1,495 @@ +/* This code is ripped from Autotrace-0.29. Small modifications by pts. */ + +/* input-pnm.ci: + * The pnm reading and writing code was written from scratch by Erik Nygren + * (nygren@mit.edu) based on the specifications in the man pages and + * does not contain any code from the netpbm or pbmplus distributions. + */ + +#ifdef __GNUC__ +#ifndef __clang__ +#pragma implementation +#endif +#endif + +/* #include "types.h" */ +#include "at_bitmap.h" +/* #include "input-pnm.h" */ +/* #include "message.h" */ +/* #include "xstd.h" */ + +/* #include <math.h> -- ceil(); emulated */ +#include <stdlib.h> /* atoi(...) */ + +/**** pts ****/ +/* #include <ctype.h> */ +#define isspace(c) ((c)=='\0' || (c)==' ' || ((unsigned char)((c)-011)<=(unsigned char)(015-011))) +/* ^^^ not strictly POSIX C locale */ +#define isdigit(c) ((unsigned char)(c-'0')<=(unsigned char)('9'-'0')) + +#if 0 +# define PNMFILE FILE +# define fread_PNMFILE(s,slen,f) fread(s, 1, slen, f) +#else +# define PNMFILE /*Filter::UngetFILED*/GenBuffer::Readable +# define fread_PNMFILE(s,slen,f) f->vi_read(s, slen) +#endif + +/* Declare local data types + */ + +typedef struct _PNMScanner +{ + PNMFILE *fd; /* The file descriptor of the file being read */ + char cur; /* The current character in the input stream */ + int eof; /* Have we reached end of file? */ +} PNMScanner; + +typedef struct _PNMInfo +{ + unsigned int xres, yres; /* The size of the image */ + int maxval; /* For ascii image files, the max value + * which we need to normalize to */ + int np; /* Number of image planes (0 for pbm) */ + int asciibody; /* 1 if ascii body, 0 if raw body */ + /* Routine to use to load the pnm body */ + void (* loader) (PNMScanner *, struct _PNMInfo *, unsigned char *); +} PNMInfo; + +/* Contains the information needed to write out PNM rows */ +typedef struct _PNMRowInfo +{ + PNMFILE *fd; /* File descriptor */ + char *rowbuf; /* Buffer for writing out rows */ + int xres; /* X resolution */ + int np; /* Number of planes */ + unsigned char *red; /* Colormap red */ + unsigned char *grn; /* Colormap green */ + unsigned char *blu; /* Colormap blue */ +} PNMRowInfo; + +/* Save info */ +typedef struct +{ + int raw; /* raw or ascii */ +} PNMSaveVals; + +typedef struct +{ + int run; /* run */ +} PNMSaveInterface; + +#define PNM_BUFLEN 512 /* The input buffer size for data returned + * from the scanner. Note that lines + * aren't allowed to be over 256 characters + * by the spec anyways so this shouldn't + * be an issue. */ + +#define SAVE_COMMENT_STRING "# CREATOR: The GIMP's PNM Filter Version 1.0\n" + +/* Declare some local functions. + */ + +static void pnm_load_ascii (PNMScanner *scan, + PNMInfo *info, + unsigned char *pixel_rgn); +static void pnm_load_raw (PNMScanner *scan, + PNMInfo *info, + unsigned char *pixel_rgn); +static void pnm_load_rawpbm (PNMScanner *scan, + PNMInfo *info, + unsigned char *pixel_rgn); + +static void pnmscanner_destroy (PNMScanner *s); +#if 0 +static void pnmscanner_createbuffer (PNMScanner *s, + unsigned int bufsize); +static void pnmscanner_getchar (PNMScanner *s); +static void pnmscanner_getsmalltoken (PNMScanner *s, unsigned char *buf); +#endif +static void pnmscanner_eatwhitespace (PNMScanner *s); +static void pnmscanner_gettoken (PNMScanner *s, + unsigned char *buf, + unsigned int bufsize); +static unsigned pnmscanner_getint(PNMScanner *s); + +static PNMScanner * pnmscanner_create (PNMFILE *fd); + + +#define pnmscanner_eof(s) ((s)->eof) +#define pnmscanner_fd(s) ((s)->fd) + +#if 0 +/* pnmscanner_getchar --- + * Reads a character from the input stream + */ +static void +pnmscanner_getchar (PNMScanner *s) +{ + if (s->inbuf) + { + s->cur = s->inbuf[s->inbufpos++]; + if (s->inbufpos >= s->inbufvalidsize) + { + if (s->inbufsize > s->inbufvalidsize) + s->eof = 1; + else + s->inbufvalidsize = fread(s->inbuf, 1, s->inbufsize, s->fd); + s->inbufpos = 0; + } + } + else + s->eof = !fread(&(s->cur), 1, 1, s->fd); +} +#endif + +#define pnmscanner_getchar(s) do { s->eof = !fread_PNMFILE(&(s->cur), 1, s->fd); } while(0) + +/* pnmscanner_eatwhitespace --- + * Eats up whitespace from the input and returns when done or eof. + * Also deals with comments. + */ +static inline void pnmscanner_eatwhitespace(PNMScanner *s) { /**** pts ****/ + while (1) { + if (s->cur=='#') { + do pnmscanner_getchar(s); while (s->cur!='\n'); + } else if (!isspace(s->cur)) { + break; + } + pnmscanner_getchar(s); + } +} + + +static struct struct_pnm_types +{ + char name; + int np; + int asciibody; + int maxval; + void (* loader) (PNMScanner *, struct _PNMInfo *, unsigned char *pixel_rgn); +} pnm_types[] = +{ + { '1', 0, 1, 1, pnm_load_ascii }, /* ASCII PBM */ + { '2', 1, 1, 255, pnm_load_ascii }, /* ASCII PGM */ + { '3', 3, 1, 255, pnm_load_ascii }, /* ASCII PPM */ + { '4', 0, 0, 1, pnm_load_rawpbm }, /* RAW PBM */ + { '5', 1, 0, 255, pnm_load_raw }, /* RAW PGM */ + { '6', 3, 0, 255, pnm_load_raw }, /* RAW PPM */ + { 0 , 0, 0, 0, NULL} +}; + +#if PTS_SAM2P +bitmap_type pnm_load_image (PNMFILE* filename) +#else +bitmap_type pnm_load_image (at_string filename) +#endif +{ + char buf[PNM_BUFLEN]; /* buffer for random things like scanning */ + PNMInfo *pnminfo; + PNMScanner * volatile scan; + int ctr; + PNMFILE* fd; + bitmap_type bitmap; + + #if PTS_SAM2P /**** pts ****/ + fd=filename; + #else + /* open the file */ + fd = xfopen (filename, "rb"); + if (fd == NULL) + { + FATAL("PNM: can't open file\n"); + BITMAP_BITS (bitmap) = NULL; + BITMAP_WIDTH (bitmap) = 0; + BITMAP_HEIGHT (bitmap) = 0; + BITMAP_PLANES (bitmap) = 0; + return (bitmap); + } + #endif + + + /* allocate the necessary structures */ + /* pnminfo = (PNMInfo *) malloc (sizeof (PNMInfo)); */ + XMALLOCT(pnminfo, PNMInfo*, sizeof(PNMInfo)); + + scan = NULL; + /* set error handling */ + + scan = pnmscanner_create(fd); + + /* Get magic number */ + pnmscanner_gettoken (scan, (unsigned char *)buf, PNM_BUFLEN); + if (pnmscanner_eof(scan)) + FATALP ("PNM: premature end of file"); + if (buf[0] != 'P' || buf[2]) + FATALP ("PNM: is not a valid file"); + + /* Look up magic number to see what type of PNM this is */ + for (ctr=0; pnm_types[ctr].name; ctr++) + if (buf[1] == pnm_types[ctr].name) + { + pnminfo->np = pnm_types[ctr].np; + pnminfo->asciibody = pnm_types[ctr].asciibody; + pnminfo->maxval = pnm_types[ctr].maxval; + pnminfo->loader = pnm_types[ctr].loader; + } + if (!pnminfo->loader) + FATALP ("PNM: file not in a supported format"); + + pnmscanner_gettoken(scan, (unsigned char *)buf, PNM_BUFLEN); + if (pnmscanner_eof(scan)) + FATALP ("PNM: premature end of file"); + pnminfo->xres = isdigit(*buf)?atoi(buf):0; + if (pnminfo->xres<=0) + FATALP ("PNM: invalid xres while loading"); + + pnmscanner_gettoken(scan, (unsigned char *)buf, PNM_BUFLEN); + if (pnmscanner_eof(scan)) + FATALP ("PNM: premature end of file"); + pnminfo->yres = isdigit(*buf)?atoi(buf):0; + if (pnminfo->yres<=0) + FATALP ("PNM: invalid yres while loading"); + + if (pnminfo->np != 0) /* pbm's don't have a maxval field */ + { + pnmscanner_gettoken(scan, (unsigned char *)buf, PNM_BUFLEN); + if (pnmscanner_eof(scan)) + FATALP ("PNM: premature end of file"); + + pnminfo->maxval = isdigit(*buf)?atoi(buf):0; + if ((pnminfo->maxval<=0) + || (pnminfo->maxval>255 && !pnminfo->asciibody)) + FATALP ("PNM: invalid maxval while loading"); + } + + BITMAP_WIDTH (bitmap) = (at_dimen_t) pnminfo->xres; + BITMAP_HEIGHT (bitmap) = (at_dimen_t) pnminfo->yres; + + BITMAP_PLANES (bitmap) = (pnminfo->np)?(pnminfo->np):1; + /* BITMAP_BITS (bitmap) = (unsigned char *) malloc (pnminfo->yres * pnminfo->xres * BITMAP_PLANES (bitmap)); */ + XMALLOCT(BITMAP_BITS (bitmap), unsigned char *, pnminfo->yres * pnminfo->xres * BITMAP_PLANES (bitmap)); + pnminfo->loader (scan, pnminfo, BITMAP_BITS (bitmap)); + /* vvv Dat: We detect truncation late truncated files will just have garbage :-( */ + if (pnmscanner_eof(scan)) + FATALP ("PNM: truncated image data"); + + /* Destroy the scanner */ + pnmscanner_destroy (scan); + + /* free the structures */ + /* free (pnminfo); */ + XFREE(pnminfo); + + /* close the file */ + /* xfclose (fd, filename); */ + + return (bitmap); +} + +static void +pnm_load_ascii (PNMScanner *scan, + PNMInfo *info, + unsigned char *data) +{ + register unsigned char *d, *dend; + unsigned u, s; + #if 0 /**** pts ****/ + /* Buffer reads to increase performance */ + /* !! convert(1) is faster -- maybe buffering helps? */ + pnmscanner_createbuffer(scan, 4096); + #endif + d = data; + if (info->np==0) { /* PBM */ + dend=d+info->xres*info->yres; + while (d!=dend) { + /* pnmscanner_getsmalltoken(scan, (unsigned char *)buf); */ + pnmscanner_eatwhitespace(scan); + *d++=-(scan->cur=='0'); + pnmscanner_getchar(scan); + } + } else { /* PGM or PPM */ /**** pts ****/ + dend=d+info->xres*info->yres*info->np; + switch (s=info->maxval) { + case 255: + while (d!=dend) { + *d++=pnmscanner_getint(scan); /* Dat: removed isdigit() */ + } + break; + case 15: + while (d!=dend) { + *d++ = pnmscanner_getint(scan)*17; + } + break; + case 3: + while (d!=dend) { + *d++ = pnmscanner_getint(scan)*85; + } + break; + case 0: /* avoid division by 0 */ + case 1: + while (d!=dend) { + *d++ = -(0==pnmscanner_getint(scan)); /* (*buf=='0')?0xff:0x00; */ + } + default: + while (d!=dend) { + u=pnmscanner_getint(scan); + *d++ = (0UL+u*255UL+(s>>1))/s; /* always <= 255 */ + } + } + } +} + +static void +pnm_load_raw (PNMScanner *scan, + PNMInfo *info, + unsigned char *data) +{ + unsigned char *d, *dend; + unsigned s=info->maxval; + slen_t delta, scanlines; + PNMFILE *fd=pnmscanner_fd(scan); + + scanlines = info->yres; + d = data; + delta=info->xres * info->np; + dend=d+delta*scanlines; + while (d!=dend) { + if (info->xres*info->np != fread_PNMFILE((char*)d, delta, fd)) return; + d+=delta; + } + d=data; + switch (s=info->maxval) { /**** pts ****/ + case 1: case 0: + for (; d!=dend; d++) if (*d!=0) *d=255; + break; + case 3: + while (d!=dend) *d++*=85; + break; + case 15: + while (d!=dend) *d++*=17; + break; + case 255: + break; + default: + for (; d!=dend; d++) *d=(0UL+*d*255UL+(s>>1))/s; /* always <= 255 */ + break; + } +} + +static void +pnm_load_rawpbm (PNMScanner *scan, + PNMInfo *info, + unsigned char *data) +{ + unsigned char *buf; + unsigned char curbyte; + unsigned char *d; + unsigned int x, i; + unsigned int start, end, scanlines; + PNMFILE *fd; + unsigned int rowlen, bufpos; + + fd = pnmscanner_fd(scan); + /****pts****/ /* rowlen = (unsigned int)ceil((double)(info->xres)/8.0);*/ + rowlen=(info->xres+7)>>3; + /* buf = (unsigned char *)malloc(rowlen*sizeof(unsigned char)); */ + XMALLOCT(buf, unsigned char*, rowlen*sizeof(unsigned char)); + + start = 0; + end = info->yres; + scanlines = end - start; + d = data; + + for (i = 0; i < scanlines; i++) + { + if (rowlen != fread_PNMFILE((char*)buf, rowlen, fd)) + FATALP ("PNM: error reading file"); + bufpos = 0; + curbyte = buf[0]; + + for (x = 0; x < info->xres; x++) + { + if ((x % 8) == 0) { + curbyte = buf[bufpos++]; + /* // if (curbyte!=0) printf("%d <%u>\n", x, curbyte); */ + } + /* // if (curbyte!=0) printf("[%u]\n", curbyte); */ + d[x] = (curbyte&0x80) ? 0x00 : 0xff; + curbyte <<= 1; + } + + d += info->xres; + } + + XFREE(buf); +} + +/**************** FILE SCANNER UTILITIES **************/ + +/* pnmscanner_create --- + * Creates a new scanner based on a file descriptor. The + * look ahead buffer is one character initially. + */ +static PNMScanner * +pnmscanner_create (PNMFILE *fd) +{ + PNMScanner *s; + + XMALLOCT (s, PNMScanner*, sizeof(PNMScanner)); + s->fd = fd; + s->eof = !fread_PNMFILE(&(s->cur), 1, s->fd); + return s; +} + +/* pnmscanner_destroy --- + * Destroys a scanner and its resources. Doesn't close the fd. + */ +static void +pnmscanner_destroy (PNMScanner *s) +{ + XFREE(s); +} + +#if 0 /**** pts ****/ +/* pnmscanner_createbuffer --- + * Creates a buffer so we can do buffered reads. + */ +static void +pnmscanner_createbuffer (PNMScanner *s, + unsigned int bufsize) +{ + /* s->inbuf = (char *)malloc(sizeof(char)*bufsize); */ + XMALLOCT(s->inbuf, char*, sizeof(char)*bufsize); + s->inbufsize = bufsize; + s->inbufpos = 0; + s->inbufvalidsize = fread(s->inbuf, 1, bufsize, s->fd); +} +#endif + +/* pnmscanner_gettoken --- + * Gets the next token, eating any leading whitespace. + */ +static void pnmscanner_gettoken (PNMScanner *s, + unsigned char *buf, + unsigned int bufsize) +{ + unsigned char *bufend=buf+bufsize-1; + pnmscanner_eatwhitespace(s); + while (!pnmscanner_eof(s) && !isspace(s->cur) && s->cur!='#') { + if (buf!=bufend) *buf++=s->cur; + pnmscanner_getchar(s); + } + *buf='\0'; +} + +static unsigned pnmscanner_getint(PNMScanner *s) { + unsigned ret=0; + pnmscanner_eatwhitespace(s); + while (!pnmscanner_eof(s)) { + if (isdigit(s->cur)) ret=10*ret+s->cur-'0'; + else if (isspace(s->cur) || s->cur=='#') break; + pnmscanner_getchar(s); + } + return ret; +} |