plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }