const char * (UsageLines [] ) = {
"p4label15: Reads text from standard input,",
"writes P4 pbm to standard output using fixed-width.",
"Usage: p4label15 (output image width) (output image height)",
"Only ASCII characters are recognized.",
"",
"January 4, 2023. Latest at
gopher://sdf.org/1/users/julianbr",
};
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );
#define NUM_ROWS 15
#define LETTER_SPACING 1
#define LINE_SPACING 1
#define MARGIN 5
int MaxNumColumns;
int (Outlines [] ) [NUM_ROWS] = {
{0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0 }, /* ! */
{0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* " */
{0, 0, 18, 18, 18, 63, 18, 18, 63, 18, 18, 18, 0, 0, 0 }, /* # */
{0, 8, 8, 62, 73, 72, 72, 62, 9, 9, 73, 62, 8, 8, 0 }, /* $ */
{0, 0, 50, 74, 52, 4, 8, 8, 16, 22, 41, 38, 0, 0, 0 }, /* % */
{0, 0, 12, 18, 18, 12, 24, 37, 34, 34, 34, 29, 0, 0, 0 }, /* & */
{0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* ' */
{0, 0, 1, 2, 4, 4, 4, 4, 4, 4, 2, 1, 0, 0, 0 }, /* ( */
{0, 0, 4, 2, 1, 1, 1, 1, 1, 1, 2, 4, 0, 0, 0 }, /* ) */
{0, 0, 0, 0, 0, 18, 12, 63, 12, 18, 0, 0, 0, 0, 0 }, /* * */
{0, 0, 0, 0, 0, 4, 4, 31, 4, 4, 0, 0, 0, 0, 0 }, /* + */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0 }, /* , */
{0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0 }, /* - */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, /* . */
{0, 0, 1, 1, 2, 2, 4, 4, 8, 8, 16, 16, 0, 0, 0 }, /* / */
{0, 0, 30, 33, 33, 35, 37, 41, 49, 33, 33, 30, 0, 0, 0 }, /* 0 */
{0, 0, 4, 12, 20, 4, 4, 4, 4, 4, 4, 31, 0, 0, 0 }, /* 1 */
{0, 0, 30, 33, 33, 1, 2, 4, 8, 16, 32, 63, 0, 0, 0 }, /* 2 */
{0, 0, 30, 33, 33, 1, 14, 1, 1, 33, 33, 30, 0, 0, 0 }, /* 3 */
{0, 0, 1, 3, 5, 9, 17, 33, 63, 1, 1, 1, 0, 0, 0 }, /* 4 */
{0, 0, 63, 32, 32, 32, 62, 1, 1, 1, 33, 30, 0, 0, 0 }, /* 5 */
{0, 0, 14, 16, 32, 32, 62, 33, 33, 33, 33, 30, 0, 0, 0 }, /* 6 */
{0, 0, 63, 1, 1, 2, 2, 4, 4, 8, 8, 8, 0, 0, 0 }, /* 7 */
{0, 0, 30, 33, 33, 33, 30, 33, 33, 33, 33, 30, 0, 0, 0 }, /* 8 */
{0, 0, 30, 33, 33, 33, 33, 31, 1, 1, 2, 28, 0, 0, 0 }, /* 9 */
{0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0 }, /* : */
{0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 2, 0, 0 }, /* ; */
{0, 0, 0, 1, 2, 4, 8, 16, 8, 4, 2, 1, 0, 0, 0 }, /* < */
{0, 0, 0, 0, 0, 0, 63, 0, 63, 0, 0, 0, 0, 0, 0 }, /* = */
{0, 0, 0, 16, 8, 4, 2, 1, 2, 4, 8, 16, 0, 0, 0 }, /* > */
{0, 0, 30, 33, 33, 33, 2, 4, 4, 0, 4, 4, 0, 0, 0 }, /* ? */
{0, 0, 62, 65, 79, 81, 81, 81, 83, 77, 64, 63, 0, 0, 0 }, /* @ */
{0, 0, 30, 33, 33, 33, 33, 63, 33, 33, 33, 33, 0, 0, 0 }, /* A */
{0, 0, 62, 33, 33, 33, 62, 33, 33, 33, 33, 62, 0, 0, 0 }, /* B */
{0, 0, 30, 33, 33, 32, 32, 32, 32, 33, 33, 30, 0, 0, 0 }, /* C */
{0, 0, 60, 34, 33, 33, 33, 33, 33, 33, 34, 60, 0, 0, 0 }, /* D */
{0, 0, 63, 32, 32, 32, 60, 32, 32, 32, 32, 63, 0, 0, 0 }, /* E */
{0, 0, 63, 32, 32, 32, 60, 32, 32, 32, 32, 32, 0, 0, 0 }, /* F */
{0, 0, 30, 33, 33, 32, 32, 39, 33, 33, 33, 30, 0, 0, 0 }, /* G */
{0, 0, 33, 33, 33, 33, 63, 33, 33, 33, 33, 33, 0, 0, 0 }, /* H */
{0, 0, 7, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 0, 0 }, /* I */
{0, 0, 7, 2, 2, 2, 2, 2, 2, 34, 34, 28, 0, 0, 0 }, /* J */
{0, 0, 33, 34, 36, 40, 48, 48, 40, 36, 34, 33, 0, 0, 0 }, /* K */
{0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 63, 0, 0, 0 }, /* L */
{0, 0, 65, 99, 85, 73, 73, 65, 65, 65, 65, 65, 0, 0, 0 }, /* M */
{0, 0, 33, 33, 33, 49, 41, 37, 35, 33, 33, 33, 0, 0, 0 }, /* N */
{0, 0, 30, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0, 0 }, /* O */
{0, 0, 62, 33, 33, 33, 33, 62, 32, 32, 32, 32, 0, 0, 0 }, /* P */
{0, 0, 30, 33, 33, 33, 33, 33, 33, 33, 37, 30, 1, 0, 0 }, /* Q */
{0, 0, 62, 33, 33, 33, 33, 62, 40, 36, 34, 33, 0, 0, 0 }, /* R */
{0, 0, 30, 33, 32, 32, 30, 1, 1, 33, 33, 30, 0, 0, 0 }, /* S */
{0, 0, 127, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0 }, /* T */
{0, 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 30, 0, 0, 0 }, /* U */
{0, 0, 33, 33, 33, 33, 33, 18, 18, 18, 12, 12, 0, 0, 0 }, /* V */
{0, 0, 65, 65, 65, 65, 65, 73, 73, 85, 99, 65, 0, 0, 0 }, /* W */
{0, 0, 33, 33, 18, 18, 12, 12, 18, 18, 33, 33, 0, 0, 0 }, /* X */
{0, 0, 65, 65, 34, 34, 20, 8, 8, 8, 8, 8, 0, 0, 0 }, /* Y */
{0, 0, 63, 1, 1, 2, 4, 8, 16, 32, 32, 63, 0, 0, 0 }, /* Z */
{0, 0, 7, 4, 4, 4, 4, 4, 4, 4, 4, 7, 0, 0, 0 }, /* [ */
{0, 0, 16, 16, 8, 8, 4, 4, 2, 2, 1, 1, 0, 0, 0 }, /* \ */
{0, 0, 7, 1, 1, 1, 1, 1, 1, 1, 1, 7, 0, 0, 0 }, /* ] */
{0, 0, 4, 10, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* ^ */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0 }, /* _ */
{2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* ` */
{0, 0, 0, 0, 0, 30, 1, 31, 33, 33, 33, 31, 0, 0, 0 }, /* a */
{0, 0, 32, 32, 32, 62, 33, 33, 33, 33, 33, 62, 0, 0, 0 }, /* b */
{0, 0, 0, 0, 0, 30, 33, 32, 32, 32, 33, 30, 0, 0, 0 }, /* c */
{0, 0, 1, 1, 1, 31, 33, 33, 33, 33, 33, 31, 0, 0, 0 }, /* d */
{0, 0, 0, 0, 0, 30, 33, 33, 63, 32, 32, 30, 0, 0, 0 }, /* e */
{0, 0, 7, 8, 8, 62, 8, 8, 8, 8, 8, 8, 0, 0, 0 }, /* f */
{0, 0, 0, 0, 0, 31, 33, 33, 33, 33, 33, 31, 1, 1, 30 }, /* g */
{0, 0, 32, 32, 32, 62, 33, 33, 33, 33, 33, 33, 0, 0, 0 }, /* h */
{0, 0, 2, 2, 0, 6, 2, 2, 2, 2, 2, 7, 0, 0, 0 }, /* i */
{0, 0, 2, 2, 0, 6, 2, 2, 2, 2, 2, 2, 34, 34, 14 }, /* j */
{0, 0, 32, 32, 32, 33, 34, 36, 56, 36, 34, 33, 0, 0, 0 }, /* k */
{0, 0, 6, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 0, 0 }, /* l */
{0, 0, 0, 0, 0, 126, 73, 73, 73, 73, 73, 73, 0, 0, 0 }, /* m */
{0, 0, 0, 0, 0, 62, 33, 33, 33, 33, 33, 33, 0, 0, 0 }, /* n */
{0, 0, 0, 0, 0, 30, 33, 33, 33, 33, 33, 30, 0, 0, 0 }, /* o */
{0, 0, 0, 0, 0, 62, 33, 33, 33, 33, 33, 62, 32, 32, 32 }, /* p */
{0, 0, 0, 0, 0, 31, 33, 33, 33, 33, 33, 31, 1, 1, 1 }, /* q */
{0, 0, 0, 0, 0, 47, 48, 32, 32, 32, 32, 32, 0, 0, 0 }, /* r */
{0, 0, 0, 0, 0, 31, 32, 32, 30, 1, 1, 62, 0, 0, 0 }, /* s */
{0, 0, 8, 8, 8, 62, 8, 8, 8, 8, 8, 7, 0, 0, 0 }, /* t */
{0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 33, 31, 0, 0, 0 }, /* u */
{0, 0, 0, 0, 0, 33, 33, 33, 18, 18, 12, 12, 0, 0, 0 }, /* v */
{0, 0, 0, 0, 0, 65, 65, 73, 73, 73, 73, 62, 0, 0, 0 }, /* w */
{0, 0, 0, 0, 0, 33, 33, 18, 12, 18, 33, 33, 0, 0, 0 }, /* x */
{0, 0, 0, 0, 0, 33, 33, 33, 33, 33, 33, 31, 1, 1, 30 }, /* y */
{0, 0, 0, 0, 0, 63, 2, 4, 8, 16, 32, 63, 0, 0, 0 }, /* z */
{0, 0, 3, 4, 4, 4, 8, 4, 4, 4, 4, 3, 0, 0, 0 }, /* { */
{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, /* | */
{0, 0, 12, 2, 2, 2, 1, 2, 2, 2, 2, 12, 0, 0, 0 }, /* } */
{0, 12, 18, 18, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* degree */
{0, 49, 73, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* ~ */
};
int NumOutlines = sizeof (Outlines) / sizeof (Outlines [0] );
#include <stdlib.h>
#include <stdio.h>
void WriteLabel (unsigned char (* TextLine) [NUM_ROWS] , int width, int height)
{
int * Outline;
int c, i, j, byte, NumTextLines, NumImageLines, NumChars, MaxNumChars, PowerOf2;
int row, position, NumColumns;
NumImageLines = 0;
printf ("P4\n");
printf ("%d %d\n", width, height);
for (i = 0; i < MARGIN; i++) {
if (NumImageLines < height) {
for (byte = 0; byte < (width + 7)/8; byte++)
putchar (0);
}
NumImageLines++;
}
NumTextLines = 0;
MaxNumChars = 0;
c = getchar ();
while (c != EOF) {
NumChars = 0;
for (i = 0; i < NUM_ROWS; i++) {
for (byte = 0; byte < (width + 7)/8; byte++)
TextLine [byte] [i] = 0;
}
while (c != '\n' && c != EOF) {
if (c - '!' >= 0 && c - '!' < NumOutlines) {
PowerOf2 = 1;
NumColumns = 0;
Outline = Outlines [c - '!'];
for (i = 0; i < NUM_ROWS; i++) {
row = Outline [i];
while (PowerOf2 <= row) {
PowerOf2 *= 2;
NumColumns++;
}
}
if (NumColumns > MaxNumColumns)
NumColumns = MaxNumColumns;
for (i = 0; i < NumColumns; i++) {
position = MARGIN + NumChars*(MaxNumColumns + LETTER_SPACING)
+ (MaxNumColumns - NumColumns)/2 + i;
if (position < width) {
byte = position/8;
for (j = 0; j < NUM_ROWS; j++) {
row = Outline [j];
if (row & (1 << (NumColumns - i - 1) ) )
TextLine [byte] [j] += (1 << (7 - position%8) );
}
}
}
}
NumChars++;
c = getchar ();
}
for (i = 0; i < NUM_ROWS; i++) {
if (NumImageLines < height) {
for (byte = 0; byte < (width + 7)/8; byte++)
putchar (TextLine [byte] [i] );
}
NumImageLines++;
}
for (i = 0; i < LINE_SPACING; i++) {
if (NumImageLines < height) {
for (byte = 0; byte < (width + 7)/8; byte++)
putchar (0);
}
NumImageLines++;
}
if (MaxNumChars < NumChars)
MaxNumChars = NumChars;
NumTextLines++;
if (c != EOF)
c = getchar ();
}
while (NumImageLines < height) {
for (byte = 0; byte < (width + 7)/8; byte++)
putchar (0);
NumImageLines++;
}
fprintf (stderr, "p4label15: Fits");
fprintf (stderr, " %d", 2*MARGIN + MaxNumChars*MaxNumColumns + LETTER_SPACING*(MaxNumChars - 1) );
fprintf (stderr, "x%d,", 2*MARGIN + (NumTextLines - 1)*LINE_SPACING + NumTextLines*NUM_ROWS);
fprintf (stderr, " writing %dx%d.\n", width, height);
}
int main (int argc, char * * argv)
{
unsigned char (* TextLine) [NUM_ROWS];
int i, j, width, height, PowerOf2, row;
char c;
PowerOf2 = 1;
MaxNumColumns = 0;
for (i = 0; i < NumOutlines; i++) {
for (j = 0; j < NUM_ROWS; j++) {
row = Outlines [i] [j];
while (PowerOf2 <= row) {
PowerOf2 *= 2;
MaxNumColumns++;
}
}
}
if (argc == 1) {
for (i = 0; i < NumUsageLines; i++)
printf ("%s\n", UsageLines [i] );
printf ("Each character %dx%d,", MaxNumColumns, NUM_ROWS);
printf (" letter spacing %d, line spacing %d,", LETTER_SPACING, LINE_SPACING);
printf (" margin %d.\n", MARGIN);
}
else if (argc == 3) {
if (
sscanf (argv [1], "%d%c", & width, & c) != 1
|| sscanf (argv [2], "%d%c", & height, & c) != 1
|| width <= 0
|| height <= 0) {
fprintf (stderr, "p4label1528: Improper \"%s\" \"%s\",", argv [1], argv [2] );
fprintf (stderr, " expecting width and height.\n");
}
else {
TextLine = malloc (NUM_ROWS*((width + 7)/8) );
if (TextLine == NULL)
fprintf (stderr, "***p4label15: Not enough memory.\n");
else {
WriteLabel (TextLine, width, height);
free (TextLine);
}
}
}
else
printf ("Usage: %s: (width) (height)\n", argv [0] );
return 0;
}