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