Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * TGA is a fairly dead standard, however in the video industry
3
 * it is still used a little for test patterns and the like.
4
 *
5
 * Thus we ignore any alpha channels, and colour mapped images.
6
 */
7
 
8
#include <u.h>
9
#include <libc.h>
10
#include <bio.h>
11
#include <draw.h>
12
#include <ctype.h>
13
#include "imagefile.h"
14
 
15
enum {
16
	HdrLen = 18,
17
};
18
 
19
typedef struct {
20
	int idlen;		/* length of string after header */
21
	int cmaptype;		/* 1 =>  datatype = 1 => colourmapped */
22
	int datatype;		/* see below */
23
	int cmaporigin;		/* index of first entry in colour map */
24
	int cmaplen;		/* length of olour map */
25
	int cmapbpp;		/* bips per pixel of colour map: 16, 24, or 32 */
26
	int xorigin;		/* source image origin */
27
	int yorigin;
28
	int width;
29
	int height;
30
	int bpp;		/* bits per pixel of image: 16, 24, or 32 */
31
	int descriptor;
32
	uchar *cmap;		/* colour map (optional) */
33
} Tga;
34
 
35
/*
36
 * descriptor:
37
 * d0-3 = number of attribute bits per pixel
38
 * d4 	= reserved, always zero
39
 * d6-7	= origin: 0=lower left, 1=upper left, 2=lower right, 3=upper right
40
 * d8-9 = interleave: 0=progressive, 1=2 way, 3 = 4 way, 4 = reserved.
41
 */
42
 
43
char *datatype[] = {
44
	[0]	"No image data",
45
	[1]	"color mapped",
46
	[2]	"RGB",
47
	[3]	"B&W",
48
	[9]	"RLE color-mapped",
49
	[10]	"RLE RGB",
50
	[11]	"Compressed B&W",
51
	[32]	"Compressed color",
52
	[33]	"Quadtree compressed color",
53
};
54
 
55
static int
56
Bgeti(Biobuf *bp)
57
{
58
	int x, y;
59
 
60
	if((x = Bgetc(bp)) < 0)
61
		return -1;
62
	if((y = Bgetc(bp)) < 0)
63
		return -1;
64
	return (y<<8)|x;
65
}
66
 
67
static Tga *
68
rdhdr(Biobuf *bp)
69
{
70
	int n;
71
	Tga *h;
72
 
73
	if((h = malloc(sizeof(Tga))) == nil)
74
		return nil;
75
	if((h->idlen = Bgetc(bp)) == -1)
76
		return nil;
77
	if((h->cmaptype = Bgetc(bp)) == -1)
78
		return nil;
79
	if((h->datatype = Bgetc(bp)) == -1)
80
		return nil;
81
	if((h->cmaporigin = Bgeti(bp)) == -1)
82
		return nil;
83
	if((h->cmaplen = Bgeti(bp)) == -1)
84
		return nil;
85
	if((h->cmapbpp = Bgetc(bp)) == -1)
86
		return nil;
87
	if((h->xorigin = Bgeti(bp)) == -1)
88
		return nil;
89
	if((h->yorigin = Bgeti(bp)) == -1)
90
		return nil;
91
	if((h->width = Bgeti(bp)) == -1)
92
		return nil;
93
	if((h->height = Bgeti(bp)) == -1)
94
		return nil;
95
	if((h->bpp = Bgetc(bp)) == -1)
96
		return nil;
97
	if((h->descriptor = Bgetc(bp)) == -1)
98
		return nil;
99
 
100
	/* skip over ID, usually empty anyway */
101
	if(Bseek(bp, h->idlen, 1) < 0){
102
		free(h);
103
		return nil;
104
	}
105
 
106
	if(h->cmaptype == 0){
107
		h->cmap = 0;
108
		return h;
109
	}
110
 
111
	n = (h->cmapbpp/8)*h->cmaplen;
112
	if((h->cmap = malloc(n)) == nil){
113
		free(h);
114
		return nil;
115
	}
116
	if(Bread(bp, h->cmap, n) != n){
117
		free(h);
118
		free(h->cmap);
119
		return nil;
120
	}
121
	return h;
122
}
123
 
124
static int
125
luma(Biobuf *bp, uchar *l, int num)
126
{
127
	return Bread(bp, l, num);
128
}
129
 
130
static int
131
luma_rle(Biobuf *bp, uchar *l, int num)
132
{
133
	uchar len;
134
	int i, got;
135
 
136
	for(got = 0; got < num; got += len){
137
		if(Bread(bp, &len, 1) != 1)
138
			break;
139
		if(len & 0x80){
140
			len &= 0x7f;
141
			len += 1;	/* run of zero is meaningless */
142
			if(luma(bp, l, 1) != 1)
143
				break;
144
			for(i = 0; i < len && got < num; i++)
145
				l[i+1] = *l;
146
		}
147
		else{
148
			len += 1;	/* raw block of zero is meaningless */
149
			if(luma(bp, l, len) != len)
150
				break;
151
		}
152
		l += len;
153
	}
154
	return got;
155
}
156
 
157
 
158
static int
159
rgba(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
160
{
161
	int i;
162
	uchar x, y, buf[4];
163
 
164
	switch(bpp){
165
	case 16:
166
		for(i = 0; i < num; i++){
167
			if(Bread(bp, buf, 2) != 2)
168
				break;
169
			x = buf[0];
170
			y = buf[1];
171
			*b++ = (x&0x1f)<<3;
172
			*g++ = ((y&0x03)<<6) | ((x&0xe0)>>2);
173
			*r++ = (y&0x1f)<<3;
174
		}
175
		break;
176
	case 24:
177
		for(i = 0; i < num; i++){
178
			if(Bread(bp, buf, 3) != 3)
179
				break;
180
			*b++ = buf[0];
181
			*g++ = buf[1];
182
			*r++ = buf[2];
183
		}
184
		break;
185
	case 32:
186
		for(i = 0; i < num; i++){
187
			if(Bread(bp, buf, 4) != 4)
188
				break;
189
			*b++ = buf[0];
190
			*g++ = buf[1];
191
			*r++ = buf[2];
192
		}
193
		break;
194
	default:
195
		i = 0;
196
		break;
197
	}
198
	return i;
199
}
200
 
201
static int
202
rgba_rle(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
203
{
204
	uchar len;
205
	int i, got;
206
 
207
	for(got = 0; got < num; got += len){
208
		if(Bread(bp, &len, 1) != 1)
209
			break;
210
		if(len & 0x80){
211
			len &= 0x7f;
212
			len += 1;	/* run of zero is meaningless */
213
			if(rgba(bp, bpp, r, g, b, 1) != 1)
214
				break;
215
			for(i = 0; i < len-1 && got < num; i++){
216
				r[i+1] = *r;
217
				g[i+1] = *g;
218
				b[i+1] = *b;
219
			}
220
		}
221
		else{
222
			len += 1;	/* raw block of zero is meaningless */
223
			if(rgba(bp, bpp, r, g, b, len) != len)
224
				break;
225
		}
226
		r += len;
227
		g += len;
228
		b += len;
229
	}
230
	return got;
231
}
232
 
233
int
234
flip(Rawimage *ar)
235
{
236
	int w, h, c, l;
237
	uchar *t, *s, *d;
238
 
239
	w = Dx(ar->r);
240
	h = Dy(ar->r);
241
	if((t = malloc(w)) == nil){
242
		werrstr("ReadTGA: no memory - %r\n");
243
		return -1;
244
	}
245
 
246
	for(c = 0; c < ar->nchans; c++){
247
		s = ar->chans[c];
248
		d = ar->chans[c] + ar->chanlen - w;
249
		for(l = 0; l < (h/2); l++){
250
			memcpy(t, s, w);
251
			memcpy(s, d, w);
252
			memcpy(d, t, w);
253
			s += w;
254
			d -= w;
255
		}
256
	}
257
	free(t);
258
	return 0;
259
}
260
 
261
int
262
reflect(Rawimage *ar)
263
{
264
	int w, h, c, l, p;
265
	uchar t, *sol, *eol, *s, *d;
266
 
267
	w = Dx(ar->r);
268
	h = Dy(ar->r);
269
 
270
	for(c = 0; c < ar->nchans; c++){
271
		sol = ar->chans[c];
272
		eol = ar->chans[c] +w -1;
273
		for(l = 0; l < h; l++){
274
			s = sol;
275
			d = eol;
276
			for(p = 0; p < w/2; p++){
277
				t = *s;
278
				*s = *d;
279
				*d = t;
280
				s++;
281
				d--;
282
			}
283
			sol += w;
284
			eol += w;
285
		}
286
	}
287
	return 0;
288
}
289
 
290
 
291
Rawimage**
292
Breadtga(Biobuf *bp)
293
{
294
	Tga *h;
295
	int n, c, num;
296
	uchar *r, *g, *b;
297
	Rawimage *ar, **array;
298
 
299
	if((h = rdhdr(bp)) == nil){
300
		werrstr("ReadTGA: bad header %r");
301
		return nil;
302
	}
303
 
304
	if(0){
305
		fprint(2, "idlen=%d\n", h->idlen);
306
		fprint(2, "cmaptype=%d\n", h->cmaptype);
307
		fprint(2, "datatype=%s\n", datatype[h->datatype]);
308
		fprint(2, "cmaporigin=%d\n", h->cmaporigin);
309
		fprint(2, "cmaplen=%d\n", h->cmaplen);
310
		fprint(2, "cmapbpp=%d\n", h->cmapbpp);
311
		fprint(2, "xorigin=%d\n", h->xorigin);
312
		fprint(2, "yorigin=%d\n", h->yorigin);
313
		fprint(2, "width=%d\n", h->width);
314
		fprint(2, "height=%d\n", h->height);
315
		fprint(2, "bpp=%d\n", h->bpp);
316
		fprint(2, "descriptor=%d\n", h->descriptor);
317
	}
318
 
319
	array = nil;
320
	if((ar = calloc(sizeof(Rawimage), 1)) == nil){
321
		werrstr("ReadTGA: no memory - %r\n");
322
		goto Error;
323
	}
324
 
325
	if((array = calloc(sizeof(Rawimage *), 2)) == nil){
326
		werrstr("ReadTGA: no memory - %r\n");
327
		goto Error;
328
	}
329
	array[0] = ar;
330
	array[1] = nil;
331
 
332
	if(h->datatype == 3){
333
		ar->nchans = 1;
334
		ar->chandesc = CY;
335
	}
336
	else{
337
		ar->nchans = 3;
338
		ar->chandesc = CRGB;
339
	}
340
 
341
	ar->chanlen = h->width*h->height;
342
	ar->r = Rect(0, 0, h->width, h->height);
343
	for (c = 0; c < ar->nchans; c++)
344
		if ((ar->chans[c] = malloc(h->width*h->height)) == nil){
345
			werrstr("ReadTGA: no memory - %r\n");
346
			goto Error;
347
		}
348
	r = ar->chans[0];
349
	g = ar->chans[1];
350
	b = ar->chans[2];
351
 
352
	num = h->width*h->height;
353
	switch(h->datatype){
354
	case 2:
355
		if(rgba(bp, h->bpp, r, g, b, num) != num){
356
			werrstr("ReadTGA: decode fail - %r\n");
357
			goto Error;
358
		}
359
		break;
360
	case 3:
361
		if(luma(bp, r, num) != num){
362
			werrstr("ReadTGA: decode fail - %r\n");
363
			goto Error;
364
		}
365
		break;
366
	case 10:
367
		if((n = rgba_rle(bp, h->bpp, r, g, b, num)) != num){
368
			werrstr("ReadTGA: decode fail (%d!=%d) - %r\n", n, num);
369
			goto Error;
370
		}
371
		break;
372
	case 11:
373
		if(luma_rle(bp, r, num) != num){
374
			werrstr("ReadTGA: decode fail - %r\n");
375
			goto Error;
376
		}
377
		break;
378
	default:
379
		werrstr("ReadTGA: type=%d (%s) unsupported\n", h->datatype, datatype[h->datatype]);
380
		goto Error;	
381
 	}
382
 
383
	if(h->xorigin != 0)
384
		reflect(ar);
385
	if(h->yorigin == 0)
386
		flip(ar);
387
 
388
	free(h->cmap);
389
	free(h);
390
	return array;
391
Error:
392
 
393
	if(ar)
394
		for (c = 0; c < ar->nchans; c++)
395
			free(ar->chans[c]);
396
	free(ar);
397
	free(array);
398
	free(h->cmap);
399
	free(h);
400
	return nil;
401
}
402
 
403
Rawimage**
404
readtga(int fd)
405
{
406
	Rawimage * *a;
407
	Biobuf b;
408
 
409
	if (Binit(&b, fd, OREAD) < 0)
410
		return nil;
411
	a = Breadtga(&b);
412
	Bterm(&b);
413
	return a;
414
}
415
 
416