/* * pnmmcut - do multiple "pnmcut" operations at once. * * pnmmcut x y w h file [x y w h file [x y w h file ...]] * * Reads a pnm file from stdin. For each quintuple x y w h file of * arguments, it performs the equivalent of a "pnmcut x y w h > file". * There is no particular prohibition against argument areas * overlapping. * * Note that all output files are opened before the input is read * beyond the header. */ #include #include #include #include #include #include extern const char *__progname; typedef struct fdesc FDESC; struct fdesc { char class; #define T_PBM 'b' #define T_PGM 'g' #define T_PPM 'p' #define T_RPBM 'B' #define T_RPGM 'G' #define T_RPPM 'P' const char *fn; FILE *f; unsigned int maxval; unsigned int w; unsigned int h; unsigned char rpbmbuf; unsigned char rpbmbit; } ; typedef struct ofile OFILE; struct ofile { FDESC desc; int x; int y; int w; int h; } ; typedef struct pixval PIXVAL; struct pixval { unsigned int r; unsigned int g; unsigned int b; } ; static FDESC idesc; static OFILE *ofiles; static int nofiles; static int number(const char *s) { char *e; int v; v = strtol(s,&e,0); if (*e || (e == s)) { fprintf(stderr,"%s: invalid number `%s'\n",__progname,s); exit(1); } return(v); } static char class_rawform(char class) { switch (class) { case T_PBM: case T_RPBM: return(T_RPBM); break; case T_PGM: case T_RPGM: return(T_RPGM); break; case T_PPM: case T_RPPM: return(T_RPPM); break; } abort(); } static void badpnm(FDESC *, const char *, ...) __attribute__((__noreturn__)); static void badpnm(FDESC *d, const char *fmt, ...) { va_list ap; va_start(ap,fmt); fprintf(stderr,"%s: %s: bad pnm file: ",__progname,d->fn); vfprintf(stderr,fmt,ap); fprintf(stderr,"\n"); va_end(ap); exit(1); } static int pnmskipcomments(FDESC *d) { int c; while (1) { c = getc(d->f); if (isspace(c)) continue; if (c == '#') { do { c = getc(d->f); } while ((c != '\n') && (c != EOF)); continue; } return(c); } } #define digitval(c) (((int)(c))-'0') static unsigned int pnmgetnum(FDESC *d, const char *what) { int c; unsigned int v; v = 0; c = pnmskipcomments(d); if (c == EOF) badpnm(d,"EOF while reading %s",what); if (! isdigit(c)) badpnm(d,"non-digit when reading %s",what); v = digitval(c); while (1) { c = getc(d->f); if (! isdigit(c)) break; v = (v * 10) + digitval(c); } ungetc(c,d->f); return(v); } static char class_is_raw(char class) { switch (class) { case T_PBM: case T_PGM: case T_PPM: return(0); break; case T_RPBM: case T_RPGM: case T_RPPM: return(1); break; } abort(); } static void skip1white(FDESC *d) { int c; c = getc(d->f); if (! isspace(c)) ungetc(c,d->f); } static void init_input(FILE *f, const char *name, FDESC *d) { int c; d->fn = name; d->f = f; c = getc(f); if (c != 'P') badpnm(d,"bad magic number"); c = getc(f); switch (c) { case '1': d->class = T_PBM; break; case '2': d->class = T_PGM; break; case '3': d->class = T_PPM; break; case '4': d->class = T_RPBM; break; case '5': d->class = T_RPGM; break; case '6': d->class = T_RPPM; break; default: badpnm(d,"bad magic number"); break; } d->w = pnmgetnum(d,"width"); d->h = pnmgetnum(d,"height"); d->maxval = 0; d->rpbmbuf = 0; d->rpbmbit = 0; switch (d->class) { case T_PGM: case T_PPM: case T_RPGM: case T_RPPM: d->maxval = pnmgetnum(d,"maxval"); break; } if (class_is_raw(d->class)) skip1white(d); } static void setup(int ac, char **av) { int i; if ((ac < 6) || ((ac%5) != 1)) { fprintf(stderr,"Usage: %s x y w h file [x y w h file ...]\n",__progname); exit(1); } nofiles = ac / 5; ofiles = malloc(nofiles*sizeof(OFILE)); init_input(stdin,"standard input",&idesc); for (i=0;ix < 0) || (f->y < 0) || (f->x+f->w > idesc.w) || (f->y+f->h > idesc.h) ) { fprintf(stderr,"%s: %s falls outside input image - %dx%d at (%d,%d) falls outside %ux%u\n",__progname,f->desc.fn,f->w,f->h,f->x,f->y,idesc.w,idesc.h); exit(1); } } } static void init_output(FDESC *f) { if (f->f == 0) { f->f = fopen(f->fn,"w"); if (f->f == 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,f->fn,strerror(errno)); exit(1); } } switch (f->class) { case T_RPBM: fprintf(f->f,"P4\n%u %u\n",f->w,f->h); f->rpbmbuf = 0; f->rpbmbit = 0x80; break; case T_RPGM: if (f->maxval > 255) { f->class = T_PGM; fprintf(f->f,"P2\n%u %u\n%u\n",f->w,f->h,f->maxval); } else { fprintf(f->f,"P5\n%u %u\n%u\n",f->w,f->h,f->maxval); } break; case T_RPPM: if (f->maxval > 255) { f->class = T_PPM; fprintf(f->f,"P3\n%u %u\n%u\n",f->w,f->h,f->maxval); } else { fprintf(f->f,"P6\n%u %u\n%u\n",f->w,f->h,f->maxval); } break; default: abort(); break; } } static void init_outputs(void) { int i; for (i=0;ifn); exit(1); } static unsigned int getrawval(FDESC *d) { int c; c = getc(d->f); if (c == EOF) dataeof(d); return(c); } static PIXVAL pnmgetpixel(FDESC *d) { PIXVAL rv; switch (d->class) { default: abort(); break; case T_PBM: { int v; v = pnmgetbit(d); if (0) { case T_RPBM: if (d->rpbmbit < 2) { v = getc(d->f); if (v == EOF) dataeof(d); d->rpbmbuf = v; d->rpbmbit = 0x80; v &= 0x80; } else { v = d->rpbmbuf & (d->rpbmbit >>= 1); } } rv.r = !v; } break; case T_PGM: { unsigned int v; v = pnmgetnum(d,"pixel value"); if (0) { case T_RPGM: v = getrawval(d); } rv.r = v; } break; case T_PPM: rv.r = pnmgetnum(d,"pixel value"); rv.g = pnmgetnum(d,"pixel value"); rv.b = pnmgetnum(d,"pixel value"); if (0) { case T_RPPM: rv.r = getrawval(d); rv.g = getrawval(d); rv.b = getrawval(d); } break; } return(rv); } static void pnmputpixel(FDESC *d, PIXVAL v) { switch (d->class) { default: abort(); break; case T_RPBM: if (d->rpbmbit == 0) { putc(d->rpbmbuf,d->f); d->rpbmbuf = 0; d->rpbmbit = 0x80; } if (! v.r) d->rpbmbuf |= d->rpbmbit; d->rpbmbit >>= 1; break; case T_PGM: fprintf(d->f,"%u\n",v.r); break; case T_RPGM: putc(v.r,d->f); break; case T_PPM: fprintf(d->f,"%u %u %u\n",v.r,v.g,v.b); break; case T_RPPM: putc(v.r,d->f); putc(v.g,d->f); putc(v.b,d->f); break; } } static void pnmget_endrow(FDESC *d) { switch (d->class) { case T_RPBM: d->rpbmbit = 0; break; } } static void pnmput_endrow(FDESC *d) { switch (d->class) { case T_RPBM: putc(d->rpbmbuf,d->f); d->rpbmbuf = 0; d->rpbmbit = 0x80; break; } } static void crank(void) { unsigned int x; unsigned int y; int i; OFILE *f; PIXVAL cur; x = 0; y = 0; while (1) { cur = pnmgetpixel(&idesc); for (i=0;i= f->x) && (y >= f->y) && (x-f->x < f->w) && (y-f->y < f->h) ) { pnmputpixel(&f->desc,cur); } } x ++; if (x >= idesc.w) { pnmget_endrow(&idesc); for (i=0;i= f->y) && (y-f->y < f->h) ) { pnmput_endrow(&f->desc); } } x = 0; y ++; if (y >= idesc.h) break; } } } int main(int, char **); int main(int ac, char **av) { setup(ac,av); check_placement(); init_outputs(); crank(); exit(0); }