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
Bgeti(Biobuf * bp)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 *
rdhdr(Biobuf * bp)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
luma(Biobuf * bp,uchar * l,int num)125 luma(Biobuf *bp, uchar *l, int num)
126 {
127 return Bread(bp, l, num);
128 }
129
130 static int
luma_rle(Biobuf * bp,uchar * l,int num)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
rgba(Biobuf * bp,int bpp,uchar * r,uchar * g,uchar * b,int num)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
rgba_rle(Biobuf * bp,int bpp,uchar * r,uchar * g,uchar * b,int num)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
flip(Rawimage * ar)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
reflect(Rawimage * ar)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**
Breadtga(Biobuf * bp)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**
readtga(int fd)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
417