surfaces-unies/src/ppm.c
2018-11-12 15:25:21 +01:00

217 lines
7.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* \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>
#define RGB_COMPONENT_COLOR 255
#define CREATOR "CL"
/**
* \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(const char *t_filename, const char* t_mode) {
FILE* fp = fopen(t_filename, t_mode);
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", t_filename);
exit(FILE_IO_ERROR);
}
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 où lire les données
* \param[in] filename Nom du fichier ouvert
*/
void read_file_format(FILE* t_fp, const char* t_filename) {
char buff[16];
if (!fgets(buff, sizeof(buff), t_fp)) {
perror(t_filename);
exit(FILE_IO_ERROR);
}
/* check file format */
if (buff[0] != 'P' || buff[1] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(FILE_FORMAT_ERROR);
}
}
/**
* Vérifie si le header contient des commentaires et les ignore le cas échéant.
*
* \param[in] fp Fichier ppm où lire les données
*/
void check_for_comments(FILE* t_fp) {
char c;
c = (char)getc(t_fp);
while (c == '#') {
while (getc(t_fp) != '\n')
;
c = (char)getc(t_fp);
}
ungetc(c, t_fp);
}
/**
* Lit la taille des données image et les écrit dans le conteneur dimages
* passé en argument.
*
* \param[in] fp Fichier ppm où lire les données
* \param[out] img Conteneur dimage où écrire les résultats
* \param[in] filename Nom du fichier ouvert
*/
void read_file_size(FILE* t_fp, Image* t_img, const char* t_filename) {
if (fscanf(t_fp, "%lu %lu", &t_img->x, &t_img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", t_filename);
exit(FILE_FORMAT_ERROR);
}
}
/**
* 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 où lire les données
* \param[in] filename Nom du fichier ouvert
*/
void read_rgb(FILE* t_fp, const char* t_filename) {
char d;
int rgb_comp_color;
/* read rgb component */
if (fscanf(t_fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", t_filename);
exit(FILE_FORMAT_ERROR);
}
fscanf(t_fp, "%c ", &d);
/* check rgb component depth */
if (rgb_comp_color != RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n", t_filename);
exit(FILE_FORMAT_ERROR);
}
}
unsigned long read_data(FILE *t_fp, Image *t_img, unsigned char **t_data,
const char *t_filename) {
unsigned long size;
/* allocation memoire */
size = t_img->x * t_img->y * 3;
printf("Size image %lu %lu => %lu\n", t_img->x, t_img->y, size);
*t_data = (unsigned char *)malloc((size_t)size * sizeof(unsigned char));
assert(*t_data);
/* read pixel data from file */
if (!fread(*t_data, (size_t)1, (size_t)size, t_fp)) {
fprintf(stderr, "Error loading image '%s'\n", t_filename);
free(t_data);
exit(FILE_IO_ERROR);
}
return size;
}
/**
* Convertit vers un tableau de `unsigned char` les pixels contenus dans un conteneur
* dimage. La taille du tableau de `unsigned char` 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 `unsigned char`
* \return return type
*/
void dataToImage(Image *t_img, unsigned char *t_data, unsigned long t_size) {
unsigned long i;
t_img->pixels = darrayNew(sizeof(Pixel));
printf("Size of data: %lu\n", t_size);
for (i = 0; i < t_size; i += 3) {
darrayPushBack(t_img->pixels,
newPixel(t_data[i], t_data[i + 1], t_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`
*/
unsigned char *imageToData(Image_t t_img) {
Pixel_t pixel;
unsigned char *data, size;
unsigned long i;
size = (unsigned char)darraySize(t_img->pixels);
data = (unsigned char *)malloc(3 * sizeof(unsigned char) * size);
for(i = 0; i < size; i += 3) {
pixel = darrayGet(t_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(const char *t_filename, Image *t_img) {
FILE *fp;
unsigned long size;
unsigned char *data = NULL;
printf("Hey auie\n");
fp = get_file(t_filename, "rb"); /* open PPM file for reading */
read_file_format(fp, t_filename); /* read image format */
check_for_comments(fp); /* check for comments */
read_file_size(fp, t_img, t_filename); /* read image size information */
read_rgb(fp, t_filename); /* read rgb component */
size = read_data(fp, t_img, &data, t_filename); /* read data from file */
dataToImage(t_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 *t_filename, Image_t t_img) {
FILE *fp;
unsigned char *data;
fp = get_file(t_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", t_img->y, t_img->y); /* image size */
fprintf(fp, "%d\n", RGB_COMPONENT_COLOR); /* rgb component depth */
data = imageToData(t_img); /* pixel data */
fwrite(data, (size_t)1, (size_t)(3 * t_img->x * t_img->y), fp);
free(data);
fclose(fp);
}