]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/crop.c
9bootfat: rename open() to fileinit and make it static as its really a internal funct...
[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         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, ulong c)
39 {
40         Memimage *n;
41         int x, y, bpl, wpl;
42         int left, right, top, bottom;
43         ulong *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(ulong);
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         ulong 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 }