summaryrefslogtreecommitdiff
path: root/appl/lib/readxbitmap.b
blob: 2c32b82267d7da92fa3efb8c80b4b34a4500a339 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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;
}