/* libpbm5.c - pbm utility library part 5 ** ** Font routines. ** ** BDF font code Copyright 1993 by George Phillips. ** ** Copyright (C) 1991 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include #include #include #include "netpbm/pm_c_util.h" #include "netpbm/mallocvar.h" #include "netpbm/nstring.h" #include "pbmfont.h" #include "pbm.h" static unsigned int const firstCodePoint = 32; /* This is the code point of the first character in a pbmfont font. In ASCII, it is a space. */ static unsigned int const nCharsInFont = 96; /* The number of characters in a pbmfont font. A pbmfont font defines characters at position 32 (ASCII space) through 127, so that's 96. */ /* The default font, packed in hex so this source file doesn't get huge. ** You can replace this with your own font using pbm_dumpfont(). */ #define DEFAULTFONT_ROWS 155 #define DEFAULTFONT_COLS 112 static unsigned long defaultfont_bits[DEFAULTFONT_ROWS][(DEFAULTFONT_COLS+31)/32] = { {0x00000000L,0x20000c00L,0x10000000L,0x00000000L}, {0xc600a000L,0x42000810L,0x00000002L,0x00000063L}, {0x6c00a000L,0x45000810L,0x00000002L,0x00000036L}, {0x6c00a000L,0x88800808L,0xf2e1dee2L,0x00000036L}, {0x54000000L,0x80000800L,0x11122442L,0x0000002aL}, {0x54000001L,0x00000800L,0x11122442L,0x0000002aL}, {0x54000001L,0x00000800L,0x11122282L,0x0000002aL}, {0x44000102L,0x00000800L,0x11122382L,0x00000022L}, {0xee000102L,0x00000800L,0x11e1e102L,0x00000077L}, {0x00000204L,0x00000800L,0x11002102L,0x00000000L}, {0x00000000L,0x00000c00L,0x11002102L,0x00000000L}, {0x00000000L,0x003f8000L,0xe3807600L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x02000080L,0x00040000L,0x00120000L,0x00000001L}, {0x04000082L,0x828e1838L,0x20210100L,0x00000002L}, {0x04000082L,0x82912448L,0x20210100L,0x00000002L}, {0x08000082L,0x8fd01940L,0x404087c2L,0x00000004L}, {0x08000080L,0x050c0622L,0x00408102L,0x00000004L}, {0x10000080L,0x05061874L,0x0040828fL,0x00008008L}, {0x10000080L,0x1f912688L,0x00408002L,0x00000008L}, {0x20000000L,0x0a11098cL,0x00408002L,0x00000010L}, {0x20000080L,0x0a0e0672L,0x00210000L,0x00000010L}, {0x40000000L,0x00040000L,0x00210000L,0x00000020L}, {0x00000000L,0x00000000L,0x00120000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x004e0838L,0x7023e1cfL,0x00008000L}, {0x00000000L,0x00913844L,0x88620208L,0x00008000L}, {0x08000000L,0x00910844L,0x08a20401L,0x00000004L}, {0x10000000L,0x01110844L,0x08a20401L,0x00000008L}, {0x20000000L,0x01110808L,0x3123c781L,0x00000010L}, {0x400003e0L,0x02110810L,0x0a202441L,0x00000020L}, {0x20000000L,0x02110820L,0x0bf02442L,0x00000010L}, {0x10008000L,0x04110844L,0x88242442L,0x00000008L}, {0x08008002L,0x040e3e7cL,0x7073c382L,0x00000004L}, {0x00010000L,0x08000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x0000e1c0L,0x00000000L,0x00000000L,0x00000000L}, {0x00011220L,0x00000000L,0x70e38f87L,0x00000000L}, {0x20011220L,0x00020020L,0x89108448L,0x00008010L}, {0x10011220L,0x00040010L,0x09314448L,0x00008008L}, {0x0800e221L,0x02083e08L,0x11514788L,0x00000004L}, {0x040111e0L,0x00100004L,0x2153e448L,0x00000002L}, {0x08011020L,0x00083e08L,0x213a2448L,0x00008004L}, {0x10011040L,0x02040010L,0x01022448L,0x00008008L}, {0x2000e381L,0x02020020L,0x20e77f87L,0x00000010L}, {0x00000000L,0x04000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x3803e7efL,0xc73bbe3dL,0xdb863ce7L,0x0000001cL}, {0x44011224L,0x48910808L,0x91036648L,0x00008022L}, {0x4c011285L,0x48910808L,0xa1036648L,0x00008026L}, {0x54011387L,0x081f0808L,0xc102a548L,0x0000802aL}, {0x54011285L,0x09910808L,0xe102a548L,0x0000802aL}, {0x4e011204L,0x08910848L,0x9112a4c8L,0x00008027L}, {0x40011224L,0x08910848L,0x891224c8L,0x00008020L}, {0x3803e7efL,0x073bbe31L,0xcff77e47L,0x0000001cL}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000003L,0x00000000L}, {0x0003e1cfL,0x87bff7efL,0xdfbf77c2L,0x00000000L}, {0x00013224L,0x48a4a244L,0x89122442L,0x00000000L}, {0x00011224L,0x4824a244L,0xa8a14482L,0x00000000L}, {0x00013227L,0x8e04226cL,0xa8414102L,0x00000000L}, {0x0001e224L,0x83842228L,0xa8a08102L,0x00000000L}, {0x00010224L,0x40842228L,0xd8a08242L,0x00000000L}, {0x00010224L,0x48843638L,0x51108442L,0x00000000L}, {0x0003c1ceL,0x6f1f1c10L,0x53b9c7c2L,0x00000000L}, {0x00000060L,0x00000000L,0x00000002L,0x00000000L}, {0x00000000L,0x00000000L,0x00000003L,0x00000000L}, {0xfe000000L,0x00000000L,0x00000000L,0x0000007fL}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00010180L,0x000000c0L,0x003001c0L,0x00000000L}, {0x08008081L,0x00040040L,0x00100200L,0x00000004L}, {0x10008082L,0x80040040L,0x00100200L,0x00000008L}, {0x10004084L,0x40023c78L,0x70f1c7c7L,0x00004008L}, {0x10004080L,0x00000244L,0x89122208L,0x00008008L}, {0x20002080L,0x00001e44L,0x8113e208L,0x00008010L}, {0x10002080L,0x00002244L,0x81120208L,0x00008008L}, {0x10001080L,0x00002244L,0x89122208L,0x00008008L}, {0x10001080L,0x00001db8L,0x70e9c787L,0x00008008L}, {0x10000880L,0x00000000L,0x00000000L,0x00008008L}, {0x08000180L,0x00000000L,0x00000000L,0x00008004L}, {0x00000000L,0x1fc00000L,0x00000007L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00030080L,0x981c0000L,0x00000000L,0x00000000L}, {0x20010000L,0x08040000L,0x00000000L,0x00000010L}, {0x10010000L,0x08040000L,0x00000000L,0x00000008L}, {0x10016387L,0x898474b8L,0x72e1d5c7L,0x00000008L}, {0x10019080L,0x8a042a64L,0x89122208L,0x00008008L}, {0x08011080L,0x8c042a44L,0x89122207L,0x00000004L}, {0x10011080L,0x8a042a44L,0x89122200L,0x00008008L}, {0x10011080L,0x89042a44L,0x89122208L,0x00008008L}, {0x1003bbe0L,0x98dfebe6L,0x71e1e787L,0x00000008L}, {0x10000000L,0x80000000L,0x01002000L,0x00000008L}, {0x20000000L,0x80000000L,0x01002000L,0x00000010L}, {0x00000007L,0x00000000L,0x03807000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00008000L,0x00000000L,0x10410000L,0x00000000L}, {0x00008000L,0x00000000L,0x20408000L,0x00000000L}, {0x0001f66eL,0xfdfbf77cL,0x20408000L,0x00000000L}, {0x24008224L,0x488a2248L,0x20408240L,0x00000012L}, {0x54008224L,0x4a842210L,0x40404540L,0x0000002aL}, {0x48008222L,0x8a8a1420L,0x20408480L,0x00000024L}, {0x00008a23L,0x85111c44L,0x20408000L,0x00000000L}, {0x000071d1L,0x0531887cL,0x20408000L,0x00000000L}, {0x00000000L,0x00000800L,0x20408000L,0x00000000L}, {0x00000000L,0x00000800L,0x10410000L,0x00000000L}, {0x00000000L,0x00003000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x00000000L,0x00000000L,0x00000000L}, {0x00000000L,0x20000c00L,0x10000000L,0x00000000L}, {0xc600a000L,0x42000810L,0x00000002L,0x00000063L}, {0x6c00a000L,0x45000810L,0x00000002L,0x00000036L}, {0x6c00a000L,0x88800808L,0xf2e1dee2L,0x00000036L}, {0x54000000L,0x80000800L,0x11122442L,0x0000002aL}, {0x54000001L,0x00000800L,0x11122442L,0x0000002aL}, {0x54000001L,0x00000800L,0x11122282L,0x0000002aL}, {0x44000102L,0x00000800L,0x11122382L,0x00000022L}, {0xee000102L,0x00000800L,0x11e1e102L,0x00000077L}, {0x00000204L,0x00000800L,0x11002102L,0x00000000L}, {0x00000000L,0x00000c00L,0x11002102L,0x00000000L}, {0x00000000L,0x003f8000L,0xe3807600L,0x00000000L} }; /* A default BDF font */ /* Not as nicely compacted as the PBM font, oh well. */ static struct glyph _g[190] = { { 1, 1, 0, 0, 3, "\0" }, { 1, 9, 1, 0, 3, "\1\1\1\1\1\1\1\0\1" }, { 3, 3, 1, 6, 5, "\1\0\1\1\0\1\1\0\1" }, { 5, 8, 0, 0, 6, "\0\1\0\1\0\0\1\0\1\0\1\1\1\1\1\0\1\0\1\0\0\1\0\1\0\1\1\1\1\1\0\1\0\1\0\0\1\0\1\0" }, { 5, 11, 0, -1, 6, "\0\0\1\0\0\0\1\1\1\0\1\0\1\0\1\1\0\1\0\0\0\1\1\0\0\0\0\1\1\0\0\0\1\0\1\0\0\1\0\1\1\0\1\0\1\0\1\1\1\0\0\0\1\0\0" }, { 8, 9, 0, 0, 9, "\0\1\1\0\0\0\1\1\1\0\0\1\1\1\1\0\1\0\0\1\0\1\0\0\0\1\1\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\1\0\1\1\0\0\0\1\0\1\0\0\1\0\1\0\0\1\0\0\1\0\1\0\0\0\1\1\0" }, { 9, 9, 0, 0, 10, "\0\0\0\1\1\0\0\0\0\0\0\1\0\0\1\0\0\0\0\0\1\0\0\1\0\0\0\0\0\0\1\1\0\1\1\1\0\1\1\1\1\0\0\1\0\1\1\0\0\1\1\1\0\0\1\0\0\0\0\1\0\0\0\1\1\0\0\1\1\1\0\1\0\1\1\1\1\0\1\1\0" }, { 2, 3, 1, 6, 4, "\1\1\0\1\1\0" }, { 3, 12, 1, -3, 5, "\0\0\1\0\1\0\0\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\0\0\1\0\0\0\1" }, { 3, 12, 0, -3, 5, "\1\0\0\0\1\0\0\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\0\0\1\0\1\0\0" }, { 5, 5, 0, 4, 6, "\0\0\1\0\0\1\0\1\0\1\0\1\1\1\0\1\0\1\0\1\0\0\1\0\0" }, { 5, 5, 1, 1, 7, "\0\0\1\0\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\0\1\0\0" }, { 2, 3, 0, -2, 3, "\0\1\0\1\1\0" }, { 5, 1, 1, 3, 8, "\1\1\1\1\1" }, { 1, 1, 1, 0, 3, "\1" }, { 3, 9, 0, 0, 3, "\0\0\1\0\0\1\0\0\1\0\1\0\0\1\0\0\1\0\1\0\0\1\0\0\1\0\0" }, { 5, 9, 0, 0, 6, "\0\1\1\1\0\1\1\0\1\1\1\0\0\0\1\1\0\0\0\1\1\0\0\0\1\1\0\0\0\1\1\0\0\0\1\1\1\0\1\1\0\1\1\1\0" }, { 4, 9, 0, 0, 6, "\0\0\1\0\0\1\1\0\1\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\1\1\1" }, { 5, 9, 0, 0, 6, "\0\1\1\1\0\1\0\0\0\1\0\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\1\1\1\1\1" }, { 5, 9, 0, 0, 6, "\0\1\1\1\0\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\1\1\1\0\0\0\0\0\1\0\0\0\0\1\1\0\0\0\1\0\1\1\1\0" }, { 5, 9, 0, 0, 6, "\0\0\0\1\0\0\0\1\1\0\0\0\1\1\0\0\1\0\1\0\0\1\0\1\0\1\0\0\1\0\1\1\1\1\1\0\0\0\1\0\0\0\0\1\0" }, { 5, 9, 0, 0, 6, "\0\0\1\1\1\0\1\0\0\0\0\1\0\0\0\0\1\1\1\0\0\0\0\1\1\0\0\0\0\1\0\0\0\0\1\1\0\0\1\1\0\1\1\1\0" }, { 5, 9, 0, 0, 6, "\0\0\0\1\1\0\1\1\0\0\0\1\0\0\0\1\1\1\1\0\1\0\0\1\1\1\0\0\0\1\1\0\0\0\1\1\1\0\0\1\0\1\1\1\0" }, { 5, 9, 0, 0, 6, "\1\1\1\1\1\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\0\0\1\0\0\0" }, { 5, 9, 0, 0, 6, "\0\1\1\1\0\1\0\0\0\1\1\0\0\0\1\1\1\0\0\1\0\1\1\1\0\1\0\0\1\1\1\0\0\0\1\1\0\0\0\1\0\1\1\1\0" }, { 5, 9, 0, 0, 6, "\0\1\1\1\0\1\0\0\1\1\1\0\0\0\1\1\0\0\0\1\1\1\0\0\1\0\1\1\1\1\0\0\0\1\0\0\0\1\1\0\1\1\0\0\0" }, { 1, 6, 1, 0, 3, "\1\0\0\0\0\1" }, { 2, 8, 0, -2, 3, "\0\1\0\0\0\0\0\0\0\0\0\1\0\1\1\0" }, { 6, 5, 0, 1, 8, "\0\0\0\0\1\1\0\0\1\1\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1" }, { 5, 3, 1, 2, 7, "\1\1\1\1\1\0\0\0\0\0\1\1\1\1\1" }, { 6, 5, 1, 1, 8, "\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\1\1\0\0\1\1\0\0\0\0" }, { 4, 9, 0, 0, 5, "\0\1\1\0\1\0\0\1\0\0\0\1\0\0\1\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\1\0\0" }, { 10, 11, 1, -2, 11, "\0\0\0\0\1\1\1\1\0\0\0\0\1\1\0\0\0\0\1\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\1\1\0\1\0\1\1\0\0\1\0\0\1\0\0\1\1\0\1\0\0\0\1\0\0\1\1\0\1\0\0\1\0\0\1\0\1\0\1\0\0\1\0\0\1\0\1\0\0\1\1\0\1\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\1\1\1\1\1\0\0\0" }, { 9, 9, 0, 0, 9, "\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 7, 9, 0, 0, 8, "\1\1\1\1\1\1\0\0\1\0\0\0\1\1\0\1\0\0\0\0\1\0\1\0\0\0\1\1\0\1\1\1\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\1\0\1\0\0\0\1\1\1\1\1\1\1\1\0" }, { 7, 9, 0, 0, 8, "\0\0\1\1\1\0\1\0\1\1\0\0\1\1\0\1\0\0\0\0\1\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\1\0\1\1\0\0\1\1\0\0\1\1\1\1\0" }, { 8, 9, 0, 0, 9, "\1\1\1\1\1\1\0\0\0\1\0\0\0\1\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\0\0\0\1\1\0\1\1\1\1\1\1\0\0" }, { 7, 9, 0, 0, 8, "\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\1\1\1\1" }, { 7, 9, 0, 0, 8, "\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\1\1\1\1\0\0\0" }, { 8, 9, 0, 0, 9, "\0\0\1\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\0\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 9, 0, 0, 9, "\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\1\1\1\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\1\1\1\0\0\1\1\1" }, { 3, 9, 0, 0, 4, "\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 4, 9, 0, 0, 4, "\0\1\1\1\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\1\0\1\0\1\1\0\0" }, { 8, 9, 0, 0, 8, "\1\1\1\0\1\1\1\0\0\1\0\0\0\1\0\0\0\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\1\1\1\0\0\0\0\0\1\0\1\1\0\0\0\0\1\0\0\1\1\0\0\0\1\0\0\0\1\1\0\1\1\1\0\0\1\1\1" }, { 6, 9, 0, 0, 7, "\1\1\1\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\1\1\1\1\1\1\1" }, { 11, 9, 0, 0, 11, "\1\1\0\0\0\0\0\0\0\1\1\0\1\1\0\0\0\0\0\1\1\0\0\1\1\0\0\0\0\0\1\1\0\0\1\0\1\0\0\0\1\0\1\0\0\1\0\1\0\0\0\1\0\1\0\0\1\0\0\1\0\1\0\0\1\0\0\1\0\0\1\0\1\0\0\1\0\0\1\0\0\0\1\0\0\0\1\0\1\1\1\0\0\1\0\0\1\1\1" }, { 9, 9, 0, 0, 9, "\1\1\0\0\0\0\1\1\1\0\1\1\0\0\0\0\1\0\0\1\1\0\0\0\0\1\0\0\1\0\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\0\1\0\0\1\0\0\0\0\1\1\0\1\1\1\0\0\0\0\1\0" }, { 8, 9, 0, 0, 9, "\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 7, 9, 0, 0, 7, "\1\1\1\1\1\1\0\0\1\0\0\0\1\1\0\1\0\0\0\0\1\0\1\0\0\0\1\1\0\1\1\1\1\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\1\1\1\0\0\0\0" }, { 8, 11, 0, -2, 9, "\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\0\0\1\1" }, { 8, 9, 0, 0, 8, "\1\1\1\1\1\1\0\0\0\1\0\0\0\1\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\1\1\0\0\1\1\1\1\1\0\0\0\1\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\1\1\1\0\0\0\1\1" }, { 6, 9, 0, 0, 7, "\0\1\1\1\0\1\1\0\0\0\1\1\1\0\0\0\0\1\0\1\1\0\0\0\0\0\1\1\1\0\0\0\0\0\1\1\1\0\0\0\0\1\1\1\0\0\1\1\1\0\1\1\1\0" }, { 7, 9, 0, 0, 7, "\1\1\1\1\1\1\1\1\0\0\1\0\0\1\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\1\1\1\0\0" }, { 8, 9, 0, 0, 8, "\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 9, 9, 0, 0, 9, "\1\1\1\0\0\0\1\1\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0" }, { 12, 9, 0, 0, 12, "\1\1\1\0\1\1\1\0\0\1\1\1\0\1\0\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\1\0\0\0\0\1\1\0\1\1\1\0\1\0\0\0\0\0\1\0\1\0\1\0\1\0\0\0\0\0\1\1\0\0\1\1\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0" }, { 8, 9, 0, 0, 8, "\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\0\1\0\0\1\0\0\0\0\1\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\1\0\1\1\0\0\0\0\1\0\0\1\0\0\0\1\0\0\0\0\1\0\1\1\1\0\0\1\1\1" }, { 9, 9, 0, 0, 9, "\1\1\1\0\0\0\1\1\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\0\1\0\0\0\0\0\1\1\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\1\1\0\0\0" }, { 7, 9, 0, 0, 8, "\1\1\1\1\1\1\1\1\0\0\0\0\1\1\0\0\0\0\1\1\0\0\0\0\1\1\0\0\0\0\1\1\0\0\0\0\1\1\0\0\0\0\1\1\0\0\0\0\0\1\0\0\0\0\0\1\1\1\1\1\1\1\1" }, { 3, 12, 1, -3, 5, "\1\1\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1" }, { 3, 9, 0, 0, 3, "\1\0\0\1\0\0\1\0\0\0\1\0\0\1\0\0\1\0\0\0\1\0\0\1\0\0\1" }, { 3, 12, 0, -3, 5, "\1\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\1" }, { 5, 5, 0, 4, 6, "\0\0\1\0\0\0\1\0\1\0\0\1\0\1\0\1\0\0\0\1\1\0\0\0\1" }, { 6, 1, 0, -3, 6, "\1\1\1\1\1\1" }, { 2, 3, 1, 6, 4, "\0\1\1\0\1\1" }, { 5, 6, 1, 0, 6, "\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 9, 0, 0, 6, "\1\1\0\0\0\0\1\0\0\0\0\1\0\0\0\0\1\1\1\0\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\1\1\0" }, { 4, 6, 1, 0, 5, "\0\1\1\0\1\0\0\1\1\0\0\0\1\0\0\0\1\0\0\1\0\1\1\0" }, { 5, 9, 1, 0, 6, "\0\0\1\1\0\0\0\0\1\0\0\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 6, 1, 0, 6, "\0\1\1\0\0\1\0\0\1\0\1\1\1\1\0\1\0\0\0\0\1\1\0\0\1\0\1\1\1\0" }, { 3, 9, 0, 0, 3, "\0\0\1\0\1\0\0\1\0\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0" }, { 5, 9, 1, -3, 6, "\0\1\1\1\1\1\0\0\1\0\1\0\0\1\0\1\1\1\0\0\0\1\0\0\0\0\1\1\1\0\1\0\0\0\1\1\0\0\0\1\0\1\1\1\0" }, { 6, 9, 0, 0, 6, "\1\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\1\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1\0\1\1" }, { 3, 9, 0, 0, 3, "\0\1\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 2, 12, 0, -3, 3, "\0\1\0\0\0\0\1\1\0\1\0\1\0\1\0\1\0\1\0\1\0\1\1\0" }, { 6, 9, 0, 0, 6, "\1\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\1\0\0\1\0\1\0\0\0\1\1\0\0\0\0\1\0\1\0\0\0\1\0\0\1\0\0\1\0\0\1\1" }, { 3, 9, 0, 0, 3, "\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 9, 6, 0, 0, 9, "\1\0\1\1\0\1\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1\0\1\1\0\1\1" }, { 6, 6, 0, 0, 6, "\1\0\1\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1\0\1\1" }, { 4, 6, 1, 0, 6, "\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 5, 9, 0, -3, 6, "\1\1\1\1\0\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\1\1\0\0\1\0\0\0\0\1\0\0\0\1\1\1\0\0" }, { 5, 9, 1, -3, 6, "\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\1\0\0\0\0\1\0\0\0\0\1\0\0\0\1\1\1" }, { 4, 6, 0, 0, 4, "\1\0\1\1\0\1\1\0\0\1\0\0\0\1\0\0\0\1\0\0\1\1\1\0" }, { 4, 6, 1, 0, 6, "\0\1\1\1\1\0\0\1\1\1\0\0\0\0\1\1\1\0\0\1\1\1\1\0" }, { 4, 7, 0, 0, 4, "\0\1\0\0\1\1\1\1\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\1" }, { 6, 6, 0, 0, 6, "\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\1\0\1" }, { 6, 6, 0, 0, 6, "\1\1\0\0\1\1\0\1\0\0\1\0\0\1\0\1\1\0\0\1\0\1\0\0\0\0\1\1\0\0\0\0\1\0\0\0" }, { 9, 6, 0, 0, 9, "\1\1\1\0\1\1\0\1\1\0\1\0\0\1\0\0\1\0\0\1\1\0\1\0\1\1\0\0\0\1\0\1\0\1\0\0\0\0\1\1\0\1\0\0\0\0\0\1\0\0\1\0\0\0" }, { 5, 6, 1, 0, 6, "\1\1\0\1\1\0\1\0\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\1\0\1\1\0\1\1" }, { 6, 9, 0, -3, 6, "\1\1\0\0\1\1\0\1\0\0\1\0\0\1\0\1\1\0\0\1\0\1\0\0\0\0\1\1\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\1\0\0\0\0\1\1\0\0\0\0" }, { 4, 6, 1, 0, 6, "\1\1\1\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\1\1" }, { 4, 12, 1, -3, 6, "\0\0\1\1\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\1" }, { 1, 9, 1, 0, 3, "\1\1\1\1\1\1\1\1\1" }, { 4, 12, 0, -3, 6, "\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\1\1\0\0" }, { 6, 2, 0, 3, 7, "\0\1\1\0\0\1\1\0\0\1\1\0" }, { 1, 9, 1, -3, 4, "\1\0\1\1\1\1\1\1\1" }, { 5, 8, 1, -1, 6, "\0\0\0\0\1\0\1\1\1\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\1\0\0\1\0\1\1\1\0\1\0\0\0\0" }, { 5, 9, 0, 0, 6, "\0\0\1\1\0\0\1\0\0\1\0\1\0\0\0\0\1\0\0\0\1\1\1\1\0\0\1\0\0\0\0\1\0\0\0\1\1\1\0\1\1\1\0\1\1" }, { 6, 7, 1, 1, 7, "\1\0\0\0\0\1\0\1\1\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\1\0\1\0\0\0\0\1" }, { 5, 9, 0, 0, 6, "\1\0\0\0\1\1\0\0\0\1\0\1\0\1\0\0\1\0\1\0\1\1\1\1\1\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\1\1\0" }, { 1, 9, 1, 0, 3, "\1\1\1\0\0\1\1\1\1" }, { 4, 12, 1, -3, 6, "\0\1\1\1\1\0\0\1\1\1\0\0\0\1\1\0\1\0\1\1\1\0\0\1\1\0\0\1\1\1\0\1\0\1\1\0\0\0\1\1\1\0\0\1\1\1\1\0" }, { 3, 1, 0, 7, 3, "\1\0\1" }, { 9, 9, 1, 0, 11, "\0\0\0\1\1\1\0\0\0\0\1\1\0\0\0\1\1\0\0\1\0\1\1\1\0\1\0\1\0\1\0\0\1\0\0\1\1\0\1\0\0\0\0\0\1\1\0\1\0\0\1\0\0\1\0\1\0\1\1\1\0\1\0\0\1\1\0\0\0\1\1\0\0\0\0\1\1\1\0\0\0" }, { 3, 6, 1, 3, 5, "\1\1\0\0\0\1\1\1\1\1\0\1\0\0\0\1\1\1" }, { 5, 5, 1, 0, 7, "\0\0\1\0\1\0\1\0\1\0\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1" }, { 6, 4, 1, 1, 8, "\1\1\1\1\1\1\0\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\1" }, { 4, 1, 1, 3, 6, "\1\1\1\1" }, { 9, 9, 1, 0, 11, "\0\0\0\1\1\1\0\0\0\0\1\1\0\0\0\1\1\0\0\1\0\1\1\1\0\1\0\1\0\0\1\0\0\1\0\1\1\0\0\1\1\1\0\0\1\1\0\0\1\0\1\0\0\1\1\1\0\1\0\1\0\1\0\0\1\1\0\0\0\1\1\0\0\0\1\1\1\1\0\0\0" }, { 4, 1, 0, 7, 4, "\1\1\1\1" }, { 4, 4, 0, 5, 5, "\0\1\1\0\1\0\0\1\1\0\0\1\0\1\1\0" }, { 5, 7, 1, 0, 7, "\0\0\1\0\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\0\1\0\0\0\0\0\0\0\1\1\1\1\1" }, { 4, 5, 0, 4, 4, "\0\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\1" }, { 3, 5, 0, 4, 4, "\1\1\1\0\0\1\0\1\0\0\0\1\1\1\0" }, { 2, 2, 1, 7, 4, "\0\1\1\0" }, { 6, 9, 0, -3, 6, "\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\1\0\0\0\0\0\1\0\0\0\0\0\1\1\0\0\0" }, { 6, 12, 0, -3, 7, "\0\1\1\1\1\1\1\1\1\0\1\0\1\1\1\0\1\0\1\1\1\0\1\0\1\1\1\0\1\0\0\1\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0" }, { 1, 1, 1, 3, 3, "\1" }, { 3, 3, 0, -3, 3, "\0\1\0\0\0\1\1\1\1" }, { 3, 5, 0, 4, 4, "\0\1\0\1\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 6, 1, 3, 5, "\0\1\0\1\0\1\1\0\1\0\1\0\0\0\0\1\1\1" }, { 5, 5, 0, 0, 7, "\1\0\1\0\0\0\1\0\1\0\0\0\1\0\1\0\1\0\1\0\1\0\1\0\0" }, { 9, 9, 0, 0, 9, "\0\1\0\0\0\0\1\0\0\1\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\1\1\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\0\0\1\0\1\0\1\0\0\0\1\0\0\1\1\1\1\0\0\1\0\0\0\0\1\0" }, { 9, 9, 0, 0, 9, "\0\1\0\0\0\0\1\0\0\1\1\0\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\1\1\0\1\0\1\1\0\0\0\0\1\0\1\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\1\0\0\1\1\1\1" }, { 9, 9, 0, 0, 9, "\1\1\1\0\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\0\0\0\0\1\1\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\0\0\1\0\1\0\1\0\0\0\1\0\0\1\1\1\1\0\0\1\0\0\0\0\1\0" }, { 4, 9, 0, -3, 5, "\0\0\1\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\1\0\0\1\0\0\0\1\0\0\1\0\1\1\0" }, { 9, 12, 0, 0, 9, "\0\0\0\1\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 9, 12, 0, 0, 9, "\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 9, 12, 0, 0, 9, "\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 9, 12, 0, 0, 9, "\0\0\0\0\1\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 9, 11, 0, 0, 9, "\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 9, 12, 0, 0, 9, "\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\1\1\1\0\0\0\1\1\1" }, { 10, 9, 0, 0, 11, "\0\0\1\1\1\1\1\1\1\1\0\0\0\1\1\0\0\0\0\1\0\0\1\0\1\0\0\0\0\0\0\0\1\0\1\0\0\0\1\0\0\1\0\0\1\1\1\1\1\0\0\1\1\1\1\0\0\0\1\0\0\1\0\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\0\1\1\1\0\0\1\1\1\1\1\1" }, { 7, 12, 0, -3, 8, "\0\0\1\1\1\0\1\0\1\1\0\0\1\1\0\1\0\0\0\0\1\1\0\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\1\0\1\1\0\0\1\1\0\0\1\1\1\1\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\1\1\1\0\0" }, { 7, 12, 0, 0, 8, "\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\1\1\1\1" }, { 7, 12, 0, 0, 8, "\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\1\1\1\1" }, { 7, 12, 0, 0, 8, "\0\0\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\1\1\1\1" }, { 7, 11, 0, 0, 8, "\0\0\1\0\1\0\0\0\0\0\0\0\0\0\1\1\1\1\1\1\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\0\0\0\1\0\0\1\1\1\1\1\0\0\1\0\0\0\1\0\0\1\0\0\0\0\0\0\1\0\0\0\0\1\1\1\1\1\1\1\1" }, { 3, 12, 0, 0, 4, "\1\0\0\0\1\0\0\0\0\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 12, 0, 0, 4, "\0\0\1\0\1\0\0\0\0\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 12, 0, 0, 4, "\0\1\0\1\0\1\0\0\0\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 11, 0, 0, 4, "\1\0\1\0\0\0\1\1\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 8, 9, 0, 0, 9, "\1\1\1\1\1\1\0\0\0\1\0\0\0\1\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\0\1\1\1\1\0\0\0\0\1\0\1\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\0\0\0\1\1\0\1\1\1\1\1\1\0\0" }, { 9, 12, 0, 0, 9, "\0\0\0\0\1\0\1\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\1\1\0\0\0\0\1\1\1\0\1\1\0\0\0\0\1\0\0\1\1\0\0\0\0\1\0\0\1\0\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\0\1\0\0\1\0\0\0\0\1\1\0\1\1\1\0\0\0\0\1\0" }, { 8, 12, 0, 0, 9, "\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 12, 0, 0, 9, "\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 12, 0, 0, 9, "\0\0\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 12, 0, 0, 9, "\0\0\0\1\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 11, 0, 0, 9, "\0\0\1\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\0\0\0\1\1\0\0\1\1\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\1\0\0\0\0\0\0\1\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 5, 5, 1, 1, 7, "\1\0\0\0\1\0\1\0\1\0\0\0\1\0\0\0\1\0\1\0\1\0\0\0\1" }, { 9, 10, 0, 0, 9, "\0\0\0\0\0\0\0\0\1\0\0\1\1\1\1\0\1\0\0\1\1\0\0\1\1\0\0\0\1\0\0\0\1\1\0\0\1\0\0\0\1\0\0\1\0\1\0\0\0\1\0\0\1\0\1\0\0\1\0\0\0\1\0\0\1\1\0\0\0\1\0\0\0\1\1\0\0\1\1\0\0\1\0\1\1\1\1\0\0\0" }, { 8, 12, 0, 0, 8, "\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 12, 0, 0, 8, "\0\0\0\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 12, 0, 0, 8, "\0\0\0\1\0\0\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 8, 11, 0, 0, 8, "\0\0\1\0\1\0\0\0\0\0\0\0\0\0\0\0\1\1\1\0\0\1\1\1\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\1\0\0\0\1\1\1\1\0\0" }, { 9, 12, 0, 0, 9, "\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\0\0\0\1\1\1\0\1\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\1\0\0\1\0\0\0\0\0\1\1\1\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\1\1\1\0\0\0" }, { 7, 9, 0, 0, 7, "\1\1\1\0\0\0\0\0\1\0\0\0\0\0\0\1\1\1\1\1\0\0\1\0\0\0\1\1\0\1\0\0\0\0\1\0\1\0\0\0\1\1\0\1\1\1\1\1\0\0\1\0\0\0\0\0\1\1\1\0\0\0\0" }, { 6, 9, 0, 0, 6, "\0\0\1\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\0\0\0\1\1\1\0\0\0\1\0\0\1\0\0\1\0\0\0\1\0\1\0\0\0\1\1\1\0\1\1\0" }, { 5, 9, 1, 0, 6, "\0\1\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 9, 1, 0, 6, "\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 9, 1, 0, 6, "\0\0\1\0\0\0\1\0\1\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 9, 1, 0, 6, "\0\1\0\1\0\1\0\1\0\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 8, 1, 0, 6, "\0\1\0\1\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 5, 9, 1, 0, 6, "\0\0\1\0\0\0\1\0\1\0\0\0\1\0\0\0\1\1\0\0\1\0\0\1\0\0\1\1\1\0\1\0\0\1\0\1\0\0\1\0\0\1\1\0\1" }, { 8, 6, 1, 0, 9, "\0\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\1\1\1\0\1\0\0\1\0\0\0\0\1\0\0\1\1\0\0\1\0\1\1\0\1\1\1\0" }, { 4, 9, 1, -3, 5, "\0\1\1\0\1\0\0\1\1\0\0\0\1\0\0\0\1\0\0\1\0\1\1\0\0\1\0\0\0\0\1\0\1\1\1\0" }, { 5, 9, 1, 0, 6, "\0\1\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\1\1\1\1\0\1\0\0\0\0\1\1\0\0\1\0\1\1\1\0" }, { 5, 9, 1, 0, 6, "\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\1\1\1\1\0\1\0\0\0\0\1\1\0\0\1\0\1\1\1\0" }, { 5, 9, 1, 0, 6, "\0\0\1\0\0\0\1\0\1\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\1\1\1\1\0\1\0\0\0\0\1\1\0\0\1\0\1\1\1\0" }, { 5, 8, 1, 0, 6, "\0\1\0\1\0\0\0\0\0\0\0\1\1\0\0\1\0\0\1\0\1\1\1\1\0\1\0\0\0\0\1\1\0\0\1\0\1\1\1\0" }, { 3, 9, 0, 0, 3, "\1\0\0\0\1\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 9, 0, 0, 3, "\0\1\0\1\0\0\0\0\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 9, 0, 0, 3, "\0\1\0\1\0\1\0\0\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 3, 8, 0, 0, 3, "\1\0\1\0\0\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1" }, { 4, 9, 1, 0, 6, "\0\1\0\0\0\1\1\1\1\0\1\0\0\1\1\1\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 6, 9, 0, 0, 6, "\0\0\1\0\1\0\0\1\0\1\0\0\0\0\0\0\0\0\1\0\1\1\0\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\1\1\1\0\1\1" }, { 4, 9, 1, 0, 6, "\0\1\0\0\0\0\1\0\0\0\0\0\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 4, 9, 1, 0, 6, "\0\0\1\0\0\1\0\0\0\0\0\0\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 4, 9, 1, 0, 6, "\0\0\1\0\0\1\0\1\0\0\0\0\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 4, 9, 1, 0, 6, "\0\1\0\1\1\0\1\0\0\0\0\0\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 4, 8, 1, 0, 6, "\1\0\1\0\0\0\0\0\0\1\1\0\1\0\0\1\1\0\0\1\1\0\0\1\1\0\0\1\0\1\1\0" }, { 5, 5, 1, 1, 7, "\0\0\1\0\0\0\0\0\0\0\1\1\1\1\1\0\0\0\0\0\0\0\1\0\0" }, { 6, 7, 0, -1, 6, "\0\0\1\1\0\1\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\1\1\0\0\1\0\0\0\0\0" }, { 6, 9, 0, 0, 6, "\0\0\1\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\1\0\1" }, { 6, 9, 0, 0, 6, "\0\0\0\1\0\0\0\0\1\0\0\0\0\0\0\0\0\0\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\1\0\1" }, { 6, 9, 0, 0, 6, "\0\0\1\0\0\0\0\1\0\1\0\0\0\0\0\0\0\0\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\1\0\1" }, { 6, 8, 0, 0, 6, "\0\1\0\1\0\0\0\0\0\0\0\0\1\1\0\1\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\1\0\0\0\1\1\0\1" }, { 6, 12, 0, -3, 6, "\0\0\0\0\1\0\0\0\0\1\0\0\0\0\0\0\0\0\1\1\0\0\1\1\0\1\0\0\1\0\0\1\0\1\1\0\0\1\0\1\0\0\0\0\1\1\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\1\0\0\0\0\1\1\0\0\0\0" }, { 5, 12, 0, -3, 6, "\1\1\0\0\0\0\1\0\0\0\0\1\0\0\0\0\1\1\1\0\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\0\0\1\0\1\1\1\0\0\1\0\0\0\0\1\0\0\0\1\1\1\0\0" }, { 6, 11, 0, -3, 6, "\0\1\0\0\1\0\0\0\0\0\0\0\1\1\0\0\1\1\0\1\0\0\1\0\0\1\0\1\1\0\0\1\0\1\0\0\0\0\1\1\0\0\0\0\1\0\0\0\0\0\1\0\0\0\0\1\0\0\0\0\1\1\0\0\0\0" } }; static struct font default_bdffont = { 14, 15, -1, -3, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _g + 0, _g + 1, _g + 2, _g + 3, _g + 4, _g + 5, _g + 6, _g + 7, _g + 8, _g + 9, _g + 10, _g + 11, _g + 12, _g + 13, _g + 14, _g + 15, _g + 16, _g + 17, _g + 18, _g + 19, _g + 20, _g + 21, _g + 22, _g + 23, _g + 24, _g + 25, _g + 26, _g + 27, _g + 28, _g + 29, _g + 30, _g + 31, _g + 32, _g + 33, _g + 34, _g + 35, _g + 36, _g + 37, _g + 38, _g + 39, _g + 40, _g + 41, _g + 42, _g + 43, _g + 44, _g + 45, _g + 46, _g + 47, _g + 48, _g + 49, _g + 50, _g + 51, _g + 52, _g + 53, _g + 54, _g + 55, _g + 56, _g + 57, _g + 58, _g + 59, _g + 60, _g + 61, _g + 62, _g + 63, _g + 64, _g + 65, _g + 66, _g + 67, _g + 68, _g + 69, _g + 70, _g + 71, _g + 72, _g + 73, _g + 74, _g + 75, _g + 76, _g + 77, _g + 78, _g + 79, _g + 80, _g + 81, _g + 82, _g + 83, _g + 84, _g + 85, _g + 86, _g + 87, _g + 88, _g + 89, _g + 90, _g + 91, _g + 92, _g + 93, _g + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _g + 95, _g + 96, _g + 97, _g + 98, _g + 99, _g + 100, _g + 101, _g + 102, _g + 103, _g + 104, _g + 105, _g + 106, _g + 107, _g + 108, _g + 109, _g + 110, _g + 111, _g + 112, _g + 113, _g + 114, _g + 115, _g + 116, _g + 117, _g + 118, _g + 119, _g + 120, _g + 121, _g + 122, _g + 123, _g + 124, _g + 125, _g + 126, _g + 127, _g + 128, _g + 129, _g + 130, _g + 131, _g + 132, _g + 133, _g + 134, _g + 135, _g + 136, _g + 137, _g + 138, _g + 139, _g + 140, _g + 141, _g + 142, _g + 143, _g + 144, _g + 145, _g + 146, _g + 147, _g + 148, _g + 149, _g + 150, _g + 151, _g + 152, _g + 153, _g + 154, _g + 155, _g + 156, _g + 157, _g + 158, _g + 159, _g + 160, _g + 161, _g + 162, _g + 163, _g + 164, _g + 165, _g + 166, _g + 167, _g + 168, _g + 169, _g + 170, _g + 171, _g + 172, _g + 173, _g + 174, _g + 175, _g + 176, _g + 177, _g + 178, _g + 179, _g + 180, _g + 181, _g + 182, _g + 183, _g + 184, _g + 185, _g + 186, _g + 187, _g + 188, _g + 189 } }; struct font * pbm_defaultfont(const char * const name) { /*---------------------------------------------------------------------------- Generate the built-in font with name 'name'. -----------------------------------------------------------------------------*/ struct font * retval; if (strcmp(name, "bdf") == 0) retval = &default_bdffont; else { bit** defaultfont; unsigned int row; if (strcmp(name, "fixed") != 0) pm_error( "built-in font name unknown, try 'bdf' or 'fixed'"); defaultfont = pbm_allocarray(DEFAULTFONT_COLS, DEFAULTFONT_ROWS); for (row = 0; row < DEFAULTFONT_ROWS; ++row) { unsigned int col; for (col = 0; col < DEFAULTFONT_COLS; col += 32) { int scol; unsigned long l; l = defaultfont_bits[row][col / 32]; /* initial value */ for (scol = MIN( col + 32, DEFAULTFONT_COLS) - 1; scol >= (int)col; --scol) { if (l & 0x01) defaultfont[row][scol] = 1; else defaultfont[row][scol] = 0; l >>= 1; } } } retval = pbm_dissectfont((const bit **)defaultfont, DEFAULTFONT_ROWS, DEFAULTFONT_COLS); } return retval; } static void findFirstBlankRow(const bit ** const font, unsigned int const fcols, unsigned int const frows, unsigned int * const browP) { unsigned int row; bool foundBlank; for (row = 0, foundBlank = false; row < frows / 6 && !foundBlank; ++row) { unsigned int col; bit col0Value = font[row][0]; bool rowIsBlank; rowIsBlank = true; /* initial assumption */ for (col = 1; col < fcols; ++col) if (font[row][col] != col0Value) rowIsBlank = false; if (rowIsBlank) { foundBlank = true; *browP = row; } } if (!foundBlank) pm_error("couldn't find blank pixel row in font"); } static void findFirstBlankCol(const bit ** const font, unsigned int const fcols, unsigned int const frows, unsigned int * const bcolP) { unsigned int col; bool foundBlank; for (col = 0, foundBlank = false; col < fcols / 6 && !foundBlank; ++col) { unsigned int row; bit row0Value = font[0][col]; bool colIsBlank; colIsBlank = true; /* initial assumption */ for (row = 1; row < frows; ++row) if (font[row][col] != row0Value) colIsBlank = false; if (colIsBlank) { foundBlank = true; *bcolP = col; } } if (!foundBlank) pm_error("couldn't find blank pixel column in font"); } static void computeCharacterSize(const bit ** const font, unsigned int const fcols, unsigned int const frows, unsigned int * const cellWidthP, unsigned int * const cellHeightP, unsigned int * const charWidthP, unsigned int * const charHeightP) { unsigned int firstBlankRow; unsigned int firstBlankCol; unsigned int heightLast11Rows; findFirstBlankRow(font, fcols, frows, &firstBlankRow); findFirstBlankCol(font, fcols, frows, &firstBlankCol); heightLast11Rows = frows - firstBlankRow; if (heightLast11Rows % 11 != 0) pm_error("The rows of characters in the font do not appear to " "be all the same height. The last 11 rows are %u pixel " "rows high (from pixel row %u up to %u), " "which is not a multiple of 11.", heightLast11Rows, firstBlankRow, frows); else { unsigned int widthLast15Cols; *cellHeightP = heightLast11Rows / 11; widthLast15Cols = fcols - firstBlankCol; if (widthLast15Cols % 15 != 0) pm_error("The columns of characters in the font do not appear to " "be all the same width. " "The last 15 columns are %u pixel " "columns wide (from pixel col %u up to %u), " "which is not a multiple of 15.", widthLast15Cols, firstBlankCol, fcols); else { *cellWidthP = widthLast15Cols / 15; *charWidthP = firstBlankCol; *charHeightP = firstBlankRow; } } } struct font* pbm_dissectfont(const bit ** const font, unsigned int const frows, unsigned int const fcols) { /* This routine expects a font bitmap representing the following text: (0,0) M ",/^_[`jpqy| M / !"#$%&'()*+ / < ,-./01234567 < > 89:;<=>?@ABC > @ DEFGHIJKLMNO @ _ PQRSTUVWXYZ[ _ { \]^_`abcdefg { } hijklmnopqrs } ~ tuvwxyz{|}~ ~ M ",/^_[`jpqy| M The bitmap must be cropped exactly to the edges. The characters in the border you see are irrelevant except for character size compuations. The 12 x 8 array in the center is the font. The top left character there belongs to code point 0, and the code points increase in standard reading order, so the bottom right character is code point 127. You can't define code points < 32 or > 127 with this font format. The characters in the top and bottom border rows must include a character with the lowest reach of any in the font (e.g. "y", "_") and one with the highest reach (e.g. '"'). The characters in the left and right border columns must include characters with the rightmost and leftmost reach of any in the font (e.g. "M" for both). The border must be separated from the font by one blank text row or text column. The dissection works by finding the first blank row and column; i.e the lower right corner of the "M" in the upper left corner of the matrix. That gives the height and width of the maximum-sized character, which is not too useful. But the distance from there to the opposite side is an integral multiple of the cell size, and that's what we need. Then it's just a matter of filling in all the coordinates. */ unsigned int cellWidth, cellHeight; /* Dimensions in pixels of each cell of the font -- that includes the glyph and the white space above and to the right of it. Each cell is a tile of the font image. The top character row and left character row don't count -- those cells are smaller because they are missing the white space. */ unsigned int charWidth, charHeight; /* Maximum dimensions of glyph itself, inside its cell */ int row, col, ch, r, c, i; struct font * fn; struct glyph * glyph; char* bmap; computeCharacterSize(font, fcols, frows, &cellWidth, &cellHeight, &charWidth, &charHeight); /* Now convert to a general font */ MALLOCVAR(fn); if (fn == NULL) pm_error("out of memory allocating font structure"); fn->maxwidth = charWidth; fn->maxheight = charHeight; fn->x = fn->y = 0; fn->oldfont = font; fn->frows = frows; fn->fcols = fcols; /* Initialize all character positions to "undefined." Those that are defined in the font will be filled in below. */ for (i = 0; i < 256; i++) fn->glyph[i] = NULL; MALLOCARRAY(glyph, nCharsInFont); if ( glyph == NULL ) pm_error( "out of memory allocating glyphs" ); bmap = (char*) malloc( fn->maxwidth * fn->maxheight * nCharsInFont ); if ( bmap == (char*) 0) pm_error( "out of memory allocating glyph data" ); /* Now fill in the 0,0 coords. */ row = cellHeight * 2; col = cellWidth * 2; for (i = 0; i < firstCodePoint; ++i) fn->glyph[i] = NULL; for ( ch = 0; ch < nCharsInFont; ++ch ) { glyph[ch].width = fn->maxwidth; glyph[ch].height = fn->maxheight; glyph[ch].x = glyph[ch].y = 0; glyph[ch].xadd = cellWidth; for ( r = 0; r < glyph[ch].height; ++r ) for ( c = 0; c < glyph[ch].width; ++c ) bmap[r * glyph[ch].width + c] = font[row + r][col + c]; glyph[ch].bmap = bmap; bmap += glyph[ch].width * glyph[ch].height; fn->glyph[firstCodePoint + ch] = &glyph[ch]; col += cellWidth; if ( col >= cellWidth * 14 ) { col = cellWidth * 2; row += cellHeight; } } for (i = firstCodePoint + nCharsInFont; i < 256; ++i) fn->glyph[i] = NULL; return fn; } struct font* pbm_loadfont(const char * const filename) { FILE* fp; struct font* fn; char line[256]; fp = pm_openr( filename ); fgets(line, 256, fp); pm_close( fp ); if (line[0] == PBM_MAGIC1 && (line[1] == PBM_MAGIC2 || line[1] == RPBM_MAGIC2)) { return pbm_loadpbmfont( filename ); } else if (!strncmp(line, "STARTFONT", 9)) { if (!(fn = pbm_loadbdffont( filename ))) pm_error( "could not load BDF font file" ); return fn; } else { pm_error( "font file not in a recognized format "); return NULL; /* should never reach here */ } } struct font * pbm_loadpbmfont(const char * const filename) { FILE * ifP; bit ** font; int fcols, frows; ifP = pm_openr(filename); font = pbm_readpbm(ifP, &fcols, &frows); pm_close(ifP); return pbm_dissectfont((const bit **)font, frows, fcols); } void pbm_dumpfont( fn ) struct font* fn; { /* Dump out font as C source code. */ int row, col, scol, lperrow; unsigned long l; if (fn->oldfont) { printf( "#define DEFAULTFONT_ROWS %d\n", fn->frows ); printf( "#define DEFAULTFONT_COLS %d\n", fn->fcols ); printf( "static unsigned long defaultfont_bits[DEFAULTFONT_ROWS][(DEFAULTFONT_COLS+31)/32] = {\n" ); for ( row = 0; row < fn->frows; ++row ) { lperrow = 0; for ( col = 0; col < fn->fcols; col += 32 ) { if ( lperrow == 0 ) printf( " {" ); else if ( lperrow % 6 == 0 ) { printf( ",\n " ); lperrow = 0; } else printf( "," ); l = 0; for ( scol = col; scol < MIN( col + 32, fn->fcols ); ++scol ) { l <<= 1; if ( fn->oldfont[row][scol] ) l |= 1; } printf( "0x%08lxL", l ); ++lperrow; } printf( "}%s\n", row == fn->frows - 1 ? "" : "," ); } printf( " };\n" ); } else { struct glyph* glyph; int i, j, ng; ng = 0; for (i = 0; i < 256; i++) if (fn->glyph[i]) ng++; printf("static struct glyph _g[%d] = {\n", ng); for (i = 0; i < 256; i++) { if (!(glyph = fn->glyph[i])) continue; printf(" { %d, %d, %d, %d, %d, \"", glyph->width, glyph->height, glyph->x, glyph->y, glyph->xadd); for (j = 0; j < glyph->width * glyph->height; j++) if (glyph->bmap[j]) printf("\\1"); else printf("\\0"); ng--; printf("\" }%s\n", ng ? "," : ""); } printf("};\n"); printf("static struct font default_bdffont = { %d, %d, %d, %d, {\n", fn->maxwidth, fn->maxheight, fn->x, fn->y); for (i = 0; i < 256; i++) { if (fn->glyph[i]) printf(" _g + %d", ng++); else printf(" 0"); if (i != 255) printf(","); printf("\n"); } printf(" }\n};\n"); exit(0); } } /* Routines for loading a BDF font file */ typedef struct { /*---------------------------------------------------------------------------- This is an object for reading lines of a font file. It reads and tokenizes them into words. -----------------------------------------------------------------------------*/ FILE * ifP; char line[1024]; /* This is the storage space for the words of the line. The words go in here, one after another, separated by NULs. It also functions as a work area for readline_read(). */ const char * arg[32]; /* These are the words; each entry is a pointer into line[] (above) */ } readline; static void readline_init(readline * const readlineP, FILE * const ifP) { readlineP->ifP = ifP; readlineP->arg[0] = NULL; } static void tokenize(char * const s, const char ** const words, unsigned int const maxWordCt) { /*---------------------------------------------------------------------------- Chop up 's' into words by changing space characters to NUL. Return as 'words' pointer to the beginning of those words in 's'. If there are more than 'maxWordCt' words in 's', ignore the excess on the right. -----------------------------------------------------------------------------*/ unsigned int n; char * p; p = &s[0]; n = 0; while (*p) { if (ISSPACE(*p)) *p++ = '\0'; else { words[n++] = p; if (n >= maxWordCt-1) break; while (*p && !ISSPACE(*p)) ++p; } } words[n] = NULL; } static void readline_read(readline * const readlineP, bool * const eofP) { /*---------------------------------------------------------------------------- Read a nonblank line from the file. Make its contents available as readlineP->arg[]. Return *eofP == true iff there is no nonblank line before EOF or we are unable to read the file. -----------------------------------------------------------------------------*/ bool gotLine; bool error; for (gotLine = false, error = false; !gotLine && !error; ) { char * rc; rc = fgets(readlineP->line, 1024, readlineP->ifP); if (rc == NULL) error = true; else { tokenize(readlineP->line, readlineP->arg, ARRAY_SIZE(readlineP->arg)); if (readlineP->arg[0] != NULL) gotLine = true; } } *eofP = error; } static void parseBitmapRow(const char * const hex, unsigned int const glyphWidth, unsigned char * const bmap, unsigned int const origBmapIndex, unsigned int * const newBmapIndexP, const char ** const errorP) { /*---------------------------------------------------------------------------- Parse one row of the bitmap for a glyph, from the hexadecimal string for that row in the font file, 'hex'. The glyph is 'glyphWidth' pixels wide. We place our result in 'bmap' at *bmapIndexP and advanced *bmapIndexP. -----------------------------------------------------------------------------*/ unsigned int bmapIndex; int i; /* dot counter */ const char * p; bmapIndex = origBmapIndex; for (i = glyphWidth, p = &hex[0], *errorP = NULL; i > 0 && !*errorP; i -= 4) { if (*p == '\0') pm_asprintf(errorP, "Not enough hexadecimal digits for glyph " "of width %u in '%s'", glyphWidth, hex); else { char const hdig = *p++; unsigned int hdigValue; if (hdig >= '0' && hdig <= '9') hdigValue = hdig - '0'; else if (hdig >= 'a' && hdig <= 'f') hdigValue = 10 + (hdig - 'a'); else if (hdig >= 'A' && hdig <= 'F') hdigValue = 10 + (hdig - 'A'); else pm_asprintf(errorP, "Invalid hex digit x%02x (%c) in bitmap data '%s'", (unsigned int)(unsigned char)hdig, isprint(hdig) ? hdig : '.', hex); if (!*errorP) { if (i > 0) bmap[bmapIndex++] = hdigValue & 0x8 ? 1 : 0; if (i > 1) bmap[bmapIndex++] = hdigValue & 0x4 ? 1 : 0; if (i > 2) bmap[bmapIndex++] = hdigValue & 0x2 ? 1 : 0; if (i > 3) bmap[bmapIndex++] = hdigValue & 0x1 ? 1 : 0; } } } *newBmapIndexP = bmapIndex; } static void readBitmap(readline * const readlineP, unsigned int const glyphWidth, unsigned int const glyphHeight, const char * const charName, unsigned char * const bmap) { int n; unsigned int bmapIndex; bmapIndex = 0; for (n = glyphHeight; n > 0; --n) { bool eof; const char * error; readline_read(readlineP, &eof); if (eof) pm_error("End of file in bitmap for character '%s' in BDF " "font file.", charName); if (!readlineP->arg[0]) pm_error("A line that is supposed to contain bitmap data, " "in hexadecimal, for character '%s' is empty", charName); parseBitmapRow(readlineP->arg[0], glyphWidth, bmap, bmapIndex, &bmapIndex, &error); if (error) { pm_error("Error in line %d of bitmap for character '%s': %s", n, charName, error); pm_strfree(error); } } } static void createBmap(unsigned int const glyphWidth, unsigned int const glyphHeight, readline * const readlineP, const char * const charName, const char ** const bmapP) { unsigned char * bmap; bool eof; if (glyphWidth > 0 && UINT_MAX / glyphWidth < glyphHeight) pm_error("Ridiculously large glyph"); MALLOCARRAY(bmap, glyphWidth * glyphHeight); if (!bmap) pm_error("no memory for font glyph byte map"); readline_read(readlineP, &eof); if (eof) pm_error("End of file encountered reading font glyph byte map from " "BDF font file."); if (streq(readlineP->arg[0], "ATTRIBUTES")) { bool eof; readline_read(readlineP, &eof); if (eof) pm_error("End of file encountered after ATTRIBUTES in BDF " "font file."); } if (!streq(readlineP->arg[0], "BITMAP")) pm_error("'%s' found where BITMAP expected in definition of " "character '%s' in BDF font file.", readlineP->arg[0], charName); assert(streq(readlineP->arg[0], "BITMAP")); readBitmap(readlineP, glyphWidth, glyphHeight, charName, bmap); *bmapP = (char *)bmap; } static void readExpectedStatement(readline * const readlineP, const char * const expected) { /*---------------------------------------------------------------------------- Have the readline object *readlineP read the next line from the file, but expect it to be a line of type 'expected' (i.e. the verb token at the beginning of the line is that, e.g. "STARTFONT"). If it isn't, fail the program. -----------------------------------------------------------------------------*/ bool eof; readline_read(readlineP, &eof); if (eof) pm_error("EOF in BDF font file where '%s' expected", expected); else if (!streq(readlineP->arg[0], expected)) pm_error("Statement of type '%s' where '%s' expected in BDF font file", readlineP->arg[0], expected); } static void skipCharacter(readline * const readlineP) { /*---------------------------------------------------------------------------- In the BDF font file being read by readline object *readlineP, skip through the end of the character we are presently in. -----------------------------------------------------------------------------*/ bool endChar; endChar = FALSE; while (!endChar) { bool eof; readline_read(readlineP, &eof); if (eof) pm_error("End of file in the middle of a character (before " "ENDCHAR) in BDF font file."); endChar = streq(readlineP->arg[0], "ENDCHAR"); } } static void interpEncoding(const char ** const arg, unsigned int * const codepointP, bool * const badCodepointP) { /*---------------------------------------------------------------------------- With arg[] being the ENCODING statement from the font, return as *codepointP the codepoint that it indicates (code point is the character code, e.g. in ASCII, 48 is '0'). But if the statement doesn't give an acceptable codepoint return *badCodepointP == TRUE. -----------------------------------------------------------------------------*/ bool gotCodepoint; bool badCodepoint; unsigned int codepoint; if (!arg[1]) pm_error("Invalid ENCODING statement - no arguments"); if (atoi(arg[1]) >= 0) { codepoint = atoi(arg[1]); gotCodepoint = true; } else { if (arg[2]) { codepoint = atoi(arg[2]); gotCodepoint = true; } else gotCodepoint = false; } if (gotCodepoint) { if (codepoint > 255) badCodepoint = true; else badCodepoint = false; } else badCodepoint = true; *badCodepointP = badCodepoint; *codepointP = codepoint; } static void readEncoding(readline * const readlineP, unsigned int * const codepointP, bool * const badCodepointP) { readExpectedStatement(readlineP, "ENCODING"); interpEncoding(readlineP->arg, codepointP, badCodepointP); } static void processChars(readline * const readlineP, struct font * const fontP) { /*---------------------------------------------------------------------------- Process the CHARS block in a BDF font file, assuming the file is positioned just after the CHARS line. Read the rest of the block and apply its contents to *fontP. -----------------------------------------------------------------------------*/ unsigned int nCharacters; unsigned int nCharsDone; if (!readlineP->arg[1]) pm_error("Invalid CHARS line - no arguments"); nCharacters = atoi(readlineP->arg[1]); nCharsDone = 0; while (nCharsDone < nCharacters) { bool eof; readline_read(readlineP, &eof); if (eof) pm_error("End of file after CHARS reading BDF font file"); if (streq(readlineP->arg[0], "COMMENT")) { /* ignore */ } else if (!streq(readlineP->arg[0], "STARTCHAR")) pm_error("no STARTCHAR after CHARS in BDF font file"); else if (!readlineP->arg[1]) pm_error("Invalid STARTCHAR - no arguments"); else { const char * const charName = readlineP->arg[1]; struct glyph * glyphP; unsigned int codepoint; bool badCodepoint; assert(streq(readlineP->arg[0], "STARTCHAR")); MALLOCVAR(glyphP); if (glyphP == NULL) pm_error("no memory for font glyph for '%s' character", charName); readEncoding(readlineP, &codepoint, &badCodepoint); if (badCodepoint) skipCharacter(readlineP); else { readExpectedStatement(readlineP, "SWIDTH"); readExpectedStatement(readlineP, "DWIDTH"); if (!readlineP->arg[1]) pm_error("Invalid DWIDTH statement - no arguments"); glyphP->xadd = atoi(readlineP->arg[1]); readExpectedStatement(readlineP, "BBX"); if (!readlineP->arg[1]) pm_error("Invalid BBX statement - no arguments"); glyphP->width = atoi(readlineP->arg[1]); if (!readlineP->arg[2]) pm_error("Invalid BBX statement - only 1 argument"); glyphP->height = atoi(readlineP->arg[2]); if (!readlineP->arg[3]) pm_error("Invalid BBX statement - only 2 arguments"); glyphP->x = atoi(readlineP->arg[3]); if (!readlineP->arg[4]) pm_error("Invalid BBX statement - only 3 arguments"); glyphP->y = atoi(readlineP->arg[4]); createBmap(glyphP->width, glyphP->height, readlineP, charName, &glyphP->bmap); readExpectedStatement(readlineP, "ENDCHAR"); assert(codepoint < 256); /* Ensured by readEncoding() */ fontP->glyph[codepoint] = glyphP; } ++nCharsDone; } } } static void processBdfFontLine(readline * const readlineP, struct font * const fontP, bool * const endOfFontP) { /*---------------------------------------------------------------------------- Process a nonblank line just read from a BDF font file. This processing may involve reading more lines. -----------------------------------------------------------------------------*/ *endOfFontP = FALSE; /* initial assumption */ assert(readlineP->arg[0] != NULL); /* Entry condition */ if (streq(readlineP->arg[0], "COMMENT")) { /* ignore */ } else if (streq(readlineP->arg[0], "SIZE")) { /* ignore */ } else if (streq(readlineP->arg[0], "STARTPROPERTIES")) { /* Read off the properties and ignore them all */ unsigned int propCount; unsigned int i; if (!readlineP->arg[1]) pm_error("Invalid STARTPROPERTIES statement - no arguments"); propCount = atoi(readlineP->arg[1]); for (i = 0; i < propCount; ++i) { bool eof; readline_read(readlineP, &eof); if (eof) pm_error("End of file after STARTPROPERTIES in BDF font file"); } } else if (streq(readlineP->arg[0], "FONTBOUNDINGBOX")) { if (!readlineP->arg[1]) pm_error("Invalid FONTBOUNDINGBOX statement - no arguments"); fontP->maxwidth = atoi(readlineP->arg[1]); if (!readlineP->arg[2]) pm_error("Invalid FONTBOUNDINGBOX statement - only 1 argument"); fontP->maxheight = atoi(readlineP->arg[2]); if (!readlineP->arg[3]) pm_error("Invalid FONTBOUNDINGBOX statement - only 2 arguments"); fontP->x = atoi(readlineP->arg[3]); if (!readlineP->arg[4]) pm_error("Invalid FONTBOUNDINGBOX statement - only 3 arguments"); fontP->y = atoi(readlineP->arg[4]); } else if (streq(readlineP->arg[0], "ENDFONT")) { *endOfFontP = true; } else if (streq(readlineP->arg[0], "CHARS")) { processChars(readlineP, fontP); } else { /* ignore */ } } struct font * pbm_loadbdffont(const char * const name) { FILE * ifP; readline readline; struct font * fontP; bool endOfFont; ifP = fopen(name, "rb"); if (!ifP) pm_error("Unable to open BDF font file name '%s'. errno=%d (%s)", name, errno, strerror(errno)); readline_init(&readline, ifP); MALLOCVAR(fontP); if (fontP == NULL) pm_error("no memory for font"); fontP->oldfont = 0; { /* Initialize all characters to nonexistent; we will fill the ones we find in the bdf file later. */ unsigned int i; for (i = 0; i < 256; ++i) fontP->glyph[i] = NULL; } fontP->x = fontP->y = 0; readExpectedStatement(&readline, "STARTFONT"); endOfFont = FALSE; while (!endOfFont) { bool eof; readline_read(&readline, &eof); if (eof) pm_error("End of file before ENDFONT statement in BDF font file"); processBdfFontLine(&readline, fontP, &endOfFont); } return fontP; }