
/************************************************************************/
#define OP_NAME      "pnmaddnoise"
#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 float Gewicht=0.2;

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

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

  /* Zeiger auf Bilddaten holen */
  if (bild.type==TYPE_PPM)
  {
    dstR=bild.redDATA;
    dstG=bild.greenDATA;
    dstB=bild.blueDATA;
  }
  else dstR=bild.DATA;

  /* 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;

    /* Koordinate des Bildpunktes */
    i=y*bild.width+x;

    /* roten Anteil verrauschen */
    diff=(int) floor(256*((double)rand()/(double)RAND_MAX));
    temp=(int) floor(Gewicht*diff+(1.0-Gewicht)*dstR[i]);
    dstR[i]=(temp<bild.maxval) ? temp : bild.maxval;

    if (bild.type==TYPE_PPM)
    {
      /* gruenen Anteil verrauschen */
      diff=(int) floor(256*((double)rand()/(double)RAND_MAX));
      temp=(int) floor(Gewicht*diff+(1.0-Gewicht)*dstG[i]);
      dstG[i]=(temp<bild.maxval) ? temp : bild.maxval;

      /* blauen Anteil verrauschen */
      diff=(int) floor(256*((double)rand()/(double)RAND_MAX));
      temp=(int) floor(Gewicht*diff+(1.0-Gewicht)*dstB[i]);
      dstB[i]=(temp<bild.maxval) ? temp : bild.maxval;
    }
   }
}

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]=='-') && argv[i][1])
    {
      switch (argv[i][1])
      {
        case 'w': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%f",&Gewicht)!=1) Gewicht=-1.0;
                      if ((Gewicht<0.0) || (Gewicht>1.0))
                      {
                        PrintMessage("Wrong value of the noise weight !");
                        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 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);
}

