aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw/readimage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdraw/readimage.c')
-rw-r--r--src/libdraw/readimage.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/libdraw/readimage.c b/src/libdraw/readimage.c
new file mode 100644
index 00000000..1d2717b0
--- /dev/null
+++ b/src/libdraw/readimage.c
@@ -0,0 +1,118 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+Image*
+readimage(Display *d, int fd, int dolock)
+{
+ char hdr[5*12+1];
+ int dy;
+ int new;
+ uint l, n;
+ int m, j, chunk;
+ int miny, maxy;
+ Rectangle r;
+ int ldepth;
+ u32int chan;
+ uchar *tmp;
+ Image *i;
+
+ if(readn(fd, hdr, 11) != 11)
+ return nil;
+ if(memcmp(hdr, "compressed\n", 11) == 0)
+ return creadimage(d, fd, dolock);
+ if(readn(fd, hdr+11, 5*12-11) != 5*12-11)
+ return nil;
+ chunk = d->bufsize - 32; /* a little room for header */
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ werrstr("readimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ werrstr("readimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ werrstr("readimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+
+ r.min.x = atoi(hdr+1*12);
+ r.min.y = atoi(hdr+2*12);
+ r.max.x = atoi(hdr+3*12);
+ r.max.y = atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ werrstr("readimage: bad rectangle");
+ return nil;
+ }
+
+ miny = r.min.y;
+ maxy = r.max.y;
+
+ l = bytesperline(r, chantodepth(chan));
+ if(dolock)
+ lockdisplay(d);
+ i = allocimage(d, r, chan, 0, -1);
+ if(dolock)
+ unlockdisplay(d);
+ if(i == nil)
+ return nil;
+ tmp = malloc(chunk);
+ if(tmp == nil)
+ goto Err;
+ while(maxy > miny){
+ dy = maxy - miny;
+ if(dy*l > chunk)
+ dy = chunk/l;
+ if(dy <= 0){
+ werrstr("readimage: image too wide for buffer");
+ goto Err;
+ }
+ n = dy*l;
+ m = readn(fd, tmp, n);
+ if(m != n){
+ werrstr("readimage: read count %d not %d: %r", m, n);
+ Err:
+ if(dolock)
+ lockdisplay(d);
+ Err1:
+ freeimage(i);
+ if(dolock)
+ unlockdisplay(d);
+ free(tmp);
+ return nil;
+ }
+ if(!new) /* an old image: must flip all the bits */
+ for(j=0; j<chunk; j++)
+ tmp[j] ^= 0xFF;
+
+ if(dolock)
+ lockdisplay(d);
+ if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+ goto Err1;
+ if(dolock)
+ unlockdisplay(d);
+ miny += dy;
+ }
+ free(tmp);
+ return i;
+}