From 1f2b1dedccdf21b629c45ece80b4ca32f6653296 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Wed, 13 Apr 2022 18:00:18 +1000 Subject: Quantum Painter (#10174) * Install dependencies before executing unit tests. * Split out UTF-8 decoder. * Fixup python formatting rules. * Add documentation for QGF/QFF and the RLE format used. * Add CLI commands for converting images and fonts. * Add stub rules.mk for QP. * Add stream type. * Add base driver and comms interfaces. * Add support for SPI, SPI+D/C comms drivers. * Include when enabled. * Add base support for SPI+D/C+RST panels, as well as concrete implementation of ST7789. * Add support for GC9A01. * Add support for ILI9341. * Add support for ILI9163. * Add support for SSD1351. * Implement qp_setpixel, including pixdata buffer management. * Implement qp_line. * Implement qp_rect. * Implement qp_circle. * Implement qp_ellipse. * Implement palette interpolation. * Allow for streams to work with either flash or RAM. * Image loading. * Font loading. * QGF palette loading. * Progressive decoder of pixel data supporting Raw+RLE, 1-,2-,4-,8-bpp monochrome and palette-based images. * Image drawing. * Animations. * Font rendering. * Check against 256 colours, dump out the loaded palette if debugging enabled. * Fix build. * AVR is not the intended audience. * `qmk format-c` * Generation fix. * First batch of docs. * More docs and examples. * Review comments. * Public API documentation. --- docs/quantum_painter_qff.md | 103 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 docs/quantum_painter_qff.md (limited to 'docs/quantum_painter_qff.md') diff --git a/docs/quantum_painter_qff.md b/docs/quantum_painter_qff.md new file mode 100644 index 0000000000..f62d59bdcb --- /dev/null +++ b/docs/quantum_painter_qff.md @@ -0,0 +1,103 @@ +# QMK Font Format :id=qmk-font-format + +QMK uses a font format _("Quantum Font Format" - QFF)_ specifically for resource-constrained systems. + +This format is capable of encoding 1-, 2-, 4-, and 8-bit-per-pixel greyscale- and palette-based images into a font. It also includes RLE for pixel data for some basic compression. + +All integer values are in little-endian format. + +The QFF is defined in terms of _blocks_ -- each _block_ contains a _header_ and an optional _blob_ of data. The _header_ contains the block's _typeid_, and the length of the _blob_ that follows. Each block type is denoted by a different _typeid_ has its own block definition below. All blocks are defined as packed structs, containing zero padding between fields. + +The general structure of the file is: + +* _Font descriptor block_ +* _ASCII glyph block_ (optional, only if ASCII glyphs are included) +* _Unicode glyph block_ (optional, only if Unicode glyphs are included) +* _Font palette block_ (optional, depending on frame format) +* _Font data block_ + +## Block Header :id=qff-block-header + +The block header is identical to [QGF's block header](quantum_painter_qgf.md#qgf-block-header), and is present for all blocks, including the font descriptor. + +## Font descriptor block :id=qff-font-descriptor + +* _typeid_ = 0x00 +* _length_ = 20 + +This block must be located at the start of the file contents, and can exist a maximum of once in an entire QGF file. It is always followed by either the _ASCII glyph table_ or the _Unicode glyph table_, depending on which glyphs are included in the font. + +_Block_ format: + +```c +typedef struct __attribute__((packed)) qff_font_descriptor_v1_t { + qgf_block_header_v1_t header; // = { .type_id = 0x00, .neg_type_id = (~0x00), .length = 20 } + uint24_t magic; // constant, equal to 0x464651 ("QFF") + uint8_t qff_version; // constant, equal to 0x01 + uint32_t total_file_size; // total size of the entire file, starting at offset zero + uint32_t neg_total_file_size; // negated value of total_file_size, used for detecting parsing errors + uint8_t line_height; // glyph height in pixels + bool has_ascii_table; // whether the font has an ascii table of glyphs (0x20...0x7E) + uint16_t num_unicode_glyphs; // the number of glyphs in the unicode table -- no table specified if zero + uint8_t format; // frame format, see below. + uint8_t flags; // frame flags, see below. + uint8_t compression_scheme; // compression scheme, see below. + uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented) +} qff_font_descriptor_v1_t; +// _Static_assert(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF"); +``` + +The values for `format`, `flags`, `compression_scheme`, and `transparency_index` match [QGF's frame descriptor block](quantum_painter_qgf.md#qgf-frame-descriptor), with the exception that the `delta` flag is ignored by QFF. + +## ASCII glyph table :id=qff-ascii-table + +* _typeid_ = 0x01 +* _length_ = 290 + +If the font contains ascii characters, the _ASCII glyph block_ must be located directly after the _font descriptor block_. + +```c +#define QFF_GLYPH_WIDTH_BITS 6 +#define QFF_GLYPH_WIDTH_MASK ((1<