
/************************************************************************/
#define OP_NAME      "pnmimpnoise"
#define VERSION      "1.02"
#define DATE         "31.01.98"
#define AUTHOR       "Stefan Diener"
/************************************************************************/

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>

#include <STIMP/pnm.c>

struct PNM_Info bild;
static float Prozent=5.0;
static int Amplitude=255, AmpliR=255, AmpliG=255, AmpliB=255;

void Do_It(void)
{
  int i, j, ende;
  int x=0, y=0, bx, by;
  unsigned char *dstR, *dstG, *dstB;

  const int ax=65;
  const int ay=17;

  if (bild.type==TYPE_PPM)
  {
    dstR=bild.redDATA;
    dstG=bild.greenDATA;
    dstB=bild.blueDATA;
  }
  else dstR=bild.DATA;

  /* auf richtiges maxval achten */
  if (Amplitude>bild.maxval) Amplitude=bild.maxval;
  if (AmpliR>bild.maxval) AmpliR=bild.maxval;
  if (AmpliG>bild.maxval) AmpliG=bild.maxval;
  if (AmpliB>bild.maxval) AmpliB=bild.maxval;

  /* Zahl der zu veraendernden Punkte */
  ende=(int) floor(bild.width*bild.height*Prozent/100.0);

  /* neue Folge von Zufallszahlen erzeugen */
  srand((unsigned)time(NULL));

  /* Ansatz: Methode der linearen Kongruenzen */
  /* Problem: ggt(bx,source.width) muesste 1 sein */
  /* und ggt(by,source.height) ebenfalls 1 */
  /* hier: Ausbuegeln der kleineren Periode und der */
  /* ev. sichtbaren Muster durch Zufallsanteil */
  bx=3*bild.width/4+1;
  by=bild.height/2+1;

  /* nur Prozentsatz der Punkte veraendern */
  for (j=0; j<ende; j++)
  {
    /* lin. Kongruenzen und Zufallsanteil */
    x=(ax*x+bx+(int) floor(50.0-100.0*((double) rand()/(double)RAND_MAX)))%bild.width;
    y=(ay*y+by+(int) floor(50.0-100.0*((double) rand()/(double)RAND_MAX)))%bild.height;

    /* Bildpunkt */
    i=y*bild.width+x;

    /* Punkt auf vorgegebene Amplitude setzen */
    if (bild.type==TYPE_PPM)
    {
      dstR[i]=AmpliR;
      dstG[i]=AmpliG;
      dstB[i]=AmpliB;
    }
    else dstR[i]=Amplitude;
  }
}

int main(int argc,char **argv)
/* Hauptprogramm */
{
  int i;
  unsigned char tempo[10];

  /* offizielle Begruessung */
  PrintOpening(argc,argv);

  /* Uebergebene Parameter auswerten */
  for (i=1; i<argc; i++)
  {
    if (argv[i][0]=='-')
    {
      switch (argv[i][1])
      {
        case 'a': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%i",&Amplitude)!=1) Amplitude=-1;
                      if ((Amplitude<0) || (Amplitude>255))
                      {
                        PrintMessage("Wrong value for the (gray) amplitude !");
                        Hilfe();
                        exit(-1);
                      }
                      else
                      {
                        AmpliR=Amplitude;
                        AmpliG=Amplitude;
                        AmpliB=Amplitude;
                      }
                      break;

        case 'r': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%i",&AmpliR)!=1) AmpliR=-1;
                      if ((AmpliR<0) || (AmpliR>255))
                      {
                        PrintMessage("Wrong value for the red amplitude !");
                        Hilfe();
                        exit(-1);
                      }
                      break;

        case 'g': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%i",&AmpliG)!=1) AmpliG=-1;
                      if ((AmpliG<0) || (AmpliG>255))
                      {
                        PrintMessage("Wrong value for the green amplitude !");
                        Hilfe();
                        exit(-1);
                      }
                      break;

        case 'b': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%i",&AmpliB)!=1) AmpliB=-1;
                      if ((AmpliB<0) || (AmpliB>255))
                      {
                        PrintMessage("Wrong value for the blue amplitude !");
                        Hilfe();
                        exit(-1);
                      }
                      break;

        case 'p': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%f",&Prozent)!=1) Prozent=0.0;
                      if ((Prozent<=0.0) || (Prozent>100.0))
                      {
                        PrintMessage("Wrong value for the percentage !");
                        Hilfe();
                        exit(-1);
                      }
                      break;

        case 'v': beVerbose=FALSE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }

    if (argv[i][0]=='+')
    {
      switch (argv[i][1])
      {
        case 'v': beVerbose=TRUE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }
  }

  /* Mindestzahl der Argumente pruefen */
  if (argc<3)
  {
    PrintMessage("Wrong number of arguments !");
    Hilfe();
    exit(-1);
  }

  /* Anzahl der Dateinamen überprüfen */
  if (FilenameCount(argc, argv)!=2)
  {
    PrintMessage("Wrong number of file names !");
    Hilfe();
    exit(-1);
  }

  if (ReadPNMFile(GetFilename(1,argc,argv), TYPE_PNM, &bild)==0)
  {
    PrintMessage("Working ...");
    Do_It();

    WritePNMFile(GetFilename(2,argc,argv), &bild);
    FreePNMArray(&bild);
  }

  PrintClosing();
  exit(0);
}

