png.c (4704B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <draw.h> 5 #include <event.h> 6 #include "imagefile.h" 7 8 extern int debug; 9 int cflag = 0; 10 int dflag = 0; 11 int eflag = 0; 12 int nineflag = 0; 13 int threeflag = 0; 14 int colorspace = CRGB; 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 void 28 eresized(int new) 29 { 30 Rectangle r; 31 32 if(new && getwindow(display, Refnone) < 0){ 33 fprint(2, "png: can't reattach to window\n"); 34 exits("resize"); 35 } 36 if(image == nil) 37 return; 38 r = rectaddpt(image->r, subpt(screen->r.min, image->r.min)); 39 if(!new && !winsize) 40 drawresizewindow(r); 41 draw(screen, r, image, nil, image->r.min); 42 flushimage(display, 1); 43 } 44 45 void 46 usage(void) 47 { 48 fprint(2, "usage: png -39cdekrtv -W winsize [file.png ...]\n"); 49 exits("usage"); 50 } 51 52 void 53 main(int argc, char *argv[]) 54 { 55 int fd, i; 56 char *err; 57 char buf[12+1]; 58 59 ARGBEGIN{ 60 case 'W': 61 winsize = EARGF(usage()); 62 break; 63 case 'c': /* produce encoded, compressed, bitmap file; no display by default */ 64 cflag++; 65 dflag++; 66 output++; 67 if(defaultcolor) 68 outchan = CMAP8; 69 break; 70 case 'D': 71 debug++; 72 break; 73 case 'd': /* suppress display of image */ 74 dflag++; 75 break; 76 case 'e': /* disable floyd-steinberg error diffusion */ 77 eflag++; 78 break; 79 case 'k': /* force black and white */ 80 defaultcolor = 0; 81 outchan = GREY8; 82 break; 83 case 'r': 84 colorspace = CRGB; 85 break; 86 case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */ 87 threeflag++; 88 /* fall through */ 89 case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */ 90 cflag++; 91 dflag++; 92 output++; 93 defaultcolor = 0; 94 outchan = RGB24; 95 break; 96 case 'v': /* force RGBV */ 97 defaultcolor = 0; 98 outchan = CMAP8; 99 break; 100 case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */ 101 nineflag++; 102 dflag++; 103 output++; 104 if(defaultcolor) 105 outchan = CMAP8; 106 break; 107 default: 108 usage(); 109 }ARGEND; 110 111 if(dflag==0 && colorspace==CYCbCr){ /* see if we should convert right to RGB */ 112 fd = open("/dev/screen", OREAD); 113 if(fd > 0){ 114 buf[12] = '\0'; 115 if(read(fd, buf, 12)==12 && chantodepth(strtochan(buf))>8) 116 colorspace = CRGB; 117 close(fd); 118 } 119 } 120 121 err = nil; 122 if(argc == 0) 123 err = show(0, "<stdin>", outchan); 124 else{ 125 for(i=0; i<argc; i++){ 126 fd = open(argv[i], OREAD); 127 if(fd < 0){ 128 fprint(2, "png: can't open %s: %r\n", argv[i]); 129 err = "open"; 130 }else{ 131 err = show(fd, argv[i], outchan); 132 close(fd); 133 } 134 if((nineflag || cflag) && argc>1 && err==nil){ 135 fprint(2, "png: exiting after one file\n"); 136 break; 137 } 138 } 139 } 140 exits(err); 141 } 142 143 char* 144 show(int fd, char *name, int outc) 145 { 146 Rawimage **array, *r, *c; 147 static int inited; 148 Image *i; 149 int j, ch, outchan; 150 Biobuf b; 151 char buf[32]; 152 153 if(Binit(&b, fd, OREAD) < 0) 154 return nil; 155 outchan = outc; 156 array = Breadpng(&b, colorspace); 157 if(array == nil || array[0]==nil){ 158 fprint(2, "png: decode %s failed: %r\n", name); 159 return "decode"; 160 } 161 Bterm(&b); 162 163 r = array[0]; 164 if(!dflag && !inited){ 165 if(initdraw(0, 0, 0) < 0){ 166 fprint(2, "png: initdraw failed: %r\n"); 167 return "initdraw"; 168 } 169 einit(Ekeyboard|Emouse); 170 if(defaultcolor && screen->depth>8 && outchan==CMAP8) 171 outchan = RGB24; 172 inited++; 173 } 174 if(outchan == CMAP8) 175 c = torgbv(r, !eflag); 176 else{ 177 if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){ 178 c = totruecolor(r, CY); 179 outchan = GREY8; 180 }else 181 c = totruecolor(r, CRGB24); 182 } 183 if(c == nil){ 184 fprint(2, "png: conversion of %s failed: %r\n", name); 185 return "torgbv"; 186 } 187 if(!dflag){ 188 if(c->chandesc == CY) 189 i = allocimage(display, c->r, GREY8, 0, 0); 190 else 191 i = allocimage(display, c->r, outchan, 0, 0); 192 if(i == nil){ 193 fprint(2, "png: allocimage %s failed: %r\n", name); 194 return "allocimage"; 195 } 196 if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ 197 fprint(2, "png: loadimage %s failed: %r\n", name); 198 return "loadimage"; 199 } 200 image = i; 201 eresized(0); 202 if((ch=ekbd())=='q' || ch==0x7F || ch==0x04) 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 print("%11s %11d %11d %11d %11d ", buf, 211 c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); 212 if(write(1, c->chans[0], c->chanlen) != c->chanlen){ 213 fprint(2, "png: %s: write error %r\n", name); 214 return "write"; 215 } 216 }else if(cflag){ 217 if(writerawimage(1, c) < 0){ 218 fprint(2, "png: %s: write error: %r\n", name); 219 return "write"; 220 } 221 } 222 for(j=0; j<r->nchans; j++) 223 free(r->chans[j]); 224 free(r->cmap); 225 free(r); 226 free(array); 227 if(c){ 228 free(c->chans[0]); 229 free(c); 230 } 231 return nil; 232 }