Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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		jflag = 0;
12
int		fflag = 0;
13
int		Fflag = 0;
14
int		nineflag = 0;
15
int		threeflag = 0;
16
int		colorspace = CYCbCr;	/* default for 8-bit displays: combine color rotation with dither */
17
int		output = 0;
18
ulong	outchan = CMAP8;
19
Image	*image;
20
int		defaultcolor = 1;
21
 
22
enum{
23
	Border	= 2,
24
	Edge		= 5
25
};
26
 
27
char	*show(int, char*, int);
28
 
29
void
30
eresized(int new)
31
{
32
	Rectangle r;
33
 
34
	if(new && getwindow(display, Refnone) < 0){
35
		fprint(2, "jpg: can't reattach to window\n");
36
		exits("resize");
37
	}
38
	if(image == nil)
39
		return;
40
	r = insetrect(screen->clipr, Edge+Border);
41
	r.max.x = r.min.x+Dx(image->r);
42
	r.max.y = r.min.y+Dy(image->r);
43
	border(screen, r, -Border, nil, ZP);
44
	drawop(screen, r, image, nil, image->r.min, S);
45
	flushimage(display, 1);
46
}
47
 
48
void
49
main(int argc, char *argv[])
50
{
51
	int fd, i, yflag;
52
	char *err;
53
	char buf[12+1];
54
 
55
	yflag = 0;
56
	ARGBEGIN{
57
	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */
58
		cflag++;
59
		dflag++;
60
		output++;
61
		if(defaultcolor)
62
			outchan = CMAP8;
63
		break;
64
	case 'd':		/* suppress display of image */
65
		dflag++;
66
		break;
67
	case 'e':		/* disable floyd-steinberg error diffusion */
68
		eflag++;
69
		break;
70
	case 'F':
71
		Fflag++;	/* make a movie */
72
		fflag++;	/* merge two fields per image */
73
		break;
74
	case 'f':
75
		fflag++;	/* merge two fields per image */
76
		break;
77
	case 'J':		/* decode jpeg only; no display or remap (for debugging, etc.) */
78
		jflag++;
79
		break;
80
	case 'k':		/* force black and white */
81
		defaultcolor = 0;
82
		outchan = GREY8;
83
		break;
84
	case 'r':
85
		colorspace = CRGB;
86
		break;
87
	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */
88
		threeflag++;
89
		/* fall through */
90
	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */
91
		cflag++;
92
		dflag++;
93
		output++;
94
		defaultcolor = 0;
95
		outchan = RGB24;
96
		break;
97
	case 'v':		/* force RGBV */
98
		defaultcolor = 0;
99
		outchan = CMAP8;
100
		break;
101
	case 'y':	/* leave it in CYCbCr; for debugging only */
102
		yflag = 1;
103
		colorspace = CYCbCr;
104
		break;
105
	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */
106
		nineflag++;
107
		dflag++;
108
		output++;
109
		if(defaultcolor)
110
			outchan = CMAP8;
111
		break;
112
	default:
113
		fprint(2, "usage: jpg -39cdefFkJrtv [file.jpg ...]\n");
114
		exits("usage");
115
	}ARGEND;
116
 
117
	if(yflag==0 && dflag==0 && colorspace==CYCbCr){	/* see if we should convert right to RGB */
118
		fd = open("/dev/screen", OREAD);
119
		if(fd > 0){
120
			buf[12] = '\0';
121
			if(read(fd, buf, 12)==12 && chantodepth(strtochan(buf))>8)
122
				colorspace = CRGB;
123
			close(fd);
124
		}
125
	}
126
 
127
	err = nil;
128
	if(argc == 0)
129
		err = show(0, "<stdin>", outchan);
130
	else{
131
		for(i=0; i<argc; i++){
132
			fd = open(argv[i], OREAD);
133
			if(fd < 0){
134
				fprint(2, "jpg: can't open %s: %r\n", argv[i]);
135
				err = "open";
136
			}else{
137
				err = show(fd, argv[i], outchan);
138
				close(fd);
139
			}
140
			if((nineflag || cflag) && argc>1 && err==nil){
141
				fprint(2, "jpg: exiting after one file\n");
142
				break;
143
			}
144
		}
145
	}
146
	exits(err);
147
}
148
 
149
Rawimage**
150
vidmerge(Rawimage **aa1, Rawimage **aa2)
151
{
152
	Rawimage **aao, *ao, *a1, *a2;
153
	int i, c, row, col;
154
 
155
	aao = nil;
156
	for (i = 0; aa1[i]; i++) {
157
 
158
		a1 = aa1[i];
159
		a2 = aa2[i];
160
		if (a2 == nil){
161
			fprint(2, "jpg: vidmerge: unequal lengths\n");
162
			return nil;
163
		}
164
		aao = realloc(aao, (i+2)*sizeof(Rawimage *));
165
		if (aao == nil){
166
			fprint(2, "jpg: vidmerge: realloc\n");
167
			return nil;
168
		}
169
		aao[i+1] = nil;
170
		ao = aao[i] = malloc(sizeof(Rawimage));
171
		if (ao == nil){
172
			fprint(2, "jpg: vidmerge: realloc\n");
173
			return nil;
174
		}
175
		memcpy(ao, a1, sizeof(Rawimage));
176
		if (!eqrect(a1->r , a2->r)){
177
			fprint(2, "jpg: vidmerge: rects different in img %d\n", i);
178
			return nil;
179
		}
180
		if (a1->cmaplen != a2->cmaplen){
181
			fprint(2, "jpg: vidmerge: cmaplen different in img %d\n", i);
182
			return nil;
183
		}
184
		if (a1->nchans != a2->nchans){
185
			fprint(2, "jpg: vidmerge: nchans different in img %d\n", i);
186
			return nil;
187
		}
188
		if (a1->fields != a2->fields){
189
			fprint(2, "jpg: vidmerge: fields different in img %d\n", i);
190
			return nil;
191
		}
192
		ao->r.max.y += Dy(ao->r);
193
		ao->chanlen += ao->chanlen;
194
		if (ao->chanlen != Dx(ao->r)*Dy(ao->r)){
195
			fprint(2, "jpg: vidmerge: chanlen wrong %d != %d*%d\n",
196
				ao->chanlen, Dx(ao->r), Dy(ao->r));
197
			return nil;
198
		}
199
		row = Dx(a1->r);
200
		for (c = 0; c < ao->nchans; c++) {
201
			uchar *po, *p1, *p2;
202
 
203
			ao->chans[c] = malloc(ao->chanlen);
204
			po = ao->chans[c];
205
			p1 = a1->chans[c];
206
			p2 = a2->chans[c];
207
			for (col = 0; col < Dy(a1->r); col++) {
208
				memcpy(po, p1, row);
209
				po += row, p1 += row;
210
				memcpy(po, p2, row);
211
				po += row, p2 += row;
212
			}
213
			free(a1->chans[c]);
214
			free(a2->chans[c]);
215
		}
216
		if(a2->cmap != nil)
217
			free(a2->cmap);
218
		free(a1);
219
		free(a2);
220
	}	
221
	if (aa2[i] != nil)
222
		fprint(2, "jpg: vidmerge: unequal lengths\n");
223
	free(aa1);
224
	free(aa2);
225
	return aao;
226
}
227
 
228
char*
229
show(int fd, char *name, int outc)
230
{
231
	Rawimage **array, *r, *c;
232
	static int inited;
233
	Image *i;
234
	int j, ch, outchan;
235
	Biobuf b;
236
	char buf[32];
237
 
238
	if(Binit(&b, fd, OREAD) < 0)
239
		return nil;
240
	outchan = outc;
241
rpt:	array = Breadjpg(&b, colorspace);
242
	if(array == nil || array[0]==nil){
243
		fprint(2, "jpg: decode %s failed: %r\n", name);
244
		return "decode";
245
	}
246
	if (fflag) {
247
		Rawimage **a;
248
 
249
		a = Breadjpg(&b, colorspace);
250
		if(a == nil || a[0]==nil){
251
			fprint(2, "jpg: decode %s-2 failed: %r\n", name);
252
			return "decode";
253
		}
254
		array = vidmerge(a, array);
255
	} else
256
		Bterm(&b);
257
 
258
	r = array[0];
259
	c = nil;
260
	if(jflag)
261
		goto Return;
262
	if(!dflag){
263
		if (!inited) {
264
			if(initdraw(0, 0, 0) < 0){
265
				fprint(2, "jpg: initdraw failed: %r\n");
266
				return "initdraw";
267
			}
268
			if(Fflag == 0)
269
				einit(Ekeyboard|Emouse);
270
			inited++;
271
		}
272
		if(defaultcolor && screen->depth>8 && outchan==CMAP8)
273
			outchan = RGB24;
274
	}
275
	if(outchan == CMAP8)
276
		c = torgbv(r, !eflag);
277
	else{
278
		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){
279
			c = totruecolor(r, CY);
280
			outchan = GREY8;
281
		}else
282
			c = totruecolor(r, CRGB24);
283
	}
284
	if(c == nil){
285
		fprint(2, "jpg: conversion of %s failed: %r\n", name);
286
		return "torgbv";
287
	}
288
	if(!dflag){
289
		if(c->chandesc == CY)
290
			i = allocimage(display, c->r, GREY8, 0, 0);
291
		else
292
			i = allocimage(display, c->r, outchan, 0, 0);
293
		if(i == nil){
294
			fprint(2, "jpg: allocimage %s failed: %r\n", name);
295
			return "allocimage";
296
		}
297
		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
298
			fprint(2, "jpg: loadimage %s failed: %r\n", name);
299
			return "loadimage";
300
		}
301
		image = i;
302
		eresized(0);
303
		if (Fflag) {
304
			freeimage(i);
305
			for(j=0; j<r->nchans; j++)
306
				free(r->chans[j]);
307
			free(r->cmap);
308
			free(r);
309
			free(array);
310
			goto rpt;
311
		}
312
		if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
313
			exits(nil);
314
		draw(screen, screen->clipr, display->white, nil, ZP);
315
		image = nil;
316
		freeimage(i);
317
	}
318
	if(nineflag){
319
		chantostr(buf, outchan);
320
		print("%11s %11d %11d %11d %11d ", buf,
321
			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
322
		if(write(1, c->chans[0], c->chanlen) != c->chanlen){
323
			fprint(2, "jpg: %s: write error %r\n", name);
324
			return "write";
325
		}
326
	}else if(cflag){
327
		if(writerawimage(1, c) < 0){
328
			fprint(2, "jpg: %s: write error: %r\n", name);
329
			return "write";
330
		}
331
	}
332
    Return:
333
	for(j=0; j<r->nchans; j++)
334
		free(r->chans[j]);
335
	free(r->cmap);
336
	free(r);
337
	free(array);
338
	if(c){
339
		free(c->chans[0]);
340
		free(c);
341
	}
342
	if (Fflag) goto rpt;
343
	return nil;
344
}