const char * UsageLines [] = {
       "Usage: p6fade (background r) (background g) (background b)",
       "\t(fade factor between -10 and 10)",
       "\t[(vertical edge across) (horizontal edge down) ]+",
       "Reads P6 PPM image from standard input and writes to",
       "standard output same size.",
       "",
       "Boundaries alternate",
       "between vertical edges specified by across (left edge = 0)",
       "and horizontal edges specified by down (top edge = 0).",
       "The edge path is always closed.  p6fade will use the",
       "first across again if needed to close path.",
       "If no path is apecified, will operate on whole image.",
       "Need a minimum of 4 numbers for any effect (4 will be a rectangle).",
       "",
       "Fade factor of 0 will cause input image to pass to output unchanged.",
       "Fade factor of 10 will replace everything outside boundary",
       "with specified background color.  Fade factor between 1 and 9",
       "will fade area outside boundary proportionally.",
       "Fade factor of -10 will replace everything inside boundary",
       "with specified background color.  Fade factor between -1 and -9",
       "will fade area inside boundary proportionally.",
       "",
       "If no boundary is specified, p6fade will operate on whole",
       "image if fade factor is between 1 and 10.",
       "",
       "April 21, 2021.  Newest is at gopher -p users/julianbr sdf.org",
       };
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );


#include <stdio.h>


void Fade (
               int width, int height,
               int backgroundr, int backgroundg, int backgroundb,
               int fade,
               int * Edges, int NumEdges)
       {
       int across1, down1, across2, across, down;
       int r, g, b, i, j, k;
       int NumCrossings;

       printf ("P6\n");
       printf ("%d %d\n", width, height);
       printf ("255\n");
       r = getchar ();
       for (down = 0; down < height; down++) {
               for (across = 0; across < width; across++) {
                       NumCrossings = 0;
                       i = 0;
                       j = 1;
                       k = 2;
                       while (j < NumEdges) {
                               across1 = Edges [i];
                               down1 = Edges [j];
                               if (k < NumEdges)
                                       across2 = Edges [k];
                               else
                                       across2 = Edges [0];
                               if (down >= down1) {
                                       if (across2 > across
                                                       && across >= across1)
                                               NumCrossings++;
                                       else if (across1 > across
                                                       && across >= across2)
                                               NumCrossings--;
                                       }
                               i += 2;
                               j += 2;
                               k += 2;
                               }
                       if (r != EOF)
                               g = getchar ();
                       if (g != EOF)
                               b = getchar ();
                       if (NumCrossings == 0) {
                               if (fade > 0) {
                                       putchar ((fade*backgroundr
                                               + (10 - fade)*r + 5)/10);
                                       putchar ((fade*backgroundg
                                               + (10 - fade)*g + 5)/10);
                                       putchar ((fade*backgroundb
                                               + (10 - fade)*b + 5)/10);
                                       }
                               else {
                                       putchar (r);
                                       putchar (g);
                                       putchar (b);
                                       }
                               }
                       else {
                               if (fade < 0) {
                                       putchar ((- fade*backgroundr
                                               + (10 + fade)*r + 5)/10);
                                       putchar ((- fade*backgroundg
                                               + (10 + fade)*g + 5)/10);
                                       putchar ((- fade*backgroundb
                                               + (10 + fade)*b + 5)/10);
                                       }
                               else {
                                       putchar (r);
                                       putchar (g);
                                       putchar (b);
                                       }
                               }
                       if (b != EOF)
                               r = getchar ();
                       }
               }
       if (b == EOF)
               fprintf (stderr, "***p6fade: Not enough image data.\n");
       if (r != EOF)
               fprintf (stderr, "***p6fade: Too much image data.\n");
       }


#include <stdlib.h>


int main (int argc, char * argv [] )
       {
       int * Edges;
       int i, width, height, r, g, b, NumEdges, ok, depth, fade;
       char c;

       Edges = NULL;
       if (argc < 2) {
               for (i = 0; i < NumUsageLines; i++)
                       printf ("%s\n", UsageLines [i] );
               }
       else if (argc < 5) {
               fprintf (stderr, "***Usage: %s", argv [0] );
               fprintf (stderr, " (r) (g) (b)");
               fprintf (stderr, " (fade) (edges)\n");
               }
       else {
               ok = 1;
               if (sscanf (argv [1], "%d%c", & r, & c) != 1) {
                       fprintf (stderr, "***p6fade: Expecting number");
                       fprintf (stderr, " for background r, found");
                       fprintf (stderr, " \"%s\".\n", argv [1] );
                       ok = 0;
                       }
               if (sscanf (argv [2], "%d%c", & g, & c) != 1) {
                       fprintf (stderr, "***p6fade: Expecting number");
                       fprintf (stderr, " for background g, found");
                       fprintf (stderr, " \"%s\".\n", argv [2] );
                       ok = 0;
                       }
               if (sscanf (argv [3], "%d%c", & b, & c) != 1) {
                       fprintf (stderr, "***p6fade: Expecting number");
                       fprintf (stderr, " for background b, found");
                       fprintf (stderr, " \"%s\".\n", argv [3] );
                       ok = 0;
                       }
               if (sscanf (argv [4], "%d%c", & fade, & c) != 1
                               || fade < -10 || fade > 10) {
                       fprintf (stderr, "***p6fade: Expecting number");
                       fprintf (stderr, " between -10 and 10 for");
                       fprintf (stderr, " fade, found");
                       fprintf (stderr, " \"%s\".\n", argv [4] );
                       ok = 0;
                       }
               if (ok) {
                       NumEdges = argc - 5;
                       Edges = NULL;
                       if (NumEdges > 0) {
                               Edges = malloc (NumEdges*sizeof (Edges [0] ) );
                               if (Edges == NULL) {
                                       fprintf (stderr, "***p6fade: Not");
                                       fprintf (stderr, " enough memory.\n");
                                       ok = 0;
                                       }
                               }
                       }
               if (ok) {
                       for (i = 0; i < NumEdges; i++) {
                               if (sscanf (argv [i + 5], "%d%c",
                                               Edges + i, & c) != 1) {
                                       fprintf (stderr, "***p6fade:");
                                       fprintf (stderr, " Expecting");
                                       fprintf (stderr, " number for edge,");
                                       fprintf (stderr, " found \"");
                                       fprintf (stderr, "%s", argv [i + 4] );
                                       fprintf (stderr, "\".\n");
                                       ok = 0;
                                       }
                               }
                       }
               if (ok) {
                       if (NumEdges > 2 && NumEdges%2 == 1
                                       && Edges [0] != Edges [NumEdges - 1] ) {
                               fprintf (stderr, "***p6fade:");
                               fprintf (stderr, " First across must be same");
                               fprintf (stderr, " as last across but found");
                               fprintf (stderr, " %d and", Edges [0] );
                               fprintf (stderr, " %d", Edges [NumEdges - 1] );
                               fprintf (stderr, ".\nCan omit last across.\n");
                               ok = 0;
                               }
                       }
               if (ok) {
                       if (getchar () != 'P'
                                       || getchar () != '6'
                                       || scanf ("%d", & width) != 1
                                       || scanf ("%d", & height) != 1
                                       || scanf ("%d", & depth) != 1
                                       || getchar () != '\n') {
                               fprintf (stderr, "***p6fade: Improper");
                               fprintf (stderr, " input,");
                               fprintf (stderr, " must be P6 PPM.\n");
                               ok = 0;
                               }
                       }
               if (ok)
                       Fade (width, height, r, g, b, fade,
                                       Edges, NumEdges);
               }
       if (Edges != NULL)
               free (Edges);
       return 0;
       }