/* * pnm: subroutines for reading PNM picture files (PPM or PGM) * * Paul Heckbert 18 Jan 94 * * Michael Garland 17 Jan 96 : Added ppm_write * * Paul Heckbert 27 Oct 98 : added PGM support, renamed ppm->pnm */ #include #include #include #include "pic.h" /* pnm_get_token: read token from PNM file in stream fp into "char tok[len]" */ char *pnm_get_token(FILE *fp, char *tok, int len) { char *t; int c; for (;;) { /* skip over whitespace and comments */ while (isspace(c = getc(fp))); if (c!='#') break; do c = getc(fp); while (c!='\n' && c!=EOF); /* gobble comment */ if (c==EOF) break; } t = tok; if (c!=EOF) { do { *t++ = c; c = getc(fp); } while (!isspace(c) && c!='#' && c!=EOF && t-tokpix (after checking that * size is sufficient), else a new Pic is allocated. * Returns Pic pointer on success, 0 on failure. */ Pic *pnm_read(char *file, Pic *opic) { FILE *fp; char tok[20]; int nx, ny, bpp, pvmax; Pic *p; /* open PNM file */ if ((fp = fopen(file, "r")) == NULL) { fprintf(stderr, "can't read PNM file %s\n", file); return 0; } /* read PNM header */ pnm_get_token(fp, tok, sizeof tok); if (strcmp(tok, "P5") && strcmp(tok, "P6")) { fprintf(stderr, "%s is not a valid binary PGM or PPM file, bad magic#\n", file); fclose(fp); return 0; } bpp = strcmp(tok, "P6") ? 1 : 3; /* set bytes per pixel * "P5" is header for PGM (grayscale), "P6" is header for PPM (color)*/ if (sscanf(pnm_get_token(fp, tok, sizeof tok), "%d", &nx) != 1 || sscanf(pnm_get_token(fp, tok, sizeof tok), "%d", &ny) != 1 || sscanf(pnm_get_token(fp, tok, sizeof tok), "%d", &pvmax) != 1) { fprintf(stderr, "%s is not a valid PNM file: bad size\n", file); fclose(fp); return 0; } if (pvmax!=255) { fprintf(stderr, "%s does not have 8-bit components: pvmax=%d\n", file, pvmax); fclose(fp); return 0; } p = pic_alloc(nx, ny, bpp, opic); printf("reading PNM file %s: %dx%d pixels, %d byte per pixel\n", file, p->nx, p->ny, p->bpp); if (fread(p->pix, p->nx*p->bpp, p->ny, fp) != p->ny) { /* read pixels */ fprintf(stderr, "premature EOF on file %s\n", file); free(p); fclose(fp); return 0; } fclose(fp); return p; } int pnm_write(char *file, Pic *pic) { FILE *pnm; if (pic->bpp!=1 && pic->bpp!=3) { fprintf(stderr, "pnm_write: can't write %d byte per pixel Pic\n", pic->bpp); return FALSE; } /* Open the file for output */ pnm = fopen(file, "w"); if( !pnm ) return FALSE; /* Always write a binary PNM file */ fprintf(pnm, "P%c %d %d 255\n", pic->bpp==1 ? '5' : '6', pic->nx, pic->ny); /* "P5" is header for PGM (grayscale), "P6" is header for PPM (color) */ if (fwrite(pic->pix, pic->nx*pic->bpp, pic->ny, pnm) != pic->ny) { fprintf(stderr, "pnm_write: error writing %s\n", file); fclose(pnm); return FALSE; } fclose(pnm); return TRUE; }