surfaces-unies/src/ppm.c

217 lines
6.6 KiB
C
Raw Normal View History

/**
* \file ppm.c
* \brief Fichier de déclaration des fonctions de manipulation d'images ppm
*
* Déclaration du corps des fonctions déclarées dans \ref ppm.h
*/
#include "ppm.h"
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define RGB_COMPONENT_COLOR 255
#define CREATOR "Cartier"
/**
* \brief function description
*
* Fonction douverture de fichier selon le mode demandé. Si la fonction ne
* peut pas ouvrir le fichier, elle arrête le processus qui renverra la valeur
* `1`. En cas de succès, la fonction renverra un pointeur de fichier vers le
* fichier ouvert.
*
* \param[in] filename Nom du fichier à ouvrir
* \param[in] mode Mode du fichier à ouvrir
* \return Pointeur de fichier
*/
FILE* get_file(char *filename, const char* mode) {
FILE* fp = fopen(filename, mode);
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
return fp;
}
/**
* Lit et vérifie le format du fichier passé en argument. Si le format nest
* pas correct, la fonction arrête le processus qui renverra la valeur `1`.
*
* \param[in] fb Fichier ppm lire les données
* \param[in] filename Nom du fichier ouvert
*/
void read_file_format(FILE* fp, char* filename) {
char buff[16];
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);
}
/* check file format */
if (buff[0] != 'P' || buff[1] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
}
}
/**
* Vérifie si le header contient des commentaires et les ignore le cas échéant.
*
* \param[in] fp Fichier ppm lire les données
*/
void check_for_comments(FILE* fp) {
char c;
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n')
;
c = getc(fp);
}
ungetc(c, fp);
}
/**
* Lit la taille des données image et les écrit dans le conteneur dimages
* passé en argument.
*
* \param[in] fp Fichier ppm lire les données
* \param[out] img Conteneur dimage écrire les résultats
* \param[in] filename Nom du fichier ouvert
*/
void read_file_size(FILE* fp, Image* img, char* filename) {
if (fscanf(fp, "%lu %lu", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
}
/**
* Vérifie le format RGB de limage ppm. Si le format nest pas correct, la
* fonction arrête le processus qui renverra la valeur `1`.
*
* \param[in] fp Fichier ppm lire les données
* \param[in] filename Nom du fichier ouvert
*/
void read_rgb(FILE* fp, char* filename) {
char d;
int rgb_comp_color;
/* read rgb component */
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
fscanf(fp, "%c ", &d);
/* check rgb component depth */
if (rgb_comp_color != RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);
}
}
unsigned long read_data(FILE *fp, Image *img, GLubyte *data, char *filename) {
unsigned long size;
/* allocation memoire */
size = img->x * img->y * 3;
printf("Size image %lu %lu => %lu\n", img->x, img->y, size);
data = (GLubyte *)malloc((size_t)size * sizeof(GLubyte));
assert(data);
/* read pixel data from file */
if (!fread(data, (size_t)1, (size_t)size, fp)) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
free(data);
return size;
}
/**
* Convertit vers un tableau de `GLubyte` les pixels contenus dans un conteneur
* dimage. La taille du tableau de `GLubyte` est la taille du tableau de
* pixels multipliée par trois du fait des trois emplacements séparés par
* couleur.
*
* \param[out] img Image dont les pixels doivent être convertis
* \param[in] data Données à convertir en structures \ref Pixel
* \param[in] size Taille du tableau de `GLubyte`
* \return return type
*/
void dataToImage(Image *img, GLubyte *data, unsigned long size) {
unsigned long i;
img->pixels = darrayNew(sizeof(Pixel));
for (i = 0; i < size; i += 3) {
darrayPushBack(img->pixels, newPixel(data[i], data[i+1], data[i+2]));
darrayPushBack(img->pixels, newPixel(data[i], data[i+1], data[i+2]));
}
}
/**
* Convertit le vecteur de pixels dun conteneur dimage en un tableau de
* valeurs de type `GLuint` afin de permettre lécriture dune image dans un
* fichier.
*
* \param[in] img Conteneur dimage contenant les pixels à convertir
* \return Tableau de pointeurs de `GLuint`
*/
GLubyte *imageToData(Image_t img) {
Pixel_t pixel;
GLubyte *data, size;
unsigned long i;
size = darraySize(img->pixels);
data = (GLubyte *)malloc(3 * sizeof(GLubyte) * size);
for(i = 0; i < size; i += 3) {
pixel = darrayGet(img->pixels, i / 3);
data[i] = pixel->r;
data[i + 1] = pixel->g;
data[i + 2] = pixel->b;
}
return data;
}
/**
* Ouvre le fichier image avec son nom de fichier passé par le paramètre
* `filename` et charge ses informations et données dans l'objet `img` dans
* lequel les données et l'image seront manipulables. Retourne la valeur 1 en
* cas de succès.
*
* \param[in] filename Nom du fichier image à ouvrir
* \param[out] img Objet \ref Image manipulable
* \return Retourne 1 en cas de succès
*/
int ImageLoadPPM(char *filename, Image *img) {
FILE *fp;
unsigned long size;
GLubyte* data = NULL;
fp = get_file(filename, "rb"); /* open PPM file for reading */
read_file_format(fp, filename); /* read image format */
check_for_comments(fp); /* check for comments */
read_file_size(fp, img, filename); /* read image size information */
read_rgb(fp, filename); /* read rgb component */
size = read_data(fp, img, data, filename); /* read data from file */
dataToImage(img, data, size);
fclose(fp);
return 1;
}
/**
* Ouvre le fichier image avec son nom de fichier passé par le paramètre
* `filename` et y écrit les informations trouvées dans lobjet `img`.
*
* \param[in] filename Nom du fichier image à ouvrir
* \param[in] img Objet \ref Image à écrire
*/
void imagesavePPM(char *filename, Image_t img) {
FILE *fp;
GLubyte *data;
fp = get_file(filename, "wb"); /* open file for output */
/* write the header file */
fprintf(fp, "P6\n"); /* image format */
fprintf(fp, "# Created by %s\n", CREATOR); /* comments */
fprintf(fp, "%lu %lu\n", img->y, img->y); /* image size */
fprintf(fp, "%d\n", RGB_COMPONENT_COLOR); /* rgb component depth */
data = imageToData(img); /* pixel data */
fwrite(data, (size_t)1, (size_t)(3 * img->x * img->y), fp);
free(data);
fclose(fp);
}