]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libdraw/readimage.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / libdraw / readimage.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4
5 Image*
6 readimage(Display *d, int fd, int dolock)
7 {
8         char hdr[5*12+1];
9         int dy;
10         int new;
11         uint l, n;
12         int m, j, chunk;
13         int miny, maxy;
14         Rectangle r;
15         int ldepth;
16         ulong chan;
17         uchar *tmp;
18         Image *i;
19
20         if(readn(fd, hdr, 11) != 11)
21                 return nil;
22         if(memcmp(hdr, "compressed\n", 11) == 0)
23                 return creadimage(d, fd, dolock);
24         if(readn(fd, hdr+11, 5*12-11) != 5*12-11)
25                 return nil;
26         if(d)
27                 chunk = d->bufsize - 32;        /* a little room for header */
28         else
29                 chunk = 8192;
30
31         /*
32          * distinguish new channel descriptor from old ldepth.
33          * channel descriptors have letters as well as numbers,
34          * while ldepths are a single digit formatted as %-11d.
35          */
36         new = 0;
37         for(m=0; m<10; m++){
38                 if(hdr[m] != ' '){
39                         new = 1;
40                         break;
41                 }
42         }
43         if(hdr[11] != ' '){
44                 werrstr("readimage: bad format");
45                 return nil;
46         }
47         if(new){
48                 hdr[11] = '\0';
49                 if((chan = strtochan(hdr)) == 0){
50                         werrstr("readimage: bad channel string %s", hdr);
51                         return nil;
52                 }
53         }else{
54                 ldepth = ((int)hdr[10])-'0';
55                 if(ldepth<0 || ldepth>3){
56                         werrstr("readimage: bad ldepth %d", ldepth);
57                         return nil;
58                 }
59                 chan = drawld2chan[ldepth];
60         }
61
62         r.min.x = atoi(hdr+1*12);
63         r.min.y = atoi(hdr+2*12);
64         r.max.x = atoi(hdr+3*12);
65         r.max.y = atoi(hdr+4*12);
66         if(r.min.x>r.max.x || r.min.y>r.max.y){
67                 werrstr("readimage: bad rectangle");
68                 return nil;
69         }
70
71         miny = r.min.y;
72         maxy = r.max.y;
73
74         l = bytesperline(r, chantodepth(chan));
75         if(d){
76                 if(dolock)
77                         lockdisplay(d);
78                 i = allocimage(d, r, chan, 0, -1);
79                 if(dolock)
80                         unlockdisplay(d);
81                 if(i == nil)
82                         return nil;
83         }else{
84                 i = mallocz(sizeof(Image), 1);
85                 if(i == nil)
86                         return nil;
87         }
88
89         tmp = malloc(chunk);
90         if(tmp == nil)
91                 goto Err;
92         while(maxy > miny){
93                 dy = maxy - miny;
94                 if(dy*l > chunk)
95                         dy = chunk/l;
96                 if(dy <= 0){
97                         werrstr("readimage: image too wide for buffer");
98                         goto Err;
99                 }
100                 n = dy*l;
101                 m = readn(fd, tmp, n);
102                 if(m != n){
103                         werrstr("readimage: read count %d not %d: %r", m, n);
104    Err:
105                         if(dolock)
106                                 lockdisplay(d);
107    Err1:
108                         freeimage(i);
109                         if(dolock)
110                                 unlockdisplay(d);
111                         free(tmp);
112                         return nil;
113                 }
114                 if(!new)        /* an old image: must flip all the bits */
115                         for(j=0; j<chunk; j++)
116                                 tmp[j] ^= 0xFF;
117
118                 if(d){
119                         if(dolock)
120                                 lockdisplay(d);
121                         if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
122                                 goto Err1;
123                         if(dolock)
124                                 unlockdisplay(d);
125                 }
126                 miny += dy;
127         }
128         free(tmp);
129         return i;
130 }