shithub: purgatorio

ref: 9f76a7f6819ac04552b4fb6588156f3e4089d1d7
dir: /appl/lib/readxbitmap.b/

View raw version
implement RImagefile;

include "sys.m";
	sys: Sys;

include "draw.m";
	draw: Draw;

include "bufio.m";
	bufio: Bufio;
	Iobuf: import bufio;

include "imagefile.m";

init(iomod: Bufio)
{
	if(sys == nil)
		sys = load Sys Sys->PATH;
	bufio = iomod;
}

readmulti(fd: ref Iobuf): (array of ref Rawimage, string)
{
	(i, err) := read(fd);
	if(i != nil){
		a := array[1] of { i };
		return (a, err);
	}
	return (nil, err);
}

read(fd: ref Iobuf): (ref Rawimage, string)
{
	width, height, fnd: int;
	(fnd, width) = get_define(fd);
	if(fnd)
		(fnd, height) = get_define(fd);
	if(!fnd)
		return (nil, "xbitmap doesn't start with width and height");
	if(height <= 0 || width <= 0)
		return (nil, "xbitmap has bad width or height");
	# now, optional x_hot, y_hot
	(fnd, nil) = get_define(fd);
	if(fnd)
		(fnd, nil) = get_define(fd);
	# now expect 'static char x...x_bits[] = {'
	if(!get_to_char(fd, '{'))
		return (nil, "xbitmap premature eof");

	bytesperline := (width+7) / 8;
	pixels := array[width*height] of byte;
	pixi := 0;
	for(i := 0; i < height; i++) {
		for(j := 0; j < bytesperline; j++) {
			(vfnd, v) := get_hexbyte(fd);
			if(!vfnd)
				return (nil,  "xbitmap premature eof");
			kend := 7;
			if(j == bytesperline-1)
				kend = (width-1)%8;
			for(k := 0; k <= kend; k++) {
				if(v & (1<<k))
					pixels[pixi] = byte 0;
				else
					pixels[pixi] = byte 1;
				pixi++;
			}
		}
	}
	cmap := array[6] of {byte 0, byte 0, byte 0,
			byte 255, byte 255, byte 255};
	chans := array[1] of {pixels};
	ans := ref Rawimage(Draw->Rect((0,0),(width,height)), cmap, 0, byte 0, 1, chans, CRGB1, 0);
	return (ans, "");
}

# get a line, which should be of form
#	'#define fieldname val'
# and return (found, integer rep of val)
get_define(fd: ref Iobuf) : (int, int)
{
	c := fd.getc();
	if(c != '#') {
		fd.ungetc();
		return (0, 0);
	}
	line := fd.gets('\n');
	for(i := len line -1; i >= 0; i--)
		if(line[i] == ' ')
			break;
	val := int line[i+1:];
	return (1, val);
}

# read fd until get char cterm; return 1 if found
get_to_char(fd: ref Iobuf, cterm: int) : int
{
	for(;;) {
		c := fd.getc();
		if(c < 0)
			return c;
		if(c == cterm)
			return 1;
	}
}

# read fd until get xDD, were DD are hex digits.
# return (found, value of DD as integer)
get_hexbyte(fd: ref Iobuf) : (int, int)
{
	if(!get_to_char(fd, 'x'))
		return (0, 0);
	n1 := hexdig(fd.getc());
	n2 := hexdig(fd.getc());
	if(n1 < 0 || n2 < 0)
		return (0, 0);
	return (1, (n1<<4) | n2);
}

hexdig(c: int) : int
{
	if('0' <= c && c <= '9')
		c -= '0';
	else if('a' <= c && c <= 'f')
		c += 10 - 'a';
	else if('A' <= c && c <= 'F')
		c += 10 - 'A';
	else
		c = -1;
	return c;
}