xref: /plan9/sys/src/cmd/crop.c (revision 0cc39a83e201996cab5ee319ea497ce6109e8d23)
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