surfaces-unies/src/common.c

131 lines
4.4 KiB
C
Raw Normal View History

2018-11-12 14:25:24 +01:00
/**
* \file common.c
* \brief Implémentation de la ()compression dimages
*/
#include "common.h"
2018-11-12 14:25:24 +01:00
/**
* 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_pixel, Zone* t_zone) {
return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g &&
t_pixel->b == t_zone->b;
}
2018-11-12 14:25:24 +01:00
/**
* Ajoute un pixel à la zone passé en argument si le pixel à lindex passé en
* argument est éligible à la zone. Si un pixel na pas encore é visité, cela
* veut dire également quil ne fait partie daucun 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 limage `t_img`
* \param[out] t_zone Zone à laquelle sera potentiellement ajouté le pixel
*/
void addPixelToSelectedZone(Image* t_img, int t_idx, Zone* t_zone) {
Pixel* current_pixel;
2018-11-07 01:03:55 +01:00
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;
}
2018-11-07 01:03:55 +01:00
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 */
2018-11-07 01:03:55 +01:00
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_img, int t_idx, darray *zones) {
Zone* current_zone;
Pixel* pixel;
size_t i;
pixel = darrayGet(t_img->pixels, t_idx);
/* if the pixel has already been visited, no need to continue */
if (pixel->visited) {
return;
}
/* for each known zone, see if it matches the current pixel's color */
for (i = 0; i < darraySize(zones); ++i) {
current_zone = darrayGet(zones, i);
/* if it does, add selected pixel and its neighbourging pixels of the same
* color */
if (sameColor(pixel, current_zone)) {
addPixelToSelectedZone(t_img, t_idx, current_zone);
return;
}
}
/* if none of the same color was found, create a new one, add it to the image
* and add the selected pixel and its neighbours of the same color to the zone
*/
current_zone = newZone(pixel->r, pixel->g, pixel->b);
darrayPushBack(zones, current_zone);
addPixelToSelectedZone(t_img, t_idx, current_zone);
}
/* converts an image to zones */
darray* imgToZones(Image* t_img) {
darray *zones;
const size_t nb_pixels = darraySize(t_img->pixels);
size_t i;
zones = darrayNew(sizeof(Zone));
/* for each pixel, try to create a new zone */
for (i = 0; i < nb_pixels; ++i) {
chooseZoneForPixel(t_img, i, zones);
}
return zones;
}
2018-11-07 01:03:55 +01:00
2018-11-11 16:32:27 +01:00
void compress(const char *input_file) {
2018-11-23 10:31:47 +01:00
Image *img;
darray *zones;
2018-11-07 01:03:55 +01:00
img = newImage();
imageLoadPPM(input_file, img);
zones = imgToZones(img);
2018-11-11 16:32:27 +01:00
2018-11-23 10:31:47 +01:00
/* print segments for debug ************************************************/
DEBUG {
printf("Detected %zu zones\n", darraySize(zones));
for (size_t i = 0; i < darraySize(zones); ++i) {
Zone *zone = darrayGet(zones, i);
printf("\n=== Zone %zu (%d %d %d) ===\n", i, zone->r, zone->g, zone->b);
for (size_t j = 0; j < darraySize(zone->segments); ++j) {
Segment *segm = darrayGet(zone->segments, j);
printf("[%zu: %d, %d]\t", segm->xg / img->x, segm->xg, segm->xd);
}
}
2018-11-23 10:31:47 +01:00
printf("\n");
}
2018-11-11 16:32:27 +01:00
2018-11-07 01:03:55 +01:00
deleteImage(img);
}