]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rotate.c
rotate: fix crash when image origin is not (0,0)
[plan9front.git] / sys / src / cmd / rotate.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5
6 Memimage*
7 rot90(Memimage *m)
8 {
9         int line, bpp, x, y, dx, dy;
10         ulong chan;
11         uchar *s, *d;
12         Memimage *w;
13         char buf[12];
14
15         bpp = m->depth/8;
16         chan = m->chan;
17         switch(chan){
18         default:
19                 sysfatal("can't handle channel type %s", chantostr(buf, chan));
20         case RGB15:
21                 bpp = 2;
22         case CMAP8:
23         case GREY8:
24         case RGB16:
25         case RGB24:
26         case RGBA32:
27         case ARGB32:
28         case XRGB32:
29                 break;
30         case GREY1:
31         case GREY2:
32         case GREY4:
33                 bpp = 1;
34                 if((w = allocmemimage(m->r, GREY8)) == nil)
35                         sysfatal("allocmemimage: %r");
36                 memimagedraw(w, w->r, m, m->r.min, nil, ZP, S);
37                 freememimage(m);
38                 m = w;
39                 break;
40         }
41
42         dx = Dx(m->r);
43         dy = Dy(m->r);
44         if((w = allocmemimage(Rect(m->r.min.x, m->r.min.y, 
45                 m->r.min.x+dy, m->r.min.y+dx), m->chan)) == nil)
46                 sysfatal("allocmemimage: %r");
47         line = w->width*sizeof(ulong);
48         for(y=0; y<dy; y++){
49                 s = byteaddr(m, addpt(m->r.min, Pt(0, y)));
50                 d = byteaddr(w, addpt(w->r.min, Pt(dy-y-1, 0)));
51                 for(x=0; x<dx; x++){
52                         switch(bpp){
53                         case 4:
54                                 d[3] = s[3];
55                         case 3:
56                                 d[2] = s[2];
57                         case 2:
58                                 d[1] = s[1];
59                         case 1:
60                                 d[0] = s[0];
61                         }
62                         s += bpp;
63                         d += line;
64                 }
65         }
66         freememimage(m);
67         if(w->chan != chan){
68                 if((m = allocmemimage(w->r, chan)) == nil)
69                         sysfatal("allocmemimage: %r");
70                 memimagedraw(m, m->r, w, w->r.min, nil, ZP, S);
71                 freememimage(w);
72                 w = m;
73         }
74         return w;
75 }
76
77 Memimage*
78 upsidedown(Memimage *m)
79 {
80         uchar *s, *d, *t;
81         int w, y, dy;
82
83         dy = Dy(m->r);
84         w = m->width * sizeof(ulong);
85         if((t = malloc(w)) == nil)
86                 sysfatal("malloc: %r");
87         for(y=0; y<dy/2; y++){
88                 s = byteaddr(m, addpt(m->r.min, Pt(0, y)));
89                 d = byteaddr(m, addpt(m->r.min, Pt(0, dy-y-1)));
90                 memmove(t, d, w);
91                 memmove(d, s, w);
92                 memmove(s, t, w);
93         }
94         free(t);
95         return m;
96 }
97
98 void
99 usage(void)
100 {
101         fprint(2, "usage: %s [ -r degree ] [ -u | -l ] [ file ]\n", argv0);
102         exits("usage");
103 }
104
105 void
106 main(int argc, char *argv[])
107 {
108         Memimage *m;
109         int fd, r;
110         char f;
111
112         f = 0;
113         r = 0;
114         fd = 0;
115         ARGBEGIN {
116         case 'u':
117                 f = 'u';
118                 break;
119         case 'l':
120                 f = 'l';
121                 break;
122         case 'r':
123                 r = atoi(EARGF(usage()));
124                 break;
125         default:
126                 usage();
127         } ARGEND;
128         if(*argv){
129                 fd = open(*argv, OREAD);
130                 if(fd < 0)
131                         sysfatal("open: %r");
132         }
133         memimageinit();
134         if((m = readmemimage(fd)) == nil)
135                 sysfatal("readmemimage: %r");
136         if(f == 'u' || f == 'l'){
137                 m = upsidedown(m);
138                 if(f == 'l')
139                         r = 180;
140         }
141         switch(r % 360){
142         case 270:
143                 m = rot90(m);
144         case 180:
145                 m = rot90(m);
146         case 90:
147                 m = rot90(m);
148                 break;
149         }
150         if(writememimage(1, m) < 0)
151                 sysfatal("writememimage: %r");
152         exits(0);
153 }
154