\chapter{Lectura y/o Escritura de archivos}

\section{Introducción a los archivos}

Los archivos son documentos donde almacenamos y leemos datos. Sería muy tedioso tener que escribir mas de 100 datos de entrada para un programa, procesarlos y copiar de pantalla los resultados. En estos casos resulta mas obvio leer un archivo, procesar la información y guardar en un archivos los datos de salida.

\noindent
El procedimiento de lectura y/o escritura lleva tres pasos 

\begin{enumerate}
\item Abrir el archivo de trabajo,
\item Leer o guardar la información y
\item Cerrar el archivo
\end{enumerate}


\section{Abrir un archivo}

\noindent
\textbf{Tipo FILE}

C define la estructura de datos FILE en el fichero de cabecera ``stdio.h'' para el manejo de ficheros. Nosotros siempre usaremos punteros a estas estructuras.

La definición de esta estructura depende del compilador, pero en general mantienen un campo con la posición actual de lectura/escritura, un buffer para mejorar las prestaciones de acceso al fichero y algunos campos para uso interno.

\noindent
\textbf{Función fopen:}

\noindent
Sintaxis:

FILE *fopen(char *nombre, char *modo);
\noindent
Esta función sirve para abrir y crear ficheros en disco. El valor de retorno es un puntero a una estructura FILE. Los parámetros de entrada son:

\noindent nombre: una cadena que contiene un nombre de fichero valido, esto depende del sistema operativo que estemos usando. El nombre puede incluir el camino completo.

\noindent modo: especifica en tipo de fichero que se abrirá o se creará y el tipo de datos que puede contener, de texto o binarios:

\noindent r: sólo lectura. El fichero debe existir.

\noindent w: se abre para escritura, se crea un fichero nuevo o se sobreescribe si ya existe.

\noindent a: añadir, se abre para escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea.

\noindent r+: lectura y escritura. El fichero debe existir.

\noindent w+: lectura y escritura, se crea un fichero nuevo o se sobre escribe si ya existe. a+: añadir, lectura y escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea.

\noindent t: tipo texto, si no se especifica ``t'' ni ``b'', se asume por defecto que es ``t''

\noindent b: tipo binario.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%    Crear un archivo 
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Cerrar un archivo}
\noindent
\textbf{Función fclose:}

\noindent
Sintaxis:

int fclose(FILE *fichero);
\noindent
Es importante cerrar los ficheros abiertos antes de abandonar la aplicación. Esta función sirve para eso. Cerrar un fichero almacena los datos que aún están en el buffer de memoria, y actualiza algunos datos de la cabecera del fichero que mantiene el sistema operativo. Además permite que otros programas puedan abrir el fichero para su uso. Muy a menudo, los ficheros no pueden ser compartidos por varios programas.

Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido algún error, el valor de retorno es la constante EOF. El parámetro es un puntero a la estructura FILE del fichero que queremos cerrar.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%    Escribir en un archivo 
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Escribir en un archivo}

A continuación se da una serie de instrucciones para la escritura de datos en un archivo.

\textbf{Función fprintf:}
\noindent
Sintaxis:

int fprintf(FILE *fichero, const char *formato, ...);

\noindent
La función fprintf funciona igual que printf en cuanto a parámetros, pero la salida se dirige a un fichero en lugar de a la pantalla.


\subsection{Función fputc:}
\noindent
Sintaxis:

int fputc(int caracter, FILE *fichero);
\noindent
Esta función escribe un carácter a un fichero.

El valor de retorno es el carácter escrito, si la operación fue completada con éxito, en caso contrario será EOF. Los parámetros de entrada son el carácter a escribir, convertido a int y un puntero a una estructura FILE del fichero en el que se hará la escritura.

\subsection{Ejemplo de la función Rosa}
Escribir el código para graficar la función polar de la rosa de 6 petalos

\begin{verbatim}
/* 
 * File:   funcion_rosa.c
 * Author: felix
 *
 * Created on 7 de diciembre de 2011, 10:50
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void ejemplo() {
    FILE *fp;
    double x, y, theta, r, a = 2, k = 6, phi = 0;
    
    fp = fopen("salida.txt","w");
    
    for(theta =0; theta <= 2*3.1416; theta += 0.01) {
        // Formula Polar para la Rosa
        r = a*cos(k*theta + phi);
        
        // Conversion a rectangular
        x = r*cos(theta);
        y = r*sin(theta);
        
        fprintf(fp, "%f, %f\n", x, y);
    }

    fclose(fp) ;
}

int main(int argc, char** argv) {
    ejemplo();
    return (EXIT_SUCCESS);
}
\end{verbatim}

\subsection{Función fputs:}
\noindent
Sintaxis:

int fputs(const char *cadena, FILE *stream);

\noindent
La función fputs escribe una cadena en un fichero. No se añade el carácter de retorno de línea ni el carácter nulo final.

El valor de retorno es un número no negativo o EOF en caso de error. Los parámetros de entrada son la cadena a escribir y un puntero a la estructura FILE del fichero donde se realizará la escritura.

\subsection{Función fwrite:}

\noindent
Sintaxis:

size\_t fwrite(void *puntero, size\_t tamaño, size\_t nregistros, FILE *fichero);

\noindent
Esta función también esta pensada para trabajar con registros de longitud constante y forma pareja con fread. Es capaz de escribir hacia un fichero uno o varios registros de la misma longitud almacenados a partir de una dirección de memoria determinada.

El valor de retorno es el número de registros escritos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.

Ejemplo:

\begin{verbatim}
// copia.c: Copia de ficheros
// Uso: copia <fichero_origen> <fichero_destino>

#include <stdio.h>

int main(int argc, char **argv) {
    FILE *fe, *fs;
    unsigned char buffer[2048]; // Buffer de 2 Kbytes
    int bytesLeidos;

    if(argc != 3) {
       printf("Usar: copia <fichero_origen> <fichero_destino>\n");
       return 1;
    }

    // Abrir el fichero de entrada en lectura y binario
    fe = fopen(argv[1], "rb");
    if(!fe) {
       printf("El fichero %s no existe o no puede ser abierto.\n", argv[1]);
       return 1;
    }
    // Crear o sobreescribir el fichero de salida en binario
    fs = fopen(argv[2], "wb");
    if(!fs) {
       printf("El fichero %s no puede ser creado.\n", argv[2]);
       fclose(fe);
       return 1;
    }
    // Bucle de copia:
    while((bytesLeidos = fread(buffer, 1, 2048, fe)))
       fwrite(buffer, 1, bytesLeidos, fs);
    // Cerrar ficheros:
    fclose(fe);
    fclose(fs);
    return 0;
}
\end{verbatim}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%    Leer un archivo 
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Leer un archivo}
A continuación se da una serie de funciones que permiten leer datos de un archivo.

\subsection{Función fscanf:}
\noindent
Sintaxis:

int fscanf(FILE *fichero, const char *formato, ...);
\noindent
La función fscanf funciona igual que scanf en cuanto a parámetros, pero la entrada se toma de un fichero en lugar del teclado.

\subsection{Ejemplo}

El siguiente es un ejemplo de escritura en un archivo de un valor entero y una cadena de texto. Note que la cadena de texto tiene números.

\begin{verbatim}
/* 
 * File:   lee_archivo.c
 * Author: felix
 *
 * Created on 6 de diciembre de 2011, 13:11
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * Escribe en un archivo y le los datos colocados en el
 */

int main(){

    FILE *fp;

    fp = fopen("test.txt","a");
    fprintf(fp,"%d %s %d\n",1,"1 a 1",2);
    fclose(fp) ;

    fp = fopen("test.txt","r");

    char texto[10];
    int a, b;
    fscanf(fp,"%d %s %d\n",&a, texto, &b);
    printf(" %d         %s    %d\n",a, texto, b);


    fclose(fp);
    return 0;
}
\end{verbatim}


\subsection{Lectura de una matriz}

El siguiente código muestra como leer los datos de una matriz almacenada en un archivo. Suponemos que en el primer renglón esta la información de los renglones y la columnas y después la información de los datos por renglones. Los datos de la matriz son números reales.

\begin{verbatim}
/* 
 * File:   Lee_Matriz_archivo.c
 * Author: felix
 *
 * Created on 7 de noviembre de 2011, 18:55
 */

#include <stdio.h>
#include <stdlib.h>

typedef float TIPO;
void Imprime_Matriz(TIPO **a, int ren, int col);
TIPO **Lee_Matriz(char *archivo, int *ren, int * col);
TIPO ** Matriz(int ren, int col);

void Imprime_Matriz(TIPO **a, int ren, int col){
  int i, j;
    
  for(i=0; i<ren; i++) {
    for (j = 0; j < col; j++)
      printf("%f ", a[i][j]);
    printf("\n");
  }
}

TIPO **Lee_Matriz(char *archivo, int *ren, int *col) {
    FILE *fp;
    int i, j, nr, nc;
    TIPO aux;
    TIPO ** A;
    
    if((fp = fopen(archivo, "r"))==NULL){
        printf("No pude abrir el archivo\n");
        exit(0);
    }  
    
    fscanf(fp, "%d %d", &nr, &nc);
    printf("Matriz de tamanio ren = %d col = %d\n", nr, nc);
    *ren = nr;
    *col = nc;
    
    A = Matriz(nr, nc);
    
    for(i=0; i<nr; i++) {
        for(j=0; j<nc; j++) {
            fscanf(fp, "%f", &aux);
            A[i][j] = aux;
        }
    }
    
    fclose(fp);  
    return A;
}

TIPO ** Matriz(int ren, int col){
  TIPO **aux;
  int i, j;

  aux = (TIPO **) calloc(ren, sizeof(TIPO*)); // buscar en stdlib.h

  for(i=0; i<ren; i++)
	aux[i] = (TIPO *) calloc(col, sizeof(TIPO));
 
  return aux;   
}


int main(int argc, char** argv) {
    int ren, col;
    TIPO** A;
    
    A = Lee_Matriz("prueba.txt", &ren, &col);
    
    Imprime_Matriz(A, ren, col);

    return (EXIT_SUCCESS);
}
\end{verbatim}


\subsection{Función fgetc:}
\noindent
Sintaxis:

int fgetc(FILE *fichero);
\noindent
Esta función lee un carácter desde un fichero.

El valor de retorno es el carácter leído como un unsigned char convertido a int. Si no hay ningún carácter disponible, el valor de retorno es EOF. El parámetro es un puntero a una estructura FILE del fichero del que se hará la lectura.

\subsection{Función fgets:}
\noindent
Sintaxis:

char *fgets(char *cadena, int n, FILE *fichero);
\noindent
Esta función está diseñada para leer cadenas de caracteres. Leer· hasta n-1 caracteres o hasta que lea un retorno de línea. En este último caso, el carácter de retorno de línea también es leído.

El parámetro n nos permite limitar la lectura para evitar desbordar el espacio disponible en la cadena.

El valor de retorno es un puntero a la cadena leÌda, si se leyó con éxito, y es NULL si se detecta el final del fichero o si hay un error. Los parámetros son: la cadena a leer, el número de caracteres máximo a leer y un puntero a una estructura FILE del fichero del que se leer·.

\subsection{Función fread:}
\noindent
Sintaxis:

size\_t fread(void *puntero, size\_t tamaño, size\_t nregistros, FILE *fichero);
\noindent
Esta función está pensada para trabajar con registros de longitud constante. Es capaz de leer desde un fichero uno o varios registros de la misma longitud y a partir de una dirección de memoria determinada. El usuario es responsable de asegurarse de que hay espacio suficiente para contener la información leída.

El valor de retorno es el número de registros leídos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.

\subsection{Lectura de un archivo en binario}

El siguiente ejemplo muestra el uso de fwrite y fread en un archivo binario. Note que así como se almacena la información en la función Escribe\_Archivo() se debe leer en la función Lee\_Archivo().

\begin{verbatim}
/* 
 * File:   archivo_binario.c
 * Author: felix
 *
 * Created on 6 de diciembre de 2011, 16:54
 */

#include <stdio.h>
#include <stdlib.h>

	/* Our structure */
struct reg
{
    int x,y,z;
};

void Escribe_Archivo();
void Lee_Archivo();

/*
 * Funcion para leer los datos que se escribieron en un archivo
 * Note que los valores se leen en la misma forma que se escriben
 */

void Lee_Archivo(){
    int i;
    FILE *ptr_archivo;
    struct reg mi_registro;
    float a;
    char c[11];

    ptr_archivo=fopen("prueba.bin","rb");
    
    if (!ptr_archivo){
        printf("No es posible abrir el archivo!");
        return ;
    }
    
    for (i=1; i<= 10; i++) {
	fread(&mi_registro, sizeof(struct reg), 1, ptr_archivo);
    
        printf("%d %d %d\n", mi_registro.x, mi_registro.y, mi_registro.z);
    }
    
    fread(&a, sizeof(float), 1, ptr_archivo);  
    fread(&i, sizeof(int), 1, ptr_archivo);
    fread(c, sizeof(char), 11, ptr_archivo);
    
    printf("%f, %d, %s\n", a, i, c);
    
    fclose(ptr_archivo);    
}

/*
 * Funcion para escribir los datos en el archivo de salida
 * Los datos deben ser leidos en la misma forma que se escriben
 */

void Escribe_Archivo(){
    int i;
    FILE *ptr_archivo;
    struct reg mi_registro;
    float a = 100.4;
    char c[11]= "Hola Mundo";

    ptr_archivo=fopen("prueba.bin","wb");
    
    if (!ptr_archivo){
        printf("No es posible abrir el archivo!");
        return ;
    }
    
    for (i=1; i<= 10; i++){
	mi_registro.x= i;
	fwrite(&mi_registro, sizeof(struct reg), 1, ptr_archivo);
    }
    
    fwrite(&a, sizeof(float), 1, ptr_archivo);
    
    fwrite(&i, sizeof(int), 1, ptr_archivo);
    fwrite(c, sizeof(char), 11, ptr_archivo);
    
    fclose(ptr_archivo);    
}

int main()
{
    Escribe_Archivo();
    Lee_Archivo();
    return 0;
}
\end{verbatim}

ver \cite{DeitelC}

\section{Otras funciones para manejo de archivos}

\subsection{Función feof:}

\noindent
Sintaxis:

int feof(FILE *fichero);

Esta función sirve para comprobar si se ha alcanzado el final del fichero. Muy frecuentemente deberemos trabajar con todos los valores almacenados en un archivo de forma secuencial, la forma que suelen tener los bucles para leer todos los datos de un archivo es permanecer leyendo mientras no se detecte el fin de fichero. Esta función suele usarse como prueba para verificar si se ha alcanzado o no ese punto.

El valor de retorno es distinto de cero solo si no se ha alcanzado el fin de fichero. El parámetro es un puntero a la estructura FILE del fichero que queremos verificar.

\subsection{Función rewind:}

\noindent
Sintaxis:

void rewind(FILE *fichero);

Es una función heredada de los tiempos de las cintas magnéticas. Literalmente significa ``rebobinar'', y hace referencia a que para volver al principio de un archivo almacenado en cinta, había que rebobinarla. Eso es lo que hace ésta función, sitúa el cursor de lectura/escritura al principio del archivo.

El parámetro es un puntero a la estructura FILE del fichero que queremos rebobinar.

Ejemplos:

\begin{verbatim}
// ejemplo1.c: Muestra un fichero dos veces.
#include <stdio.h>

int main() {
   FILE *fichero;

   fichero = fopen("ejemplo1.c", "r");
   while(!feof(fichero)) fputc(fgetc(fichero), stdout);
   rewind(fichero);
   while(!feof(fichero)) fputc(fgetc(fichero), stdout);
   fclose(fichero);
   getchar();
   return 0;
}
\end{verbatim}

\subsection{Función fflush:}
\noindent
Sintaxis:

int fflush(FILE *fichero);

Esta función fuerza la salida de los datos acumulados en el buffer de salida del fichero. Para mejorar las prestaciones del manejo de ficheros se utilizan buffers, almacenes temporales de datos en memoria, las operaciones de salida se hacen a travéss del buffer, y solo cuando el buffer se llena se realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese
buffer de un modo manual, para eso sirve ésta función.

El valor de retorno es cero si la función se ejecutó con éxito, y EOF si hubo algún error. El parámetro de entrada es un puntero a la estructura FILE del fichero del que se quiere vaciar el buffer. Si es NULL se hará el vaciado de todos los ficheros abiertos.

\subsection{Función fseek:}
\noindent
Sintaxis:

int fseek(FILE *fichero, long int desplazamiento, int origen);

Esta función sirve para situar el cursor del fichero para leer o escribir en el lugar deseado.

El valor de retorno es cero si la función tuvo éxito, y un valor distinto de cero si hubo algún error.

Los parámetros de entrada son: un puntero a una estructura FILE del fichero en el que queremos cambiar el cursor de lectura/escritura, el valor del desplazamiento y el punto de origen desde el que se calculará el desplazamiento.

El parámetro origen puede tener tres posibles valores:

SEEK\_SET el desplazamiento se cuenta desde el principio del
fichero. El primer byte del fichero tiene un desplazamiento cero.
SEEK\_CUR el desplazamiento se cuenta desde la posición actual del
cursor. SEEK\_END el desplazamiento se cuenta desde el final del
fichero.

\subsection{Función ftell:}
\noindent
Sintaxis:

long int ftell(FILE *fichero);

La función ftell sirve para averiguar la posición actual del cursor de lectura\/escritura de un fichero.

El valor de retorno será esa posición, o -1 si hay algún error.

El parámetro de entrada es un puntero a una estructura FILE del fichero del que queremos leer la posición del cursor de lectura\/escritura.

\section{Aplicaciones}

\subsection{Lectura de algunos tipos de datos}

Este ejemplo muestra como leer desde un archivo, utilizando como terminado la función feof(), caracteres, números flotantes y palabras.

\begin{verbatim}
/* 
 * File:   lee_datos.c
 * Author: felix
 *
 * Created on 14 de diciembre de 2011, 18:08
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * Estas funciones permiten leer datos de archivos en diferentes formatos
 */

void Lee_flotantes(char *nombre) {
    FILE *fp;
    char c[100];
    float f;
    
    printf("Nombre del archivo %s\n", nombre);
    
    fp = fopen(nombre, "r");
    
    if(!fp) {
        printf("No pude abrir el archivo\n");
        return;
    }
    
    while(!feof(fp)) {
        fscanf(fp, "%f,", &f);
        if(feof(fp)) break;
        printf("%f\n", f);      
    } 
    
    fclose(fp);
    
    return;    
}

int Lee_Palabras(char *nombre) {
    FILE *fp;
    char c[100];
    
    printf("Nombre del archivo %s\n", nombre);
    
    fp = fopen(nombre, "rb");
    
    if(!fp) {
        printf("No pude abrir el archivo\n");
        return 0;
    }
    
    while(!feof(fp)) {
        fscanf(fp, "%s,", c);
        if(feof(fp)) break;
        printf("%s\n", c);      
    } 
    
    fclose(fp);
    
    return 0;    
}

int Lee_Caracteres(char *nombre) {
    FILE *fp;
    char c;
    
    printf("Nombre del archivo %s\n", nombre);
    
    fp = fopen(nombre, "rb");
    
    if(!fp) {
        printf("No pude abrir el archivo\n");
        return 0;
    }
    
    printf("Comienzo a leer \n");

    while(!feof(fp)) {
        c = fgetc(fp);
        if(feof(fp)) break;
        printf("%c ", c);      
    } 
    
    fclose(fp);
    
    return 0;    
}

int main(int argc, char** argv) {
    Lee_Caracteres("entrada.txt");
    //Lee_Palabras("entrada.txt");
    //Lee_flotantes("salida.txt");
    return (EXIT_SUCCESS);
}
\end{verbatim}

\subsection{Código}

El siguiente es un ejemplo de la codificación de un archivo de texto. Las letras son cambiadas de acuerdo con lo siguiente:

\noindent
Si el carácter leído es a  pone z, si es b pone x, y así sucesivamente hasta z pone a. Para los números lo hace de manera muy similar 0-9, 1-8, 2-7, etc. 

\begin{verbatim}
/* 
 * File:   codigo.c
 * Author: felix
 *
 * Created on 14 de diciembre de 2011, 18:08
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * Estas funciones permiten leer datos de archivos en diferentes formatos
 */

char codigo(char a) ;
int Lee_Caracteres(char *entrada, char *salida);

int Lee_Caracteres(char *entrada, char *salida) {
    FILE *fp1, *fp2;
    char c;
        
    fp1 = fopen(entrada, "r");
    fp2 = fopen(salida, "w");
    
    if(!fp1) {
        printf("No pude abrir el archivo %s\n", entrada);
        return 0;
    }
    
    while(!feof(fp1)) {
        c = fgetc(fp1);
        if(feof(fp1)) break;
        fprintf(fp2, "%c", codigo(c));      
    } 
    
    fclose(fp1);
    fclose(fp2);
    
    return 0;    
}

char codigo(char a) {
   if(a >= 'a' && a <= 'z') return ('a'+'z' -a);
   if(a >= 'A' && a <= 'Z') return ('A' + 'Z' -a);
   if(a >= '0' && a <= '9') return ('0'+'9' -a); 
   return a;
}

int main(int argc, char** argv) {
    Lee_Caracteres("entrada.txt", "salida.txt");

    return (EXIT_SUCCESS);
}
\end{verbatim}


\subsection{Cambia orden de la palabras}

El siguiente es un ejemplo de lectura de un archivo. Las palabras leídas se cambia el orden de las letras si cambiar la primer letra y la última y se imprime. Lo sorprendente es que el resultado es un texto que se puede leer.

\begin{verbatim}
/* 
 * File:   palabras.c
 * Author: felix
 *
 * Created on 21 de junio de 2012, 20:38
 */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

void cambia_orden(char *a) {
    int i, k, l, N;
    int aux;
    
    N = strlen(a);
    
    if(N==2) return;  
    
    for(i=0; i<2*N; i++) {
        k = numero_aleatorio(N);
        l = numero_aleatorio(N);
        
        aux = a[k];
        a[k] = a[l];
        a[l] = aux;
    }
}

int numero_aleatorio(int N)
{
   int n;
   n = 1 + rand() % (N-2);  
   return(n);
}

int Lee_Palabras(char *nombre) {
    FILE *fp;
    char c[100];
    
    printf("Nombre del archivo %s\n", nombre);
    
    fp = fopen(nombre, "rb");
    
    if(!fp) {
        printf("No pude abrir el archivo\n");
        return 0;
    }
    
    while(1) {
        fscanf(fp, "%s,", c);
        if(feof(fp)) break;
        cambia_orden(c);
        printf("%s ", c);      
    } 
    
    fclose(fp);
    
    return 0;    
}

int main(int argc, char** argv) {
    
    Lee_Palabras("entrada.txt");
    
    return (EXIT_SUCCESS);
}
\end{verbatim}

\subsection{Lectura de Imágenes en formato PPM}

Una imagen en formato consiste de lo siguiente:

\begin{enumerate}
\item Un numero mágico que identifica el tipo de archivo. Un número mágico son los caracteres P6.
\item El ancho y alto de la imagen en formato ASCII separados por un espacio
\item El color máximo de la imagen, normalmente 255
\item Un vector con los colores correspondientes a cada punto de la imagen comenzando en la esquina superior izquierda y terminando en la esquina inferior derecha
\end{enumerate}

\begin{verbatim}
/* 
 * File:   imagen_ppm.c
 * Author: felix
 *
 * Created on 6 de diciembre de 2011, 17:44
 */

#include <stdio.h>
#include <stdlib.h>

void Esfera_Imagen();
void Guarda_Imagen(double ***I, int dimx, int dimy);
double ***Imagen(int N, int M);
double ***Imagen(int N, int M);
double *** Lee_Imagen(char *nombre, int *nr, int *nc);
void Lee_linea(FILE *fp);

/*
 * Crea una imagen de una esfera
 */

void Esfera_Imagen() {
  const int dimx = 800, dimy = 800;
  int i, j;
  FILE *fp = fopen("first.ppm", "wb"); /* b - binary mode */
  static unsigned char color[3];  
  int x, y;
  
  fprintf(fp, "P6\n");
  fprintf(fp, "# Imagen creada por mi\n");
  fprintf(fp, "%d %d\n", dimx, dimy);
  fprintf(fp, "255\n");
  
  for (j = 0; j < dimy; ++j)
  {
    for (i = 0; i < dimx; ++i) {
      x = i - dimx/2;
      y = j - dimy/2;
      
      if(x*x + y*y < 100000) {
          color[0] = 255 - (x*x + y*y) /500;  /* red */
          color[1] = 255 - (x*x + y*y) /500;  /* green */
          color[2] = 255 - (x*x + y*y) /500;  /* blue */
      }
      else {
          color[0] = 0;
          color[1] = 0;
          color[2] = 0;
      }
      (void) fwrite(color, 1, 3, fp);
      }
  }
  fclose(fp);    
}
/*
 * Guarda una Imagen 
 */

void Guarda_Imagen(double ***I, int dimx, int dimy) {
  int i, j, k;
  FILE *fp = fopen("salida.ppm", "wb"); /* b - binary mode */
  static unsigned char color[3];  
  static unsigned char aux;
  
  fprintf(fp, "P6\n");
  fprintf(fp, "# Imagen creada por mi\n");
  fprintf(fp, "%d %d\n", dimx, dimy);
  fprintf(fp, "255\n");
  
  for (j = 0; j < dimy; j++){
    for (i = 0; i < dimx; i++) {
        for(k=0; k<3; k++) {
            aux = (unsigned char) I[k][i][j] %255; 
            color[k] = aux;
        }
      fwrite(color, 1, 3, fp);
    }
  }
  fclose(fp);    
}

/*
 * Reserva la memoria necesaria para almacenar una imagen en Color
 */

double ***Imagen(int N, int M)
{
    double ***a;
    int i, k;
        
    a = (double ***) calloc(3, sizeof(double**));
        
    for(k=0; k<3; k++)
        a[k] = (double **) calloc (N, sizeof(double*));

    for(k=0; k<3; k++)
        for(i=0; i<N; i++)
            a[k][i] = (double *) calloc(M, sizeof (double));
    return a;
}

/*
 * Lee una linea del archivo indicado por el apuntador fp
 */

void Lee_linea(FILE *fp) {
    char c;
    
    do{
        fscanf(fp,"%c", &c);
        printf("%c", c);
    } while(c != '\n');        
}

/*
 *  Lee una imagen desde archivo
 */

double *** Lee_Imagen(char *nombre, int *nr, int *nc) {
    FILE *fp;    
    int dimx, dimy;
    int i, j, k;
    static unsigned char color[3];      
    double ***I; 
    
    fp = fopen(nombre, "rb"); /* b - binary mode */
    if(!fp) {
        printf("Error al abrir el archivo\n");
        return;
    }
    
    printf("Formato del archivo PPM: ");
    Lee_linea(fp);
    printf("Creado por: ");
    Lee_linea(fp);
    
    fscanf(fp, "%d %d", &dimx, &dimy);
    printf("Renglones %d Columnas %d\n", dimy, dimx);
    *nr = dimx;
    *nc = dimy;
    
    I = Imagen(dimx, dimy);
    
    for(j=0; j<dimy; j++)
        for(i=0; i<dimx; i++){
            fread(color, 1, 3, fp);
            for(k=0; k<3; k++)
                I[k][i][j] = color[k];
        }
    fclose(fp);
    
    return I;
}

void Ejemplo01() {
    double ***I;
    int nr, nc;
    int i, j, k;
    I = Lee_Imagen("lena2.ppm", &nr, &nc);
    
    for(k=0; k<3; k++)
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                I[k][i][j] = 255 - I[k][i][j];
    
    Guarda_Imagen(I, nr, nc);    
}

void Ejemplo02() {
    double ***I;
    int nr, nc;
    int i, j, k;
    double suma;
    
    I = Lee_Imagen("lena2.ppm", &nr, &nc);
    
    for(i=0; i<nr; i++)
        for(j=0; j<nc; j++) {
            suma = 0;
            for(k=0; k<3; k++)
                suma += I[k][i][j];
            for(k=0; k<3; k++)
                I[k][i][j] = suma/3;
        }
    
    Guarda_Imagen(I, nr, nc);    
}

int main(int argc, char** argv) {
    Ejemplo02();

    return (EXIT_SUCCESS);
}
\end{verbatim}

