17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <memdraw.h>
57dd7cddfSDavid du Colombier
67dd7cddfSDavid du Colombier enum
77dd7cddfSDavid du Colombier {
87dd7cddfSDavid du Colombier None,
97dd7cddfSDavid du Colombier Inset, /* move border in or out uniformly */
107dd7cddfSDavid du Colombier Insetxy, /* move border in or out; different parameters for x and y */
117dd7cddfSDavid du Colombier Set, /* set rectangle to absolute values */
127dd7cddfSDavid du Colombier Blank, /* cut off blank region according to color value */
137dd7cddfSDavid du Colombier /* Blank is not actually set as a mode; it can be combined with others */
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier void
usage(void)177dd7cddfSDavid du Colombier usage(void)
187dd7cddfSDavid du Colombier {
19*0cc39a83SDavid du Colombier fprint(2, "usage: crop [-b rgb] [-c rgb] [-i ±inset | -r R | -x ±inset | -y ±inset] [-t tx ty] [imagefile]\n");
20*0cc39a83SDavid du Colombier fprint(2, "\twhere R is a rectangle: minx miny maxx maxy\n");
21*0cc39a83SDavid du Colombier fprint(2, "\twhere rgb is a color: red green blue\n");
227dd7cddfSDavid du Colombier exits("usage");
237dd7cddfSDavid du Colombier }
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier int
getint(char * s)267dd7cddfSDavid du Colombier getint(char *s)
277dd7cddfSDavid du Colombier {
287dd7cddfSDavid du Colombier if(s == nil)
297dd7cddfSDavid du Colombier usage();
307dd7cddfSDavid du Colombier if(*s == '+')
317dd7cddfSDavid du Colombier return atoi(s+1);
327dd7cddfSDavid du Colombier if(*s == '-')
337dd7cddfSDavid du Colombier return -atoi(s+1);
347dd7cddfSDavid du Colombier return atoi(s);
357dd7cddfSDavid du Colombier }
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier Rectangle
crop(Memimage * m,ulong c)387dd7cddfSDavid du Colombier crop(Memimage *m, ulong c)
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier Memimage *n;
417dd7cddfSDavid du Colombier int x, y, bpl, wpl;
427dd7cddfSDavid du Colombier int left, right, top, bottom;
437dd7cddfSDavid du Colombier ulong *buf;
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier left = m->r.max.x;
467dd7cddfSDavid du Colombier right = m->r.min.x;
477dd7cddfSDavid du Colombier top = m->r.max.y;
487dd7cddfSDavid du Colombier bottom = m->r.min.y;
497dd7cddfSDavid du Colombier n = nil;
507dd7cddfSDavid du Colombier if(m->chan != RGBA32){
517dd7cddfSDavid du Colombier /* convert type for simplicity */
527dd7cddfSDavid du Colombier n = allocmemimage(m->r, RGBA32);
537dd7cddfSDavid du Colombier if(n == nil)
547dd7cddfSDavid du Colombier sysfatal("can't allocate temporary image: %r");
556a9fc400SDavid du Colombier memimagedraw(n, n->r, m, m->r.min, nil, ZP, S);
567dd7cddfSDavid du Colombier m = n;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier wpl = wordsperline(m->r, m->depth);
597dd7cddfSDavid du Colombier bpl = wpl*sizeof(ulong);
607dd7cddfSDavid du Colombier buf = malloc(bpl);
617dd7cddfSDavid du Colombier if(buf == nil)
627dd7cddfSDavid du Colombier sysfatal("can't allocate buffer: %r");
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier for(y=m->r.min.y; y<m->r.max.y; y++){
657dd7cddfSDavid du Colombier x = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), (uchar*)buf, bpl);
667dd7cddfSDavid du Colombier if(x != bpl)
677dd7cddfSDavid du Colombier sysfatal("unloadmemimage");
687dd7cddfSDavid du Colombier for(x=0; x<wpl; x++)
697dd7cddfSDavid du Colombier if(buf[x] != c){
707dd7cddfSDavid du Colombier if(x < left)
717dd7cddfSDavid du Colombier left = x;
727dd7cddfSDavid du Colombier if(x > right)
737dd7cddfSDavid du Colombier right = x;
747dd7cddfSDavid du Colombier if(y < top)
757dd7cddfSDavid du Colombier top = y;
767dd7cddfSDavid du Colombier bottom = y;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier if(n != nil)
817dd7cddfSDavid du Colombier freememimage(n);
827dd7cddfSDavid du Colombier return Rect(left, top, right+1, bottom+1);
837dd7cddfSDavid du Colombier }
847dd7cddfSDavid du Colombier
857dd7cddfSDavid du Colombier void
main(int argc,char * argv[])867dd7cddfSDavid du Colombier main(int argc, char *argv[])
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier int fd, mode, red, green, blue;
897dd7cddfSDavid du Colombier Rectangle r, rparam;
9080ee5cbfSDavid du Colombier Point t;
917dd7cddfSDavid du Colombier Memimage *m, *new;
927dd7cddfSDavid du Colombier char *file;
937dd7cddfSDavid du Colombier ulong bg, cropval;
9480ee5cbfSDavid du Colombier long dw;
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier memimageinit();
977dd7cddfSDavid du Colombier mode = None;
987dd7cddfSDavid du Colombier bg = 0;
997dd7cddfSDavid du Colombier cropval = 0;
10080ee5cbfSDavid du Colombier t = ZP;
1017dd7cddfSDavid du Colombier memset(&rparam, 0, sizeof rparam);
1027dd7cddfSDavid du Colombier
1037dd7cddfSDavid du Colombier ARGBEGIN{
1047dd7cddfSDavid du Colombier case 'b':
1057dd7cddfSDavid du Colombier if(bg != 0)
1067dd7cddfSDavid du Colombier usage();
1077dd7cddfSDavid du Colombier red = getint(ARGF())&0xFF;
1087dd7cddfSDavid du Colombier green = getint(ARGF())&0xFF;
1097dd7cddfSDavid du Colombier blue = getint(ARGF())&0xFF;
1107dd7cddfSDavid du Colombier bg = (red<<24)|(green<<16)|(blue<<8)|0xFF;
1117dd7cddfSDavid du Colombier break;
1127dd7cddfSDavid du Colombier case 'c':
1137dd7cddfSDavid du Colombier if(cropval != 0)
1147dd7cddfSDavid du Colombier usage();
1157dd7cddfSDavid du Colombier red = getint(ARGF())&0xFF;
1167dd7cddfSDavid du Colombier green = getint(ARGF())&0xFF;
1177dd7cddfSDavid du Colombier blue = getint(ARGF())&0xFF;
1187dd7cddfSDavid du Colombier cropval = (red<<24)|(green<<16)|(blue<<8)|0xFF;
1197dd7cddfSDavid du Colombier break;
1207dd7cddfSDavid du Colombier case 'i':
1217dd7cddfSDavid du Colombier if(mode != None)
1227dd7cddfSDavid du Colombier usage();
1237dd7cddfSDavid du Colombier mode = Inset;
1247dd7cddfSDavid du Colombier rparam.min.x = getint(ARGF());
1257dd7cddfSDavid du Colombier break;
1267dd7cddfSDavid du Colombier case 'x':
1277dd7cddfSDavid du Colombier if(mode != None && mode != Insetxy)
1287dd7cddfSDavid du Colombier usage();
1297dd7cddfSDavid du Colombier mode = Insetxy;
1307dd7cddfSDavid du Colombier rparam.min.x = getint(ARGF());
1317dd7cddfSDavid du Colombier break;
1327dd7cddfSDavid du Colombier case 'y':
1337dd7cddfSDavid du Colombier if(mode != None && mode != Insetxy)
1347dd7cddfSDavid du Colombier usage();
1357dd7cddfSDavid du Colombier mode = Insetxy;
1367dd7cddfSDavid du Colombier rparam.min.y = getint(ARGF());
1377dd7cddfSDavid du Colombier break;
1387dd7cddfSDavid du Colombier case 'r':
1397dd7cddfSDavid du Colombier if(mode != None)
1407dd7cddfSDavid du Colombier usage();
1417dd7cddfSDavid du Colombier mode = Set;
1427dd7cddfSDavid du Colombier rparam.min.x = getint(ARGF());
1437dd7cddfSDavid du Colombier rparam.min.y = getint(ARGF());
1447dd7cddfSDavid du Colombier rparam.max.x = getint(ARGF());
1457dd7cddfSDavid du Colombier rparam.max.y = getint(ARGF());
1467dd7cddfSDavid du Colombier break;
14780ee5cbfSDavid du Colombier case 't':
14880ee5cbfSDavid du Colombier t.x = getint(ARGF());
14980ee5cbfSDavid du Colombier t.y = getint(ARGF());
15080ee5cbfSDavid du Colombier break;
1517dd7cddfSDavid du Colombier default:
1527dd7cddfSDavid du Colombier usage();
1537dd7cddfSDavid du Colombier }ARGEND
1547dd7cddfSDavid du Colombier
15580ee5cbfSDavid du Colombier if(mode == None && cropval == 0 && eqpt(ZP, t))
1567dd7cddfSDavid du Colombier usage();
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier file = "<stdin>";
1597dd7cddfSDavid du Colombier fd = 0;
1607dd7cddfSDavid du Colombier if(argc > 1)
1617dd7cddfSDavid du Colombier usage();
1627dd7cddfSDavid du Colombier else if(argc == 1){
1637dd7cddfSDavid du Colombier file = argv[0];
1647dd7cddfSDavid du Colombier fd = open(file, OREAD);
1657dd7cddfSDavid du Colombier if(fd < 0)
1667dd7cddfSDavid du Colombier sysfatal("can't open %s: %r", file);
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier m = readmemimage(fd);
1707dd7cddfSDavid du Colombier if(m == nil)
1717dd7cddfSDavid du Colombier sysfatal("can't read %s: %r", file);
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier r = m->r;
1747dd7cddfSDavid du Colombier if(cropval != 0){
1757dd7cddfSDavid du Colombier r = crop(m, cropval);
1767dd7cddfSDavid du Colombier m->clipr = r;
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier switch(mode){
1807dd7cddfSDavid du Colombier case None:
1817dd7cddfSDavid du Colombier break;
1827dd7cddfSDavid du Colombier case Inset:
1837dd7cddfSDavid du Colombier r = insetrect(r, rparam.min.x);
1847dd7cddfSDavid du Colombier break;
1857dd7cddfSDavid du Colombier case Insetxy:
1867dd7cddfSDavid du Colombier r.min.x += rparam.min.x;
1877dd7cddfSDavid du Colombier r.max.x -= rparam.min.x;
1887dd7cddfSDavid du Colombier r.min.y += rparam.min.y;
1897dd7cddfSDavid du Colombier r.max.y -= rparam.min.y;
1907dd7cddfSDavid du Colombier break;
1917dd7cddfSDavid du Colombier case Set:
1927dd7cddfSDavid du Colombier r = rparam;
1937dd7cddfSDavid du Colombier break;
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier new = allocmemimage(r, m->chan);
1977dd7cddfSDavid du Colombier if(new == nil)
1987dd7cddfSDavid du Colombier sysfatal("can't allocate new image: %r");
1997dd7cddfSDavid du Colombier if(bg != 0)
2007dd7cddfSDavid du Colombier memfillcolor(new, bg);
2017dd7cddfSDavid du Colombier else
2027dd7cddfSDavid du Colombier memfillcolor(new, 0x000000FF);
20380ee5cbfSDavid du Colombier
2046a9fc400SDavid du Colombier memimagedraw(new, m->clipr, m, m->clipr.min, nil, ZP, S);
20580ee5cbfSDavid du Colombier dw = byteaddr(new, ZP) - byteaddr(new, t);
20680ee5cbfSDavid du Colombier new->r = rectaddpt(new->r, t);
20780ee5cbfSDavid du Colombier new->zero += dw;
2087dd7cddfSDavid du Colombier if(writememimage(1, new) < 0)
2097dd7cddfSDavid du Colombier sysfatal("write error on output: %r");
2107dd7cddfSDavid du Colombier exits(nil);
2117dd7cddfSDavid du Colombier }
212