const char * UsageLines [] = {
"Reads text lines from standard input.",
"Writes P4 PBM image to standard output.",
"Each input character becomes an output pixel.",
"Character specified as (key) becomes a '1' output pixel.",
"All other inputs become a '0' output pixel.",
"All input lines must be same size = output width.",
"Number of input lines = output height.",
"May 20, 2020. Newest is at gopher -p users/julianbr sdf.org",
"(See 'p4show' for the opposite of 'p4paint'.)",
};
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );
struct ImageLine {
unsigned char * data;
int width;
struct ImageLine * next;
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WidthIncrement 5
int ReadKey (struct ImageLine * * ImageLinesPtr, char key)
{
struct ImageLine * ImageLine, * * ImageLinePtr;
unsigned char * WiderLine;
char c;
ImageLinesPtr [0] = NULL;
ImageLinePtr = ImageLinesPtr;
c = getchar ();
while (c != EOF) {
ImageLine = malloc (sizeof (ImageLine [0] ) );
if (ImageLine == NULL) {
fprintf (stderr, "***p4paint: Not enough memory.\n");
return 0;
}
ImageLinePtr [0] = ImageLine;
ImageLine->width = 0;
ImageLine->next = NULL;
ImageLinePtr = & ImageLine->next;
while (c != EOF && c != '\n') {
if (ImageLine->width%(8*WidthIncrement) == 0) {
WiderLine = malloc (ImageLine->width/8
+ WidthIncrement);
if (WiderLine == NULL) {
fprintf (stderr, "***p4paint: Not");
fprintf (stderr, " enough memory.\n");
return 0;
}
if (ImageLine->width > 0) {
memcpy (WiderLine, ImageLine->data,
ImageLine->width/8);
free (ImageLine->data);
}
ImageLine->data = WiderLine;
}
if (ImageLine->width%8 == 0)
ImageLine->data [ImageLine->width/8] = 0;
if (c == key)
ImageLine->data [ImageLine->width/8]
+= 1<<(7 - ImageLine->width%8);
ImageLine->width++;
c = getchar ();
}
if (c != EOF)
c = getchar ();
}
if (ImageLinesPtr [0] == NULL) {
fprintf (stderr, "***p4paint: No input found.\n");
return 0;
}
return 1;
}
void WriteImage (struct ImageLine * ImageLines)
{
struct ImageLine * ImageLine;
int width, height;
height = 0;
ImageLine = ImageLines;
while (ImageLine != NULL) {
height++;
if (ImageLine == ImageLines)
width = ImageLine->width;
else if (ImageLine->width != width) {
fprintf (stderr, "***p4paint: line #%d", height - 1);
fprintf (stderr, " is %d long,", width);
fprintf (stderr, " line #%d", height);
fprintf (stderr, " is %d long.\n", ImageLine->width);
fprintf (stderr, "***p4paint: All input lines");
fprintf (stderr, " must be same length.\n");
return;
}
ImageLine = ImageLine->next;
}
printf ("P4\n");
printf ("%d %d\n", width, height);
ImageLine = ImageLines;
while (ImageLine != NULL) {
if (ImageLine->width > 0)
fwrite (
ImageLine->data,
(ImageLine->width + 7)/8,
1,
stdout);
ImageLine = ImageLine->next;
}
}
void CloseImage (struct ImageLine * ImageLines)
{
struct ImageLine * ImageLine, * NextImageLine;
ImageLine = ImageLines;
while (ImageLine != NULL) {
NextImageLine = ImageLine->next;
if (ImageLine->width > 0)
free (ImageLine->data);
free (ImageLine);
ImageLine = NextImageLine;
}
}
int main (int argc, char * argv [] )
{
struct ImageLine * ImageLines;
char key, c;
int i;
if (argc != 2) {
fprintf (stderr, "Usage: p4paint (key)\n");
for (i = 0; i < NumUsageLines; i++)
printf ("%s\n", UsageLines [i] );
}
else if (sscanf (argv [1], "%c%c", & key, & c) != 1) {
fprintf (stderr, "***p4paint: Improper \"%s\":", argv [1] );
fprintf (stderr, " must be single character.\n");
}
else {
if (ReadKey (& ImageLines, key) )
WriteImage (ImageLines);
CloseImage (ImageLines);
}
return 0;
}