#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* Bring in the gd library functions */
#include "gd.h"

/* Bring in standard I/O and string manipulation functions */
#include <stdio.h>
#include <stdlib.h>            /* for atoi() */
#include <string.h>

#if defined(__IBMC__)
   #include <process.h>
#else
 #ifdef  _WIN32
  #include <process.h>
  int
  getpid ()
  {
    return _getpid ();
  }
 #else
  #include <unistd.h>            /* for getpid(), unlink() */
 #endif
#endif

int
main (int argc, char **argv)
{
  FILE *in;
  FILE *out;
  char outFn[20];
  int useStdinStdout = 0;

  /* Declare our image pointer */
  gdImagePtr im = 0;
  int i;
  /* We'll clear 'no' once we know the user has made a
     reasonable request. */
  int no = 1;
  /* We'll set 'write' once we know the user's request
     requires that the image be written back to disk. */
  int write = 0;
  /* C programs always get at least one argument; we want at
     least one more (the image), more in practice. */
  if (argc < 2 || !strcmp (argv[1], "--help"))
    {
      no = 1;
      goto usage;
    }

  /* The last argument should be the image. Open the file. */
  if (strcmp ("-", argv[argc - 1]) == 0)
    {                          /* - is synonymous with STDIN */
      useStdinStdout = 1;
      in = stdin;
    }
  else
    {
      in = fopen (argv[argc - 1], "rb");
    }
  if (!in)
    {
      fprintf (stderr, "Error: can't open file %s.\n", argv[argc - 1]);
      exit (1);
    }
  /* Now load the image. */
#ifdef HAVE_LIBPNG
  im = gdImageCreateFromPng (in);
#else
  fprintf (stderr, "No PNG library support.\n");
#endif
  fclose (in);
  /* If the load failed, it must not be a PNG file. */
  if (!im)
    {
      fprintf (stderr,
              "Error: %s is not a valid PNG file.\n", argv[argc - 1]);
      exit (1);
    }
  /* Consider each argument in turn. */
  for (i = 1; (i < (argc - 1)); i++)
    {
      /* -i turns on and off interlacing. */
      if (!strcmp (argv[i], "--help"))
       {
         /* Every program should use this for help! :) */
         no = 1;
         goto usage;
       }
      else if (!strcmp (argv[i], "-i"))
       {
         if (i == (argc - 2))
           {
             fprintf (stderr, "Error: -i specified without y or n.\n");
             no = 1;
             goto usage;
           }
         if (!strcmp (argv[i + 1], "y"))
           {
             /* Set interlace. */
             gdImageInterlace (im, 1);
           }
         else if (!strcmp (argv[i + 1], "n"))
           {
             /* Clear interlace. */
             gdImageInterlace (im, 0);
           }
         else
           {
             fprintf (stderr, "Error: -i specified without y or n.\n");
             no = 1;
             goto usage;
           }
         i++;
         no = 0;
         write = 1;
       }
      else if (!strcmp (argv[i], "-t"))
       {
         /* Set transparent index (or none). */
         int index;
         if (i == (argc - 2))
           {
             fprintf (stderr,
                      "Error: -t specified without a color table index.\n");
             no = 1;
             goto usage;
           }
         if (!strcmp (argv[i + 1], "none"))
           {
             /* -1 means not transparent. */
             gdImageColorTransparent (im, -1);
           }
         else
           {
             /* OK, get an integer and set the index. */
             index = atoi (argv[i + 1]);
             gdImageColorTransparent (im, index);
           }
         i++;
         write = 1;
         no = 0;
       }
      else if (!strcmp (argv[i], "-l"))
       {
         /* List the colors in the color table. */
         int j;
         if (!im->trueColor)
           {
             /* Tabs used below. */
             printf ("Index    Red     Green   Blue Alpha\n");
             for (j = 0; (j < gdImageColorsTotal (im)); j++)
               {
                 /* Use access macros to learn colors. */
                 printf ("%d   %d      %d      %d      %d\n",
                         j,
                         gdImageRed (im, j),
                         gdImageGreen (im, j),
                         gdImageBlue (im, j), gdImageAlpha (im, j));
               }
           }
         else
           {
             printf ("Truecolor image, no palette entries to list.\n");
           }
         no = 0;
       }
      else if (!strcmp (argv[i], "-d"))
       {
         /* Output dimensions, etc. */
         int t;
         printf ("Width: %d Height: %d Colors: %d\n",
                 gdImageSX (im), gdImageSY (im), gdImageColorsTotal (im));
         t = gdImageGetTransparent (im);
         if (t != (-1))
           {
             printf ("First 100%% transparent index: %d\n", t);
           }
         else
           {
             /* -1 means the image is not transparent. */
             printf ("First 100%% transparent index: none\n");
           }
         if (gdImageGetInterlaced (im))
           {
             printf ("Interlaced: yes\n");
           }
         else
           {
             printf ("Interlaced: no\n");
           }
         no = 0;
       }
      else if (!strcmp (argv[i], "-a"))
       {
         /* Alpha channel info -- thanks to Wez Furlong */
         int maxx, maxy, x, y, alpha, pix, nalpha = 0;

         maxx = gdImageSX (im);
         maxy = gdImageSY (im);

         printf ("alpha channel information:\n");

         if (im->trueColor)
           {
             for (y = 0; y < maxy; y++)
               {
                 for (x = 0; x < maxx; x++)
                   {
                     pix = gdImageGetPixel (im, x, y);
                     alpha = gdTrueColorGetAlpha (pix);

                     if (alpha > gdAlphaOpaque)
                       {
                         /* Use access macros to learn colors. */
                         printf ("%d   %d      %d      %d\n",
                                 gdTrueColorGetRed (pix),
                                 gdTrueColorGetGreen (pix),
                                 gdTrueColorGetBlue (pix), alpha);
                         nalpha++;
                       }

                   }
               }
           }
         else
           printf ("NOT a true color image\n");
         no = 0;
         printf ("%d alpha channels\n", nalpha);

       }
      else
       {
         fprintf (stderr, "Unknown argument: %s\n", argv[i]);
         break;
       }
    }
usage:
  if (no)
    {
      /* If the command failed, output an explanation. */
      fprintf (stderr,
              "Usage: webpng [-i y|n ] [-l] [-t index|none ] [-d] pngname.png\n"
              "  -i [y|n]   Turns on/off interlace\n"
              "  -l         Prints the table of color indexes\n"
              "  -t [index] Set the transparent color to the specified index (0-255 or \"none\")\n"
              "  -d         Reports the dimensions and other characteristics of the image.\n"
              "  -a         Prints all alpha channels that are not 100%% opaque.\n"
              "\n"
              "If you specify '-' as the input file, stdin/stdout will be used input/output.\n");
    }
  if (write)
    {
      if (useStdinStdout)
       {
         out = stdout;
       }
      else
       {
         /* Open a temporary file. */

         /* "temp.tmp" is not good temporary filename. */
         sprintf (outFn, "webpng.tmp%d", getpid ());
         out = fopen (outFn, "wb");

         if (!out)
           {
             fprintf (stderr, "Unable to write to %s -- exiting\n", outFn);
             exit (1);
           }
       }

      /* Write the new PNG. */
#ifdef HAVE_LIBPNG
      gdImagePng (im, out);
#else
      fprintf (stderr, "No PNG library support.\n");
#endif
      if (!useStdinStdout)
       {
         fclose (out);
         /* Erase the old PNG. */
         unlink (argv[argc - 1]);
         /* Rename the new to the old. */
         if (rename (outFn, argv[argc - 1]) != 0)
           {
             perror ("rename");
             exit (1);
           }
       }
    }
  /* Delete the image from memory. */
  if (im)
    {
      gdImageDestroy (im);
    }
  /* All's well that ends well. */
  return 0;
}
