Unix pages
Home -> UNIX software -> PSF Tools -> Amstrad Font Redefinition -> LocoScript 2, LocoChar and LocoFont

LocoScript 2, LocoChar and LocoFont

Within LocoScript 2, the dot-matrix printer font is defined either by the printer file MATRIX.PRI (LocoScript 2.00-2.19) or a font file such as MATRIX.#ST (LocoScript 2.12 onward).

Similar font files are also used to store other types of printer font (such as daisywheel layouts, bitmaps for 24-pin printers, or other character mappings). This document only covers files of type 1, fonts for the PCW dot-matrix printer.

Fonts

Standard fonts
The original font is called Standard, and is a derivative of the printer font used in LocoScript 1 (though with detail differences to many of the character shapes).
From LocoScript 2.16, a second font, Sans-Serif, was also supplied.
LocoFont
The LocoFont add-on font pack provides nine additional fonts:
Capitals (small caps)
Copper Plate (no draft version)
Definite (no draft version)
Deco (no draft version)
Finesse (no draft version)
Modern
Roman (no draft version)
Standard 2 (a version of the Standard font similar to the old LocoScript 1 outline)
Script (no draft version)

LocoChar

From version 2.12, LocoScript allows up to 16 characters in a font to be replaced by user-defined characters. The characters available for replacement are the circled digits and the six curly quote characters that follow them.

The program LocoChar performs the redefinition. Starting with one of the standard font files, it allows a custom version of that file to be created, containing replacement screen and printer bitmaps for the 16 user-defined characters. The original LocoChar is written in BASIC; later versions are machine-code programs that run under CP/M.

Font-file format

Conventions

LocoScript saves its files on CP/M-formatted discs, and therefore uses CP/M conventions such as 8.3 filenames and 128-byte records.

A byte is 8 bits. A word is 16 bits, in little-endian format.

Versions

There are three versions of the file format:

Version 1
Used in LocoScript 2.00-2.11. Supports up to 480 characters. User-defined characters not supported.
Version 2
Used in LocoScript 2.12-2.19. Supports up to 480 characters. User-defined characters supported.
Version 3
Used in LocoScript 2.20+. Supports up to 512 characters. User-defined characters supported. The characters are rearranged:
  • In version 2, characters 0-15 are the top halves of double-height characters (tall Sigma, tall Pi etc) and characters 16-31 are combining accents. In version 3, characters 0-31 are combining accents and the double-height characters move to the 272-287 range.
  • Characters 256 and up have their numbers increased by 32.
  • Some character outlines have been redesigned.
  • The PS widths table retains 480 entries, skipping over characters 256-287.
The LocoScript installer contains a specific function to upgrade pre-2.20 font files from version 2 to 3, and a new version of LocoChar was created to support the version 3 format.

File header

Like nearly all LocoScript files, a font begins with a 128-byte header:

Offset	Value			Notes
==============================================================================
00h	'CHR' or 'PRI'		File type ('CHR' for a font, 'PRI' 
				for the printer driver itself)
03h	Major version		1-3, as above
04h	Minor version		Always appears to be 1
05h	Identity		File identity, 3 lines each of 30
				ASCII bytes
5Fh	Word: Link number	Purpose unknown, not used by LocoChar
61h	Word: Checksum		16-bit checksum of file (excluding header)
63h	Word: Length		Length of file in 128-byte records 
				(excluding header)
65h	Style name		12 ASCII bytes
71h	Byte: Style pitch?	LocoChar calls this STYPITCH but does not
				access it.
72h	Byte: Type flags	Bits 0-2: Font type. Possible values include:
					   1 => PCW8000 dot-matrix
					   2 => PCW9000 daisywheel
					   3 => External printer driven
					        using text (eg 9-pin matrix
                                                or daisywheel)
					   4 => External 24-pin dot-matrix
				Bit 3: Set for a font, clear for the printer 
				      driver itself.
				Bit 4: Set for a dot-matrix character set
73h	8 bytes: Driver		LocoChar calls this DRIVER but does not 
				access it.
7Bh	Word: Font offset	Offset to the font within this file
7Dh	Word			LocoChar calls this OPTIONS but does not 
				access it.
7Fh	Byte: Checksum		8-bit checksum of the preceding 127 bytes
==============================================================================

For a font file, the offset to the font is 0x80 (ie, the font immediately follows the header). For a printer driver file, the driver comes first and the font further on.

Font data

Taking 0 as the start of the font, it has this format:

Offset	Value			Notes
==============================================================================
0000h	12 bytes: Char set 	Character set name
000Ch	2 bytes			Unknown
000Eh	1 byte			Bit 7 set if all bitmaps are uncompressed?
000Fh	1 byte			Flags. Bit 6 is set if the screen characters
				have been redesigned.
------------------------------------------------------------------------------
0010h	240 bytes		PS widths table: Widths for 480 characters.
				For character n, the width is at entry (n/2),
				with the low nibble giving the width of the
				even-numbered character and the high nibble
				giving the width of the odd-numbered character.
				Add 9 to the value to get the actual PS width.
------------------------------------------------------------------------------
0100h	128 bytes (v2/v3 only)  16 8x8 bitmaps giving the screen appearance 
                                of the user-defined characters.
------------------------------------------------------------------------------
	1922 bytes (v1/v2)	Index table; four bytes per character, plus
	2050 bytes (v3)		one extra word for end of file. Index entries 
				are defined below.
------------------------------------------------------------------------------
	124 bytes		NLQ character bitmaps (second pass)
	124 bytes		NLQ character bitmaps (first pass)
	124 bytes		Draft character bitmaps
------------------------------------------------------------------------------
	varies			Character pattern data
==============================================================================

Each index entry is formed:

	DW	offset
	DB	flags
	DB	extra

The top three bits of the offset indicate how the rest of the offset is to be treated:

Offset 0E000h-0FFFFh
This is an accented character. Bits 13-0 of the offset give the base character number. Bits 4-0 of the flags give the accent character number. For example, character 200 (รข) might be stored as 61 E0 03 42. Offset 0E061h means the base character is 61h ('a'). Flags 03h mean the accent number is 3 (circumflex — character 13h in v1/v2 files, character 03h in v3 files).
Offset 0C000h-0DFFFh
This is a duplicate character. Bits 13-0 of the offset give the duplicate character. For example, character 352 (capital Alpha) might be stored as 41 C0 FF 57. Offset 0C041h means the shape from character 41h ('A') is used.
Offset 08000h-0BFFFh
This is an uncompressed character (normally this would apply only to user-defined characters). Bits 13-0 of the offset give the address of its bitmaps relative to the start of the index table. The bitmaps are a standard size: 11 bytes for draft, 48 for NLQ.
Offset 00000h-03FFFh
This is a standard character. Bits 13-0 of the offset give the address of its bitmaps relative to the start of the index table. The low 4 bits of byte 3 ('extra') give length of the 'draft' bitmap, and the remainder is the 'NLQ' bitmap.

For characters with offset above 0C000h, byte 3 (extra) is used to calculate the length of the previous character. This is normally calculated as (offset of next character & 0x7FFF) - (offset of this character & 07FFF). However if the next character is an accent or other cross-reference, the offset needs to be calculated from byte 3:

	if (char[n].offset & 0x4000) 
	{
		return 0;	/* This character is a reference */
	}
	else if (char[n+1].offset & 0x4000) 
	{
		/* Next character is a reference */
		unsigned offset2 = (char[n].offset & 0x1F00) | char[n+1].extra;
		if (offset2 < (char[n].offset & 0x1FFF)) offset2 += 0x100;
		length = offset2 - (char[n].offset & 0x1FFF);
	}
	else
	{
		/* Next character is not a reference */ 
		length = (char[n+1].offset & 0x1FFF) - (char[n].offset & 0x1FFF);
	}

For a character that isn't a reference, the flags byte has the following meaning:

Bit    7: Character shifted down. Shifted-down characters are printed on the 
	  bottom 8 printer pins, rather than the top 8; intended for 
          characters with descenders.
Bit    6: Character is shifted down when an accent is superimposed on it.
Bit    5: Character cannot be copied in LocoChar. Set on the large mathematical 
          symbols (large Pi, large Sigma etc.) because they are drawn in two
          halves, top and bottom.
Bit    4: Accent replaces a dot (eg, on 'i' or 'j'). Any non-blank line from
	  the accent will completely replace the corresponding line from the
	  character.
Bits 3-0: Proportional spacing columns minus 11

For a character that isn't a reference, the 'extra' byte has the following meaning:

Bits 7-5: Blank columns at left (NLQ)
Bit    4: Blank column at left (draft)
Bits 3-0: Number of bytes in draft character shape (compressed characters)				

For compressed characters, following the offset in the index table leads you to the draft-mode pattern. 'extra' gives the length of the draft-mode pattern in bytes; add it to the offset to get the address of the NLQ pattern.

In the pattern, bit 7 of a byte is set if it should be preceded by a blank column. Bits 6-0 give a pattern number:

00h-7Bh
Bitmap reference. The bitmaps begin immediately after the index table; I have called this address index_end.
NLQ (v1)
There is a table of bitmaps at index_end, containing 124 words. Within each word, the high byte is for the first pass and the low byte is for the second pass.
NLQ (v2/v3)
There are two tables of bitmaps, each containing 124 bytes. The bitmaps for the first pass are at index_end + 7Ch and the bitmaps for the second pass are at index_end.
Draft
There is a single set of bitmaps, at index_end + 0F8h.
Within each bitmap byte, bit 0 is the top pin and bit 7 is the bottom pin.
7Ch
Literal (only found in NLQ patterns). Followed by two bytes giving the pin bitmaps for the second and first passes.
7Dh-7Fh
Repeat. The following column is repeated value-79h times.

For uncompressed characters, following the offset in the index table leads you to 11 bytes giving the character bitmap for draft mode, followed by 48 defining it in NLQ mode.

The draft mode shape is 11 bytes. In each byte, bits 0-7 give the pin bitmap (bit 0 is the top pin, bit 7 the bottom).

The NLQ mode shape is 24 words. In each word, the high 8 bits give the pin bitmap on the first pass, and the low 8 bits the pin bitmap on the second pass.


John Elliott 2022-02-02