commit 5c45736740e5e63439692615506078427913ea18 Author: Neil Stockbridge Date: Tue Jul 20 13:11:09 2010 +1200 The source files are now under revision control diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0daf880 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ + +PROJECT = setfont2 +STAGING_DIR = $(HOME)/nanonote/openwrt-xburst/staging_dir +ROOT_DIR = $(STAGING_DIR)/target-mipsel_uClibc-0.9.30.1 +#ROOT_DIR = "" +CC = $(STAGING_DIR)/toolchain-mipsel_gcc-4.3.3+cs_uClibc-0.9.30.1/usr/bin/mipsel-openwrt-linux-uclibc-gcc +STRIP = $(STAGING_DIR)/toolchain-mipsel_gcc-4.3.3+cs_uClibc-0.9.30.1/usr/mipsel-openwrt-linux-uclibc/bin/strip +#STRIP = strip +CFLAGS = -Wall -Os +INCLUDES = -I. -I$(ROOT_DIR)/usr/include +LIBS = -L$(ROOT_DIR)/usr/lib +PARTS = setfont2.o + +.c.o: + $(RM) $@ + $(CC) -c $(CFLAGS) $(DEFINES) $(INCLUDES) $*.c + +.SILENT: + +all: $(PROJECT) + +$(PROJECT): $(PARTS) + $(CC) -Wl,-rpath-link=$(ROOT_DIR)/usr/lib $(DEFINES) $(LIBS) -o $(PROJECT) $(PARTS) + $(STRIP) $(PROJECT) + +clean: + rm -f *.o $(PROJECT) + diff --git a/fonts/un-fuzzy-4x8-font.pnm b/fonts/un-fuzzy-4x8-font.pnm new file mode 100644 index 0000000..45d2381 Binary files /dev/null and b/fonts/un-fuzzy-4x8-font.pnm differ diff --git a/fonts/un-fuzzy-6x10-font.pnm b/fonts/un-fuzzy-6x10-font.pnm new file mode 100644 index 0000000..826cc37 Binary files /dev/null and b/fonts/un-fuzzy-6x10-font.pnm differ diff --git a/setfont2.c b/setfont2.c new file mode 100644 index 0000000..6fbd16b --- /dev/null +++ b/setfont2.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2010 Neil Stockbridge + * LICENSE: GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef char bool; +#define false 0 +#define true 1 + + +// This console magic is gratefully pinched from consolechars +int is_a_console(int fd) +{ + char arg; + + arg = 0; + return (ioctl(fd, KDGKBTYPE, &arg) == 0 + && ((arg == KB_101) || (arg == KB_84))); +} + +static int open_a_console(char *fnam) +{ + int fd; + + /* try read-only */ + fd = open(fnam, O_RDWR); + + /* if failed, try read-only */ + if (fd < 0 && errno == EACCES) + fd = open(fnam, O_RDONLY); + + /* if failed, try write-only */ + if (fd < 0 && errno == EACCES) + fd = open(fnam, O_WRONLY); + + /* if failed, fail */ + if (fd < 0) + return -1; + + /* if not a console, fail */ + if (! is_a_console(fd)) + { + close(fd); + return -1; + } + + /* success */ + return fd; +} + +int get_console_fd() +{ + int fd; + + fd = open_a_console("/dev/tty"); + if (fd >= 0) + return fd; + + fd = open_a_console("/dev/tty0"); + if (fd >= 0) + return fd; + + fd = open_a_console("/dev/console"); + if (fd >= 0) + return fd; + + for (fd = 0; fd < 3; fd++) + if (is_a_console(fd)) + return fd; + + fprintf(stderr, + "Couldnt get a file descriptor referring to the console\n"); + return -1; +} + + +typedef enum +{ + EXPECTING_FINGERPRINT, + EXPECTING_DIMENSIONS, + EXPECTING_MAXVAL, +} +ParserState; + + +typedef struct +{ + uint16_t width; + uint16_t height; + uint16_t maximum_value; + uint8_t *data; +} +Image; + + +// Loads a PNM P6 image ( 24-bit colour with binary pixel data). +// Returns 0 if the image was successfully loaded, non-zero on error. On +// error, the "error" pointer will refer to a human-readable description of +// what was wrong. +// The fields in the "image" struct may be in an undefined state on error. +// The "data" field of the image must be passed to free() when no longer +// required. +// +int load_pnm_p6( char *path_to_file, Image *image, char **error) +{ + /* EXAMPLE PNM P6 HEADER: +P6 +# CREATOR: GIMP PNM Filter Version 1.1 +128 24 +255 + + */ + FILE *f = fopen( path_to_file, "r"); + if ( NULL == f) { + *error = "Could not open file"; + return 1; // TODO - proper error code + } + + char line_store[ 80]; + ParserState state = EXPECTING_FINGERPRINT; + bool reading_header = true; + int outcome = 1; // indicating an error + + while ( reading_header) + { + char *line = fgets( line_store, sizeof(line_store), f); + + if ( NULL == line) + { + *error = "Premature end of file"; + goto tidy_up; + } + + switch ( state) + { + case EXPECTING_FINGERPRINT: + // Check that the file is in fact a P6 PNM file + if ( 0 == strcmp("P6\n", line)) { + state = EXPECTING_DIMENSIONS; + } + else { + *error = "Not a PNM P6 file"; + goto tidy_up; + } + break; + case EXPECTING_DIMENSIONS: + // If this line does NOT contain a comment.. + if ( line[ 0] != '#') + { + // Try to get the dimensions of the image from the line + int count = sscanf( line, "%hu %hu\n", &image->width, &image->height); + if ( count != 2) { + *error = "Bad dimensions line"; + goto tidy_up; + } + state = EXPECTING_MAXVAL; + } + break; + case EXPECTING_MAXVAL: + { + // Try to get the maximum pixel value in the image from the line + int count = sscanf( line, "%hu\n", &image->maximum_value); + if ( count != 1) { + *error = "Bad maxval line"; + goto tidy_up; + } + // The binary data follows the Depth line + reading_header = false; + } + } + } + + image->data = malloc( 3 * image->width * image->height); + size_t rows_read = fread( image->data, 3 * image->width, image->height, f); + if ( rows_read != image->height) + { + *error = "Some data is missing"; + goto tidy_up; + } + + // Indicate that no error occurred + outcome = 0; + + tidy_up: + fclose( f); + + return outcome; +} + + +int main( int argc, char **argv) +{ + if ( argc != 2) + { + fprintf( stderr, "Use: %s path-to-glyph-sheet.pnm\n", argv[0]); + exit( 1); + } + + // Load the glyph sheet from the PNM file + Image image; + char *error; + int outcome = load_pnm_p6( argv[1], &image, &error); + if ( outcome != 0) + { + fprintf( stderr, "Could not load glyph sheet: %s\n", error); + exit( 1); + } + + bool should_emit_data = false; + + // The glyph sheet is expected to have 8 rows of 32 glyphs. The image + // dimensions will be used to determine the glyph cell dimensions. + uint8_t pixels_across_glyph = image.width / 32; + uint8_t pixels_down_glyph = image.height / 8; + uint8_t bytes_across_glyph = 4 * pixels_across_glyph; + uint8_t bytes_per_glyph = bytes_across_glyph * pixels_down_glyph; + + uint16_t charcount = 256; + unsigned char data[ bytes_per_glyph * charcount]; + + // Initialize the kernel glyph sheet so that unused pixels are empty + memset( data, 0x00, sizeof(data)); + + int ch, y, x; + for ( ch = 0; ch < 256; ++ch) + { + // Work out the row number on the glyph sheet of the glyph for "ch" + // There are 8 rows of 32 glyphs on the image + uint8_t glyph_sheet_row = ch / 32; + uint8_t glyph_sheet_column = ch % 32; + uint8_t top_edge_of_glyph = pixels_down_glyph * glyph_sheet_row; + uint8_t left_edge_of_glyph = pixels_across_glyph * glyph_sheet_column; + + if ( should_emit_data) { + printf("%c\n", ch); + } + + for ( y = 0; y < pixels_down_glyph; ++ y) + { + uint8_t *file_glyph_row = &image.data[ 3 * ( image.width * ( top_edge_of_glyph + y) + left_edge_of_glyph)]; + uint8_t *kernel_glyph_row = &data[ bytes_per_glyph * ch + bytes_across_glyph * y]; + if ( bytes_per_glyph * ch + bytes_across_glyph * y + bytes_across_glyph <= sizeof(data)) + { + // Copy the row of pixels from the file sheet to the kernel sheet + for ( x = 0; x < pixels_across_glyph; ++ x) + { + kernel_glyph_row[ 4*x + 0] = file_glyph_row[ 3*x + 2]; + kernel_glyph_row[ 4*x + 1] = file_glyph_row[ 3*x + 1]; + kernel_glyph_row[ 4*x + 2] = file_glyph_row[ 3*x + 0]; + if ( should_emit_data) { + uint8_t *row = kernel_glyph_row + 4*x; + printf("%02hx,%02hx,%02hx,%02hx ", row[0], row[1], row[2], row[3]); + } + } + if ( should_emit_data) { + printf("\n"); + } + } + else { + fprintf( stderr, "Shit\n"); + goto tidy_up; + } + } + } + + // Leave a fingerprint of this non-standard font so the kernel can recognise + // it as such + *(uint32_t*)data = 0x6a127efd; + + struct console_font_op request = { op: KD_FONT_OP_SET, + width: pixels_across_glyph, + height: pixels_down_glyph, + charcount: 256, + data: data, + }; + + if ( ioctl( get_console_fd(), KDFONTOP, &request)) { + perror("Bugger"); + } + + tidy_up: + free( image.data); + + return 0; +} +