]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/readtga.c
Libflac: Tell it that we have stdint.h so it finds SIZE_MAX
[plan9front.git] / sys / src / cmd / jpg / readtga.c
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.
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 colour map */
25         int cmapbpp;            /* bits 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]    "RLE 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 int
68 fixcmap(uchar *cmap, int *cmapbpp, int cmaplen)
69 {
70         int i;
71         ushort x;
72         uchar tmp;
73
74         switch(*cmapbpp){
75         case 32:
76                 /* swap B with R */
77                 for(i = 0; i < cmaplen; i++){
78                         tmp = cmap[4*i+0];
79                         cmap[4*i+0] = cmap[4*i+2];
80                         cmap[4*i+2] = tmp;
81                 }
82                 break;
83         case 24:
84                 /* swap B with R */
85                 for(i = 0; i < cmaplen; i++){
86                         tmp = cmap[3*i+0];
87                         cmap[3*i+0] = cmap[3*i+2];
88                         cmap[3*i+2] = tmp;
89                 }
90                 break;
91         case 16:
92         case 15:
93                 /* convert to 24-bit colormap */
94                 if((cmap = realloc(cmap, 3*cmaplen)) == nil)
95                         return -1;
96                 for(i = cmaplen-1; i >= 0; i--){
97                         x = (cmap[2*i+1]<<8) | cmap[2*i+0];
98                         tmp = (x>>0)&0x1f;
99                         cmap[3*i+2] = (tmp<<3) | (tmp>>2);
100                         tmp = (x>>5)&0x1f;
101                         cmap[3*i+1] = (tmp<<3) | (tmp>>2);
102                         tmp = (x>>10)&0x1f;
103                         cmap[3*i+0] = (tmp<<3) | (tmp>>2);
104                 }
105                 *cmapbpp = 24;
106                 break;
107         default:
108                 break;
109         }
110
111         return 0;
112 }
113
114 static Tga *
115 rdhdr(Biobuf *bp)
116 {
117         int n;
118         Tga *h;
119
120         if((h = malloc(sizeof(Tga))) == nil)
121                 return nil;
122         if((h->idlen = Bgetc(bp)) == -1)
123                 return nil;
124         if((h->cmaptype = Bgetc(bp)) == -1)
125                 return nil;
126         if((h->datatype = Bgetc(bp)) == -1)
127                 return nil;
128         if((h->cmaporigin = Bgeti(bp)) == -1)
129                 return nil;
130         if((h->cmaplen = Bgeti(bp)) == -1)
131                 return nil;
132         if((h->cmapbpp = Bgetc(bp)) == -1)
133                 return nil;
134         if((h->xorigin = Bgeti(bp)) == -1)
135                 return nil;
136         if((h->yorigin = Bgeti(bp)) == -1)
137                 return nil;
138         if((h->width = Bgeti(bp)) == -1)
139                 return nil;
140         if((h->height = Bgeti(bp)) == -1)
141                 return nil;
142         if((h->bpp = Bgetc(bp)) == -1)
143                 return nil;
144         if((h->descriptor = Bgetc(bp)) == -1)
145                 return nil;
146
147         /* skip over ID, usually empty anyway */
148         if(Bseek(bp, h->idlen, 1) < 0){
149                 free(h);
150                 return nil;
151         }
152
153         if(h->cmaptype == 0){
154                 h->cmap = 0;
155                 return h;
156         }
157
158         /* skip over unused color map data */
159         n = (h->cmapbpp/8)*h->cmaporigin;
160         if(Bseek(bp, n, 1) < 0){
161                 free(h);
162                 return nil;
163         }
164         h->cmaplen -= h->cmaporigin;
165
166         n = (h->cmapbpp/8)*h->cmaplen;
167         if((h->cmap = malloc(n)) == nil){
168                 free(h);
169                 return nil;
170         }
171         if(Bread(bp, h->cmap, n) != n){
172                 free(h);
173                 free(h->cmap);
174                 return nil;
175         }
176         if(fixcmap(h->cmap, &h->cmapbpp, h->cmaplen) != 0){
177                 free(h);
178                 free(h->cmap);
179                 return nil;
180         }
181         return h;
182 }
183
184 static int
185 cmap(Biobuf *bp, uchar *l, int num)
186 {
187         return Bread(bp, l, num);
188 }
189
190 static int
191 luma(Biobuf *bp, int bpp, uchar *l, int num)
192 {
193         char tmp[2];
194         int got;
195
196         if(bpp == 8){
197                 got = Bread(bp, l, num);
198         }
199         else{
200                 for(got = 0; got < num; got++){
201                         if(Bread(bp, tmp, 2) != 2)
202                                 break;
203                         *l++ = tmp[0];
204                 }
205         }
206         return got;
207 }
208
209 static int
210 luma_rle(Biobuf *bp, int bpp, uchar *l, int num)
211 {
212         uchar len, p;
213         int got;
214
215         for(got = 0; got < num;){
216                 if(Bread(bp, &len, 1) != 1)
217                         break;
218                 if(len & 0x80){
219                         len &= 0x7f;
220                         if(luma(bp, bpp, &p, 1) != 1)
221                                 break;
222                         for(len++; len > 0 && got < num; len--, got++)
223                                 *l++ = p;
224                 }
225                 else{
226                         for(len++; len > 0 && got < num; len--, got++)
227                                 if(luma(bp, bpp, l++, 1) != 1)
228                                         return got;
229                 }
230         }
231         return got;
232 }
233
234 static int
235 cmap_rle(Biobuf *bp, uchar *l, int num)
236 {
237         return luma_rle(bp, 8, l, num);
238 }
239
240 static int
241 rgba(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
242 {
243         int i;
244         uchar buf[4], tmp;
245         ushort x;
246
247         switch(bpp){
248         case 16:
249         case 15:
250                 for(i = 0; i < num; i++){
251                         if(Bread(bp, buf, 2) != 2)
252                                 break;
253                         x = (buf[1]<<8) | buf[0];
254                         tmp = (x>>0)&0x1f;
255                         *b++ = (tmp<<3) | (tmp>>2);
256                         tmp = (x>>5)&0x1f;
257                         *g++ = (tmp<<3) | (tmp>>2);
258                         tmp = (x>>10)&0x1f;
259                         *r++ = (tmp<<3) | (tmp>>2);
260                 }
261                 break;
262         case 24:
263                 for(i = 0; i < num; i++){
264                         if(Bread(bp, buf, 3) != 3)
265                                 break;
266                         *b++ = buf[0];
267                         *g++ = buf[1];
268                         *r++ = buf[2];
269                 }
270                 break;
271         case 32:
272                 for(i = 0; i < num; i++){
273                         if(Bread(bp, buf, 4) != 4)
274                                 break;
275                         *b++ = buf[0];
276                         *g++ = buf[1];
277                         *r++ = buf[2];
278                 }
279                 break;
280         default:
281                 i = 0;
282                 break;
283         }
284         return i;
285 }
286
287 static int
288 rgba_rle(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
289 {
290         uchar len;
291         int i, got;
292
293         for(got = 0; got < num; got += len){
294                 if(Bread(bp, &len, 1) != 1)
295                         break;
296                 if(len & 0x80){
297                         len &= 0x7f;
298                         len += 1;       /* run of zero is meaningless */
299                         if(rgba(bp, bpp, r, g, b, 1) != 1)
300                                 break;
301                         for(i = 1; i < len && got+i < num; i++){
302                                 r[i] = *r;
303                                 g[i] = *g;
304                                 b[i] = *b;
305                         }
306                         len = i;
307                 }
308                 else{
309                         len += 1;       /* raw block of zero is meaningless */
310                         if(rgba(bp, bpp, r, g, b, len) != len)
311                                 break;
312                 }
313                 r += len;
314                 g += len;
315                 b += len;
316         }
317         return got;
318 }
319
320 int
321 flip(Rawimage *ar)
322 {
323         int w, h, c, l;
324         uchar *t, *s, *d;
325
326         w = Dx(ar->r);
327         h = Dy(ar->r);
328         if((t = malloc(w)) == nil){
329                 werrstr("ReadTGA: no memory - %r\n");
330                 return -1;
331         }
332
333         for(c = 0; c < ar->nchans; c++){
334                 s = ar->chans[c];
335                 d = ar->chans[c] + ar->chanlen - w;
336                 for(l = 0; l < (h/2); l++){
337                         memcpy(t, s, w);
338                         memcpy(s, d, w);
339                         memcpy(d, t, w);
340                         s += w;
341                         d -= w;
342                 }
343         }
344         free(t);
345         return 0;
346 }
347
348 int
349 reflect(Rawimage *ar)
350 {
351         int w, h, c, l, p;
352         uchar t, *sol, *eol, *s, *d;
353
354         w = Dx(ar->r);
355         h = Dy(ar->r);
356
357         for(c = 0; c < ar->nchans; c++){
358                 sol = ar->chans[c];
359                 eol = ar->chans[c] +w -1;
360                 for(l = 0; l < h; l++){
361                         s = sol;
362                         d = eol;
363                         for(p = 0; p < w/2; p++){
364                                 t = *s;
365                                 *s = *d;
366                                 *d = t;
367                                 s++;
368                                 d--;
369                         }
370                         sol += w;
371                         eol += w;
372                 }
373         }
374         return 0;
375 }
376
377
378 Rawimage**
379 Breadtga(Biobuf *bp)
380 {
381         Tga *h;
382         int n, c, num;
383         uchar *r, *g, *b;
384         Rawimage *ar, **array;
385
386         if((h = rdhdr(bp)) == nil){
387                 werrstr("ReadTGA: bad header %r");
388                 return nil;
389         }
390
391         if(0){
392                 fprint(2, "idlen=%d\n", h->idlen);
393                 fprint(2, "cmaptype=%d\n", h->cmaptype);
394                 fprint(2, "datatype=%s\n", datatype[h->datatype]);
395                 fprint(2, "cmaporigin=%d\n", h->cmaporigin);
396                 fprint(2, "cmaplen=%d\n", h->cmaplen);
397                 fprint(2, "cmapbpp=%d\n", h->cmapbpp);
398                 fprint(2, "xorigin=%d\n", h->xorigin);
399                 fprint(2, "yorigin=%d\n", h->yorigin);
400                 fprint(2, "width=%d\n", h->width);
401                 fprint(2, "height=%d\n", h->height);
402                 fprint(2, "bpp=%d\n", h->bpp);
403                 fprint(2, "descriptor=%d\n", h->descriptor);
404         }
405
406         array = nil;
407         if((ar = calloc(1, sizeof(Rawimage))) == nil){
408                 werrstr("ReadTGA: no memory - %r\n");
409                 goto Error;
410         }
411
412         if((array = calloc(2, sizeof(Rawimage *))) == nil){
413                 werrstr("ReadTGA: no memory - %r\n");
414                 goto Error;
415         }
416         array[0] = ar;
417         array[1] = nil;
418
419         if(h->datatype == 3 || h->datatype == 11){
420                 ar->nchans = 1;
421                 ar->chandesc = CY;
422         }
423         else if(h->datatype == 1){
424                 ar->nchans = 1;
425                 ar->chandesc = CRGB1;
426         }
427         else if(h->datatype == 9){
428                 ar->nchans = 1;
429                 ar->chandesc = (h->cmapbpp == 32) ? CRGBV : CRGB1;
430         }
431         else{
432                 ar->nchans = 3;
433                 ar->chandesc = CRGB;
434         }
435
436         ar->cmap = h->cmap;
437         ar->cmaplen = (h->cmapbpp/8)*h->cmaplen;
438         ar->chanlen = h->width*h->height;
439         ar->r = Rect(0, 0, h->width, h->height);
440         for(c = 0; c < ar->nchans; c++)
441                 if((ar->chans[c] = malloc(h->width*h->height)) == nil){
442                         werrstr("ReadTGA: no memory - %r\n");
443                         goto Error;
444                 }
445         r = ar->chans[0];
446         g = ar->chans[1];
447         b = ar->chans[2];
448
449         num = h->width*h->height;
450         switch(h->datatype){
451         case 1:
452                 n = cmap(bp, r, num);
453                 break;
454         case 2:
455                 n = rgba(bp, h->bpp, r, g, b, num);
456                 break;
457         case 3:
458                 n = luma(bp, h->bpp, r, num);
459                 break;
460         case 9:
461                 n = cmap_rle(bp, r, num);
462                 break;
463         case 10:
464                 n = rgba_rle(bp, h->bpp, r, g, b, num);
465                 break;
466         case 11:
467                 n = luma_rle(bp, h->bpp, r, num);
468                 break;
469         default:
470                 werrstr("ReadTGA: type=%d (%s) unsupported\n", h->datatype, datatype[h->datatype]);
471                 goto Error;     
472         }
473
474         if(n != num){
475                 werrstr("ReadTGA: decode fail (%d!=%d) - %r\n", n, num);
476                 goto Error;
477         }
478         if((h->descriptor&(1<<4)) != 0)
479                 reflect(ar);
480         if((h->descriptor&(1<<5)) == 0)
481                 flip(ar);
482
483         free(h);
484         return array;
485 Error:
486
487         if(ar)
488                 for (c = 0; c < ar->nchans; c++)
489                         free(ar->chans[c]);
490         free(ar);
491         free(array);
492         free(h->cmap);
493         free(h);
494         return nil;
495 }
496
497 Rawimage**
498 readtga(int fd)
499 {
500         Rawimage * *a;
501         Biobuf b;
502
503         if(Binit(&b, fd, OREAD) < 0)
504                 return nil;
505         a = Breadtga(&b);
506         Bterm(&b);
507         return a;
508 }
509
510