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