Skip to content

Instantly share code, notes, and snippets.

@damieng
Last active December 7, 2025 12:45
Show Gist options
  • Select an option

  • Save damieng/684516231c92158457b0d95efb0e5ec0 to your computer and use it in GitHub Desktop.

Select an option

Save damieng/684516231c92158457b0d95efb0e5ec0 to your computer and use it in GitHub Desktop.
Convert LINC manual charset octets to Speccy CH8 file
using System.Collections.Generic;
using var outFile = File.OpenWrite("linc.ch8");
for (var x = 32; x < 128; x++)
{
byte[] c = [0, 0, 0, 0, 0, 0, 0, 0];
if (CharacterPatterns.Patterns.TryGetValue(Convert.ToChar(x), out var pattern))
{
c = CharacterPatterns.MapPatternToRaw(pattern);
}
for (var y = 0; y < 8; y++)
outFile.WriteByte(c[y]);
}
static class CharacterPatterns
{
public static byte[] MapPatternToRaw(string[] octets)
{
var bitstream = OctalToBitstream(octets);
var pixels = BitstreamToGlyph(bitstream);
//Dump8x8Glyph(pixels);
return GlyphToCh8(pixels);
}
private static byte[] GlyphToCh8(bool[,] pixels)
{
var font = new byte[8];
for (var row = 0; row < 8; row++)
{
byte byteVal = 0;
for (var col = 0; col < 8; col++)
{
if (pixels[col, row])
{
byteVal |= (byte)(1 << (7 - col));
}
}
font[row] = byteVal;
}
return font;
}
private static void Dump8x8Glyph(bool[,] pixels)
{
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
Console.Write(pixels[x, y] ? "#" : "_");
}
Console.WriteLine();
}
Console.WriteLine();
}
private static bool[,] BitstreamToGlyph(List<bool> bits)
{
var pixels = new bool[8, 8];
{
var x = 2;
var y = 6;
foreach (var t in bits)
{
pixels[x, y--] = t;
if (y == 0)
{
y = 6;
x++;
}
}
}
return pixels;
}
private static List<bool> OctalToBitstream(string[] octets)
{
// Convert octal strings to bits
var bits = new List<bool>();
foreach (var octal in octets.Reverse())
{
foreach (var digitChar in octal)
{
// Extract 3 bits from each octal digit (MSB first)
var digit = digitChar - '0';
bits.Add((digit & 4) == 4);
bits.Add((digit & 2) == 2);
bits.Add((digit & 1) == 1);
}
}
bits.Reverse();
return bits;
}
public static readonly Dictionary<char, string[]> Patterns = new()
{
{ '0', ["4136", "3641"] },
{ '1', ["2101", "0177"] },
{ '2', ["4523", "2151"] },
{ '3', ["4122", "2651"] },
{ '4', ["2414", "0477"] },
{ '5', ["5172", "0651"] },
{ '6', ["1506", "4225"] },
{ '7', ["4443", "6050"] },
{ '8', ["5126", "2651"] },
{ '9', ["5120", "3651"] },
{ 'A', ["4477", "7744"] },
{ 'B', ["5177", "2651"] },
{ 'C', ["4136", "2241"] },
{ 'D', ["4177", "3641"] },
{ 'E', ["4577", "4145"] },
{ 'F', ["4477", "4044"] },
{ 'G', ["4136", "2645"] },
{ 'H', ["1077", "7710"] },
{ 'I', ["7741", "0041"] },
{ 'J', ["4142", "4076"] },
{ 'K', ["1077", "4324"] },
{ 'L', ["0177", "0301"] },
{ 'M', ["3077", "7730"] },
{ 'N', ["3077", "7706"] },
{ 'O', ["4177", "7741"] },
{ 'P', ["4477", "3044"] },
{ 'Q', ["4276", "0376"] },
{ 'R', ["4477", "3146"] },
{ 'S', ["5121", "4651"] },
{ 'T', ["4040", "4077"] },
{ 'U', ["0177", "7701"] },
{ 'V', ["0176", "7402"] },
{ 'W', ["0677", "7701"] },
{ 'X', ["1463", "6314"] },
{ 'Y', ["0770", "7007"] },
{ 'Z', ["4543", "6151"] },
{ '=', ["1212", "1212"] },
{ 'u', ["0107", "0107"] },
{ ',', ["0500", "0006"] },
{ '.', ["0001", "0000"] },
{ '\u25a1', ["4577", "7745"] }, // Box character
{ '[', ["4177", "0000"] },
{ 'i', ["0101", "0126"] },
{ 'p', ["3700", "3424"] },
{ '-', ["0404", "0404"] },
{ '+', ["0404", "0437"] },
{ '|', ["0000", "0077"] },
{ '#', ["3614", "1436"] },
{ ' ', ["0000", "0000"] }, // SPACE
{ '\0', ["0000", "0000"] } // NULL/EOL/del/CASE
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment