]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/readtga.c
cwfs: back to previous version
[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, 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