fontpic

package module
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2025 License: BSD-3-Clause Imports: 12 Imported by: 1

README

fontpic

Goal of the project - allow to easily generate images with text using widely available CGA/EGA/VGA ROM fonts. This can be useful for generating captcha images for website or telegram chats.

It comes with 8x8, 8x14 and 8x16 fonts in DOS 866 (Cyrillic) encoding in fnt directory. Font files 08x08.fnt, 08x14.fnt, 08x16.fnt were distributed with the freeware KeyRus program, and are used in this library by default as a tribute to Dmitry Gurtyak (1971-1998), author of KeyRus.

Currenly the project supports only raw font files, it's easy to tell if it's a raw FNT by looking at the file size:

  • 8x8 - 2048 bytes
  • 8x14 - 3584 bytes
  • 8x16 - 4096 bytes

Where to get more fonts

  1. There is a great project that contains a lot of fonts extracted from different ROMs: romfont
  2. Extract fonts from a BIOS of the old PC. Read the romfont repository README.
  3. Unpack fonts from the Abandonware programs. I.e. DOS distribution includes '*.CPI' files that contain fonts. You can use psf2inc utility to extract them. If you went down that path, you'd probably know what to do with the output.
  4. Convert BDF fonts.

Licensing

BSD 3-clause. See LICENSE.

Included fonts are freeware (c) Dmitry Gurtyak.

Documentation

Overview

Package fontpic is a package for rendering fonts to images.

Index

Constants

View Source
const (
	DefaultWidth  = 720
	DefaultHeight = 540
)
View Source
const (
	// CharsetSz is the number of characters in a font file.  It is unlikely to
	// ever change.
	CharsetSz = 256
)

Variables

View Source
var (
	// Face8x8 is the Keyrus 8x8 face.
	Face8x8 = FntToFace(fntKr8x8, 8, 8)
	// Face8x14 is the Keyrus 8x14 font face.
	Face8x14 = FntToFace(fntKr8x14, 8, 14)
	// Face8x16 is the Keyrus 8x16 font face.
	Face8x16 = FntToFace(fntKr8x16, 8, 16)

	// Face4x4 is Microfont 4x4 font face.
	Face4x4 = &basicfont.Face{
		Advance: 5,
		Width:   8,
		Height:  5,
		Ascent:  4,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntMicrofont[0x20*5:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face4x4Bold is Microfont Bold 4x4 font face.
	Face4x4Bold = &basicfont.Face{
		Advance: 5,
		Width:   8,
		Height:  5,
		Ascent:  4,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntMicrofontBold[0x20*5:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face4x4Italic is Microfont Italic 4x4 font face.
	Face4x4Italic = &basicfont.Face{
		Advance: 5,
		Width:   8,
		Height:  5,
		Ascent:  4,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntMicrofontItalic[0x20*5:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face4x5 is the Millifont 5x4 font face.
	Face4x5 = &basicfont.Face{
		Advance: 4,
		Width:   8,
		Height:  6,
		Ascent:  5,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntMilifont[0x20*6:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face6x5 is the Stupid Simple font face.
	Face6x5 = &basicfont.Face{
		Advance: 6,
		Width:   8,
		Height:  6,
		Ascent:  5,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntStupidsimplefont[0x20*6:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face6x5Bold is the Stupid Simple Bold font face.
	Face6x5Bold = &basicfont.Face{
		Advance: 6,
		Width:   8,
		Height:  6,
		Ascent:  5,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntStupidsimplefontBold[0x20*6:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	// Face6x5Italic is the Stupid Simple Italic font face.
	Face6x5Italic = &basicfont.Face{
		Advance: 6,
		Width:   8,
		Height:  6,
		Ascent:  5,
		Descent: 1,
		Left:    -4,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(fntStupidsimplefontItalic[0x20*6:]),
			Stride: 8,
			Rect:   image.Rectangle{Max: image.Point{8, 96 * 8}},
		},
		Ranges: basicfont.Face7x13.Ranges,
	}

	FaceRobotron = &basicfont.Face{
		Advance: 10,
		Width:   9,
		Height:  18,
		Ascent:  14,
		Descent: 4,
		Left:    7,
		Mask: &image.Alpha{
			Pix:    Bytes2pixels(uint16ToUint8Rev(everySecond(robotronFnt))),
			Stride: krStride * 2,
			Rect:   image.Rectangle{Max: image.Point{16, 173 * 18}},
		},
		Ranges: []basicfont.Range{
			{Low: 32, High: 204, Offset: 0},
			{Low: '\ufffd', High: '\ufffe', Offset: 1},
		},
	}
)
View Source
var (
	// FontDefault is the default font.
	Fnt8x8     = Must(ToFntCharset(fntKr8x8, "866"))
	Fnt8x14    = Must(ToFntCharset(fntKr8x14, "866"))
	Fnt8x16    = Must(ToFntCharset(fntKr8x16, "866"))
	FntDefault = Fnt8x16
)
View Source
var (
	// These fonts are GPL2+ font by mibi88
	// https://git.planet-casio.com/mibi88/microfont/src/branch/master/microfont.png
	//
	//	microfont.png:
	//	  name: microfont
	//	  type: font
	//	  charset: print
	//	  width: 4
	//	  grid.size: 4x4
	//	  grid.padding: 1
	//	  proportional: false
	IFMicrofont = ImageFont{
		Name:        "microfont",
		Width:       4,
		GridSize:    image.Pt(4, 4),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}

	IFMicrofontBold = ImageFont{
		Name:        "microfont_bold",
		Width:       4,
		GridSize:    image.Pt(4, 4),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}
	IFMicrofontItalic = ImageFont{
		Name:        "microfont_italic",
		Width:       4,
		GridSize:    image.Pt(4, 4),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}

	// https://git.planet-casio.com/mibi88/microfont/src/branch/master/milifont.png
	// milifont.png:
	//	name: milifont
	//	type: font
	//	charset: print
	//	width: 3
	//	grid.size: 3x5
	//	grid.padding: 1
	//	proportional: false
	IFMiliFont = ImageFont{
		Name:        "milifont",
		Width:       3,
		GridSize:    image.Pt(3, 5),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}

	IFStupidSimple = ImageFont{
		Name:        "font",
		Width:       5,
		GridSize:    image.Pt(5, 5),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}
	IFStupidSimpleBold = ImageFont{
		Name:        "font_bold",
		Width:       5,
		GridSize:    image.Pt(5, 5),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}
	IFStupidSimpleItalic = ImageFont{
		Name:        "font_italic",
		Width:       5,
		GridSize:    image.Pt(5, 5),
		GridPadding: 1,
		CharStart:   32,
		Transparent: color.Transparent,
		CharEnd:     127,
	}
)

Functions

func Bytes2pixels added in v0.0.5

func Bytes2pixels(b []byte) []byte

Bytes2pixels converts a bytes slice where each bit represents a pixel to a byte slice where each byte represents a pixel. If the source bit is 1, the corresponding byte will be 0xff (white), and if the source pixel is 0, the corresponding byte will be 0x00 (black).

func FntToFace added in v0.0.5

func FntToFace(data []byte, width, height int) *basicfont.Face

FntToFace creates a basicfont.Face from fnt file data. Width and height are the width and height of the font in pixels. The data must be a valid fnt file. It is designed to work with standard 8x8, 8x14 and 8x16 fonts with 256 characters, and might not work correctly with non-standard height and width values. For non-standard fonts, you might want to define your own face based on the basicfont.Face struct, and convert the font data to pixels using Bytes2pixels before assigning it to the Mask.Pix field.

func RenderCharAt

func RenderCharAt(img draw.Image, at image.Point, width, height int, bits []byte, hi color.Color, lo color.Color)

RenderCharAt is a low level function that renders a character, defined in bits, at the given position on the image. It uses width and height to know how to render the character in bits.

Types

type Canvas

type Canvas struct {
	Width      int
	Height     int
	Background color.Color
	Foreground color.Color // Color to use for the font
	Font       *FNT        // Font to use
	Spacing    image.Point // Spacing between characters.
	Scale      image.Point // scaling factor (not used yet)
	// contains filtered or unexported fields
}

Canvas is a canvas that can be rendered to.

The member function naming convention is the following:

  • Render* - renders text or lines of text to the canvas
  • With* - sets a property

Render functions, that have Text in the name do the minimum amount of transformations to the text to make it renderable. For example, tabs are replaced with spaces, and newlines are treated as line separators.

Render functions without Text in the name, render the provided lines of text verbatim, so any \n or \t characters will be rendered as a characters from the supplied font.

Render functions, that have At in the name, render the text at the specified location.

Zero canvas value is usable. It will use the default font, and will render the text in Grey (0xa8) on Black background, just like the good old days.

func NewCanvas

func NewCanvas(defavlt *FNT) *Canvas

NewCanvas creates the new canvas with the default font.

func (*Canvas) CalcSize

func (c *Canvas) CalcSize(lines [][]byte) *Canvas

CalcSize calculates the size of the canvas based on the provided lines of text.

func (*Canvas) Image

func (c *Canvas) Image() draw.Image

func (*Canvas) Render

func (c *Canvas) Render(lines [][]byte) *Canvas

Render renders the lines of text to the canvas.

func (*Canvas) RenderAt

func (c *Canvas) RenderAt(lines [][]byte, at image.Point) *Canvas

RenderAt renders the lines of text at the specified location.

func (*Canvas) RenderText

func (c *Canvas) RenderText(text []byte) *Canvas

RenderText renders the text to the canvas.

func (*Canvas) RenderTextAt

func (c *Canvas) RenderTextAt(text []byte, at image.Point) *Canvas

RenderTextAt renders the text at the specified location.

func (*Canvas) WithBackground

func (c *Canvas) WithBackground(bg color.Color) *Canvas

func (*Canvas) WithFont

func (c *Canvas) WithFont(font *FNT) *Canvas

func (*Canvas) WithForeground

func (c *Canvas) WithForeground(fg color.Color) *Canvas

func (*Canvas) WithImage

func (c *Canvas) WithImage(img draw.Image) *Canvas

func (*Canvas) WithSize

func (c *Canvas) WithSize(w, h int) *Canvas

func (*Canvas) WithSpacing

func (c *Canvas) WithSpacing(x, y int) *Canvas

type FNT added in v0.0.4

type FNT struct {
	Width   int
	Height  int
	Charset string
	Chars   [CharsetSz][]byte
}

func LoadFnt added in v0.0.4

func LoadFnt(filename string, width int) (*FNT, error)

func Must

func Must(fnt *FNT, err error) *FNT

func ToFnt added in v0.0.4

func ToFnt(b []byte, width int) (*FNT, error)

ToFnt converts byte data to a Font structure. It detects the font height based on the slice size.

func ToFnt8 added in v0.0.4

func ToFnt8(b []byte) (*FNT, error)

ToFnt8 is a shortcut for calling ToFont(b, 8).

Usual slice sizes for 8-bit wide fonts:

  1. 8x8 font: 2048 bytes (1x8bytes x 256)
  2. 8x14 font: 3584 bytes (1x14bytes x 256)
  3. 8x16 font: 4096 bytes (1x16bytes x 256)

func ToFntCharset added in v0.0.4

func ToFntCharset(b []byte, charset string) (*FNT, error)

func (*FNT) Bytes added in v0.0.4

func (f *FNT) Bytes() []byte

func (*FNT) Sample added in v0.0.4

func (f *FNT) Sample(perLine int) image.Image

Sample renders a sample of the font. The font is rendered in a grid of perLine characters. The sx and sy parameters are space between characters in pixels

func (*FNT) SampleColor added in v0.0.4

func (f *FNT) SampleColor(perLine int, fg, bg color.Color) image.Image

func (*FNT) TextAt added in v0.0.4

func (f *FNT) TextAt(img draw.Image, x, y int, text []byte, fg, bg color.Color)

func (*FNT) WriteTo added in v0.0.4

func (f *FNT) WriteTo(w io.Writer) (n int64, err error)

type ImageFont added in v0.0.4

type ImageFont struct {
	Name        string
	Width       int
	GridSize    image.Point // Single Character dimensions
	GridPadding int         // amount of whitespace in the image between chars
	CharStart   byte        // ASCII code of the first character
	CharEnd     byte        // ASCII code of the last character
	Image       image.Image
	Transparent color.Color
	Chars       []image.Image
}

ImageFont represents a bitmap font loaded from an image file. A great example of such a font is the MicroFont, which is a 4x4 pixel font with a grid size of 5x4 pixels and a padding of 1 pixel

func (*ImageFont) Bytes added in v0.0.4

func (f *ImageFont) Bytes(ypad uint8) []byte

func (*ImageFont) Char added in v0.0.4

func (f *ImageFont) Char(c byte) image.Image

func (*ImageFont) DrawChar added in v0.0.4

func (f *ImageFont) DrawChar(dst draw.Image, c byte, at image.Point, fg, bg color.Color) error

func (*ImageFont) Load added in v0.0.4

func (f *ImageFont) Load(r io.Reader) error

Load the font.

func (*ImageFont) ToBitmap added in v0.0.4

func (f *ImageFont) ToBitmap(ypad uint8) [256][]byte

ToBitmap converts the font a byte array. Each byte represents a horizontal line of pixels. The first byte is the top row of the first character, the second byte is the second row of the first character, and so on. Each bit in the byte represents a pixel, with the least significant bit being the leftmost pixel. If the bit is set, the pixel is on, otherwise it is off. The array is indexed by the ASCII value of the character.

ypad is how many lines of padding to add to the bottom of each character.

func (*ImageFont) WriteBitmap added in v0.0.4

func (f *ImageFont) WriteBitmap(w io.Writer, ypad uint8) error

func (*ImageFont) WriteString added in v0.0.4

func (f *ImageFont) WriteString(dst draw.Image, s string, at image.Point, fg, bg color.Color) error

func (*ImageFont) XWidth added in v0.0.4

func (f *ImageFont) XWidth(s string) int

Directories

Path Synopsis
cmd
faceview command
fntgen command
Command fntgen is just a sandbox to fuck around.
Command fntgen is just a sandbox to fuck around.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL