This is ppmread.c in view mode; [Download] [Up]
#include <stdio.h> #include <stdlib.h> #include <libc.h> #include "ppm.h" #include "strfunc.h" /* PPM Format Px : Header Width Height MAX : pbm does not have this field Bitmap : in ASCII / Binary */ #define PXOF 0xff #define PAOF 0xfe #define UnknownHD 0 /* PX original Format PX : Header Width Height Colors : Colors := Number of colors in palette - 1 Count : if Trans is there Count=1, otherwise Count=0. Trans : Transparent + 256 [Palette] : Binary [Bitmap] : Binary */ /* PA original Format PA : Header Width Height MAX Planes : Planes = 1,2,3 or 4. (planes 2 and 4 have ALPHA) [Bitmap] : Binary */ static int ppmkind = 0, ppmmax = 0; static int pxtrans = 0; static char ppmcomm[MAX_COMMENT]; static void ppm_skip(FILE *fp) { int c; while ((c = getc(fp)) != EOF) { if (c == '\n') { c = getc(fp); while (c == '#') { while ((c = getc(fp)) != '\n') if (c == EOF) return; c = getc(fp); } } if (c > ' ') { ungetc(c, fp); return; } } } static int ppm_head(FILE *fp) { int c, i, kind = UnknownHD; if ((c = getc(fp)) != 'P') return UnknownHD; c = getc(fp); if (c >= '0' && c <= '9') kind = c - '0'; else if (c == 'X') kind = PXOF; else if (c == 'A') kind = PAOF; ppmcomm[0] = 0; while ((c = getc(fp)) <= ' ') ; if (c == '#') { for (i = 0; (c = getc(fp)) != '\n'; i++) if (i < MAX_COMMENT-1) ppmcomm[i] = c; else { while (getc(fp) != '\n') ; break; } ppmcomm[i] = 0; ungetc('\n', fp); ppm_skip(fp); }else ungetc(c, fp); return kind; } static int ppm_getint(FILE *fp) { int c; int v = 0; c = getc(fp); while (c < '0' || c > '9') { if (c == EOF) return -1; c = getc(fp); } while (c >= '0' && c <= '9') { v = (v * 10) + c - '0'; c = getc(fp); } if (c != EOF && c < ' ') ungetc(c, fp); return v; } commonInfo *loadPpmHeader(FILE *fp, int *errcode) { int w, err; commonInfo *cinf; *errcode = err = 0; ppmkind = ppm_head(fp); if (ppmkind == UnknownHD) { *errcode = Err_FORMAT; return NULL; } if ((w = ppm_getint(fp)) >= MAXWidth) { *errcode = Err_IMPLEMENT; return NULL; } if ((cinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL) { *errcode = Err_MEMORY; return NULL; } cinf->width = w; cinf->alpha = NO; cinf->type = Type_ppm; cinf->isplanar = YES; cinf->palsteps = 0; cinf->palette = NULL; cinf->memo[0] = 0; ppm_skip(fp); cinf->height = ppm_getint(fp); if (ppmkind == PBMa || ppmkind == PBMb) { ppmmax = 2; cinf->numcolors = 1; cinf->cspace = NX_OneIsBlackColorSpace; cinf->bits = 1; cinf->xbytes = byte_length(1, cinf->width); (void)getc(fp); /* feed last CR */ return cinf; } ppm_skip(fp); ppmmax = ppm_getint(fp) + 1; if (ppmkind == PAOF) { int pn; ppm_skip(fp); pn = ppm_getint(fp); if (pn < 1 || pn > 4) { /* PAOF must have alpha */ *errcode = Err_FORMAT; return NULL; } if (pn >= 3) { cinf->numcolors = 3; cinf->cspace = NX_RGBColorSpace; }else { cinf->numcolors = 1; cinf->cspace = NX_OneIsWhiteColorSpace; } (void)getc(fp); /* feed last CR */ cinf->alpha = (pn == 2 || pn == 4); }else if (ppmkind == PXOF) { int cnt; pxtrans = -1; ppm_skip(fp); cnt = ppm_getint(fp); if (cnt-- > 0) { ppm_skip(fp); pxtrans = ppm_getint(fp); } while (cnt-- > 0) { /* skip unknown parameters */ ppm_skip(fp); (void) ppm_getint(fp); } (void)getc(fp); /* feed last CR */ if (pxtrans >= 256) { cinf->alpha = YES; pxtrans -= 256; }else pxtrans = -1; cinf->numcolors = 3; cinf->cspace = NX_RGBColorSpace; cinf->bits = 8; cinf->xbytes = cinf->width; return cinf; }else { (void)getc(fp); /* feed last CR */ if (ppmkind == PPMa || ppmkind == PPMb) { cinf->numcolors = 3; cinf->cspace = NX_RGBColorSpace; }else { cinf->numcolors = 1; cinf->cspace = NX_OneIsWhiteColorSpace; } } cinf->bits = (ppmmax > 16) ? 8 : ((ppmmax > 4) ? 4 : ((ppmmax > 2) ? 2 : 1)); cinf->xbytes = byte_length(cinf->bits, cinf->width); return cinf; } static int isGrayPPM(unsigned char **planes, int length) { int i; unsigned char *rr, *gg, *bb; rr = planes[0]; gg = planes[1]; bb = planes[2]; for (i = 0; i < length; i++) { if (rr[i] != gg[i] || gg[i] != bb[i]) return 0; } return 1; } static int bitsOfPPM(unsigned char **planes, commonInfo *cinf) { unsigned char *p, buf[256]; int i, pn, pnmx, w, num; w = cinf->width * cinf->height; for (i = 0; i < 256; i++) buf[i] = 0; num = 0; pnmx = cinf->numcolors; if (cinf->alpha) pnmx++; for (pn = 0; pn < pnmx; pn++) { p = planes[pn]; for (i = 0; i < w; i++) if (buf[p[i]] == 0) { buf[p[i]] = 1; if (++num > 16) return 8; } } return optimalBits(buf, num); } static int getPXOF(FILE *fp, commonInfo *cinf, unsigned char **planes, int *aflag) { int i, x, y; unsigned char *p, *rr, *gg, *bb; cinf->palette = (paltype *)malloc(sizeof(paltype) * ppmmax); if (cinf->palette == NULL) return Err_MEMORY; cinf->palsteps = ppmmax; for (i = 0; i < ppmmax; i++) { p = cinf->palette[i]; for (x = 0; x < 3; x++) p[x] = getc(fp); } rr = planes[0]; gg = planes[1]; bb = planes[2]; if (! cinf->alpha) { for (y = 0; y < cinf->height; y++) { for (x = 0; x < cinf->width; x++) { p = cinf->palette[getc(fp)]; *rr++ = p[RED]; *gg++ = p[GREEN]; *bb++ = p[BLUE]; } } }else { unsigned char *aa = planes[3]; int cc; for (y = 0; y < cinf->height; y++) { for (x = 0; x < cinf->width; x++) { if ((cc = getc(fp)) == pxtrans) { *rr++ = *gg++ = *bb++ = 255; *aa++ = AlphaTransp; *aflag = YES; }else { p = cinf->palette[cc]; *rr++ = p[RED]; *gg++ = p[GREEN]; *bb++ = p[BLUE]; *aa++ = AlphaOpaque; } } } if (pxtrans != ppmmax - 1) { unsigned char *q; p = cinf->palette[ppmmax-1]; q = cinf->palette[pxtrans]; for (i = 0; i < 3; i++) q[i] = p[i]; cinf->palsteps = pxtrans = ppmmax - 1; p = cinf->palette[pxtrans]; for (i = 0; i < 3; i++) p[i] = 255; } } return 0; } static int PPMplanes(FILE *fp, commonInfo *cinf, int pn, unsigned char **planes, int *hasalpha) { int i, r, x, y; unsigned char work[MAXPLANE][MAXWidth]; unsigned char *pp; int width = cinf->width; int rdmax = ppmmax - 1; int aflag = NO; for (y = 0; y < cinf->height; y++) { if (feof(fp)) return Err_SHORT; if (isPPMascii(ppmkind)) { for (x = 0; x < width; x++) for (i = 0; i < pn; i++) { ppm_skip(fp); work[i][x] = ((r = ppm_getint(fp)) >= rdmax) ? 255 : ((r << 8) / ppmmax); } }else if (ppmkind == PBMb) { int mask, cc; for (x = 0; x < width; ) { cc = getc(fp); for (mask = 0x80; mask; mask >>= 1) { work[0][x] = (cc & mask) ? 0xff : 0; if (++x >= width) break; } } }else { for (x = 0; x < width; x++) { for (i = 0; i < pn; i++) work[i][x] = ((r = getc(fp)) >= rdmax) ? 255 : ((r << 8) / ppmmax); } } for (i = 0; i < pn; i++) { pp = planes[i] + y * cinf->xbytes; packImage(pp, work[i], width, cinf->bits); } if (cinf->alpha && aflag == NO) { pp = work[pn - 1]; for (i = 0; i < width; i++) { if (*pp++ != AlphaOpaque) { aflag = YES; break; } } } } *hasalpha = aflag; return 0; } int ppmGetImage(FILE *fp, commonInfo *cinf, unsigned char **planes, const char *fkind) { int i, y, pn, bits, err; int width, xbyte; const char *kp; int aflag = NO; width = cinf->width; pn = cinf->numcolors; if (cinf->alpha) pn++; err = allocImage(planes, width, cinf->height, cinf->bits, pn); if (err) return err; if (ppmkind == PXOF) err = getPXOF(fp, cinf, planes, &aflag); else err = PPMplanes(fp, cinf, pn, planes, &aflag); if (err) return err; /* ALPHA image ? */ if (cinf->alpha && aflag == NO) { cinf->alpha = NO; --pn; } /* Is this image Gray ? */ if (pn == 3 && isGrayPPM(planes, cinf->xbytes * cinf->height)) { size_t newsize = planes[1] - planes[0]; planes[0] = (unsigned char *)realloc(planes[0], newsize); planes[1] = planes[2] = NULL; pn = cinf->numcolors = 1; cinf->cspace = NX_OneIsWhiteColorSpace; } /* How many bits are needed ? */ if (cinf->bits == 8 && (bits = bitsOfPPM(planes, cinf)) < 8) { unsigned char *src, *dst, *newmap[MAXPLANE]; err = allocImage(newmap, width, cinf->height, bits, pn); if (err) return 0; /* Error */ xbyte = byte_length(bits, width); for (i = 0; i < pn; i++) { src = planes[i]; dst = newmap[i]; for (y = 0; y < cinf->height; y++) { packImage(dst, src, width, bits); src += width; dst += xbyte; } } free((void *)planes[0]); for (i = 0; i < pn; i++) planes[i] = newmap[i]; cinf->xbytes = xbyte; cinf->bits = bits; } sprintf(cinf->memo, "%d x %d ", cinf->width, cinf->height); if (fkind) kp = fkind; else if (ppmkind == PXOF) kp = "PXOF"; else if (ppmkind == PAOF) kp = "PAOF"; else kp = PPMname(ppmkind); strcat(cinf->memo, kp); if ((bits = cinf->bits) == 1) strcat(cinf->memo, " 1bit"); else { i = strlen(cinf->memo); sprintf(cinf->memo + i, " %dbits%s", bits, (pn > 2 ? "" : " gray")); } if (pn == 2 || pn == 4) strcat(cinf->memo, " Alpha"); if (ppmcomm[0]) { const char *p = ppmcomm; while (*p == ' ') p++; if (*p != 0) { strcat(cinf->memo, " "); comm_cat(cinf->memo, p); } } return 0; } #ifdef _TEST main() { printf("kind=P%d\n", ppm_head(stdin)); while (!feof(stdin)) { ppm_skip(stdin); printf("%d\n", ppm_getint(stdin)); } } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.