]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/crop.c
c1234e26d631e396a01f505abd835063cec7a757
[plan9front.git] / sys / src / cmd / crop.c
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 [-b rgb] [-c rgb] [-i ±inset | -r R | -x ±inset | -y ±inset] [-t tx ty] [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         return strtol(s, 0, 0);
31 }
32
33 Rectangle
34 crop(Memimage *m, ulong c)
35 {
36         Memimage *n;
37         int x, y, bpl, wpl;
38         int left, right, top, bottom;
39         ulong *buf;
40
41         left = m->r.max.x;
42         right = m->r.min.x;
43         top = m->r.max.y;
44         bottom = m->r.min.y;
45         n = nil;
46         if(m->chan != RGBA32){
47                 /* convert type for simplicity */
48                 n = allocmemimage(m->r, RGBA32);
49                 if(n == nil)
50                         sysfatal("can't allocate temporary image: %r");
51                 memimagedraw(n, n->r, m, m->r.min, nil, ZP, S);
52                 m = n;
53         }
54         wpl = wordsperline(m->r, m->depth);
55         bpl = wpl*sizeof(ulong);
56         buf = malloc(bpl);
57         if(buf == nil)
58                 sysfatal("can't allocate buffer: %r");
59
60         for(y=m->r.min.y; y<m->r.max.y; y++){
61                 x = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), (uchar*)buf, bpl);
62                 if(x != bpl)
63                         sysfatal("unloadmemimage");
64                 for(x=0; x<wpl; x++)
65                         if(buf[x] != c){
66                                 if(x < left)
67                                         left = x;
68                                 if(x > right)
69                                         right = x;
70                                 if(y < top)
71                                         top = y;
72                                 bottom = y;
73                         }
74         }
75         
76         if(n != nil)
77                 freememimage(n);
78         return Rect(left, top, right+1, bottom+1);
79 }
80
81 void
82 main(int argc, char *argv[])
83 {
84         int fd, mode, red, green, blue;
85         Rectangle r, rparam;
86         Point t;
87         Memimage *m, *new;
88         char *file;
89         ulong bg, cropval;
90         long dw;
91
92         memimageinit();
93         mode = None;
94         bg = 0;
95         cropval = 0;
96         t = ZP;
97         memset(&rparam, 0, sizeof rparam);
98
99         ARGBEGIN{
100         case 'b':
101                 if(bg != 0)
102                         usage();
103                 red = getint(ARGF())&0xFF;
104                 green = getint(ARGF())&0xFF;
105                 blue = getint(ARGF())&0xFF;
106                 bg = (red<<24)|(green<<16)|(blue<<8)|0xFF;
107                 break;
108         case 'c':
109                 if(cropval != 0)
110                         usage();
111                 red = getint(ARGF())&0xFF;
112                 green = getint(ARGF())&0xFF;
113                 blue = getint(ARGF())&0xFF;
114                 cropval = (red<<24)|(green<<16)|(blue<<8)|0xFF;
115                 break;
116         case 'i':
117                 if(mode != None)
118                         usage();
119                 mode = Inset;
120                 rparam.min.x = getint(ARGF());
121                 break;
122         case 'x':
123                 if(mode != None && mode != Insetxy)
124                         usage();
125                 mode = Insetxy;
126                 rparam.min.x = getint(ARGF());
127                 break;
128         case 'y':
129                 if(mode != None && mode != Insetxy)
130                         usage();
131                 mode = Insetxy;
132                 rparam.min.y = getint(ARGF());
133                 break;
134         case 'r':
135                 if(mode != None)
136                         usage();
137                 mode = Set;
138                 rparam.min.x = getint(ARGF());
139                 rparam.min.y = getint(ARGF());
140                 rparam.max.x = getint(ARGF());
141                 rparam.max.y = getint(ARGF());
142                 break;
143         case 't':
144                 t.x = getint(ARGF());
145                 t.y = getint(ARGF());
146                 break;
147         default:
148                 usage();
149         }ARGEND
150
151         if(mode == None && cropval == 0 && eqpt(ZP, t))
152                 usage();
153
154         file = "<stdin>";
155         fd = 0;
156         if(argc > 1)
157                 usage();
158         else if(argc == 1){
159                 file = argv[0];
160                 fd = open(file, OREAD);
161                 if(fd < 0)
162                         sysfatal("can't open %s: %r", file);
163         }
164
165         m = readmemimage(fd);
166         if(m == nil)
167                 sysfatal("can't read %s: %r", file);
168
169         r = m->r;
170         if(cropval != 0){
171                 r = crop(m, cropval);
172                 m->clipr = r;
173         }
174
175         switch(mode){
176         case None:
177                 break;
178         case Inset:
179                 r = insetrect(r, rparam.min.x);
180                 break;
181         case Insetxy:
182                 r.min.x += rparam.min.x;
183                 r.max.x -= rparam.min.x;
184                 r.min.y += rparam.min.y;
185                 r.max.y -= rparam.min.y;
186                 break;
187         case Set:
188                 r = rparam;
189                 break;
190         }
191
192         new = allocmemimage(r, m->chan);
193         if(new == nil)
194                 sysfatal("can't allocate new image: %r");
195         if(bg != 0)
196                 memfillcolor(new, bg);
197         else
198                 memfillcolor(new, 0x000000FF);
199
200         memimagedraw(new, m->clipr, m, m->clipr.min, nil, ZP, S);
201         dw = byteaddr(new, ZP) - byteaddr(new, t);
202         new->r = rectaddpt(new->r, t);
203         new->zero += dw;
204         if(writememimage(1, new) < 0)
205                 sysfatal("write error on output: %r");
206         exits(nil);
207 }