Transfonter
Description of the page content
Tool written in SBASIC that creates an ISO 8859-1 QL font.
Transfonter creates an ISO 8859-1 font for the Sinclair QL. I had three reasons for writing it:
First: The original QL charset isn't standard. Besides, it lacks four letters needed in Spanish (Á, Í, Ó, Ú). That always was inconvenient for me.
Second: In August 2010 I started some projects in S*BASIC for SMSQ/E. In order to work more efficiently, I write the source code with the Vim editor on Debian (I run QPC2 on it, with Wine). So I needed to use the same charset in both systems.
Third: I didn't find a QL font with a modern standard charset. It seems nobody has done it before, or at least nobody has published it.
The program takes some chars from standard QL fonts and from the Code Page 437 font created by Dilwyn Jones (all bundled with Dilwyn Jones' Font Editor) and creates the rest. Three of the 35 new chars were difficult to fit into the 5x9 grid: "Â" ("A" with circumflex), the registered mark sign (practically illegible) and the "3/4".
I'm working on the next part: the corresponding keyboard table.
Screenshots
Source code
The following listing is the original version, without line numbers. In the download section there's a version with line numbers.
rem Transfonter
rem This program creates a Sinclair QL ISO 8859-1 font.
rem It is written in SBASIC.
rem It has been tested with the QPC2 QL emulator
rem running on Debian GNU/Linux with Wine.
rem Copyright (C) 2010 Marcos Cruz (http://programandala.net)
rem License: http://programandala.net/license
rem ---------------- Changelog
rem 2010-08-21
rem * First draft.
rem 2010-08-22
rem * First working version.
rem 2010-08-23
rem * New system: patterns are taken from several input fonts.
rem 2010-08-24
rem * All missing characters are defined.
rem 2010-08-26
rem * Some character names are fixed.
rem * Bug fixed: now the pattern for undefined characters is a constant, not peeked from one of the input fonts (what worked only with the old system, with only one input font).
rem * Bug fixed: now input_font_address is set to zero after releasing its space; this makes it possible to run the program more than once, otherwise an error was reported.
rem ---------------- Global
let char_bytes = 9 : rem Bytes per char pattern.
dim pattern$(char_bytes-1,8) : rem Temporary store for patterns, in strings of 8-bit binary values.
let undefined_pattern$ = "T(T(T(T(T" : rem Checkered pattern used for undefined chars.
let input_fonts_dir$ = "win1_prg_font_editor_" : rem Path of all input fonts.
rem ---------------- Main
create_iso_8859_1_font "dos1_fonts_iso_8859-1_font"
stop
rem ---------------- Font manipulation
defproc open_input_font(input_font$)
if input_font_address : close_input_font
let input_font_length = flen(\input_fonts_dir$&input_font$)
let input_font_address = alchp(input_font_length)
lbytes input_fonts_dir$&input_font$,input_font_address
let input_first_char = first_char_in_font(input_font_address)
let input_chars = chars_in_font(input_font_address)
let input_last_char = input_first_char+input_chars-1
enddef
defproc open_output_font
let output_first_char = 32
let output_last_char = 255
let output_chars = output_last_char-output_first_char+1
let output_font_length = 2+char_bytes+output_chars*char_bytes
let output_font_address = alchp(output_font_length)
create_output_font_header
enddef
defproc create_output_font_header
poke output_font_address,output_first_char-1
poke output_font_address+1,output_chars
poke$ output_font_address+2,undefined_pattern$
enddef
defproc close_input_font
rechp input_font_address
let input_font_address = 0
enddef
defproc save_output_font(output_font$)
sbytes_o output_font$,output_font_address,output_font_length
rechp output_font_address
enddef
rem ---------------- Char manipulation
defproc undefined_chars(first_char,last_char)
rem Copy into the specified range of chars of the output font
rem the undefined pattern.
local char
for char = first_char to last_char
poke$ output_char_address(char),undefined_pattern$
endfor char
enddef
defproc copy_chars(first_char,last_char)
rem Copy a range of chars from the input font into the same position of the output font.
local char
for char = first_char to last_char
copy_char char,char
endfor char
enddef
defproc copy_char(input_char,output_char)
rem Copy one char from the input font into the output font.
poke$ output_char_address(output_char),peek$(input_char_address(input_char),char_bytes)
enddef
defproc pattern_to_char(char)
local char_base_address
local row
let char_base_address = output_char_address(char)
for row=0 to char_bytes-1
poke char_base_address+row,bin(pattern$(row))
endfor row
enddef
deffn input_char_address(char)
rem Return the address of a char of the input font.
return char_address(input_font_address,char)
enddef
deffn output_char_address(char)
rem Return the address of a char of the output font.
return char_address(output_font_address,char)
enddef
rem ---------------- Font information
deffn char_address(font_address,char)
rem Return the address of a char in a font.
return font_address + 2 + char_bytes + char_bytes*(char-first_char_in_font(font_address))
enddef
deffn first_char_in_font(font_address)
rem Return the code of the first char in a font.
return peek(font_address)+1
enddef
deffn chars_in_font(font_address)
rem Return the number of chars in a font.
return peek(font_address+1)
enddef
rem ---------------- Font translation
defproc create_iso_8859_1_font(output_font$)
rem Create an ISO 8859-1 font
rem by getting character patterns from other fonts.
rem The fonts used are bundled with Font Editor, by Dilwyn Jones
rem (http://www.dilwyn.me.uk/fonts/).
rem References on the Internet:
rem http://en.wikipedia.org/wiki/ISO/IEC_8859-1
rem http://ciberia.ya.com/rulo_sinclairql/charset.html
open_output_font
open_input_font "qlfont1_font" : rem QL font 1 (chars 32-127)
copy_chars 32,126 : rem ASCII
undefined_chars 127,255 : rem the rest is undefined by default
copy_char 32,160 : rem no-break space (NBSP)
copy_char 45,173 : rem soft hyphen (SHY)
copy_char 96,163 : rem pound sign
copy_char 127,169 : rem copyright sign
open_input_font "qlfont2_font" : rem QL font 2 (chars 128-191)
copy_char 128,228 : rem a with diaeresis
copy_char 129,227 : rem a tilde
copy_char 130,229 : rem a with ring
copy_char 131,233 : rem e with acute
copy_char 132,246 : rem o with diaeresis
copy_char 133,245 : rem o tilde
copy_char 134,248 : rem o with stroke
copy_char 135,252 : rem u with diaeresis
copy_char 136,231 : rem c with cedilla
copy_char 137,241 : rem n tilde
copy_char 138,230 : rem ae
rem char 139 (oe) doesn't exist in ISO 8859-1
copy_char 140,225 : rem a with acute
copy_char 141,224 : rem a with grave
copy_char 142,226 : rem a with circumflex
copy_char 143,235 : rem e with diaeresis
copy_char 144,232 : rem e with grave
copy_char 145,234 : rem e with circumflex
copy_char 146,239 : rem i with diaeresis
copy_char 147,237 : rem i with acute
copy_char 148,236 : rem i with grave
copy_char 149,238 : rem i with circumflex
copy_char 150,243 : rem o with acute
copy_char 151,242 : rem o with grave
copy_char 152,244 : rem o with circumflex
copy_char 153,250 : rem u with acute
copy_char 154,249 : rem u with grave
copy_char 155,251 : rem u with circumflex
copy_char 156,223 : rem sharp s
copy_char 157,162 : rem cent sign
copy_char 158,165 : rem yen sign
copy_char 159,96 : rem grave accent
copy_char 160,196 : rem A with diaeresis
copy_char 161,195 : rem A tilde
copy_char 162,197 : rem A with ring
copy_char 163,201 : rem E with acute
copy_char 164,214 : rem O with diaeresis
copy_char 165,213 : rem O tilde
copy_char 166,216 : rem O with stroke
copy_char 167,220 : rem U with diaeresis
copy_char 168,199 : rem C with cedilla
copy_char 169,209 : rem N tilde
copy_char 170,198 : rem AE
rem char 171 (OE) doesn't exist in ISO 8859-1
rem chars 172-175 (greek letters) don't exist in ISO 8859-1
copy_char 176,181 : rem micro sign
rem chars 177-178 (greek letters) don't exist in ISO 8859-1
copy_char 179,161 : rem inverted exclamation mark
copy_char 180,191 : rem inverted question mark
rem char 181 doesn't exist in ISO 8859-1
copy_char 182,167 : rem section sign
copy_char 183,164 : rem currency sign
copy_char 184,171 : rem left-pointing double angle quotation mark
copy_char 185,187 : rem right-pointing double angle quotation mark
copy_char 186,176 : rem degree sign
copy_char 187,247 : rem division sign
rem chars 188-191 (arrows) don't exist in ISO 8859-1
open_input_font "pc8_combined_font" : rem Code Page 437 font, by Dilwyn Jones
copy_char 152,255 : rem y with diaeresis
copy_char 166,170 : rem feminine ordinal indicator
copy_char 167,186 : rem masculine ordinal indicator
copy_char 169,172 : rem not sign
copy_char 171,189 : rem 1/2
copy_char 172,188 : rem 1/4
copy_char 241,177 : rem plus-minus sign
rem copy_char 248,176 : rem degree sign (already in QL font, character 186)
rem copy_char 250,183 : rem middle dot (it doesn't look fine; it will be redefined)
copy_char 253,178 : rem superscript 2
rem Missing chars have to be defined
rem 166, broken vertical bar
let pattern$(0)="00010000"
let pattern$(1)="00010000"
let pattern$(2)="00010000"
let pattern$(3)="00000000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00010000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 166
rem 168, diaeresis
let pattern$(0)="01000100"
let pattern$(1)="00000000"
let pattern$(2)="00000000"
let pattern$(3)="00000000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 168
rem 174, registered sign
let pattern$(0)="00111000"
let pattern$(1)="01000100"
let pattern$(2)="01110100"
let pattern$(3)="01001100"
let pattern$(4)="01110100"
let pattern$(5)="01001100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 174
rem 175, macron
let pattern$(0)="01111100"
let pattern$(1)="00000000"
let pattern$(2)="00000000"
let pattern$(3)="00000000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 175
rem 179, superscript 3
rem first version
let pattern$(0)="01100000"
let pattern$(1)="00010000"
let pattern$(2)="01100000"
let pattern$(3)="00010000"
let pattern$(4)="01100000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
rem second version
let pattern$(0)="01110000"
let pattern$(1)="00110000"
let pattern$(2)="00010000"
let pattern$(3)="01110000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 179
rem 180, acute accent
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="00000000"
let pattern$(3)="00000000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 180
rem 182, paragraph sign / pilcrow sign
let pattern$(0)="00111100"
let pattern$(1)="01110100"
let pattern$(2)="01110100"
let pattern$(3)="00110100"
let pattern$(4)="00010100"
let pattern$(5)="00010100"
let pattern$(6)="00010100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 182
rem 183, middle dot
let pattern$(0)="00000000"
let pattern$(1)="00000000"
let pattern$(2)="00000000"
let pattern$(3)="00011000"
let pattern$(4)="00011000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 183
rem 184, cedilla
let pattern$(0)="00000000"
let pattern$(1)="00000000"
let pattern$(2)="00000000"
let pattern$(3)="00000000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00010000"
let pattern$(8)="00100000"
pattern_to_char 184
rem 185, superscript 1
rem first version
let pattern$(0)="00110000"
let pattern$(1)="01010000"
let pattern$(2)="00010000"
let pattern$(3)="00010000"
let pattern$(4)="00010000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
rem second version
let pattern$(0)="00100000"
let pattern$(1)="01100000"
let pattern$(2)="00100000"
let pattern$(3)="01110000"
let pattern$(4)="00000000"
let pattern$(5)="00000000"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 185
rem 190, 3/4
rem first version
let pattern$(0)="01110000"
let pattern$(1)="00110000"
let pattern$(2)="00010000"
let pattern$(3)="01111000"
let pattern$(4)="00010000"
let pattern$(5)="00101000"
let pattern$(6)="01011000"
let pattern$(7)="00111100"
let pattern$(8)="00001000"
rem second version
let pattern$(0)="01110000"
let pattern$(1)="00110000"
let pattern$(2)="00011000"
let pattern$(3)="01110000"
let pattern$(4)="00101000"
let pattern$(5)="01011000"
let pattern$(6)="00111100"
let pattern$(7)="00001000"
let pattern$(8)="00000000"
pattern_to_char 190
rem 192, A with grave
let pattern$(0)="00100000"
let pattern$(1)="00010000"
let pattern$(2)="00101000"
let pattern$(3)="01000100"
let pattern$(4)="01111100"
let pattern$(5)="01000100"
let pattern$(6)="01000100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 192
rem 193, A with acute
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="00101000"
let pattern$(3)="01000100"
let pattern$(4)="01111100"
let pattern$(5)="01000100"
let pattern$(6)="01000100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 193
rem 194, A with circumflex
let pattern$(0)="00010000"
let pattern$(1)="00101000"
let pattern$(2)="00000000"
let pattern$(3)="00111000"
let pattern$(4)="01000100"
let pattern$(5)="01111100"
let pattern$(6)="01000100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 194
rem 200, E with grave
let pattern$(0)="00100000"
let pattern$(1)="00010000"
let pattern$(2)="01111100"
let pattern$(3)="01000000"
let pattern$(4)="01111100"
let pattern$(5)="01000000"
let pattern$(6)="01111100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 200
rem 202, E with circumflex
let pattern$(0)="00010000"
let pattern$(1)="00101000"
let pattern$(2)="01111100"
let pattern$(3)="01000000"
let pattern$(4)="01111100"
let pattern$(5)="01000000"
let pattern$(6)="01111100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 202
rem 203, E with diaeresis
let pattern$(0)="01000100"
let pattern$(1)="00000000"
let pattern$(2)="01111100"
let pattern$(3)="01000000"
let pattern$(4)="01111100"
let pattern$(5)="01000000"
let pattern$(6)="01111100"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 203
rem 204, I with grave
let pattern$(0)="00100000"
let pattern$(1)="00010000"
let pattern$(2)="00111000"
let pattern$(3)="00010000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 204
rem 205, I with acute
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="00111000"
let pattern$(3)="00010000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 205
rem 206, I with circumflex
let pattern$(0)="00010000"
let pattern$(1)="00101000"
let pattern$(2)="00000000"
let pattern$(3)="00111000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 206
rem 207, I with diaeresis
let pattern$(0)="00100100"
let pattern$(1)="00000000"
let pattern$(2)="00111000"
let pattern$(3)="00010000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 207
rem 208, capital Eth
let pattern$(0)="00111000"
let pattern$(1)="00100100"
let pattern$(2)="00100100"
let pattern$(3)="01110100"
let pattern$(4)="00100100"
let pattern$(5)="00100100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 208
rem 210, O with grave
let pattern$(0)="00100000"
let pattern$(1)="00010000"
let pattern$(2)="00111000"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 210
rem 211, O with acute
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="00111000"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 211
rem 211, O with circumflex
let pattern$(0)="00010000"
let pattern$(1)="00101000"
let pattern$(2)="00111000"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 212
rem 215, multiplication sign
let pattern$(0)="00000000"
let pattern$(1)="01000100"
let pattern$(2)="00101000"
let pattern$(3)="00010000"
let pattern$(4)="00101000"
let pattern$(5)="01000100"
let pattern$(6)="00000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 215
rem 217, U with grave
let pattern$(0)="00100000"
let pattern$(1)="00010000"
let pattern$(2)="01000100"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 217
rem 218, U with acute
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="01000100"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 218
rem 219, U with circumflex
let pattern$(0)="00010000"
let pattern$(1)="00101000"
let pattern$(2)="01000100"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 219
rem 221, Y with acute
let pattern$(0)="00001000"
let pattern$(1)="01010100"
let pattern$(2)="01000100"
let pattern$(3)="00101000"
let pattern$(4)="00010000"
let pattern$(5)="00010000"
let pattern$(6)="00010000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 221
rem 222, capital Thorn
let pattern$(0)="00000000"
let pattern$(1)="01000000"
let pattern$(2)="01111000"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01111000"
let pattern$(6)="01000000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 222
rem 240, small Eth
let pattern$(0)="00100000"
let pattern$(1)="01111000"
let pattern$(2)="00010000"
let pattern$(3)="00111000"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111000"
let pattern$(7)="00000000"
let pattern$(8)="00000000"
pattern_to_char 240
rem 253, y with acute
let pattern$(0)="00001000"
let pattern$(1)="00010000"
let pattern$(2)="01000100"
let pattern$(3)="01000100"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="00111100"
let pattern$(7)="00000100"
let pattern$(8)="00111000"
pattern_to_char 253
rem 254, small Thorn
let pattern$(0)="00000000"
let pattern$(1)="01000000"
let pattern$(2)="01000000"
let pattern$(3)="01111000"
let pattern$(4)="01000100"
let pattern$(5)="01000100"
let pattern$(6)="01111000"
let pattern$(7)="01000000"
let pattern$(8)="01000000"
pattern_to_char 254
close_input_font
show_output_font
save_output_font output_font$
enddef
rem ---------------- Show the fonts
defproc show_output_font
print output_font$
show_font output_font_address
enddef
defproc show_input_font
rem Used while debugging.
show_font input_font_address
enddef
defproc show_font(font_address)
local column,row,char
char_use font_address,0
print
for column = 0 to 15
print to 2;hex$(column,4);
endfor column
print\\
for row = 0 to 15
print hex$(row,4);
for column = 0 to 15
let char = row*16+column
if char=10
char_use 0,0
print to 2;chr$(0);
char_use font_address,0
else
print to 2;chr$(char);
endif
endfor column
print
endfor row
char_use 0,0
enddef