ref: d180b70c6c69ffe8168cc8571772ad6e15ac6aba
dir: /load.myr/
use std
use sys
use "types"
use "chan"
use "image"
use "pack"
pkg draw =
const load : (dpy : display#, buf : byte[:] -> std.result(image#, err))
const xload : (dpy : display#, buf : byte[:] -> std.result((image#, std.size), err))
;;
const load = {dpy, buf
match xload(dpy, buf)
| `std.Ok (img, n):
if n != buf.len
// freeimg(img)
-> `std.Err `Efmt
;;
-> `std.Ok img
| `std.Err e:
-> `std.Err e
;;
}
const xload = {dpy, buf
var chan, rect, compressed
var n, img
if !parsehdr(buf, &chan, &rect, &compressed, &buf)
-> `std.Err `Efmt
;;
img = genallocimage(dpy, 0, Refnone, chan, DWhite, false, rect, rect)
if compressed
n = 5*12 + 11
n += loadcomp(dpy, img, buf)
else
n = 5*12
n += loadraw(dpy, img, buf)
;;
if n > 0
-> `std.Ok (img, n)
else
// freeimg(img)
-> `std.Err `Efmt
;;
}
const loadcomp = {dpy, img, buf
var l, n, ymin, ymax, err
l = 0
ymin = img.r.y0
while ymin != img.r.y1
if buf.len < 24
-> -1
;;
err = false
ymax = getint(buf[:12], &err)
n = getint(buf[12:24], &err)
if err
-> -1
;;
l += 24
buf = buf[24:]
pack(dpy, "biiiiid", (n : std.size), \
('Y' : byte), \
img.id, \
img.r.x0, \
ymin, \
img.r.x1, \
ymax, \
buf[:n])
buf = buf[n:]
ymin = ymax
l += n
;;
-> (l : std.size)
}
const loadraw = {dpy, img, buf
var chunk, btp, btl
var l, n, r, dx, dy
l = 0
r = img.r
dx = r.x1 - r.x0
btp = (chandepth(img.chan) / 8 : int)
btl = btp * dx
chunk = dpy.buf.len - 64
while r.y0 != r.y1
dy = r.y1 - r.y0
/* FIXME: deal with images where btl > chunk */
if dy * btl > chunk
dy = chunk / btl
;;
n = dy * btl
pack(dpy, "biiiiid", (n : std.size), \
('y' : byte), \
img.id, \
r.x0, \
r.y0, \
r.x1, \
r.y0 + dy, \
buf[:n])
l += n
buf = buf[n:]
r.y0 += dy
;;
-> (l : std.size)
}
const parsehdr = {buf, chanp, rectp, compressedp, bufp
if buf.len < 5*12
-> false
;;
if std.sleq(buf[:11], "compressed\n") && buf.len >= 5*12 + 11
compressedp# = true
bufp# = buf[5*12 + 11:]
-> parsefmt(buf[11:11+5*12], chanp, rectp)
else
compressedp# = false
bufp# = buf[5*12:]
-> parsefmt(buf[:5*12], chanp, rectp)
;;
}
const parsefmt = {buf, chanp, rectp
var spbuf : byte[:][5]
var sp, err
sp = std.bstrtok(spbuf[:], buf)
if sp.len == 0
-> false
;;
match chanparse(sp[0])
| `std.Some c: chanp# = c
| `std.None: std.fatal("bad chan\n"); -> false
;;
err = false
rectp.x0 = getint(sp[1], &err)
rectp.y0 = getint(sp[2], &err)
rectp.x1 = getint(sp[3], &err)
rectp.y1 = getint(sp[4], &err)
-> !err
}