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