Transfonter

Description of the page content

Tool written in SBASIC that creates an ISO 8859-1 QL font.

Tags:

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

ISO 8859-1 fontResult

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

Downloads