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