add crop
This commit is contained in:
parent
1d2533d010
commit
228bb71d16
1 changed files with 211 additions and 0 deletions
211
src/cmd/draw/crop.c
Normal file
211
src/cmd/draw/crop.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue