/* * Copy files between picture files, converting formats, clipping, etc. */ #include #include #include #include struct picture{ char *name; /* name of picture file */ PICFILE *pf; /* picture file pointer */ Rectangle picr; /* rectangle in file or on screen */ Rectangle r; /* rectangle actually copied */ char *chan; /* argument of CHAN= */ int nchan; /* strlen(chan) */ char *buf; /* scanline buffer */ }in, out; char *inoutp; /* pointer to beginning of output line in input buffer */ int readp(int), writep(int); void conversion(char *, char *, char *); #define NCVTROU 10 struct cvtrou{ void (*rou)(int, int, int); int i, o; }cvtrou[NCVTROU]; struct cvtrou *ecvtrou=cvtrou; void cvt(void); int needcmap=0; /* does the output file need the incoming colormap? */ main(int argc, char *argv[]){ char *type="runcode"; char *cmap=0; Rectangle win; int t, y; char *ldepth; switch(getflags(argc, argv, "w:4[x0 y0 x1 y1]o:2[x y]t:1[pictype]c:1[rgbaz...]C:1[rgbaz...]l:1[ldepth]")){ default: usage("[infile [outfile]]"); case 3: in.name=argv[1]; out.name=argv[2]; break; case 2: in.name=argv[1]; out.name="OUT"; break; case 1: in.name="IN"; out.name="OUT"; break; } in.pf=picopen_r(in.name); if(in.pf==0){ picerror(in.name); exits("open input"); } if(flag['l']) ldepth=flag['l'][0]; else ldepth=picgetprop(in.pf, "LDEPTH"); in.r.min.x=PIC_XOFFS(in.pf); in.r.min.y=PIC_YOFFS(in.pf); in.r.max=add(in.r.min, Pt(PIC_WIDTH(in.pf), PIC_HEIGHT(in.pf))); in.picr=in.r; in.chan=in.pf->chan; in.nchan=PIC_NCHAN(in.pf); if(in.chan[0]=='?') switch(in.nchan){ case 1: in.chan="m"; break; case 2: in.chan="ma"; break; case 3: in.chan="rgb"; break; case 4: in.chan="rgba"; break; case 5: in.chan="mz..."; break; case 6: in.chan="maz..."; break; case 7: in.chan="rgbz..."; break; case 8: in.chan="rgbaz..."; break; } type=in.pf->type; cmap=in.pf->cmap; if(flag['t']) type=flag['t'][0]; if(flag['w']){ win.min.x=atoi(flag['w'][0]); win.min.y=atoi(flag['w'][1]); win.max.x=atoi(flag['w'][2]); win.max.y=atoi(flag['w'][3]); if(win.max.xin.r.min.x) in.r.min.x=win.min.x; if(win.min.y>in.r.min.y) in.r.min.y=win.min.y; if(win.max.xrou)(out.r.max.x-out.r.min.x, p->i, p->o); } /* * No transformation: zap output buffer pointer, avoid copying */ void ident(int npix, int i, int o){ out.buf=inoutp; } void cpchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ *q = *p; p+=in.nchan; q+=out.nchan; } } void cp3chan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ q[0]=p[0]; q[1]=p[1]; q[2]=p[2]; p+=in.nchan; q+=out.nchan; } } void cp4chan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=in.buf+npix*in.nchan; while(p!=ep){ q[0]=p[0]; q[1]=p[1]; q[2]=p[2]; q[3]=p[3]; p+=in.nchan; q+=out.nchan; } } void lumchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ q[0]=((p[0]&255)*299+(p[1]&255)*587+(p[2]&255)*114)/1000; p+=in.nchan; q+=out.nchan; } } char cmap[256][3]; void mapchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan, *r; while(p!=ep){ r=cmap[p[0]&255]; q[0]=r[0]; q[1]=r[1]; q[2]=r[2]; p+=in.nchan; q+=out.nchan; } } void maprchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ q[0]=cmap[p[0]&255][0]; p+=in.nchan; q+=out.nchan; } } void mapgchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ q[0]=cmap[p[0]&255][1]; p+=in.nchan; q+=out.nchan; } } void mapbchan(int npix, int i, int o){ register char *p=inoutp+i, *q=out.buf+o, *ep=p+npix*in.nchan; while(p!=ep){ q[0]=cmap[p[0]&255][2]; p+=in.nchan; q+=out.nchan; } } void rgb0chan(int npix, int i, int o){ register char *q=out.buf+o, *eq=q+npix*out.nchan; while(q!=eq){ q[0]=q[1]=q[2]=0; q+=out.nchan; } } void zerochan(int npix, int i, int o){ register char *q=out.buf+o, *eq=q+npix*out.nchan; while(q!=eq){ *q=0; q+=out.nchan; } } void a255chan(int npix, int i, int o){ register char *q=out.buf+o, *eq=q+npix*out.nchan; while(q!=eq){ *q=255; q+=out.nchan; } } void z1chan(int npix, int i, int o){ register char *q=out.buf+o, *eq=q+npix*out.nchan; while(q!=eq){ *(float *)q = 1.; /* could suffer alignment death */ q+=out.nchan; } } /* * The input picture has channels in, and colormap *cmapp. * The user has asked for channels out. Figure out what to do. */ struct conv{ char *new; /* desired channels */ char *old; /* available channels */ void (*rou)(int, int, int); /* conversion routine */ int savecmap; /* should we copy the colormap? */ }conv[]={ "rgba", "rgba", cp4chan, 1, "rgb", "rgb", cp3chan, 1, "rgb", "m", mapchan, 0, "rgb", "r", mapchan, 0, /* some old 1-channel pictures have CHAN=r */ "rgb", "", rgb0chan,0, "r", "rgb", cpchan, 0, "r", "m", maprchan,0, "r", "", zerochan,0, "g", "g", cpchan, 0, "g", "m", mapgchan,0, "g", "", zerochan,0, "b", "b", cpchan, 0, "b", "m", mapbchan,0, "b", "", zerochan,0, "a", "a", cpchan, 0, "a", "", a255chan,0, "m", "m", cpchan, 1, "m", "rgb", lumchan, 0, "m", "r", cpchan, 0, /* some old 1-channel pictures have CHAN=r */ "m", "", zerochan,0, "z...", "z...", cp4chan, 0, "z...", "", z1chan, 0, "0", "0", cpchan, 0, "0", "", zerochan,0, 0 }; void conversion(char *old, char *new, char *cmapp){ register struct conv *cp; register i, o; if(cmapp){ for(i=0;i!=256;i++){ cmap[i][0]=cmapp[3*i]; cmap[i][1]=cmapp[3*i+1]; cmap[i][2]=cmapp[3*i+2]; } } else{ for(i=0;i!=256;i++) cmap[i][0]=cmap[i][1]=cmap[i][2]=i; } if(strcmp(old, new)==0){ ecvtrou++->rou=ident; return; } for(o=0;new[o];){ for(cp=conv;cp->new;cp++) if(strncmp(new+o, cp->new, strlen(cp->new))==0){ for(i=0;old[i];i++) if(strncmp(old+i, cp->old, strlen(cp->old))==0){ ecvtrou->i=i; ecvtrou->o=o; ecvtrou++->rou=cp->rou; if(cp->savecmap) needcmap=1; goto Found; } } fprint(2, "pcp: Can't convert %s to %s\n", old, new); exits("unknown conversion"); Found: o+=strlen(cp->new); } }