2018-10-21 19:42:58 +00:00
|
|
|
|
/**
|
|
|
|
|
* \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
|
2018-11-03 15:35:06 +00:00
|
|
|
|
#define CREATOR "CL"
|
2018-10-21 19:42:58 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief function description
|
|
|
|
|
*
|
|
|
|
|
* Fonction d’ouverture 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.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_filename Nom du fichier à ouvrir
|
|
|
|
|
* \param[in] t_mode Mode du fichier à ouvrir
|
2018-10-21 19:42:58 +00:00
|
|
|
|
* \return Pointeur de fichier
|
|
|
|
|
*/
|
2018-11-24 20:58:55 +00:00
|
|
|
|
FILE *get_file(const char *t_filename, const char *t_mode) {
|
|
|
|
|
FILE *fp = fopen(t_filename, t_mode);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
if (!fp) {
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fprintf(stderr, "Unable to open file '%s'\n", t_filename);
|
|
|
|
|
exit(FILE_IO_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
return fp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lit et vérifie le format du fichier passé en argument. Si le format n’est
|
|
|
|
|
* pas correct, la fonction arrête le processus qui renverra la valeur `1`.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_fp Fichier ppm où lire les données
|
|
|
|
|
* \param[in] t_filename Nom du fichier ouvert
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 20:58:55 +00:00
|
|
|
|
void read_file_format(FILE *t_fp, const char *t_filename) {
|
2018-10-21 19:42:58 +00:00
|
|
|
|
char buff[16];
|
2018-11-03 15:35:06 +00:00
|
|
|
|
if (!fgets(buff, sizeof(buff), t_fp)) {
|
|
|
|
|
perror(t_filename);
|
|
|
|
|
exit(FILE_IO_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
/* check file format */
|
|
|
|
|
if (buff[0] != 'P' || buff[1] != '6') {
|
|
|
|
|
fprintf(stderr, "Invalid image format (must be 'P6')\n");
|
2018-11-03 15:35:06 +00:00
|
|
|
|
exit(FILE_FORMAT_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vérifie si le header contient des commentaires et les ignore le cas échéant.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_fp Fichier ppm où lire les données
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 20:58:55 +00:00
|
|
|
|
void check_for_comments(FILE *t_fp) {
|
2018-10-21 19:42:58 +00:00
|
|
|
|
char c;
|
2018-11-03 15:35:06 +00:00
|
|
|
|
c = (char)getc(t_fp);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
while (c == '#') {
|
2018-11-24 21:51:25 +00:00
|
|
|
|
while (getc(t_fp) != '\n') {
|
|
|
|
|
}
|
2018-11-03 15:35:06 +00:00
|
|
|
|
c = (char)getc(t_fp);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
2018-11-03 15:35:06 +00:00
|
|
|
|
ungetc(c, t_fp);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lit la taille des données image et les écrit dans le conteneur d’images
|
|
|
|
|
* passé en argument.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_fp Fichier ppm où lire les données
|
|
|
|
|
* \param[out] t_img Conteneur d’image où écrire les résultats
|
|
|
|
|
* \param[in] t_filename Nom du fichier ouvert
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 20:58:55 +00:00
|
|
|
|
void read_file_size(FILE *t_fp, Image *t_img, const char *t_filename) {
|
2018-11-26 01:28:15 +00:00
|
|
|
|
if (fscanf(t_fp, "%lu %lu", &t_img->sizeX, &t_img->sizeY) != 2) {
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fprintf(stderr, "Invalid image size (error loading '%s')\n", t_filename);
|
|
|
|
|
exit(FILE_FORMAT_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vérifie le format RGB de l’image ppm. Si le format n’est pas correct, la
|
|
|
|
|
* fonction arrête le processus qui renverra la valeur `1`.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_fp Fichier ppm où lire les données
|
|
|
|
|
* \param[in] t_filename Nom du fichier ouvert
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 20:58:55 +00:00
|
|
|
|
void read_rgb(FILE *t_fp, const char *t_filename) {
|
2018-10-21 19:42:58 +00:00
|
|
|
|
char d;
|
|
|
|
|
int rgb_comp_color;
|
|
|
|
|
/* read rgb component */
|
2018-11-03 15:35:06 +00:00
|
|
|
|
if (fscanf(t_fp, "%d", &rgb_comp_color) != 1) {
|
|
|
|
|
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", t_filename);
|
|
|
|
|
exit(FILE_FORMAT_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fscanf(t_fp, "%c ", &d);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
/* check rgb component depth */
|
|
|
|
|
if (rgb_comp_color != RGB_COMPONENT_COLOR) {
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fprintf(stderr, "'%s' does not have 8-bits components\n", t_filename);
|
|
|
|
|
exit(FILE_FORMAT_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-24 21:41:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* \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 d’entré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));
|
2018-11-11 17:17:33 +00:00
|
|
|
|
assert(*t_data);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
/* read pixel data from file */
|
2018-11-24 21:41:29 +00:00
|
|
|
|
if (!fread(*t_data, (size_t)1, t_size, t_fp)) {
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fprintf(stderr, "Error loading image '%s'\n", t_filename);
|
2018-11-24 20:33:47 +00:00
|
|
|
|
free(*t_data);
|
2018-11-03 15:35:06 +00:00
|
|
|
|
exit(FILE_IO_ERROR);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-11-24 20:58:55 +00:00
|
|
|
|
* Convertit vers un tableau de `unsigned char` les pixels contenus dans un
|
|
|
|
|
* conteneur d’image. 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.
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \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`
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 21:41:29 +00:00
|
|
|
|
void dataToImage(Image *t_img, uint8_t *t_data, uint64_t t_size) {
|
2018-11-24 21:51:25 +00:00
|
|
|
|
uint64_t i;
|
2018-11-03 15:35:06 +00:00
|
|
|
|
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]));
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convertit le vecteur de pixels d’un conteneur d’image en un tableau de
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* valeurs de type `uint8_t` afin de permettre l’écriture d’une image dans un
|
2018-10-21 19:42:58 +00:00
|
|
|
|
* fichier.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_img Conteneur d’image contenant les pixels à convertir
|
|
|
|
|
* \return Tableau de pointeurs de `uint8_t`
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-24 21:41:29 +00:00
|
|
|
|
uint8_t *imageToData(Image *t_img) {
|
2018-11-24 20:58:55 +00:00
|
|
|
|
Pixel *pixel;
|
2018-11-24 21:41:29 +00:00
|
|
|
|
uint8_t *data, size;
|
2018-11-24 21:51:25 +00:00
|
|
|
|
uint64_t i;
|
2018-11-24 21:41:29 +00:00
|
|
|
|
size = (uint8_t)darraySize(t_img->pixels);
|
|
|
|
|
data = (uint8_t *)malloc(3 * sizeof(uint8_t) * size);
|
2018-11-24 20:58:55 +00:00
|
|
|
|
for (i = 0; i < size; i += 3) {
|
2018-11-03 15:35:06 +00:00
|
|
|
|
pixel = darrayGet(t_img->pixels, i / 3);
|
2018-11-26 01:28:15 +00:00
|
|
|
|
data[i] = pixel->red;
|
|
|
|
|
data[i + 1] = pixel->green;
|
|
|
|
|
data[i + 2] = pixel->blue;
|
2018-10-21 19:42:58 +00:00
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_filename Nom du fichier image à ouvrir
|
|
|
|
|
* \param[out] t_img Objet \ref Image manipulable
|
2018-10-21 19:42:58 +00:00
|
|
|
|
* \return Retourne 1 en cas de succès
|
|
|
|
|
*/
|
2018-11-11 15:32:27 +00:00
|
|
|
|
int imageLoadPPM(const char *t_filename, Image *t_img) {
|
2018-10-21 19:42:58 +00:00
|
|
|
|
FILE *fp;
|
2018-11-24 21:41:29 +00:00
|
|
|
|
uint64_t size;
|
2018-11-12 13:25:06 +00:00
|
|
|
|
unsigned char *data = NULL;
|
2018-11-03 15:35:06 +00:00
|
|
|
|
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 */
|
2018-11-26 01:28:15 +00:00
|
|
|
|
size = t_img->sizeX * t_img->sizeY * 3;
|
2018-11-24 21:41:29 +00:00
|
|
|
|
read_data(fp, size, &data, t_filename); /* read data from file */
|
2018-11-03 15:35:06 +00:00
|
|
|
|
dataToImage(t_img, data, size);
|
2018-11-24 20:33:47 +00:00
|
|
|
|
free(data);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
fclose(fp);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-11-06 15:08:20 +00:00
|
|
|
|
() * Ouvre le fichier image avec son nom de fichier passé par le paramètre
|
2018-10-21 19:42:58 +00:00
|
|
|
|
* `filename` et y écrit les informations trouvées dans l’objet `img`.
|
|
|
|
|
*
|
2018-11-24 21:41:29 +00:00
|
|
|
|
* \param[in] t_filename Nom du fichier image à ouvrir
|
|
|
|
|
* \param[in] t_img Objet \ref Image à écrire
|
2018-10-21 19:42:58 +00:00
|
|
|
|
*/
|
2018-11-26 01:28:15 +00:00
|
|
|
|
void imageSavePPM(const char *t_filename, Image *t_img, uint8_t *t_data) {
|
2018-10-21 19:42:58 +00:00
|
|
|
|
FILE *fp;
|
2018-11-03 15:35:06 +00:00
|
|
|
|
fp = get_file(t_filename, "wb"); /* open file for output */
|
2018-10-21 19:42:58 +00:00
|
|
|
|
/* write the header file */
|
2018-11-26 01:28:15 +00:00
|
|
|
|
fprintf(fp, "P6\n"); /* image format */
|
|
|
|
|
fprintf(fp, "# Created by %s\n", CREATOR); /* comments */
|
|
|
|
|
fprintf(fp, "%lu %lu\n", t_img->sizeY, 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);
|
2018-10-21 19:42:58 +00:00
|
|
|
|
fclose(fp);
|
|
|
|
|
}
|