Last active
December 8, 2023 13:38
-
-
Save Makistos/694804b76ac7c1964bf925ab43eb79ea to your computer and use it in GitHub Desktop.
Render psf fonts to terminal. #c #linux #psf #fonts #libz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
src = $(wildcard *.c) | |
obj = $(src:.c=.o) | |
LDFLAGS = -lz | |
psf: $(obj) | |
$(CC) -o $@ $^ $(LDFLAGS) | |
.PHONY: clean | |
clean: | |
rm -f $(obj) psf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <zlib.h> | |
#include <errno.h> | |
#include <stdarg.h> | |
#include <uchar.h> | |
#define SLOGD(x,...) printf(x, __VA_ARGS__) | |
#define SLOGE(x,...) printf(x, __VA_ARGS__) | |
#define PSF1_MAGIC0 0x36 | |
#define PSF1_MAGIC1 0x04 | |
#define PSF1_MODE512 0x01 | |
#define PSF1_MODEHASTAB 0x02 | |
#define PSF1_MODEHASSEQ 0x04 | |
#define PSF1_MAXMODE 0x05 | |
#define PSF1_SEPARATOR 0xFFFF | |
#define PSF1_STARTSEQ 0xFFFE | |
struct psf1_header { | |
unsigned char magic[2]; /* Magic number */ | |
unsigned char mode; /* PSF font mode */ | |
unsigned char charsize; /* Character size */ | |
}; | |
#define PSF1_MAGIC_OK(x) ( \ | |
(x)->magic[0] == PSF1_MAGIC0 \ | |
&& (x)->magic[1] == PSF1_MAGIC1 \ | |
) | |
enum { | |
PSF2_MAGIC0 = 0x72, | |
PSF2_MAGIC1 = 0xb5, | |
PSF2_MAGIC2 = 0x4a, | |
PSF2_MAGIC3 = 0x86, | |
PSF2_HAS_UNICODE_TABLE = 0x01, | |
PSF2_MAXVERSION = 0, | |
PSF2_STARTSEQ = 0xfe, | |
PSF2_SEPARATOR = 0xff | |
}; | |
struct psf2_header { | |
unsigned char magic[4]; | |
unsigned int version; | |
unsigned int headersize; /* offset of bitmaps in file */ | |
unsigned int flags; | |
unsigned int length; /* number of glyphs */ | |
unsigned int charsize; /* number of bytes for each character */ | |
unsigned int height; /* max dimensions of glyphs */ | |
unsigned int width; /* charsize = height * ((width + 7) / 8) */ | |
}; | |
#define psf2h(x) ((struct psf2_header*)(x)) | |
#define PSF2_MAGIC_OK(x) ( \ | |
(x)->magic[0] == PSF2_MAGIC0 \ | |
&& (x)->magic[1] == PSF2_MAGIC1 \ | |
&& (x)->magic[2] == PSF2_MAGIC2 \ | |
&& (x)->magic[3] == PSF2_MAGIC3 \ | |
) | |
static uint8_t *glyphs_buttons; | |
static void render_char(wchar_t c, uint8_t *glyphs, struct psf2_header *header) | |
{ | |
uint8_t *glyph = &glyphs[c * header->charsize]; | |
uint32_t stride = header->charsize / header->height; | |
uint32_t y0; | |
uint32_t x0; | |
printf("Index = %d (0x%x)\n", c, c); | |
printf("Pos = %d (0x%x)\n", header->headersize + c * header->charsize, header->headersize + c * header->charsize); | |
if (glyph == NULL) { | |
SLOGE("No fonts provided for %c.\n", c); | |
return; | |
} | |
for (y0 = 0; y0 < header->height; ++y0) { | |
for (x0 = 0; x0 < header->width; ++x0) { | |
uint8_t bits = glyph[y0 * stride + x0 / 8]; | |
uint8_t bit = bits >> (7 - x0 % 8) & 1; | |
if (bit) printf("%c", '0'); | |
else printf("%c", ' '); | |
} | |
printf("\n"); | |
} | |
} | |
void print_header(struct psf2_header *header, const char *font_file) | |
{ | |
SLOGD("=== FONT INFO for %s ===\n", font_file); | |
if (PSF2_MAGIC_OK(header)) { | |
printf("PSF2 format\n"); | |
} else { | |
printf("PSF1 format\n"); | |
} | |
SLOGD("magic = %x%x%x%x\n", header->magic[0], header->magic[1], header->magic[2], header->magic[3]); | |
SLOGD("version = %d\n", header->version); | |
SLOGD("headersize = %d\n", header->headersize); | |
SLOGD("flags = %d\n", header->flags); | |
SLOGD("length = %d\n", header->length); | |
SLOGD("charsize = %d\n", header->charsize); | |
SLOGD("height = %d\n", header->height); | |
SLOGD("width = %d\n", header->width); | |
} | |
static int load_font(const char *font_file, uint8_t **glyphs, struct psf2_header **header) | |
{ | |
*header = (struct psf2_header*)malloc(sizeof(struct psf2_header)); | |
printf("foo"); | |
gzFile font = gzopen(font_file, "r"); | |
if (font == NULL) { | |
SLOGE("Failed to load font %s\n", font_file); | |
return ENOENT; | |
} | |
gzread(font, *header, sizeof(struct psf2_header)); | |
print_header(*header, font_file); | |
if (PSF2_MAGIC_OK(*header) == 0) { | |
SLOGD("Magic nof PSF2 for font %s\n", font_file); | |
return EBFONT; | |
} | |
*glyphs = (uint8_t*)malloc((*header)->length*(*header)->charsize); | |
gzread(font, *glyphs, (*header)->charsize * (*header)->length); | |
return 0; | |
} | |
static int load_font_psf1(const char *font_file, uint8_t **glyphs, struct psf2_header **header) | |
{ | |
struct psf1_header *tmp_header; | |
*header = (struct psf2_header*)malloc(sizeof(struct psf2_header)); | |
tmp_header = (struct psf1_header*)malloc(sizeof(struct psf1_header)); | |
gzFile font = gzopen(font_file, "r"); | |
if (font == NULL) { | |
SLOGE("Failed to load font %s\n", font_file); | |
return ENOENT; | |
} | |
gzread(font, tmp_header, sizeof(struct psf1_header)); | |
if (PSF1_MAGIC_OK(tmp_header) == 0) { | |
SLOGD("Magic nof PSF2 for font %s\n", font_file); | |
return EBFONT; | |
} | |
(*header)->headersize = sizeof(struct psf2_header); | |
if (tmp_header->mode & PSF1_MODE512) { | |
(*header)->length = 512; | |
} else { | |
(*header)->length = 256; | |
} | |
(*header)->magic[0] = tmp_header->magic[0]; | |
(*header)->magic[1] = tmp_header->magic[1]; | |
(*header)->flags = tmp_header->mode; | |
(*header)->charsize = tmp_header->charsize; | |
(*header)->width = 8; | |
(*header)->height = tmp_header->charsize; | |
print_header(*header, font_file); | |
*glyphs = (uint8_t*)malloc((*header)->length*(*header)->charsize); | |
gzread(font, *glyphs, (*header)->charsize * (*header)->length); | |
free(tmp_header); | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
struct psf2_header *font_header; | |
int retval; | |
printf("argc = %d\n", argc); | |
if (argc < 1) { | |
printf("No font file or character defined.\n"); | |
return -1; | |
} | |
font_header = (struct psf2_header*)malloc(sizeof(struct psf2_header)); | |
retval = load_font(argv[1], &glyphs_buttons, &font_header); | |
if (retval == EBFONT) { | |
retval = load_font_psf1(argv[1], &glyphs_buttons, &font_header); | |
} | |
if (argc == 3) { | |
printf("Printing character %c\n", argv[2][0]); | |
render_char(argv[2][0], glyphs_buttons, font_header); | |
} else { | |
for (int i = 0; i < font_header->length; i++) { | |
render_char(i, glyphs_buttons, font_header); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment