/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Utility to convert X11 fonts to a PCX file, ready for use in the * grabber. * * By Michael Bukin, 1998. * * Minor changes in 2002 by Peter Wang. * * Minor changes in 2003 by Elias Pschernig. * * See readme.txt for copyright information. */ #include #include #include #include #ifndef SCAN_DEPEND #include #include #endif /* usage: * Show usage information. */ static void usage(char *argv0) { printf("Usage: %s [OPTIONS]\n\n", argv0); printf(" -f FONTNAME Font name pattern ('*' by default).\n" " -o FILENAME Output file name ('font.pcx' by default).\n" " -r NUM-NUM Character range, default = 0x20-0xff.\n" " -c COLOR Character color (default 000000000 -- black).\n" " -b COLOR Background color (default 255255255 -- white).\n" " -g COLOR Grid color (default 255000255 -- magenta).\n" " Colors are specified as RRRGGGBBB values,\n" " with each RRR, GGG and BBB in the range [0, 255].\n" " -h This help.\n" "\n" "Find the font you want to convert using xlsfonts or xfontsel.\n\n" "Example 1:\n" "bash> xlsfonts -fn '*' | less\n" "bash> %s -f '-adobe-courier-medium-r-normal--34-*'\n" "bash> grabber\n\n" "In grabber, create a new font 'Object|New|Font'. Use 'Object|Grab'\n" "on this object and choose the pcx file with the font (font.pcx).\n\n" "Example 2:\n" "./xf2pcx -f '-*-clearlyu-*-*-*-*-17-*-*-*-p--iso10646-1' -r 0x2800-0x28ff -o braille.pcx\n\n" "Writes the Braille alphabet into braille.pcx.\n", argv0); } int main(int argc, char *argv[]) { /* default values for -f, -i, -r, -c, -b, -g */ char *fontname = "*"; char *filename = "font.pcx"; int start_char = 32, end_char = 255; int ccolor = 000000000; int bcolor = 255255255; int gcolor = 255000255; /* X11 variables */ Display *display; int screen_number; int default_depth; Window window; Font font; GC gc, gc2; Pixmap pixmap; XImage *image; XCharStruct overall; /* misc variables */ int bitmap_width, bitmap_height; int max_ascent, max_descent; int max_width, max_height; int i, opt, x, y, cx, cy, sx, sy, lines; unsigned long black, white; BITMAP *bitmap; RGB palette[256]; /* show usage if no options */ if (argc == 1) { usage(argv[0]); exit(EXIT_SUCCESS); } /* only to access bitmap operations */ install_allegro(SYSTEM_NONE, &errno, atexit); /* parse options */ opterr = 0; while ((opt = getopt(argc, argv, "f:o:z:c:b:g:r:h")) != EOF) { switch (opt) { case 'f': fontname = optarg; break; case 'o': filename = optarg; break; case 'c': ccolor = atol(optarg); break; case 'b': bcolor = atol(optarg); break; case 'g': gcolor = atol(optarg); break; case 'r': { char *str; start_char = strtol(optarg, &str, 0); end_char = strtol(str + 1, NULL, 0); break; } case 'h': usage(argv[0]); exit(EXIT_SUCCESS); default: fprintf(stderr, "%s: unrecognized option -- '%c'\n", argv[0], optopt); fprintf(stderr, "%s: try '%s -h' for more information\n", argv[0], argv[0]); exit(EXIT_FAILURE); } } /* open display */ display = XOpenDisplay(0); if (display == 0) { fprintf(stderr, "%s: XOpenDisplay failed\n", argv[0]); exit(EXIT_FAILURE); } /* default screen number and window */ screen_number = XDefaultScreen(display); default_depth = XDefaultDepth(display, screen_number); window = XDefaultRootWindow(display); /* load font */ font = XLoadFont(display, fontname); /* create gcs */ { unsigned long val_mask; XGCValues val_bits; val_mask = GCForeground | GCBackground | GCFont | GCFunction; val_bits.function = GXcopy; val_bits.foreground = white = WhitePixel(display, screen_number); val_bits.background = black = BlackPixel(display, screen_number); val_bits.font = font; gc = XCreateGC(display, window, val_mask, &val_bits); val_mask = GCForeground; val_bits.foreground = black; gc2 = XCreateGC(display, window, val_mask, &val_bits); } /* query font ascent and descent */ { XFontStruct *xfs; int min, max; xfs = XQueryFont(display, font); max_ascent = xfs->ascent; max_descent = xfs->descent; if (xfs->min_byte1 == 0 && xfs->max_byte1 == 0) { min = xfs->min_char_or_byte2; max = xfs->max_char_or_byte2; } else { min = (xfs->min_byte1 << 8) + xfs->min_char_or_byte2; max = (xfs->max_byte1 << 8) + xfs->max_char_or_byte2; } if (start_char < min || end_char > max) fprintf(stderr, "You specified characters %04x-%04x, but this font " "only has the range %04x-%04x\n", start_char, end_char, min, max); XFreeFontInfo(NULL, xfs, 0); } /* calculate bitmap width and maximum ascent and descent of characters * (can exceed the font ascent/descent queried above!) */ max_width = 0; lines = 1 + (end_char - start_char) / 16; for (cy = 0; cy < lines; cy++) { for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) { int dir, ascent, descent; int width; XChar2b string[2] = { {0, 0}, {0, 0} }; /* query character size */ string[0].byte1 = (start_char + cy * 16 + cx) >> 8; string[0].byte2 = (start_char + cy * 16 + cx) & 255; XQueryTextExtents16(display, font, string, 1, &dir, &ascent, &descent, &overall); width = overall.width; if (width < 1) width = 1; if (width > max_width) max_width = width; if (max_ascent < overall.ascent) max_ascent = overall.ascent; if (max_descent < overall.descent) max_descent = overall.descent; } } max_height = max_ascent + max_descent; bitmap_width = (max_width + 1) * 16 + 1; bitmap_height = (max_height + 1) * lines + 1; /* create bitmap */ bitmap = create_bitmap(bitmap_width, bitmap_height); if (bitmap == 0) { fprintf(stderr, "%s: can not create bitmap\n", argv[0]); exit(EXIT_FAILURE); } /* fill with filler color */ clear_to_color(bitmap, 255); /* process all characters */ sy = 1; for (cy = 0; cy < lines; cy++) { sx = 1; for (cx = 0; cx < 16 && start_char + cy * 16 + cx <= end_char; cx++) { int dir, ascent, descent; XChar2b string[2] = { {0, 0}, {0, 0} }; /* query character size */ string[0].byte1 = (start_char + cy * 16 + cx) >> 8; string[0].byte2 = (start_char + cy * 16 + cx) & 255; XQueryTextExtents16(display, font, string, 1, &dir, &ascent, &descent, &overall); if (overall.width < 1) overall.width = 1; /* create pixmap and draw character there */ pixmap = XCreatePixmap(display, window, overall.width, max_height, default_depth); /* some fonts draw outside their ascent/descent, so we need to clear * the pixmap before drawing the glyph */ XFillRectangle(display, pixmap, gc2, 0, 0, overall.width, max_height); XDrawImageString16(display, pixmap, gc, 0, max_ascent, string, 1); /* create image with pixmap contents */ image = XGetImage(display, pixmap, 0, 0, overall.width, max_height, AllPlanes, ZPixmap); if (image == 0) { fprintf(stderr, "%s: can not get image\n", argv[0]); exit(EXIT_FAILURE); } /* copy image to bitmap */ for (y = 0; y < max_height; y++) for (x = 0; x < overall.width; x++) { if (XGetPixel(image, x, y) == white) putpixel(bitmap, sx + x, sy + y, 1); else putpixel(bitmap, sx + x, sy + y, 0); } XDestroyImage(image); XFreePixmap(display, pixmap); sx += max_width + 1; } sy += max_height + 1; } /* initialize palette */ for (i = 0; i < 256; i++) palette[i].r = palette[i].g = palette[i].b = 0; #define CLAMP(v) (((v / 4) > 63) ? 63 : (v / 4)) palette[0].r = CLAMP(bcolor / 1000000); palette[0].g = CLAMP((bcolor % 1000000) / 1000); palette[0].b = CLAMP(bcolor % 1000); palette[1].r = CLAMP(ccolor / 1000000); palette[1].g = CLAMP((ccolor % 1000000) / 1000); palette[1].b = CLAMP(ccolor % 1000); palette[255].r = CLAMP(gcolor / 1000000); palette[255].g = CLAMP((gcolor % 1000000) / 1000); palette[255].b = CLAMP(gcolor % 1000); #undef CLAMP save_pcx(filename, bitmap, palette); /* clean up */ destroy_bitmap(bitmap); XFreeGC(display, gc); XFreeGC(display, gc2); XUnloadFont(display, font); XCloseDisplay(display); exit(EXIT_SUCCESS); } END_OF_MAIN()