shithub: libdraw.myr

ref: d180b70c6c69ffe8168cc8571772ad6e15ac6aba
dir: /load.myr/

View raw version
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
}