surfaces-unies/src/ppm.c

222 lines
7.2 KiB
C
Raw Permalink 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] t_filename Nom du fichier à ouvrir
* \param[in] t_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] t_fp Fichier ppm où lire les données
* \param[in] t_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] t_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] t_fp Fichier ppm où lire les données
* \param[out] t_img Conteneur dimage où écrire les résultats
* \param[in] t_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->sizeX, &t_img->sizeY) != 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] t_fp Fichier ppm où lire les données
* \param[in] t_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);
}
}
/**
* \brief function description
*
* Lit les données images brutes du fichier ppm ouvert et les stocke dans \p
* t_data.
*
* \param[in] t_fp Fichier ppm ouvert source
* \param[in] t_size Taille des données brutes
* \param[out] t_data Pointeur vers le tableau de sortie des données brutes
* \param[in] t_filename Nom du fichier dentrée
* \return Taille du tableau de données obtenu
*/
void read_data(FILE *t_fp, uint64_t t_size, unsigned char **t_data,
const char *t_filename) {
*t_data = (unsigned char *)malloc(t_size * sizeof(unsigned char));
assert(*t_data);
/* read pixel data from file */
if (!fread(*t_data, (size_t)1, t_size, t_fp)) {
fprintf(stderr, "Error loading image '%s'\n", t_filename);
free(*t_data);
exit(FILE_IO_ERROR);
}
}
/**
* 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] t_img Image dont les pixels doivent être convertis
* \param[in] t_data Données à convertir en structures \ref Pixel
* \param[in] t_size Taille du tableau de `unsigned char`
*/
void dataToImage(Image *t_img, uint8_t *t_data, uint64_t t_size) {
uint64_t i;
t_img->pixels = darrayNew(sizeof(Pixel));
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 `uint8_t` afin de permettre lécriture dune image dans un
* fichier.
*
* \param[in] t_img Conteneur dimage contenant les pixels à convertir
* \return Tableau de pointeurs de `uint8_t`
*/
uint8_t *imageToData(Image *t_img) {
Pixel *pixel;
uint8_t *data, size;
uint64_t i;
size = (uint8_t)darraySize(t_img->pixels);
data = (uint8_t *)malloc(3 * sizeof(uint8_t) * size);
for (i = 0; i < size; i += 3) {
pixel = darrayGet(t_img->pixels, i / 3);
data[i] = pixel->red;
data[i + 1] = pixel->green;
data[i + 2] = pixel->blue;
}
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] t_filename Nom du fichier image à ouvrir
* \param[out] t_img Objet \ref Image manipulable
* \return Retourne 1 en cas de succès
*/
int imageLoadPPM(const char *t_filename, Image *t_img) {
FILE *fp;
uint64_t size;
unsigned char *data = NULL;
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 = t_img->sizeX * t_img->sizeY * 3;
read_data(fp, size, &data, t_filename); /* read data from file */
dataToImage(t_img, data, size);
free(data);
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] t_filename Nom du fichier image à ouvrir
* \param[in] t_img Objet \ref Image à écrire
* \param[in] t_data Données décompressées de limage au format natif ppm
*/
void imageSavePPM(const char *t_filename, Image *t_img, uint8_t *t_data) {
FILE *fp;
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->sizeX, t_img->sizeY); /* image size */
fprintf(fp, "%d\n", RGB_COMPONENT_COLOR); /* rgb component depth */
fwrite(t_data, (size_t)1, (size_t)(3 * t_img->sizeX * t_img->sizeY), fp);
free(t_data);
fclose(fp);
}