Root/setfont2.c

1/*
2 * Copyright (C) 2010 Neil Stockbridge
3 * LICENSE: GPL
4 */
5
6#include <fcntl.h>
7#include <errno.h>
8#include <linux/kd.h>
9#include <malloc.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/ioctl.h>
15#include <unistd.h>
16
17
18typedef char bool;
19#define false 0
20#define true 1
21
22
23// This console magic is gratefully pinched from consolechars
24int is_a_console(int fd)
25{
26  char arg;
27
28  arg = 0;
29  return (ioctl(fd, KDGKBTYPE, &arg) == 0
30    && ((arg == KB_101) || (arg == KB_84)));
31}
32
33static int open_a_console(char *fnam)
34{
35  int fd;
36
37  /* try read-only */
38  fd = open(fnam, O_RDWR);
39
40  /* if failed, try read-only */
41  if (fd < 0 && errno == EACCES)
42      fd = open(fnam, O_RDONLY);
43
44  /* if failed, try write-only */
45  if (fd < 0 && errno == EACCES)
46      fd = open(fnam, O_WRONLY);
47
48  /* if failed, fail */
49  if (fd < 0)
50      return -1;
51
52  /* if not a console, fail */
53  if (! is_a_console(fd))
54    {
55      close(fd);
56      return -1;
57    }
58
59  /* success */
60  return fd;
61}
62
63int get_console_fd()
64{
65  int fd;
66
67  fd = open_a_console("/dev/tty");
68  if (fd >= 0)
69    return fd;
70
71  fd = open_a_console("/dev/tty0");
72  if (fd >= 0)
73    return fd;
74
75  fd = open_a_console("/dev/console");
76  if (fd >= 0)
77    return fd;
78
79  for (fd = 0; fd < 3; fd++)
80    if (is_a_console(fd))
81      return fd;
82
83  fprintf(stderr,
84    "Couldnt get a file descriptor referring to the console\n");
85  return -1;
86}
87
88
89typedef enum
90{
91  EXPECTING_FINGERPRINT,
92  EXPECTING_DIMENSIONS,
93  EXPECTING_MAXVAL,
94}
95ParserState;
96
97
98typedef struct
99{
100  uint16_t width;
101  uint16_t height;
102  uint16_t maximum_value;
103  uint8_t *data;
104}
105Image;
106
107
108// Loads a PNM P6 image ( 24-bit colour with binary pixel data).
109// Returns 0 if the image was successfully loaded, non-zero on error. On
110// error, the "error" pointer will refer to a human-readable description of
111// what was wrong.
112// The fields in the "image" struct may be in an undefined state on error.
113// The "data" field of the image must be passed to free() when no longer
114// required.
115//
116int load_pnm_p6( char *path_to_file, Image *image, char **error)
117{
118  /* EXAMPLE PNM P6 HEADER:
119P6
120# CREATOR: GIMP PNM Filter Version 1.1
121128 24
122255
123<binary data>
124  */
125  FILE *f = fopen( path_to_file, "r");
126  if ( NULL == f) {
127    *error = "Could not open file";
128    return 1; // TODO - proper error code
129  }
130
131  char line_store[ 80];
132  ParserState state = EXPECTING_FINGERPRINT;
133  bool reading_header = true;
134  int outcome = 1; // indicating an error
135
136  while ( reading_header)
137  {
138    char *line = fgets( line_store, sizeof(line_store), f);
139
140    if ( NULL == line)
141    {
142      *error = "Premature end of file";
143      goto tidy_up;
144    }
145
146    switch ( state)
147    {
148      case EXPECTING_FINGERPRINT:
149        // Check that the file is in fact a P6 PNM file
150        if ( 0 == strcmp("P6\n", line)) {
151          state = EXPECTING_DIMENSIONS;
152        }
153        else {
154          *error = "Not a PNM P6 file";
155          goto tidy_up;
156        }
157        break;
158      case EXPECTING_DIMENSIONS:
159        // If this line does NOT contain a comment..
160        if ( line[ 0] != '#')
161        {
162          // Try to get the dimensions of the image from the line
163          int count = sscanf( line, "%hu %hu\n", &image->width, &image->height);
164          if ( count != 2) {
165            *error = "Bad dimensions line";
166            goto tidy_up;
167          }
168          state = EXPECTING_MAXVAL;
169        }
170        break;
171      case EXPECTING_MAXVAL:
172      {
173        // Try to get the maximum pixel value in the image from the line
174        int count = sscanf( line, "%hu\n", &image->maximum_value);
175        if ( count != 1) {
176          *error = "Bad maxval line";
177          goto tidy_up;
178        }
179        // The binary data follows the Depth line
180        reading_header = false;
181      }
182    }
183  }
184
185  image->data = malloc( 3 * image->width * image->height);
186  size_t rows_read = fread( image->data, 3 * image->width, image->height, f);
187  if ( rows_read != image->height)
188  {
189    *error = "Some data is missing";
190    goto tidy_up;
191  }
192
193  // Indicate that no error occurred
194  outcome = 0;
195
196 tidy_up:
197  fclose( f);
198
199  return outcome;
200}
201
202
203int main( int argc, char **argv)
204{
205  if ( argc != 2)
206  {
207    fprintf( stderr, "Use: %s path-to-glyph-sheet.pnm\n", argv[0]);
208    exit( 1);
209  }
210
211  // Load the glyph sheet from the PNM file
212  Image image;
213  char *error;
214  int outcome = load_pnm_p6( argv[1], &image, &error);
215  if ( outcome != 0)
216  {
217    fprintf( stderr, "Could not load glyph sheet: %s\n", error);
218    exit( 1);
219  }
220
221  bool should_emit_data = false;
222
223  // The glyph sheet is expected to have 8 rows of 32 glyphs. The image
224  // dimensions will be used to determine the glyph cell dimensions.
225  uint8_t pixels_across_glyph = image.width / 32;
226  uint8_t pixels_down_glyph = image.height / 8;
227  uint8_t bytes_across_glyph = 4 * pixels_across_glyph;
228  uint8_t bytes_per_glyph = bytes_across_glyph * pixels_down_glyph;
229
230  uint16_t charcount = 256;
231  unsigned char data[ bytes_per_glyph * charcount];
232
233  // Initialize the kernel glyph sheet so that unused pixels are empty
234  memset( data, 0x00, sizeof(data));
235
236  int ch, y, x;
237  for ( ch = 0; ch < 256; ++ch)
238  {
239    // Work out the row number on the glyph sheet of the glyph for "ch"
240    // There are 8 rows of 32 glyphs on the image
241    uint8_t glyph_sheet_row = ch / 32;
242    uint8_t glyph_sheet_column = ch % 32;
243    uint8_t top_edge_of_glyph = pixels_down_glyph * glyph_sheet_row;
244    uint8_t left_edge_of_glyph = pixels_across_glyph * glyph_sheet_column;
245
246    if ( should_emit_data) {
247      printf("%c\n", ch);
248    }
249
250    for ( y = 0; y < pixels_down_glyph; ++ y)
251    {
252      uint8_t *file_glyph_row = &image.data[ 3 * ( image.width * ( top_edge_of_glyph + y) + left_edge_of_glyph)];
253      uint8_t *kernel_glyph_row = &data[ bytes_per_glyph * ch + bytes_across_glyph * y];
254      if ( bytes_per_glyph * ch + bytes_across_glyph * y + bytes_across_glyph <= sizeof(data))
255      {
256        // Copy the row of pixels from the file sheet to the kernel sheet
257        for ( x = 0; x < pixels_across_glyph; ++ x)
258        {
259          kernel_glyph_row[ 4*x + 0] = file_glyph_row[ 3*x + 2];
260          kernel_glyph_row[ 4*x + 1] = file_glyph_row[ 3*x + 1];
261          kernel_glyph_row[ 4*x + 2] = file_glyph_row[ 3*x + 0];
262          if ( should_emit_data) {
263            uint8_t *row = kernel_glyph_row + 4*x;
264            printf("%02hx,%02hx,%02hx,%02hx ", row[0], row[1], row[2], row[3]);
265          }
266        }
267        if ( should_emit_data) {
268          printf("\n");
269        }
270      }
271      else {
272        fprintf( stderr, "Shit\n");
273        goto tidy_up;
274      }
275    }
276  }
277
278  // Leave a fingerprint of this non-standard font so the kernel can recognise
279  // it as such
280  *(uint32_t*)data = 0x6a127efd;
281
282  struct console_font_op request = { op: KD_FONT_OP_SET,
283                                      width: pixels_across_glyph,
284                                      height: pixels_down_glyph,
285                                      charcount: 256,
286                                      data: data,
287                                    };
288
289  if ( ioctl( get_console_fd(), KDFONTOP, &request)) {
290    perror("Bugger");
291  }
292
293  tidy_up:
294  free( image.data);
295
296  return 0;
297}
298
299

Archive Download this file

Branches:
master



interactive