/*+-------------------------------------------------------------------------+
  | MORFOLOGIA MATEMATICA                                                   |
  | ---------------------                                                   |
  |                                                                         |
  | IMAGEM.H                                                                |
  |                                                                         |
  |            Arquivo que contem as rotinas para ler/gravar imagens em for-|
  | mato PBM/PGM/PPM ASCII, que nada mais sao do que formatos textos simples|
  | para imagens binarias, numericas (niveis de cinza) e coloridas respecti-|
  | vamente.                                                                |
  |                                                                         |
  +-------------------------------------------------------------------------+*/

#define TRUE  1
#define FALSE 0
#define CREATOR "# CREATOR: IMAGEM.H - by Luiz Eduardo V:2.00 R: 08/05/97\n"

/*+-------------------------------------------------------------------------+
  | Rotinas para ALOCAR e DESALOCAR dinamicamente espaco de memoria para um |
  | vetor monodimensional que armazenara' a imagem.                         |
  | PARAMETROS:                                                             |
  | I  = Endereco do vetor (ponteiro de inteiros).                          |
  | nl = Numero de linhas.                                                  |
  | nc = Numero de colunas.                                                 |
  +-------------------------------------------------------------------------+*/
int aloca_memo (int **I, int nl, int nc) {
    *I = (int *) malloc (nl * nc * sizeof (int));
    if (*I) return TRUE;
    else return FALSE;
}

int desaloca_memo (int **I) {
    free (*I);
}

/*+-------------------------------------------------------------------------+
  | Rotina que faz a leitura de uma imagem em formato .PBM ASCII e armazena |
  | num vetor monodimensional. Um exemplo de imagem .PBM ASCII gravada neste|
  | formato:                                                                |
  |                                                                         |
  | P1                                                                      |
  | # CREATOR: XV Version 3.10a  Rev: 12/29/94                              |
  | 115 81                                                                  |
  | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
  | 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
  | (...)                                                                   |
  |                                                                         |
  | Lin 1: contem P1, o que identifica este arquivo como PBM ASCII.         |
  | Lin 2: contem um comentario qualquer iniciado com #.                    |
  | Lin 3: numero de colunas e numero de linhas da imagem.                  |
  | Lin 4 em diante: pixel's da imagem (0 e 1's)                            |
  |                                                                         |
  | PARAMETROS:                                                             |
  | nome = nome do arquivo (entra)                                          |
  | I    = ponteiro para o vetor imagem (retorna)                           |
  | nl   = numero de linhas da imagem.                                      |
  | nc   = numero de colunas da imagem.                                     | 
  +-------------------------------------------------------------------------+*/
int le_imagem_pbm (char *nome, int **I, int *nl, int *nc) {
  int i, j, k, LIMX, LIMY, MAX_NIVEL;
  char c, LINHA[100];
  FILE *arq;
  if ((arq = fopen (nome, "r")) == NULL) {
     printf ("Erro na ABERTURA do arquivo <%s>\n\n", nome);
     return FALSE;
  }
 
  /*-- PBM = "P1" -----------*/
  fgets(LINHA, 80, arq);
  if (!strstr (LINHA, "P1")) {
     printf ("Erro no FORMATO do arquivo <%s>\n", nome);
     printf ("%s\n\n", LINHA);
     return FALSE;  
  }

  /*-- Dimensoes da imagem --*/
  fgets (LINHA, 80, arq);
  do {
     fgets(LINHA, 80, arq);
  } while (strchr (LINHA, '#'));
  sscanf (LINHA, "%d %d", &LIMX, &LIMY);

  if (LIMX == 0 || LIMY == 0) {
     printf ("Erro nas DIMENSOES do arquivo <%s>\n\n", nome);
     return FALSE;  
  }
  
  if (aloca_memo (I, LIMY, LIMX)) {     
      for (i = 0; i < LIMY; i++) {
	  for (j = 0; j < LIMX; j++) {
	      fscanf (arq, "%d", &k);
              if (k != 0 && k != 1) {
                 printf ("Erro nos DADOS do arquivo <%s>\n\n", nome);
                 return FALSE;  
              }	      
	      *(*(I) + i * LIMX + j) = k;
	  }
      }
      fclose (arq);
  }
  else {
     printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n\n");
     printf ("Rotina: le_imagem_pbm\n\n");
     fclose (arq);
     return FALSE;
  }
  *nc = LIMX;
  *nl = LIMY;
  return TRUE;
}

/*+-------------------------------------------------------------------------+
  | Rotina que grava o arquivo da imagem em formato PBM ASCII.              |
  | PARAMETROS:                                                             |
  | I    = ponteiro para o vetor imagem (entra).                            |
  | nome = nome do arquivo (entra).                                         |
  | nl   = numero de linhas (entra).                                        |
  | nc   = numero de colunas (entra).                                       |
  +-------------------------------------------------------------------------+*/
void grava_imagem_pbm (int *I, char *nome, int nl, int nc){ 
  int i, j, x ,k, valores_por_linha;
  FILE *arq;
  if ((arq = fopen (nome, "wt")) == NULL) {
      printf ("Erro na CRIACAO do arquivo <%s>\n\n", nome);
  }
  else {
       fputs ("P1\n", arq);
       fputs (CREATOR, arq);
       fprintf (arq, "%d  %d\n", nc, nl);
       
       valores_por_linha = 36;
       for (i =0, k=0; i < nl; i++)
          for (j = 0; j < nc; j++) {
            x = *(I + i * nc + j);
            fprintf (arq, "%d ", x);
            k++;
            if (k > valores_por_linha) {
              fprintf (arq, "\n");
              k = 0;
	    }
	  }
    }
  fclose (arq);
}

/*+-------------------------------------------------------------------------+
  | Rotina que faz a leitura de uma imagem em formato .PGM ASCII e armazena |
  | num vetor monodimensional. Um exemplo de imagem .PGM ASCII gravada neste|
  | formato:                                                                |
  |                                                                         |
  | P2                                                                      |
  | # CREATOR: XV Version 3.10a  Rev: 12/29/94                              |
  | 124 122                                                                 |
  | 255                                                                     |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255     |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255     |
  | (...)                                                                   |
  |                                                                         |
  | Lin 1: contem P2, o que identifica este arquivo como PGM ASCII.         |
  | Lin 2: contem um comentario qualquer iniciado com #.                    |
  | Lin 3: numero de colunas e numero de linhas da imagem.                  |
  | Lin 4: maximo nivel de cinza na imagem (255 normalmente).               |
  | Lin 5 em diante: valores de cinza da imagem.                            |
  |                                                                         |
  | PARAMETROS:                                                             |
  | nome = nome do arquivo (entra).                                         |
  | I    = ponteiro para o vetor imagem (retorna).                          |
  | nl   = numero de linhas da imagem (retorna).                            |
  | nc   = numero de colunas da imagem (retorna).                           |
  | mn   = maximo nivel de cinza (retorna).                                 |
  +-------------------------------------------------------------------------+*/
int le_imagem_pgm (char *nome, int **I, int *nl, int *nc, int *mn) {
  int i, j, k, LIMX, LIMY, MAX_NIVEL;
  char c, LINHA[100];
  FILE *arq;
  if ((arq = fopen (nome, "r")) == NULL) {
     printf ("Erro na ABERTURA do arquivo <%s>\n\n", nome);
     return FALSE;
  }
  
  /*-- PGM = "P2" -----------*/  
  fgets(LINHA, 80, arq);
  if (!strstr (LINHA, "P2")) {
     printf ("Erro no FORMATO do arquivo <%s>\n\n", nome);  
     return FALSE;  
  }

  /*-- Dimensoes da imagem --*/
  fgets (LINHA, 80, arq);
  do {
     fgets(LINHA, 80, arq);
  } while (strchr (LINHA, '#'));
  sscanf (LINHA, "%d %d", &LIMX, &LIMY);
  fscanf(arq,"%d",&MAX_NIVEL);

  if (LIMX == 0 || LIMY == 0 || MAX_NIVEL == 0) {
     printf ("Erro nas DIMENSOES do arquivo <%s>\n\n", nome);
     return FALSE;  
  }

  if (aloca_memo (I, LIMY, LIMX)) {     
      for (i = 0; i < LIMY; i++) {
	  for (j = 0; j < LIMX; j++) {
	      fscanf (arq, "%d", &k);
              if (k > MAX_NIVEL) {
                 printf ("Erro nos DADOS do arquivo <%s>\n", nome);
		 printf ("Valor lido: %d   Max Nivel: %d\n\n", k, MAX_NIVEL);
                 return FALSE;  
              }	      	      
	      *(*(I) + i * LIMX + j) = k;
	  }
      }
      fclose (arq);
  }
  else {
     printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n\n");  
     printf ("Rotina: le_imagem_pgm\n\n");
     fclose (arq);
     return FALSE;
  }
  *nc = LIMX;
  *nl = LIMY;
  *mn = MAX_NIVEL;
  return TRUE;
}

/*+-------------------------------------------------------------------------+
  | Rotina que grava o arquivo da imagem em formato PGM ASCII.              |
  | PARAMETROS:                                                             |
  | I    = ponteiro para o vetor imagem (entra).                            |
  | nome = nome do arquivo (entra).                                         |
  | nl   = numero de linhas (entra).                                        |
  | nc   = numero de colunas (entra).                                       |
  | mn   = maximo nivel de cinza (entra).                                   |
  +-------------------------------------------------------------------------+*/
void grava_imagem_pgm (int *I, char *nome, int nl, int nc, int mn){ 
  int i, j, x ,k, valores_por_linha;
  FILE *arq;
  if ((arq = fopen (nome, "wt")) == NULL) {
      printf ("Erro na CRIACAO do arquivo <%s>\n\n", nome);
  }
  else {
       fputs ("P2\n", arq);
       fputs (CREATOR, arq);
       fprintf (arq, "%d  %d\n", nc, nl);
       fprintf (arq, "%d\n", mn);
       valores_por_linha = 16;
       for (i =0, k=0; i < nl; i++)
          for (j = 0; j < nc; j++) {
            x = *(I + i * nc + j);	    
	    fprintf (arq, "%3d ", x);
            k++;
            if (k > valores_por_linha) {
              fprintf (arq, "\n");
              k = 0;
	    }
	  }
    }
  fclose (arq);
}


/*+-------------------------------------------------------------------------+
  | Rotina que faz a leitura de uma imagem em formato .PPM ASCII e armazena |
  | em 3 (tres) vetores monodimensionais (cada vetor armazena uma BANDA do  |
  | modelo RGB). Um exemplo de imagem .PPM ASCII gravada neste formato:     |
  |                                                                         |
  | P3                                                                      |
  | # CREATOR: XV Version 3.10a  Rev: 12/29/94                              |
  | 124 122                                                                 |
  | 255                                                                     |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255             |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255             |
  | (...)                                                                   |
  |                                                                         |
  | Lin 1: contem P3, o que identifica este arquivo como PPM ASCII.         |
  | Lin 2: contem um comentario qualquer iniciado com #.                    |
  | Lin 3: numero de colunas e numero de linhas da imagem.                  |
  | Lin 4: maximo valor em cada banda no modelo RGB.                        |
  | Lin 5 em diante: valores de cada banda na ordem Red, Blue e Green.      |
  |                                                                         |
  | PARAMETROS:                                                             |
  | nome = nome do arquivo (entra).                                         |
  | R    = ponteiro da banda R (Red) da Imagem (retorna).                   |
  | G    = ponteiro da banda G (Green) da Imagem (retorna).                 |
  | B    = ponterio da banda B (Blue) da Imagem (retorna).                  |
  | nl   = numero de linhas da imagem (retorna).                            |
  | nc   = numero de colunas da imagem (retorna).                           |
  | mn   = maximo valor em cada banda (retorna).                            |
  +-------------------------------------------------------------------------+*/
int le_imagem_ppm (char *nome, int **R, int **G, int **B, 
                   int *nl, int *nc, int *mc) {
  int i, j, k, banda, OK,  LIMX, LIMY, MAX_CORES;
  char c, LINHA[100];
  FILE *arq;
  if ((arq = fopen (nome, "r")) == NULL) {
     printf ("Erro na ABERTURA do arquivo <%s>\n\n", nome);
     return FALSE;
  }
  
  /*-- PPM = "P3" -----------*/
  fgets(LINHA, 80, arq);
  if (!strstr (LINHA, "P3")) {
     printf ("Erro no FORMATO do arquivo <%s>\n\n", nome);    
     return FALSE;  
  }

  /*-- Dimensoes da imagem --*/
  fgets (LINHA, 80, arq);
  do {
      fgets(LINHA, 80, arq);
  } while (strchr (LINHA, '#'));
  sscanf (LINHA, "%d %d", &LIMX, &LIMY);
  fscanf(arq,"%d",&MAX_CORES);
  
  if (LIMX == 0 || LIMY == 0 || MAX_CORES == 0) {
     printf ("Erro nas DIMENSOES do arquivo <%s>\n\n", nome);
     return FALSE;  
  }
  
  banda = 0;
  OK = aloca_memo (R, LIMY, LIMX);
  if (OK) aloca_memo (G, LIMY, LIMX);
  if (OK) aloca_memo (B, LIMY, LIMX);
  if (OK) {     
      for (i = 0; i < LIMY; i++) {
	  for (j = 0; j < LIMX; j++) {
              for (banda = 0; banda < 3; banda++) {
	         fscanf (arq, "%d", &k);
                 if (k < 0 || k > MAX_CORES) {
                    printf ("Erro nos DADOS do arquivo <%s>\n\n", nome);
                    return FALSE;  
                 }	      
	         switch (banda) {
	           case 0 : *(*(R) + i * LIMX + j) = k; break;
	      	   case 1 : *(*(G) + i * LIMX + j) = k; break;
	      	   case 2 : *(*(B) + i * LIMX + j) = k; break;
	         }
	      }
	  }
      }
      fclose (arq);
  }
  else {
     printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n\n");
     printf ("Rotina: le_imagem_ppm\n\n");
     fclose (arq);
     return FALSE;
  }
  *nc = LIMX;
  *nl = LIMY;
  *mc = MAX_CORES;
  return TRUE;
}

/*+-------------------------------------------------------------------------+
  | Rotina que grava o arquivo da imagem em formato PPM ASCII.              |
  | PARAMETROS:                                                             |
  | R    = banda R da imagem (entra).                                       |
  | G    = banda G da imagem (entra).                                       |
  | B    = banda B da imagem (entra).                                       |
  | nome = nome do arquivo (entra).                                         |
  | nl   = numero de linhas (entra).                                        |
  | nc   = numero de colunas (entra).                                       |
  | mn   = maximo nivel de cinza (entra).                                   |
  +-------------------------------------------------------------------------+*/
void grava_imagem_ppm (int *R, int *G, int *B, 
                       char *nome, int nl, int nc, int mn){ 
  int i, j, x ,k, banda, valores_por_linha;
  FILE *arq;
   if ((arq = fopen (nome, "wt")) == NULL) {
      printf ("Erro na criacao do arquivo <%s>\n\n", nome);
    }

    else {
       fputs ("P3\n", arq);
       fputs (CREATOR, arq);
       fprintf (arq, "%d  %d\n", nc, nl);
       fprintf (arq, "%d\n", mn);
       valores_por_linha = 14;
       banda = 0;
       for (i =0, k=0; i < nl; i++)
          for (j = 0; j < nc; j++) {
              for (banda = 0; banda < 3; banda++) { 
                  switch (banda) {
                     case 0: x = *(R+i*nc+j); break;
                     case 1: x = *(G+i*nc+j); break;
                     case 2: x = *(B+i*nc+j); break;
                  }
                  fprintf (arq, "%3d ", x);
		  k++;
              }
              if (k > valores_por_linha) {
                 fprintf (arq, "\n");
                 k = 0;
	      }
	  }
    }
  fclose (arq);
}



/*+-------------------------------------------------------------------------+
  | Rotina que faz a leitura de uma imagem em formato .TXT(Texto)e armazena |
  | num vetor monodimensional. Um exemplo de imagem .TXT gravada neste for- |
  | to:                                                                     |
  |                                                                         |
  | TXT                                                                     |
  | 10 6 5                                                                  |
  | 1 1 1 1 1 1 1 1 1 1                                                     |
  | 1 2 2 2 2 1 4 4 4 1                                                     |
  | 1 2 3 3 2 1 4 5 4 1                                                     |
  | 1 2 3 3 2 1 4 4 4 1                                                     |
  | 1 2 2 2 2 1 1 1 1 1                                                     |
  | 1 1 1 1 1 1 1 1 1 1                                                     |
  |                                                                         |
  | Lin 1: contem TXT, o que identifica este arquivo como TEXTO.            |
  | Lin 2: numero de colunas e numero de linhas da imagem e maximo nivel.   |
  | Lin 4 em diante: valores da imagem.                                     |
  |                                                                         |
  | PARAMETROS:                                                             |
  | nome = nome do arquivo (entra).                                         |
  | I    = ponteiro para o vetor imagem (retorna).                          |
  | nl   = numero de linhas da imagem (retorna).                            |
  | nc   = numero de colunas da imagem (retorna).                           |
  | mn   = maximo nivel de cinza (retorna).                                 |
  +-------------------------------------------------------------------------+*/
int le_imagem_txt (char *nome, int **I, int *nl, int *nc, int *mn) {
  int i, j, k, LIMX, LIMY, MAX_NIVEL;
  char c, LINHA[100];
  FILE *arq;
  if ((arq = fopen (nome, "r")) == NULL) {
     printf ("Erro na ABERTURA do arquivo <%s>\n\n", nome);
     return FALSE;
  }
  
  /*-- TXT = "TXT" -----------*/
  fgets(LINHA, 80, arq);
  if (!strstr (LINHA, "TXT")) {
     printf ("Erro no FORMATO do arquivo <%s>\n\n", nome);  
     return FALSE;    
  } 

  /*-- Dimensoes da imagem --*/
  fgets (LINHA, 80, arq);
  sscanf(LINHA, "%d %d %d", &LIMX, &LIMY, &MAX_NIVEL);
    
  if (LIMX == 0 || LIMY == 0 || MAX_NIVEL == 0) {
     printf ("Erro nas DIMENSOES do arquivo <%s>\n\n", nome);
     return FALSE;  
  }
  
  if (aloca_memo (I, LIMY, LIMX)) {     
      for (i = 0; i < LIMY; i++) {
	  for (j = 0; j < LIMX; j++) {
	      fscanf (arq, "%d", &k);	      	      
	      *(*(I) + i * LIMX + j) = k;
	  }
      }
      fclose (arq);
  }
  else {
     printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n\n");
     printf ("Rotina: le_imagem_txt\n\n");
     fclose (arq);
     return FALSE;
  }
  *nc = LIMX;
  *nl = LIMY;
  *mn = MAX_NIVEL;
  return TRUE;
}

/*+-------------------------------------------------------------------------+
  | Rotina que grava o arquivo da imagem em formato TEXTO.                  |
  | PARAMETROS:                                                             |
  | I    = ponteiro para o vetor imagem (entra).                            |
  | nome = nome do arquivo (entra).                                         |
  | nl   = numero de linhas (entra).                                        |
  | nc   = numero de colunas (entra).                                       |
  | mn   = maximo nivel de cinza (entra).                                   |
  +-------------------------------------------------------------------------+*/
void grava_imagem_txt (int *I, char *nome, int nl, int nc, int mn){ 
  int i, j, x ,k, valores_por_linha;
  FILE *arq;
   if ((arq = fopen (nome, "wt")) == NULL) {
      printf ("Erro na criacao do arquivo <%s>\n\n", nome);
    }

    else {
       fputs ("TXT\n", arq);
       fprintf (arq, "%d %d %d\n", nc, nl, mn);
       for (i =0; i < nl; i++){
          for (j = 0; j < nc; j++) {
            x = *(I + i * nc + j);	    
            fprintf (arq, "%4d ", x);
	  }
	  fprintf (arq, "\n");
       }
    }
  fclose (arq);
}

/*+-------------------------------------------------------------------------+
  | Apresenta informacoes sobre um arquivo de imagem.                       |
  | Parametros:                                                             |
  |   nome = nome fisico do arquivo de imagem.                              |
  |   nl   = numero de linhas da imagem.                                    |
  |   nc   = numero de colunas da imagem.                                   |
  |   mn   = maximo nivel de cinza da imagem.                               |
  +-------------------------------------------------------------------------+*/
void info_imagem (char *nome, int nl, int nc, int mn) {
    printf ("\nINFORMACOES SOBRE A IMAGEM:");
    printf ("\n--------------------------\n");
    printf ("Nome do arquivo.............: %s \n", nome);
    printf ("Numero de linhas............: %d \n", nl);
    printf ("Numero de colunas...........: %d \n", nc);
    printf ("Maximo nivel-de-cinza/cores.: %d \n\n", mn);
}
