/* * pnminsdel - insert strips into, or remove strips from, a pnm file * * pnminsdel spec [spec ...] * * Reads a pnm file from stdin. Conceptually, applies the specs in * order, producing the result on stdout. A spec can be: * * delx nnn@mmm * delx nnn-mmm * delx nnn- * delx nnn * dely nnn@mmm * dely nnn-mmm * dely nnn- * dely nnn * Deletes a strip. The x or y specifies whether the * strip is horizontal or vertical (x specifies a vertical * strip - ie, the insertion or deletion moves things * along the x axis - and y a horizontal strip). If a * single number follows, only one pixel is deleted. To * delete a strip multiple pixels wide, specify either * nnn-mmm (which deletes pixels nnn through mmm * inclusive) or nnn@mmm (which deletes a strip nnn pixels * wide starting at mmm). The nnn- forms delete from * pixel nnn through the highest existing pixel. In the * nnn and nnn@mmm forms, nnn can be prefixed with a minus * sign, in which case it has the image's width or height * (according as delx or dely is used) added to it; if it * is still negative after this, an error occurs. In the * @mmm forms, mmm may also be prefixed with a minus sign * to have a similar addition applied. * * delx nnn@ooo%mmm * delx ooo%mmm * dely nnn@ooo%mmm * dely ooo%mmm * Deletes strips at each vvv for which vvv % mmm == ooo * and vvv is in range for the image. It is not an error * if there are no such possible vvv values. It also is * not an error for a strip to only partially exist (such * as deleting 5@10%100 in a 105-pixel dimension). * * insx nnn@mmm colour * insx nnn-mmm colour * insx nnn colour * insy nnn@mmm colour * insy nnn-mmm colour * insy nnn colour * Inserts a strip. The x or y specifies the orientation, * as for delx/dely. The next argument specifies where * the strip is to be placed. The spec is similar to the * way the corresponding syntaxes for the del forms work: * nnn inserts a single-pixel strip at coordinate nnn, * nnn-mmm inserts a strip mmm+1-nnn pixels wide starting * at nnn (ie, running from nnn through mmm), and nnn@mmm * inserts a strip nnn pixels wide starting at mmm. In * the nnn and nnn@mmm forms, nnn may have a minus sign * prepended to have the image's dimension added to it; in * the nnn@mmm forms, so may mmm. colour specifies the * colour of the inserted pixels. If the input is a pbm * file, colour must be 0 or 1, if pgm, either an integer * from 0 through the maxval for the file or a * floating-point number from 0 through 1.0, and if ppm, * an r-g-b triple, three values (interpreted as if they * were pgm specs) with slashes or commas separating them, * if pam, same as ppm but with a fourth component added. * A ppm file will also accept a pgm spec, in which case * the single value is used for all three primaries. * Specifying a pgm spec for a pbm file, a pnm spec for a * pbm or pgm file, or a pam spec for a non-pam file, will * promote the input image accordingly. * * insx nnn@ooo%mmm colour * insx ooo%mmm colour * insy nnn@ooo%mmm colour * insy ooo%mmm colour * Inserts strips at each vvv for which vvv % mmm == ooo * and vvv is in range for the image. It is not an error * if there are no such possible vvv values. * * noraw * This does not affect the pixels, but causes the output * file to be the non-raw form (eg, PGM instead of raw * PGM). * * It is an error to delete pixels that don't exist, or to insert * pixels at a coordinate that is higher than immediately after the * highest existing coordinate. * * Note that the specs are applied in order, and the coordinate system * for each spec is the coordinate system left after the previous * specs have been applied. Thus, for example, * delx 5@10 delx 5@20 * is equivalent to not * delx 5@20 delx 5@10 * but rather * delx 5@25 delx 5@10 * It is therefore usually advisable to apply specs in order of * decreasing coordinates. * * For deletions, or for insertions of the same colour, it makes no * difference whether an X operation is done before or after a Y * operation, but for insertions of different colours order matters. */ #include #include #include #include #include #include extern const char *__progname; typedef enum { OP_INS = 1, OP_DEL } OP; typedef enum { C_X = 1, C_Y } COORD; typedef enum { T_PBM = 1, T_PGM, T_PPM, T_PAM, T_RPBM, T_RPGM, T_RPPM, T_RPAM } PCLASS; typedef struct fdesc FDESC; typedef struct pixval PIXVAL; typedef struct opn OPN; struct fdesc { PCLASS class; const char *fn; FILE *f; unsigned int maxval; unsigned int maxval2; unsigned int w; unsigned int h; unsigned char pbmbuf; unsigned char pbmbit; } ; struct pixval { unsigned int r; unsigned int g; unsigned int b; unsigned int a; } ; struct opn { OPN *link; OP op; COORD coord; int width; int at; int mod; int newsize; const char *colour; PIXVAL pv; const char *locspec; unsigned int flags; #define OPNF_NEG_WIDTH 0x00000001 #define OPNF_NEG_AT 0x00000002 } ; static FDESC odesc; static FDESC idesc; static OPN *ops; static int noraw = 0; #define Cdigit(x) isdigit((unsigned char)(x)) #define Cspace(x) isspace((unsigned char)(x)) static void usage(const char *, ...) __attribute__((__format__(__printf__,1,2),__noreturn__)); static void usage(const char *fmt, ...) { va_list ap; if (fmt) { fprintf(stderr,"%s: ",__progname); va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fprintf(stderr,"\n"); } fprintf(stderr,"Usage: %s spec [spec ...]\n",__progname); if (fmt) { fprintf(stderr,"`%s -help' for more help\n",__progname); } else { fprintf(stderr,"a spec can be:\n"); fprintf(stderr," delx nnn@mmm\n"); fprintf(stderr," delx nnn-mmm\n"); fprintf(stderr," delx nnn\n"); fprintf(stderr," delx nnn@ooo%mmm\n"); fprintf(stderr," delx ooo%mmm\n"); fprintf(stderr," dely (same)\n"); fprintf(stderr," insx (same) colour\n"); fprintf(stderr," insy (same) colour\n"); fprintf(stderr," noraw\n"); fprintf(stderr,"colour can be:\n"); fprintf(stderr," 0 or 1 (for pbm files)\n"); fprintf(stderr," 0 through maxval (for pgm files)\n"); fprintf(stderr," 0.0 through 1.0 (for pgm files)\n"); fprintf(stderr," r/g/b (for ppm files - r, g, b are as for pgm)\n"); fprintf(stderr," r,g,b (like r/g/b)\n"); fprintf(stderr," for pam files, like pgm but with /a or ,a appended\n"); fprintf(stderr,"Pixel coordinates are after all previous specs have been applied.\n"); } exit(1); } static void badpnm(FDESC *, const char *, ...) __attribute__((__format__(__printf__,2,3),__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); } #define digitval(c) (((int)(c))-'0') 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); } } 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(PCLASS class) { switch (class) { case T_PBM: case T_PGM: case T_PPM: case T_PAM: return(0); break; case T_RPBM: case T_RPGM: case T_RPPM: case T_RPAM: 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 '7': d->class = T_PAM; break; case '4': d->class = T_RPBM; break; case '5': d->class = T_RPGM; break; case '6': d->class = T_RPPM; break; case '8': d->class = T_RPAM; break; default: badpnm(d,"bad magic number"); break; } d->w = pnmgetnum(d,"width"); d->h = pnmgetnum(d,"height"); d->maxval = 0; d->maxval2 = 0; d->pbmbuf = 0; d->pbmbit = 0; switch (d->class) { case T_PBM: case T_RPBM: d->maxval = 1; break; case T_PGM: case T_PPM: case T_PAM: case T_RPGM: case T_RPPM: case T_RPAM: d->maxval = pnmgetnum(d,"maxval"); break; default: break; } switch (d->class) { case T_PAM: case T_RPAM: d->maxval2 = pnmgetnum(d,"maxval2"); break; default: break; } if (class_is_raw(d->class)) skip1white(d); } static void parse_location(OPN *o, const char *s) { char *ep; unsigned long int uliv; int iv; int neg; void bad(void) { usage("invalid %s%s spec %s",(o->op==OP_INS)?"ins":"del",(o->coord==C_X)?"x":"y",s); } o->locspec = s; o->flags &= ~(OPNF_NEG_WIDTH | OPNF_NEG_AT); while (*s && Cspace(*s)) s ++; if (*s == '-') { neg = 1; s ++; } else { neg = 0; } uliv = strtoul(s,&ep,0); iv = uliv; if ((ep == s) || (iv < 0) || (iv != uliv)) bad(); switch (*ep) { case '\0': o->width = 1; o->at = iv; o->mod = 0; if (neg) o->flags |= OPNF_NEG_AT; return; case '-': if (neg) bad(); if ((ep[1] == '\0') && (o->op == OP_DEL)) { o->width = -iv; o->at = iv; o->mod = 0; break; } o->at = iv; s = ep + 1; uliv = strtol(s,&ep,0); iv = uliv; if ((ep == s) || (iv < 0) || (iv != uliv) || (iv < o->at)) bad(); o->width = iv + 1 - o->at; o->mod = 0; break; case '@': if (neg && (o->op != OP_DEL)) bad(); o->width = iv; if (neg) o->flags |= OPNF_NEG_WIDTH; s = ep + 1; if (*s == '-') { s ++; neg = 1; } else { neg = 0; } uliv = strtol(s,&ep,0); iv = uliv; if ((ep == s) || (iv < 0) || (iv != uliv)) bad(); o->at = iv; if (neg) o->flags |= OPNF_NEG_AT; if (! *ep) { o->mod = 0; } else if (*ep == '%') { s = ep + 1; uliv = strtol(s,&ep,0); iv = uliv; if ((ep == s) || (iv <= 0) || (iv != uliv)) bad(); o->mod = iv; if (o->flags & OPNF_NEG_AT) { o->at = o->mod - (o->at % o->mod); o->flags &= ~OPNF_NEG_AT; } o->at %= o->mod; } else { bad(); } break; default: bad(); break; } } static char class_rawform(PCLASS 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; case T_PAM: case T_RPAM: return(T_RPAM); break; } abort(); } static void setup(int ac, char **av) { __label__ restart_; OPN *o; OPN **ot; unsigned int w; unsigned int h; unsigned int *d; const char *dstr; const char *ep; unsigned int pixnum(const char *s, const char **endp) { char *ep; unsigned long int v; v = strtoul(s,&ep,10); if (*ep == '.') { const char *dp; for (dp=ep+1;Cdigit(*dp);dp++) ; switch (*dp) { case '\0': case ' ': case ',': case '/': { double d; d = strtod(s,&ep); *endp = ep; switch (class_rawform(odesc.class)) { case T_RPBM: odesc.class = T_RPGM; odesc.maxval = 255; goto restart_; break; case T_RPGM: case T_RPPM: case T_RPAM: if (odesc.maxval < 255) { odesc.maxval = 255; goto restart_; } break; } v = d * (odesc.maxval + 1); if (v > odesc.maxval) v = odesc.maxval; return(v); } break; } } *endp = ep; return(v); } unsigned int alphanum(const char *s, const char **endp) { char *ep; unsigned long int v; v = strtoul(s,&ep,10); if (*ep == '.') { const char *dp; for (dp=ep+1;Cdigit(*dp);dp++) ; switch (*dp) { case ' ': case ',': case '/': { double d; d = strtod(s,&ep); *endp = ep; if (odesc.maxval2 < 255) { odesc.maxval2 = 255; goto restart_; } v = d * (odesc.maxval + 1); if (v > odesc.maxval) v = odesc.maxval; return(v); } break; } } *endp = ep; return(v); } ac --; av ++; ot = &ops; if ((ac == 1) && !strcmp(av[0],"-help")) { usage(0); } while (ac > 0) { o = malloc(sizeof(OPN)); if (!strcmp(av[0],"delx")) { o->op = OP_DEL; o->coord = C_X; } else if (!strcmp(av[0],"dely")) { o->op = OP_DEL; o->coord = C_Y; } else if (!strcmp(av[0],"insx")) { o->op = OP_INS; o->coord = C_X; } else if (!strcmp(av[0],"insy")) { o->op = OP_INS; o->coord = C_Y; } else if (!strcmp(av[0],"noraw")) { free(o); noraw = 1; ac --; av ++; continue; } else { usage("bad key string"); } switch (o->op) { case OP_INS: switch (ac) { case 1: usage("missing arguments after %s",av[0]); break; case 2: usage("missing argument after %s",av[0]); break; } parse_location(o,av[1]); o->colour = av[2]; ac -= 3; av += 3; break; case OP_DEL: switch (ac) { case 1: usage("missing argument after %s",av[0]); break; } parse_location(o,av[1]); ac -= 2; av += 2; break; default: abort(); break; } *ot = o; ot = &o->link; } *ot = 0; init_input(stdin,"standard input",&idesc); w = idesc.w; h = idesc.h; odesc.class = class_rawform(idesc.class); odesc.fn = "standard output"; odesc.f = stdout; odesc.maxval = idesc.maxval; odesc.maxval2 = idesc.maxval2; restart_:; for (o=ops;o;o=o->link) { switch (o->coord) { case C_X: d = &w; dstr = "x"; break; case C_Y: d = &h; dstr = "y"; break; default: abort(); break; } switch (o->op) { case OP_INS: if (o->mod == 0) { if (o->flags & OPNF_NEG_AT) { o->at = *d - o->at; if (o->at < 0) usage("bad ins%s spec %s (offset still negative)",dstr,o->locspec); } if (o->at > *d) usage("ins%s at %d out of range 0-%d\n",dstr,o->at,*d); if (o->width+*d < *d) usage("ins%s overflow\n",dstr); *d += o->width; } else { *d += o->width * ((*d / o->mod) + ((*d % o->mod) >= o->at)); } o->newsize = *d; switch (idesc.class) { case T_PBM: case T_RPBM: if (!strcmp(o->colour,"0")) { o->pv.r = 0; o->pv.g = 0; o->pv.b = 0; } else if (!strcmp(o->colour,"1")) { o->pv.r = odesc.maxval; o->pv.g = odesc.maxval; o->pv.b = odesc.maxval; } else { usage("bad colour spec `%s' for PBM input file",o->colour); } o->pv.a = 0; break; case T_PGM: case T_RPGM: o->pv.r = pixnum(o->colour,&ep); if (*ep) usage("bad colour spec `%s' for PGM input file",o->colour); o->pv.g = o->pv.r; o->pv.b = o->pv.r; o->pv.a = 0; break; case T_PPM: case T_RPPM: o->pv.r = pixnum(o->colour,&ep); if (! *ep) { o->pv.g = o->pv.r; o->pv.b = o->pv.r; } else { switch <"green"> (*ep) { case ',': case '/': o->pv.g = pixnum(ep+1,&ep); switch (*ep) { case ',': case '/': o->pv.b = pixnum(ep+1,&ep); if (*ep) { default: default <"green">: usage("bad colour spec `%s' for PPM input file",o->colour); } break; } break; } } o->pv.a = 0; break; case T_PAM: case T_RPAM: o->pv.r = pixnum(o->colour,&ep); if (! *ep) { o->pv.g = o->pv.r; o->pv.b = o->pv.r; o->pv.a = 0; } else { switch <"green"> (*ep) { case ',': case '/': o->pv.g = pixnum(ep+1,&ep); switch <"blue"> (*ep) { case ',': case '/': o->pv.b = pixnum(ep+1,&ep); switch (*ep) { case ',': case '/': o->pv.a = alphanum(ep+1,&ep); if (*ep) { default: default <"blue">: default <"green">: usage("bad colour spec `%s' for PAM input file",o->colour); } break; } break; } break; } } break; } break; case OP_DEL: if (o->mod == 0) { if (o->flags & OPNF_NEG_WIDTH) { o->width = *d - o->width; if (o->width < 0) usage("invalid del%s spec %s (width still negative)",dstr,o->locspec); } if (o->flags & OPNF_NEG_AT) { o->at = *d - o->at; if (o->at < 0) usage("invalid del%s spec %s (offset still negative)",dstr,o->locspec); } if ((o->at > *d) || (o->at+o->width > *d)) usage("del%s %d at %d out of range 0-%d\n",dstr,o->width,o->at,*d); *d -= o->width; } else { int r; int n; if (o->width >= o->mod) usage("invalid del%s spec %s (width >= mod)",(o->coord==C_X)?"x":"y",o->locspec); r = *d % o->mod; n = (*d / o->mod) * (o->mod - o->width); if (o->at+o->width > o->mod) { if (r >= o->at) { n += o->mod - o->width; } else if (r >= o->at+o->width-o->mod) { n += r - (o->at + o->width - o->mod); } } else { if (r <= o->at) { n += r; } else if (r <= o->at+o->width) { n += o->at; } else { n += r - o->width; } } *d = n; } o->newsize = *d; break; default: abort(); break; } } odesc.w = w; odesc.h = h; } static void init_output(void) { switch (odesc.class) { case T_RPBM: if (noraw) { odesc.class = T_PBM; printf("P1\n%u %u\n",odesc.w,odesc.h); odesc.pbmbit = 0; } else { printf("P4\n%u %u\n",odesc.w,odesc.h); odesc.pbmbuf = 0; odesc.pbmbit = 0x80; } break; case T_RPGM: if (noraw || (odesc.maxval > 255)) { odesc.class = T_PGM; printf("P2\n%u %u\n%u\n",odesc.w,odesc.h,odesc.maxval); } else { printf("P5\n%u %u\n%u\n",odesc.w,odesc.h,odesc.maxval); } break; case T_RPPM: if (noraw || (odesc.maxval > 255)) { odesc.class = T_PPM; printf("P3\n%u %u\n%u\n",odesc.w,odesc.h,odesc.maxval); } else { printf("P6\n%u %u\n%u\n",odesc.w,odesc.h,odesc.maxval); } break; case T_RPAM: if (noraw || (odesc.maxval > 255) || (odesc.maxval2 > 255)) { odesc.class = T_PAM; printf("P7\n%u %u\n%u %u\n",odesc.w,odesc.h,odesc.maxval,odesc.maxval2); } else { printf("P8\n%u %u\n%u %u\n",odesc.w,odesc.h,odesc.maxval,odesc.maxval2); } break; default: abort(); break; } } static void pnmputpixel(FDESC *d, PIXVAL v) { switch (d->class) { default: abort(); break; case T_PBM: if (d->pbmbit >= 70) { putc('\n',d->f); d->pbmbit = 0; } putc(v.r?'0':'1',d->f); d->pbmbit ++; break; case T_RPBM: if (d->pbmbit == 0) { putc(d->pbmbuf,d->f); d->pbmbuf = 0; d->pbmbit = 0x80; } if (! v.r) d->pbmbuf |= d->pbmbit; d->pbmbit >>= 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; case T_PAM: fprintf(d->f,"%u %u %u %u\n",v.r,v.g,v.b,v.a); break; case T_RPAM: putc(v.r,d->f); putc(v.g,d->f); putc(v.b,d->f); putc(v.a,d->f); break; } } static void pnmput_endrow(FDESC *d) { switch (d->class) { case T_RPBM: putc(d->pbmbuf,d->f); d->pbmbuf = 0; d->pbmbit = 0x80; break; default: break; } } static int pnmgetbit(FDESC *d) { int c; unsigned int v; v = 0; c = pnmskipcomments(d); if (c == EOF) badpnm(d,"EOF while reading pixel value"); switch (c) { case '0': return(0); break; case '1': return(1); break; } badpnm(d,"invalid pixel character"); } static void dataeof(FDESC *) __attribute__((__noreturn__)); static void dataeof(FDESC *d) { fprintf(stderr,"%s: %s: EOF while reading pixels\n",__progname,d->fn); 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->pbmbit < 2) { v = getc(d->f); if (v == EOF) dataeof(d); d->pbmbuf = v; d->pbmbit = 0x80; v &= 0x80; } else { v = d->pbmbuf & (d->pbmbit >>= 1); } } rv.r = ! v; } break; case T_PGM: { unsigned int v; v = pnmgetnum(d,"pixel value"); if (0) { case T_RPGM: v = getrawval(d); } if (d->maxval != odesc.maxval) v = (v * (odesc.maxval+1)) / (d->maxval+1); 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); } if (d->maxval != odesc.maxval) { rv.r = (rv.r * (odesc.maxval+1)) / (d->maxval+1); rv.g = (rv.g * (odesc.maxval+1)) / (d->maxval+1); rv.b = (rv.b * (odesc.maxval+1)) / (d->maxval+1); } break; } return(rv); } static void pnmget_endrow(FDESC *d) { switch (d->class) { case T_RPBM: d->pbmbit = 0; break; default: break; } } static void crank(void) { unsigned int ix; unsigned int iy; PIXVAL cur; unsigned int ox; unsigned int oy; void pass_down(int x, int y, unsigned int w, unsigned int h, PIXVAL pv, OPN *o) { unsigned int i; unsigned int j; unsigned int k; unsigned int m; #ifdef CRANK_DETAIL printf("# pass_down %d,%d %u,%u %d/%d/%d/%d %p\n",x,y,w,h,pv.r,pv.g,pv.b,pv.a,(void *)o); #endif if (o == 0) { if ((x >= odesc.w) || (y >= odesc.h)) return; #ifdef CRANK_DETAIL printf("# gen pixel %d,%d\n",ox,oy); #endif pnmputpixel(&odesc,pv); ox ++; if (ox >= odesc.w) { pnmput_endrow(&odesc); #ifdef CRANK_DETAIL printf("# gen end of row\n"); #endif ox = 0; oy ++; } return; } switch (o->op) { case OP_INS: switch (o->coord) { case C_X: if (o->mod && (x >= 0)) { m = x % o->mod; k = (x / o->mod) * (o->mod + o->width); if (m == o->at) { for (i=0;iwidth;i++) { pass_down(k+m+i,y,o->newsize,h,o->pv,o->link); } } if (m < o->at) { pass_down(k+m,y,o->newsize,h,pv,o->link); } else { pass_down(k+m+o->width,y,o->newsize,h,pv,o->link); } } else { if (x == o->at) { for (i=0;iwidth;i++) { pass_down(x+i,y,o->newsize,h,o->pv,o->link); } } if (x < o->at) { pass_down(x,y,o->newsize,h,pv,o->link); } else { pass_down(x+o->width,y,o->newsize,h,pv,o->link); } } break; case C_Y: if (o->mod) { m = y % o->mod; k = (y / o->mod) * (o->mod + o->width); if ((x <= 0) && (m == o->at)) { for (i=0;iwidth;i++) { for (j=0;jnewsize,o->pv,o->link); pass_down(w,k+m+i,w,o->newsize,o->pv,o->link); } } if (m < o->at) { pass_down(x,k+m,w,o->newsize,pv,o->link); } else { pass_down(x,k+m+o->width,w,o->newsize,pv,o->link); } } else { if ((x <= 0) && (y == o->at)) { for (i=0;iwidth;i++) { for (j=0;jwidth,o->pv,o->link); pass_down(w,y+i,w,o->newsize,o->pv,o->link); } } if (y < o->at) { pass_down(x,y,w,o->newsize,pv,o->link); } else { pass_down(x,y+o->width,w,o->newsize,pv,o->link); } } break; default: abort(); break; } break; case OP_DEL: switch (o->coord) { case C_X: if (o->mod) { if (x >= w) { pass_down(o->newsize,y,o->newsize,h,pv,o->link); break; } m = x % o->mod; k = (x / o->mod) * (o->mod - o->width); if (o->at+o->width > o->mod) { if ((m >= o->at) || (m < o->at+o->width-o->mod)) break; k += m - (o->at + o->width - o->mod); } else { if ((m >= o->at) && (m < o->at+o->width)) break; k += (m >= o->at) ? (m - o->width) : m; } pass_down(k,y,o->newsize,h,pv,o->link); } else { if (x < o->at) { pass_down(x,y,w-o->width,h,pv,o->link); } else { x -= o->width; if (x >= o->at) pass_down(x,y,w-o->width,h,pv,o->link); } } break; case C_Y: if (o->mod) { if (y >= h) { pass_down(x,o->newsize,w,o->newsize,pv,o->link); break; } m = y % o->mod; k = (y / o->mod) * (o->mod - o->width); if (o->at+o->width > o->mod) { if ((m >= o->at) || (m < o->at+o->width-o->mod)) break; k += m - (o->at + o->width - o->mod); } else { if ((m >= o->at) && (m < o->at+o->width)) break; k += (m >= o->at) ? (m - o->width) : m; } pass_down(x,k,w,o->newsize,pv,o->link); } else { if (y < o->at) { pass_down(x,y,w,h-o->width,pv,o->link); } else { y -= o->width; if (y >= o->at) pass_down(x,y,w,h-o->width,pv,o->link); } } break; default: abort(); break; } break; default: abort(); break; } } ix = 0; iy = 0; ox = 0; oy = 0; #ifdef CRANK_DETAIL printf("# idesc size %d,%d odesc size %d,%d\n",idesc.w,idesc.h,odesc.w,odesc.h); #endif while (1) { cur = pnmgetpixel(&idesc); #ifdef CRANK_DETAIL printf("# input pixel %d,%d\n",ix,iy); #endif pass_down(ix,iy,idesc.w,idesc.h,cur,ops); ix ++; if (ix >= idesc.w) { pnmget_endrow(&idesc); #ifdef CRANK_DETAIL printf("# input end of row\n"); #endif pass_down(idesc.w,iy,idesc.w,idesc.h,cur,ops); ix = 0; iy ++; if (iy >= idesc.h) break; } } #ifdef CRANK_DETAIL printf("# input end of image\n"); #endif pass_down(-1,idesc.h,idesc.w,idesc.h,cur,ops); if (ox || (oy != odesc.h)) abort(); } int main(int, char **); int main(int ac, char **av) { setup(ac,av); init_output(); crank(); exit(0); }