add crop
diff --git a/src/cmd/draw/crop.c b/src/cmd/draw/crop.c
new file mode 100644
index 0000000..e397a31
--- /dev/null
+++ b/src/cmd/draw/crop.c
@@ -0,0 +1,211 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+enum
+{
+	None,
+	Inset,	/* move border in or out uniformly */
+	Insetxy,	/* move border in or out; different parameters for x and y */
+	Set,		/* set rectangle to absolute values */
+	Blank,	/* cut off blank region according to color value */
+			/* Blank is not actually set as a mode; it can be combined with others */
+};
+
+void
+usage(void)
+{
+	fprint(2, "usage: crop [-c rgb] [-i ±inset | -r R | -x ±inset | -y ±inset] [-t tx ty] [-b rgb ] [imagefile]\n");
+	fprint(2, "\twhere R is a rectangle minx miny maxx maxy\n");
+	fprint(2, "\twhere rgb is a color red green blue\n");
+	exits("usage");
+}
+
+int
+getint(char *s)
+{
+	if(s == nil)
+		usage();
+	if(*s == '+')
+		return atoi(s+1);
+	if(*s == '-')
+		return -atoi(s+1);
+	return atoi(s);
+}
+
+Rectangle
+crop(Memimage *m, ulong c)
+{
+	Memimage *n;
+	int x, y, bpl, wpl;
+	int left, right, top, bottom;
+	ulong *buf;
+
+	left = m->r.max.x;
+	right = m->r.min.x;
+	top = m->r.max.y;
+	bottom = m->r.min.y;
+	n = nil;
+	if(m->chan != RGBA32){
+		/* convert type for simplicity */
+		n = allocmemimage(m->r, RGBA32);
+		if(n == nil)
+			sysfatal("can't allocate temporary image: %r");
+		memimagedraw(n, n->r, m, m->r.min, nil, ZP, S);
+		m = n;
+	}
+	wpl = wordsperline(m->r, m->depth);
+	bpl = wpl*sizeof(ulong);
+	buf = malloc(bpl);
+	if(buf == nil)
+		sysfatal("can't allocate buffer: %r");
+
+	for(y=m->r.min.y; y<m->r.max.y; y++){
+		x = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), (uchar*)buf, bpl);
+		if(x != bpl)
+			sysfatal("unloadmemimage");
+		for(x=0; x<wpl; x++)
+			if(buf[x] != c){
+				if(x < left)
+					left = x;
+				if(x > right)
+					right = x;
+				if(y < top)
+					top = y;
+				bottom = y;
+			}
+	}
+	
+	if(n != nil)
+		freememimage(n);
+	return Rect(left, top, right+1, bottom+1);
+}
+
+void
+main(int argc, char *argv[])
+{
+	int fd, mode, red, green, blue;
+	Rectangle r, rparam;
+	Point t;
+	Memimage *m, *new;
+	char *file;
+	ulong bg, cropval;
+	long dw;
+
+	memimageinit();
+	mode = None;
+	bg = 0;
+	cropval = 0;
+	t = ZP;
+	memset(&rparam, 0, sizeof rparam);
+
+	ARGBEGIN{
+	case 'b':
+		if(bg != 0)
+			usage();
+		red = getint(ARGF())&0xFF;
+		green = getint(ARGF())&0xFF;
+		blue = getint(ARGF())&0xFF;
+		bg = (red<<24)|(green<<16)|(blue<<8)|0xFF;
+		break;
+	case 'c':
+		if(cropval != 0)
+			usage();
+		red = getint(ARGF())&0xFF;
+		green = getint(ARGF())&0xFF;
+		blue = getint(ARGF())&0xFF;
+		cropval = (red<<24)|(green<<16)|(blue<<8)|0xFF;
+		break;
+	case 'i':
+		if(mode != None)
+			usage();
+		mode = Inset;
+		rparam.min.x = getint(ARGF());
+		break;
+	case 'x':
+		if(mode != None && mode != Insetxy)
+			usage();
+		mode = Insetxy;
+		rparam.min.x = getint(ARGF());
+		break;
+	case 'y':
+		if(mode != None && mode != Insetxy)
+			usage();
+		mode = Insetxy;
+		rparam.min.y = getint(ARGF());
+		break;
+	case 'r':
+		if(mode != None)
+			usage();
+		mode = Set;
+		rparam.min.x = getint(ARGF());
+		rparam.min.y = getint(ARGF());
+		rparam.max.x = getint(ARGF());
+		rparam.max.y = getint(ARGF());
+		break;
+	case 't':
+		t.x = getint(ARGF());
+		t.y = getint(ARGF());
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(mode == None && cropval == 0 && eqpt(ZP, t))
+		usage();
+
+	file = "<stdin>";
+	fd = 0;
+	if(argc > 1)
+		usage();
+	else if(argc == 1){
+		file = argv[0];
+		fd = open(file, OREAD);
+		if(fd < 0)
+			sysfatal("can't open %s: %r", file);
+	}
+
+	m = readmemimage(fd);
+	if(m == nil)
+		sysfatal("can't read %s: %r", file);
+
+	r = m->r;
+	if(cropval != 0){
+		r = crop(m, cropval);
+		m->clipr = r;
+	}
+
+	switch(mode){
+	case None:
+		break;
+	case Inset:
+		r = insetrect(r, rparam.min.x);
+		break;
+	case Insetxy:
+		r.min.x += rparam.min.x;
+		r.max.x -= rparam.min.x;
+		r.min.y += rparam.min.y;
+		r.max.y -= rparam.min.y;
+		break;
+	case Set:
+		r = rparam;
+		break;
+	}
+
+	new = allocmemimage(r, m->chan);
+	if(new == nil)
+		sysfatal("can't allocate new image: %r");
+	if(bg != 0)
+		memfillcolor(new, bg);
+	else
+		memfillcolor(new, 0x000000FF);
+
+	memimagedraw(new, m->clipr, m, m->clipr.min, nil, ZP, S);
+	dw = byteaddr(new, ZP) - byteaddr(new, t);
+	new->r = rectaddpt(new->r, t);
+	new->zero += dw;
+	if(writememimage(1, new) < 0)
+		sysfatal("write error on output: %r");
+	exits(nil);
+}