-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprint_al_font.c
232 lines (199 loc) · 7.63 KB
/
print_al_font.c
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
/*
* Print Xerox Alto fonts AL format in ascii art
*
* Font formats from the era are documented in http://www.bitsavers.org/pdf/xerox/alto/printing/AltoFontFormats_Oct1980.pdf
*
*/
/*
* charData can be AT MOST 16 horizonal bits, therefore the structure size can and do varries
* 377b = 255 = 0xFF
* charactes can have extensions, more bits
* if XW <= 16 char width = (XW-1)/2
* else XW is code for the extension charcter multiplied by 2
* the pointers point to the computer word in XHdata for XW
* this pointers needed to be added to the numeric value of the ASCII character and the two word offset for the header then multiplied by two to get the right offset in bytes. I assume adding the offset of the pointer + it's value (times two) should produce the same final offset for the relative XHdata structture.
*
*/
uint16_t swap_uint16(uint16_t val)
{
return (val << 8) | (val >> 8);
}
struct Scanline {
unsigned int bits: 16;
};
struct XHdata {
uint16_t XW;
uint8_t HD;
uint8_t XH;
}__attribute__((packed));
struct AL {
uint16_t height;
unsigned int proportional : 1;
unsigned int baseline : 7;
uint8_t maxWidth;
uint16_t pointers[0377]; // 255 in octal
}__attribute__((packed));
void replace(char *str, char from, char to)
{
for (int i = 0; i < strlen(str); i++) {
if (str[i] == from) str[i] = to;
}
}
int main(int argc, char *argv[])
{
int fd;
struct stat statbuf;
size_t file_size;
if (argc <= 1) {
printf("usage: %s [-pointers -header -text] font.al\n", argv[0]);
exit(1);
}
int print_header = 1;
int print_pointers = 1;
int print_text = 0;
if (argc >= 2) {
if (strncmp("-pointers", argv[1], 10) == 0) {
print_pointers = 1;
print_header = 0;
}
if (strncmp("-header", argv[1], 7) == 0) {
print_header = 1;
print_pointers = 0;
}
if (strncmp("-text", argv[1], 7) == 0) {
print_header = 0;
print_pointers = 0;
print_text = 1;
}
}
fd = open(argv[argc - 1], O_RDONLY);
assert(fd > 0);
fstat(fd, &statbuf);
file_size = statbuf.st_size;
assert(file_size > sizeof(struct AL));
struct AL al;
assert(sizeof(struct XHdata) == 4);
int bytes_read = read(fd, &al, sizeof(al));
assert(bytes_read == sizeof(al));
if (print_header) {
printf("Height: %i\n", swap_uint16(al.height));
printf("Is %sproportional\n", al.proportional ? "" : "not ");
printf("Baseline: %i\n", al.baseline);
printf("maxWidth: %i\n", al.maxWidth);
}
if (print_pointers) {
// print the "self-relative pointers" table
for (int i = 0; i < 255; i++) {
printf("pointer at %d = 0x%X => 0x%X\n", i, swap_uint16(al.pointers[i]), (swap_uint16(al.pointers[i]) + i + 2) * 2);
}
}
struct XHdata charData;
char buffer[17];
// Dummy XW = 1, XH = 0, HD = 0 at
// 0x203: 0x01 0x00, 0x00 0x00
if (!print_text) {
for (int i = 0; i < 128; i++) {
//printf("%X offset %d\n", i, al.pointers[i]);
uint16_t charData_offset = swap_uint16(al.pointers[i]);
// pointer + char * 2 + header offset
int real_offset = (charData_offset + i + 2)*2;
printf("offset = %d => 0x%x => 0x%X\n", i, charData_offset, real_offset);
// seek the file to XHdata for this char
off_t cur_offset = lseek(fd, real_offset, SEEK_SET);
assert(cur_offset != -1);
printf("ASCII char '%c'\n", i);
bytes_read = read(fd, &charData, sizeof(struct XHdata));
uint16_t scanlines[16] = {0};
// go back in file XH words
cur_offset = lseek(fd, real_offset - (charData.XH * 2), SEEK_SET);
bytes_read = read(fd, scanlines, charData.XH * 2);
// FIXME: We need to put the wider charactes toguether
// FIXME: We need to handle the omited all zeroes scanlines
for (int i = 0; i < charData.XH; i++) {
sprintf(buffer, "%016b", swap_uint16(scanlines[i]));
replace(buffer, '0', ' ');
replace(buffer, '1', '#');
printf("%s\n", buffer);
}
printf("XW = %d HD = %d XH = %d\n", swap_uint16(charData.XW), charData.HD, charData.XH);
}
} else {
char *text = argv[2];
// Now we need (16 x strlen(text)) x 16 bits of height to place the pixels
// uint16_t *out_buffer = malloc(strlen(text) * 16 * 16);
uint16_t out_buffer[16][strlen(text)];
memset(out_buffer, (uint16_t) 0, strlen(text) * 16 * 2);
assert(out_buffer!=NULL);
for (int i = 0; i < strlen(text); i++) {
uint16_t bit_buffer[16] = {0};
uint16_t charData_offset = swap_uint16(al.pointers[(int)text[i]]);
int real_offset = (charData_offset + text[i] + 2)*2;
//printf("offset for %c is 0x%X\n", text[i], real_offset);
off_t cur_offset = lseek(fd, real_offset, SEEK_SET);
assert(cur_offset != -1);
struct XHdata charData;
int bytes_read = read(fd, &charData, sizeof(struct XHdata));
assert(bytes_read == sizeof(struct XHdata));
cur_offset = lseek(fd, real_offset - (charData.XH * 2), SEEK_SET);
assert(cur_offset != -1);
bytes_read = read(fd, bit_buffer, charData.XH * 2);
assert(bytes_read == charData.XH * 2);
// FIXME: respect the XW value
// FIXME: write in less than 16 increments/spaces
printf("XW = %d HD = %d XW = %d\n", swap_uint16(charData.XW), charData.HD, charData.XH);
#if 0
char print_buf0[18];
for (int x = 0; x < charData.XH; x++) {
sprintf(print_buf0, "%016b\n", swap_uint16(bit_buffer[x]));
replace(print_buf0, '0', ' ');
replace(print_buf0, '1', '#');
printf("%s", print_buf0);
}
#endif
//printf("----------------------------------\n");
for (int row = 0; row < charData.XH; row++) {
//printf("row %d \tbit_buffer = %016b\n", row, swap_uint16(bit_buffer[row]));
//out_buffer[row + 16-charData.XH][i] = swap_uint16(bit_buffer[row]);
out_buffer[row + 16-charData.XH][i] = bit_buffer[row];
}
}
close(fd); // just in case
#if 1
char filename_buffer[50];
sprintf(filename_buffer, "%s.pbm", argv[argc-1]);
int new_fd = open(filename_buffer, O_WRONLY|O_CREAT|O_TRUNC, 0600);
if (new_fd < 0) {
perror("Opening file");
exit(-1);
};
char header[40];
sprintf(header, "P4\n%d %d\n", (int) strlen(text) * 16, 16);
int written = write(new_fd, header, strlen(header));
assert(written == strlen(header));
written = write(new_fd, (uint8_t *) &out_buffer, sizeof(out_buffer));
assert(written == sizeof(out_buffer));
fsync(new_fd);
close(new_fd);
#endif
for (int y = 0; y < 16; y++) {
for (int x = 0; x < strlen(text); x++) {
char print_buf[17] = {0};
sprintf(print_buf, "%016b", out_buffer[y][x]);
replace(print_buf, '0', ' ');
replace(print_buf, '1', '#');
printf("%s", print_buf);
}
printf("|\n");
}
//free(out_buffer);
}
return EXIT_SUCCESS;
}