]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/png.c
disk/format: implement long name support
[plan9front.git] / sys / src / cmd / jpg / png.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <draw.h>
5 #include <event.h>
6 #include <keyboard.h>
7 #include "imagefile.h"
8
9 extern int      debug;
10 int     cflag = 0;
11 int     dflag = 0;
12 int     eflag = 0;
13 int     nineflag = 0;
14 int     threeflag = 0;
15 int     output = 0;
16 ulong   outchan = CMAP8;
17 Image   *image;
18 int     defaultcolor = 1;
19
20 enum{
21         Border  = 2,
22         Edge    = 5
23 };
24
25 char    *show(int, char*, int);
26
27 Rectangle
28 imager(Image *i)
29 {
30         Point p1, p2;
31
32         p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
33         p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
34         return rectaddpt(i->r, subpt(p2, p1));
35 }
36
37 void
38 eresized(int new)
39 {
40         Rectangle r;
41
42         if(new && getwindow(display, Refnone) < 0){
43                 fprint(2, "png: can't reattach to window\n");
44                 exits("resize");
45         }
46         if(image == nil)
47                 return;
48         r = imager(image);
49         border(screen, r, -Border, nil, ZP);
50         draw(screen, r, image, nil, image->r.min);
51         flushimage(display, 1);
52 }
53
54 void
55 main(int argc, char *argv[])
56 {
57         int fd, i;
58         char *err;
59
60         ARGBEGIN{
61         case 'c':               /* produce encoded, compressed, bitmap file; no display by default */
62                 cflag++;
63                 dflag++;
64                 output++;
65                 if(defaultcolor)
66                         outchan = CMAP8;
67                 break;
68         case 'D':
69                 debug++;
70                 break;
71         case 'd':               /* suppress display of image */
72                 dflag++;
73                 break;
74         case 'e':               /* disable floyd-steinberg error diffusion */
75                 eflag++;
76                 break;
77         case 'k':               /* force black and white */
78                 defaultcolor = 0;
79                 outchan = GREY8;
80                 break;
81         case '3':               /* produce encoded, compressed, three-color bitmap file; no display by default */
82                 threeflag++;
83                 /* fall through */
84         case 't':               /* produce encoded, compressed, true-color bitmap file; no display by default */
85                 cflag++;
86                 dflag++;
87                 output++;
88                 defaultcolor = 0;
89                 outchan = RGB24;
90                 break;
91         case 'v':               /* force RGBV */
92                 defaultcolor = 0;
93                 outchan = CMAP8;
94                 break;
95         case '9':               /* produce plan 9, uncompressed, bitmap file; no display by default */
96                 nineflag++;
97                 dflag++;
98                 output++;
99                 if(defaultcolor)
100                         outchan = CMAP8;
101                 break;
102         default:
103                 fprint(2, "usage: png [-39cdekrtv] [file.png ...]\n");
104                 exits("usage");
105         }ARGEND;
106
107         err = nil;
108         if(argc == 0)
109                 err = show(0, "<stdin>", outchan);
110         else{
111                 for(i=0; i<argc; i++){
112                         fd = open(argv[i], OREAD);
113                         if(fd < 0){
114                                 fprint(2, "png: can't open %s: %r\n", argv[i]);
115                                 err = "open";
116                         }else{
117                                 err = show(fd, argv[i], outchan);
118                                 close(fd);
119                         }
120                         if((nineflag || cflag) && argc>1 && err==nil){
121                                 fprint(2, "png: exiting after one file\n");
122                                 break;
123                         }
124                 }
125         }
126         exits(err);
127 }
128
129 char*
130 show(int fd, char *name, int outc)
131 {
132         Rawimage **array, *r, *c;
133         Image *i, *i2;
134         int j, ch, outchan;
135         long len;
136         Biobuf b;
137         char buf[32];
138         static int inited;
139
140         if(Binit(&b, fd, OREAD) < 0)
141                 return nil;
142         outchan = outc;
143         array = Breadpng(&b, CRGB);
144         if(array == nil || array[0]==nil){
145                 fprint(2, "png: decode %s failed: %r\n", name);
146                 return "decode";
147         }
148         Bterm(&b);
149
150         r = array[0];
151         if(!dflag){
152                 if (!inited) {
153                         if(initdraw(0, 0, 0) < 0){
154                                 fprint(2, "png: initdraw failed: %r\n");
155                                 return "initdraw";
156                         }
157                         einit(Ekeyboard|Emouse);
158                         inited++;
159                 }
160                 if(defaultcolor && screen->depth>8 && outchan==CMAP8)
161                         outchan = RGB24;
162         }
163         if(outchan == CMAP8)
164                 c = torgbv(r, !eflag);
165         else{
166                 switch(r->chandesc){
167                 case CY:
168                         outchan = GREY8;
169                         break;
170                 case CYA16:
171                         outchan = CHAN2(CGrey, 8, CAlpha, 8);
172                         break;
173                 case CRGB24:
174                         outchan = RGB24;
175                         break;
176                 case CRGBA32:
177                         outchan = RGBA32;
178                         break;
179                 }
180                 c = r;
181         }
182         if(c == nil){
183                 fprint(2, "png: conversion of %s failed: %r\n", name);
184                 return "torgbv";
185         }
186         if(!dflag){
187                 i = allocimage(display, c->r, outchan, 0, 0);
188                 if(i == nil){
189                         fprint(2, "png: allocimage %s failed: %r\n", name);
190                         return "allocimage";
191                 }
192                 if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
193                         fprint(2, "png: loadimage %s of %d bytes failed: %r\n",
194                                 name, c->chanlen);
195                         return "loadimage";
196                 }
197                 i2 = allocimage(display, c->r, outchan, 0, 0);
198                 draw(i2, i2->r, display->black, nil, ZP);
199                 draw(i2, i2->r, i, nil, i->r.min);
200                 image = i2;
201                 eresized(0);
202                 if((ch=ekbd())=='q' || ch==Kdel || ch==Keof)
203                         exits(nil);
204                 draw(screen, screen->clipr, display->white, nil, ZP);
205                 image = nil;
206                 freeimage(i);
207         }
208         if(nineflag){
209                 chantostr(buf, outchan);
210                 len = (c->r.max.x - c->r.min.x) * (c->r.max.y - c->r.min.y);
211                 switch(c->chandesc){
212                 case CY:
213                         // len *= 1;
214                         break;
215                 case CYA16:
216                         len *= 2;
217                         break;
218                 case CRGB24:
219                         len *= 3;
220                         break;
221                 case CRGBA32:
222                         len *= 4;
223                         break;
224                 }
225                 if(c->chanlen != len)
226                         fprint(2, "%s: writing %d bytes for len %ld chan %s\n",
227                                 argv0, c->chanlen, len, buf);
228                 print("%11s %11d %11d %11d %11d ", buf,
229                         c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
230                 if(write(1, c->chans[0], c->chanlen) != c->chanlen){
231                         fprint(2, "png: %s: write error %r\n", name);
232                         return "write";
233                 }
234         }else if(cflag){
235                 if(writerawimage(1, c) < 0){
236                         fprint(2, "png: %s: write error: %r\n", name);
237                         return "write";
238                 }
239         }
240         for(j=0; j<r->nchans; j++)
241                 free(r->chans[j]);
242         free(r->cmap);
243         free(r);
244         free(array);
245         if(c && c != r){
246                 free(c->chans[0]);
247                 free(c);
248         }
249         return nil;
250 }