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