plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

crop.c (4138B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <draw.h>
      4 #include <memdraw.h>
      5 
      6 enum
      7 {
      8 	None,
      9 	Inset,	/* move border in or out uniformly */
     10 	Insetxy,	/* move border in or out; different parameters for x and y */
     11 	Set,		/* set rectangle to absolute values */
     12 	Blank	/* cut off blank region according to color value */
     13 			/* Blank is not actually set as a mode; it can be combined with others */
     14 };
     15 
     16 void
     17 usage(void)
     18 {
     19 	fprint(2, "usage: crop [-c rgb] [-i ±inset | -r R | -x ±inset | -y ±inset] [-t tx ty] [-b rgb ] [imagefile]\n");
     20 	fprint(2, "\twhere R is a rectangle minx miny maxx maxy\n");
     21 	fprint(2, "\twhere rgb is a color red green blue\n");
     22 	exits("usage");
     23 }
     24 
     25 int
     26 getint(char *s)
     27 {
     28 	if(s == nil)
     29 		usage();
     30 	if(*s == '+')
     31 		return atoi(s+1);
     32 	if(*s == '-')
     33 		return -atoi(s+1);
     34 	return atoi(s);
     35 }
     36 
     37 Rectangle
     38 crop(Memimage *m, uint32 c)
     39 {
     40 	Memimage *n;
     41 	int x, y, bpl, wpl;
     42 	int left, right, top, bottom;
     43 	uint32 *buf;
     44 
     45 	left = m->r.max.x;
     46 	right = m->r.min.x;
     47 	top = m->r.max.y;
     48 	bottom = m->r.min.y;
     49 	n = nil;
     50 	if(m->chan != RGBA32){
     51 		/* convert type for simplicity */
     52 		n = allocmemimage(m->r, RGBA32);
     53 		if(n == nil)
     54 			sysfatal("can't allocate temporary image: %r");
     55 		memimagedraw(n, n->r, m, m->r.min, nil, ZP, S);
     56 		m = n;
     57 	}
     58 	wpl = wordsperline(m->r, m->depth);
     59 	bpl = wpl*sizeof(uint32);
     60 	buf = malloc(bpl);
     61 	if(buf == nil)
     62 		sysfatal("can't allocate buffer: %r");
     63 
     64 	for(y=m->r.min.y; y<m->r.max.y; y++){
     65 		x = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), (uchar*)buf, bpl);
     66 		if(x != bpl)
     67 			sysfatal("unloadmemimage");
     68 		for(x=0; x<wpl; x++)
     69 			if(buf[x] != c){
     70 				if(x < left)
     71 					left = x;
     72 				if(x > right)
     73 					right = x;
     74 				if(y < top)
     75 					top = y;
     76 				bottom = y;
     77 			}
     78 	}
     79 
     80 	if(n != nil)
     81 		freememimage(n);
     82 	return Rect(left, top, right+1, bottom+1);
     83 }
     84 
     85 void
     86 main(int argc, char *argv[])
     87 {
     88 	int fd, mode, red, green, blue;
     89 	Rectangle r, rparam;
     90 	Point t;
     91 	Memimage *m, *new;
     92 	char *file;
     93 	uint32 bg, cropval;
     94 	long dw;
     95 
     96 	memimageinit();
     97 	mode = None;
     98 	bg = 0;
     99 	cropval = 0;
    100 	t = ZP;
    101 	memset(&rparam, 0, sizeof rparam);
    102 
    103 	ARGBEGIN{
    104 	case 'b':
    105 		if(bg != 0)
    106 			usage();
    107 		red = getint(ARGF())&0xFF;
    108 		green = getint(ARGF())&0xFF;
    109 		blue = getint(ARGF())&0xFF;
    110 		bg = (red<<24)|(green<<16)|(blue<<8)|0xFF;
    111 		break;
    112 	case 'c':
    113 		if(cropval != 0)
    114 			usage();
    115 		red = getint(ARGF())&0xFF;
    116 		green = getint(ARGF())&0xFF;
    117 		blue = getint(ARGF())&0xFF;
    118 		cropval = (red<<24)|(green<<16)|(blue<<8)|0xFF;
    119 		break;
    120 	case 'i':
    121 		if(mode != None)
    122 			usage();
    123 		mode = Inset;
    124 		rparam.min.x = getint(ARGF());
    125 		break;
    126 	case 'x':
    127 		if(mode != None && mode != Insetxy)
    128 			usage();
    129 		mode = Insetxy;
    130 		rparam.min.x = getint(ARGF());
    131 		break;
    132 	case 'y':
    133 		if(mode != None && mode != Insetxy)
    134 			usage();
    135 		mode = Insetxy;
    136 		rparam.min.y = getint(ARGF());
    137 		break;
    138 	case 'r':
    139 		if(mode != None)
    140 			usage();
    141 		mode = Set;
    142 		rparam.min.x = getint(ARGF());
    143 		rparam.min.y = getint(ARGF());
    144 		rparam.max.x = getint(ARGF());
    145 		rparam.max.y = getint(ARGF());
    146 		break;
    147 	case 't':
    148 		t.x = getint(ARGF());
    149 		t.y = getint(ARGF());
    150 		break;
    151 	default:
    152 		usage();
    153 	}ARGEND
    154 
    155 	if(mode == None && cropval == 0 && eqpt(ZP, t))
    156 		usage();
    157 
    158 	file = "<stdin>";
    159 	fd = 0;
    160 	if(argc > 1)
    161 		usage();
    162 	else if(argc == 1){
    163 		file = argv[0];
    164 		fd = open(file, OREAD);
    165 		if(fd < 0)
    166 			sysfatal("can't open %s: %r", file);
    167 	}
    168 
    169 	m = readmemimage(fd);
    170 	if(m == nil)
    171 		sysfatal("can't read %s: %r", file);
    172 
    173 	r = m->r;
    174 	if(cropval != 0){
    175 		r = crop(m, cropval);
    176 		m->clipr = r;
    177 	}
    178 
    179 	switch(mode){
    180 	case None:
    181 		break;
    182 	case Inset:
    183 		r = insetrect(r, rparam.min.x);
    184 		break;
    185 	case Insetxy:
    186 		r.min.x += rparam.min.x;
    187 		r.max.x -= rparam.min.x;
    188 		r.min.y += rparam.min.y;
    189 		r.max.y -= rparam.min.y;
    190 		break;
    191 	case Set:
    192 		r = rparam;
    193 		break;
    194 	}
    195 
    196 	new = allocmemimage(r, m->chan);
    197 	if(new == nil)
    198 		sysfatal("can't allocate new image: %r");
    199 	if(bg != 0)
    200 		memfillcolor(new, bg);
    201 	else
    202 		memfillcolor(new, 0x000000FF);
    203 
    204 	memimagedraw(new, m->clipr, m, m->clipr.min, nil, ZP, S);
    205 	dw = byteaddr(new, ZP) - byteaddr(new, t);
    206 	new->r = rectaddpt(new->r, t);
    207 	new->zero += dw;
    208 	if(writememimage(1, new) < 0)
    209 		sysfatal("write error on output: %r");
    210 	exits(nil);
    211 }