107 lines
3.4 KiB
C
107 lines
3.4 KiB
C
/**
|
||
* \file common.c
|
||
* \brief Implémentation de la (dé)compression d’images
|
||
*/
|
||
|
||
#include "common.h"
|
||
|
||
/**
|
||
* Cette fonction permet d’évaluer si le pixel passé en argument est éligible à
|
||
* la zone passée également en argument.
|
||
*
|
||
* \param[in] t_pixel Pointeur vers le pixel dont l’éligibilité est testée
|
||
* \param[in] t_zone Zone à laquelle le pixel est éligible ou non
|
||
* \return Valeur booléenne, `true` si le pixel est éligible, `false` sinon
|
||
*/
|
||
bool sameColor(Pixel_t t_pixel, Zone_t t_zone) {
|
||
return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g &&
|
||
t_pixel->b == t_zone->b;
|
||
}
|
||
|
||
/**
|
||
* Ajoute un pixel à la zone passé en argument si le pixel à l’index passé en
|
||
* argument est éligible à la zone. Si un pixel n’a pas encore été visité, cela
|
||
* veut dire également qu’il ne fait partie d’aucun segment, il sera donc
|
||
* ajouté à un nouveau segment auquel seront rajoutés tous les pixels connexes
|
||
* éligibles à la zone. Ensuite, le segment est ajouté à la zone, et la
|
||
* fonction actuelle est appelée sur tous les pixels supérieurs et inférieurs
|
||
* aux pixels du segment.
|
||
*
|
||
* \param[in] t_img Image contenant les pixels explorés
|
||
* \param[in] t_idx Index du pixel actuel dans l’image `t_img`
|
||
* \param[out] t_zone Zone à laquelle sera potentiellement ajouté le pixel
|
||
*/
|
||
void addPixelToSelectedZone(Image_t t_img, int t_idx, Zone_t t_zone) {
|
||
Pixel_t current_pixel;
|
||
int xd, xg, y = t_idx / (int)t_img->x;
|
||
current_pixel = darrayGet(t_img->pixels, t_idx);
|
||
if (current_pixel->visited || t_idx >= (int)darraySize(t_img->pixels) ||
|
||
t_idx < 0 || !sameColor(current_pixel, t_zone)) {
|
||
return;
|
||
}
|
||
(*current_pixel).visited = true;
|
||
for(xd = t_idx; xd % (int)t_img->x != 0; ++xd) { /* fetch right limit of segment */
|
||
current_pixel = darrayGet(t_img->pixels, xd);
|
||
if(!sameColor(current_pixel, t_zone)) {
|
||
break;
|
||
}
|
||
(*current_pixel).visited = true;
|
||
}
|
||
for(xg = t_idx; xg - y >= 0; --xg) { /* fetch right limit of segment */
|
||
current_pixel = darrayGet(t_img->pixels, xd);
|
||
if(!sameColor(current_pixel, t_zone)) {
|
||
break;
|
||
}
|
||
(*current_pixel).visited = true;
|
||
}
|
||
/* Add segment to its zone */
|
||
darrayPushBack(t_zone->segments, newSegment(y, xd, xg));
|
||
for(; xg <= xd; ++xg) { /* process every pixel up and down the segment */
|
||
addPixelToSelectedZone(t_img, t_idx + t_img->x, t_zone);
|
||
}
|
||
}
|
||
|
||
/* Selects the zone related to the pixel, skip tests if pixel has
|
||
already been visited */
|
||
void chooseZoneForPixel(Image_t t_img, int t_idx, darray_t zones) {
|
||
Zone_t current_zone;
|
||
Pixel_t pixel;
|
||
size_t i;
|
||
pixel = darrayGet(t_img->pixels, t_idx);
|
||
if (pixel->visited)
|
||
return;
|
||
for (i = 0; i < darraySize(zones); ++i) {
|
||
current_zone = darrayGet(zones, i);
|
||
if (sameColor(pixel, current_zone)) {
|
||
addPixelToSelectedZone(t_img, t_idx, current_zone);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* converts an image to zones */
|
||
darray_t imgToZones(Image_t t_img) {
|
||
darray_t zones;
|
||
const size_t nb_pixels = darraySize(t_img->pixels);
|
||
size_t i;
|
||
zones = darrayNew(sizeof(Zone));
|
||
|
||
for (i = 0; i < nb_pixels; ++i) {
|
||
chooseZoneForPixel(t_img, i, zones);
|
||
}
|
||
return zones;
|
||
}
|
||
|
||
void compress(const char *input_file) {
|
||
Image_t img;
|
||
darray_t zones;
|
||
img = newImage();
|
||
imageLoadPPM(input_file, img);
|
||
zones = imgToZones(img);
|
||
darrayDelete(zones);
|
||
|
||
printf("Detected %zu zones\n", darraySize(zones));
|
||
|
||
deleteImage(img);
|
||
}
|