I think I fixed zones detection, still got memory leak
This commit is contained in:
parent
0f1b59b159
commit
a27a31a0ae
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@ build
|
||||
debug
|
||||
!.gitignore
|
||||
*.out
|
||||
\.idea/
|
||||
cmake-build-debug/
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
* \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
|
||||
* \return Valeur booléenne, `1` si le pixel est éligible, `0` sinon
|
||||
*/
|
||||
bool sameColor(Pixel* t_pixel, Zone* t_zone) {
|
||||
return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g &&
|
||||
@ -31,31 +31,42 @@ bool sameColor(Pixel* t_pixel, Zone* t_zone) {
|
||||
* \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_img, int t_idx, Zone* t_zone) {
|
||||
Pixel *current_pixel = darrayGet(t_img->pixels, t_idx);
|
||||
int xd, xg, y = t_idx / (int)t_img->x;
|
||||
if (t_idx >= (int)darraySize(t_img->pixels) ||
|
||||
t_idx < 0 || !sameColor(current_pixel, t_zone)) {
|
||||
void addPixelToSelectedZone(Image *t_img, long t_idx, Zone *t_zone) {
|
||||
const size_t img_size = darraySize(t_img->pixels);
|
||||
Pixel *current_pixel;
|
||||
const uint32_t y = (uint32_t)(t_idx / t_img->x);
|
||||
long left_limit, right_limit;
|
||||
const long xd_limit = (long)t_img->x * (y + 1);
|
||||
|
||||
if (t_idx >= (long)img_size || t_idx < 0) {
|
||||
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);
|
||||
current_pixel = darrayGet(t_img->pixels, (size_t)t_idx);
|
||||
if (current_pixel->visited || !sameColor(current_pixel, t_zone)) {
|
||||
return;
|
||||
}
|
||||
(*current_pixel).visited = 1;
|
||||
for (right_limit = t_idx; right_limit < xd_limit; ++right_limit) {
|
||||
current_pixel = darrayGet(t_img->pixels, (size_t)right_limit);
|
||||
if (!sameColor(current_pixel, t_zone)) {
|
||||
break;
|
||||
}
|
||||
(*current_pixel).visited = true;
|
||||
current_pixel->visited = 1;
|
||||
}
|
||||
for(xg = t_idx; xg - y >= 0; --xg) { /* fetch right limit of segment */
|
||||
current_pixel = darrayGet(t_img->pixels, xd);
|
||||
|
||||
for (left_limit = t_idx; left_limit - (y - 1) * (long)t_img->x >= 0;
|
||||
--left_limit) { /* fetch right limit of segment */
|
||||
current_pixel = darrayGet(t_img->pixels, (size_t)left_limit);
|
||||
if (current_pixel->visited || !sameColor(current_pixel, t_zone)) {
|
||||
break;
|
||||
}
|
||||
(*current_pixel).visited = true;
|
||||
(*current_pixel).visited = 1;
|
||||
}
|
||||
/* Add segment to its zone */
|
||||
darrayPushBack(t_zone->segments, newSegment(xd, xg));
|
||||
for(; xg <= xd; ++xg) { /* process every pixel up and down the segment */
|
||||
darrayPushBack(t_zone->segments,
|
||||
newSegment((uint32_t)right_limit, (uint32_t)left_limit));
|
||||
for (; left_limit <= right_limit;
|
||||
++left_limit) { /* process every pixel up and down the segment */
|
||||
addPixelToSelectedZone(t_img, t_idx + t_img->x, t_zone);
|
||||
}
|
||||
}
|
||||
@ -69,12 +80,12 @@ void addPixelToSelectedZone(Image* t_img, int t_idx, Zone* t_zone) {
|
||||
* \param[in] t_idx Index du pixel à tester
|
||||
* \param[out] t_zones Liste des zones de l’image
|
||||
*/
|
||||
void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
|
||||
void chooseZoneForPixel(Image *t_img, long t_idx, darray *zones) {
|
||||
Zone *current_zone;
|
||||
Pixel *pixel;
|
||||
size_t i;
|
||||
|
||||
pixel = darrayGet(t_img->pixels, t_idx);
|
||||
pixel = darrayGet(t_img->pixels, (size_t)t_idx);
|
||||
/* if the pixel has already been visited, no need to continue */
|
||||
if (pixel->visited) {
|
||||
return;
|
||||
@ -82,7 +93,7 @@ void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
|
||||
/* 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
|
||||
/* if it does, add selected pixel and its neighbouring pixels of the same
|
||||
* color */
|
||||
if (sameColor(pixel, current_zone)) {
|
||||
addPixelToSelectedZone(t_img, t_idx, current_zone);
|
||||
@ -106,11 +117,11 @@ void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
|
||||
darray *imgToZones(Image *t_img) {
|
||||
darray *zones;
|
||||
const size_t nb_pixels = darraySize(t_img->pixels);
|
||||
size_t i;
|
||||
long i;
|
||||
zones = darrayNew(sizeof(Zone));
|
||||
|
||||
/* for each pixel, try to create a new zone */
|
||||
for (i = 0; i < nb_pixels; ++i) {
|
||||
for (i = 0; i < (long)nb_pixels; ++i) {
|
||||
chooseZoneForPixel(t_img, i, zones);
|
||||
}
|
||||
return zones;
|
||||
@ -125,28 +136,16 @@ darray* imgToZones(Image* t_img) {
|
||||
void compress(const char *t_input_file) {
|
||||
Image *img;
|
||||
darray *zones;
|
||||
Zone *current_zone;
|
||||
size_t i;
|
||||
img = newImage();
|
||||
imageLoadPPM(t_input_file, img);
|
||||
zones = imgToZones(img);
|
||||
|
||||
/* print segments for debug ************************************************/
|
||||
DEBUG {
|
||||
printf("Detected %zu zones\n", darraySize(zones));
|
||||
for (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);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
deleteImage(img);
|
||||
for(i = 0; i < darraySize(zones); ++i) {
|
||||
deleteZoneContent(darrayGet(zones, i));
|
||||
current_zone = darrayGet(zones, i);
|
||||
darrayDelete(current_zone->segments);
|
||||
}
|
||||
darrayDelete(zones);
|
||||
}
|
||||
|
@ -11,9 +11,9 @@
|
||||
/// Teste l’éligibilité d’un pixel à une zone
|
||||
bool sameColor(Pixel *t_pixel, Zone *t_zone);
|
||||
/// Ajoute un pixel et ses pixels connexes à une zone
|
||||
void addPixelToSelectedZone(Image *t_img, int t_idx, Zone *t_zone);
|
||||
void addPixelToSelectedZone(Image *t_img, long t_idx, Zone *t_zone);
|
||||
/// Sélectionne la zone correspondant à la couleur d'un pixel
|
||||
void chooseZoneForPixel(Image *t_img, int t_idx, darray *zones);
|
||||
void chooseZoneForPixel(Image *t_img, long t_idx, darray *zones);
|
||||
/// Créé les zones d'une image
|
||||
darray *imgToZones(Image *t_img);
|
||||
/// Compresse l'image d'entrée
|
||||
|
11
src/darray.c
11
src/darray.c
@ -44,8 +44,7 @@ void darrayInsert(darray *t_self, void *t_pos, void *t_elem) {
|
||||
darrayExtend(t_self);
|
||||
}
|
||||
itr = (char *)t_self->begin + pos_aux;
|
||||
memmove(itr + t_self->element_size, itr,
|
||||
(unsigned long)((char *)t_self->end - itr));
|
||||
memmove(itr + t_self->element_size, itr, ((char *)t_self->end - itr));
|
||||
memcpy(itr, t_elem, t_self->element_size);
|
||||
(*t_self).end = (char *)t_self->end + t_self->element_size;
|
||||
}
|
||||
@ -84,8 +83,7 @@ void darrayExtend(darray *t_self) {
|
||||
*/
|
||||
void darrayErase(darray *t_self, void *t_pos) {
|
||||
memmove(t_pos, (char *)t_pos + t_self->element_size,
|
||||
(unsigned long)(((char *)t_self->end - t_self->element_size) -
|
||||
(char *)t_pos));
|
||||
(((char *)t_self->end - t_self->element_size) - (char *)t_pos));
|
||||
(*t_self).end = (char *)t_self->end - t_self->element_size;
|
||||
}
|
||||
|
||||
@ -144,6 +142,11 @@ size_t darraySize(darray* t_self) {
|
||||
* \return Pointeur de type `void*` pointant sur l’élément si l’index est valide, sur NULL sinon.
|
||||
*/
|
||||
void *darrayGet(darray* t_self, size_t t_idx) {
|
||||
if(t_idx >= darraySize(t_self)) {
|
||||
fprintf(stderr, "Error in `darrayGet`, out of bound idx: %zu (max: %zu)\n",
|
||||
t_idx, darraySize(t_self));
|
||||
exit(PTR_ERROR);
|
||||
}
|
||||
void *itr;
|
||||
itr = (char *)t_self->begin + t_idx * t_self->element_size;
|
||||
return itr;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define PTR_ERROR 2
|
||||
/// Constante pour les erreurs liées à la lecture et écriture de fichiers
|
||||
#define FILE_IO_ERROR 3
|
||||
/// Constante pour les erreurs liées au format de fichiers
|
||||
#define FILE_FORMAT_ERROR 4
|
||||
|
||||
#endif /* ERRORCODES_H */
|
||||
|
13
src/main.c
13
src/main.c
@ -8,7 +8,7 @@
|
||||
* des fonctions cœures du programme.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "compress.h"
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -49,7 +49,7 @@ Options available:\n\
|
||||
struct Argres {
|
||||
char *input; /*!< Nom du fichier d'entrée */
|
||||
char *output; /*!< Nom du fichier de sortie */
|
||||
bool compress; /*!< Le fichier d'entrée doit-il être compressé ? */
|
||||
char compress; /*!< Le fichier d'entrée doit-il être compressé ? */
|
||||
};
|
||||
typedef struct Argres Argres;
|
||||
|
||||
@ -62,14 +62,14 @@ typedef struct Argres Argres;
|
||||
* \param[out] t_args Result of the arguments processing
|
||||
* \param[in] t_c Switch or option passed
|
||||
*/
|
||||
void get_args(Argres *t_args, int *t_c) {
|
||||
void get_args(Argres *t_args, const int * const t_c) {
|
||||
switch (*t_c) {
|
||||
case 0: break;
|
||||
case 'h': help(NOERROR); break;
|
||||
case 'i': (*t_args).input = optarg; break;
|
||||
case 'o': (*t_args).output = optarg; break;
|
||||
case 'c': (*t_args).compress = true; break;
|
||||
case 'u': (*t_args).compress = false; break;
|
||||
case 'c': (*t_args).compress = 1; break;
|
||||
case 'u': (*t_args).compress = 0; break;
|
||||
case '?':
|
||||
default: help(ARGERROR);
|
||||
}
|
||||
@ -91,8 +91,9 @@ void get_args(Argres *t_args, int *t_c) {
|
||||
Argres process_args(const int t_argc, char *t_argv[]) {
|
||||
Argres res;
|
||||
res.input = NULL;
|
||||
res.compress = 1;
|
||||
res.output = "output.su";
|
||||
while (true) {
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'}, {"input", required_argument, NULL, 'i'},
|
||||
|
@ -119,7 +119,7 @@ unsigned long read_data(FILE *t_fp, Image *t_img, unsigned char **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);
|
||||
free(*t_data);
|
||||
exit(FILE_IO_ERROR);
|
||||
}
|
||||
return size;
|
||||
@ -190,6 +190,7 @@ int imageLoadPPM(const char *t_filename, Image *t_img) {
|
||||
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);
|
||||
free(data);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
@ -28,16 +28,6 @@ Pixel *newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructeur d’un pixel. Étant donné qu’un pixel ne contient aucune donnée
|
||||
* pointée par un pointeur, la seule action de la fonction sera de libérer la
|
||||
* mémoire pointée par le pointeur de pixel en lui-même et donc le pixel passé
|
||||
* en argument.
|
||||
*
|
||||
* \param[in] self Pointeur vers le pixel à détruire
|
||||
*/
|
||||
void deletePixel(Pixel *t_self) { free(t_self); }
|
||||
|
||||
/**
|
||||
* Constructeur d’un conteneur d’image. Les dimensions sont initialisées à zéro
|
||||
* (0) et son tableau de pixels a été créé et initialisé en tableau vide. Le
|
||||
@ -80,23 +70,13 @@ void deleteImage(Image *t_self) {
|
||||
* \param[in] xg Abscisse extrême gauche du segment
|
||||
* \return Pointeur sur un conteneur de segment
|
||||
*/
|
||||
Segment *newSegment(uint16_t t_xd, uint16_t t_xg) {
|
||||
Segment *res;
|
||||
res = (Segment *)malloc(sizeof(Segment));
|
||||
Segment *newSegment(uint32_t t_xd, uint32_t t_xg) {
|
||||
Segment *res = (Segment *)malloc(sizeof(Segment));
|
||||
res->xd = t_xd;
|
||||
res->xg = t_xg;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructeur de conteneur de segment. Les conteneurs de segments ne contenant
|
||||
* pas de pointeur propriétaire de données, le destructeur libérera simplement
|
||||
* de la mémoire le conteneur pointé par le pointeur passé en argument.
|
||||
*
|
||||
* \param[in] self Conteneur de segment à détruire
|
||||
*/
|
||||
void deleteSegment(Segment *t_self) { free(t_self); }
|
||||
|
||||
/**
|
||||
* \brief function description
|
||||
*
|
||||
@ -110,8 +90,7 @@ void deleteSegment(Segment *t_self) { free(t_self); }
|
||||
* \return Pointeur vers la structure créée
|
||||
*/
|
||||
Zone *newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
|
||||
Zone *res;
|
||||
res = (Zone *)malloc(sizeof(Zone));
|
||||
Zone *res = (Zone *)malloc(sizeof(Zone));
|
||||
res->r = t_r;
|
||||
res->g = t_g;
|
||||
res->b = t_b;
|
||||
@ -120,22 +99,11 @@ Zone *newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructeur de zone, libère de la mémoire les segments contenus dans le
|
||||
* tableau de segments, puis le tableau en lui-même pour ultimement libérer
|
||||
* de la mémoire le conteneur de zone en lui-même pointé par le pointeur passé
|
||||
* en argument du destructeur.
|
||||
* Destructeur de zone, libère la zone mémoire utilisée pour stocker les
|
||||
* segments. Ne libère pas \p t_self lui-même mais son membre `segments`.
|
||||
*
|
||||
* \param[in] self Conteneur de zone à détruire
|
||||
*/
|
||||
void deleteZone(Zone *t_self) {
|
||||
unsigned long i;
|
||||
for (i = 0; i < darraySize(t_self->segments); ++i) {
|
||||
deleteSegment(darrayGet(t_self->segments, i));
|
||||
}
|
||||
void deleteZoneContent(Zone *t_self) {
|
||||
darrayDelete(t_self->segments);
|
||||
free(t_self);
|
||||
}
|
||||
|
||||
Pixel *imgAt(Image *t_img, int t_x, int t_y) {
|
||||
return (Pixel *)darrayGet(t_img->pixels, t_x + t_y * t_img->x);
|
||||
}
|
@ -22,14 +22,8 @@
|
||||
|
||||
#ifdef Debug
|
||||
#define DEBUG if (1)
|
||||
#define PDEB \
|
||||
if (1) \
|
||||
printf
|
||||
#else
|
||||
#define DEBUG if (0)
|
||||
#define PDBEF \
|
||||
if (0) \
|
||||
printf
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -74,7 +68,7 @@ struct Pixel {
|
||||
uint8_t r; /*!< Couleur rouge du pixel */
|
||||
uint8_t g; /*!< Couleur verte du pixel */
|
||||
uint8_t b; /*!< Couleur bleue du pixel */
|
||||
bool visited; /*!< Le pixel a-t-il été visité avant */
|
||||
unsigned char visited; /*!< Le pixel a-t-il été visité avant */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -98,8 +92,8 @@ struct Zone {
|
||||
* à son extrême droite et à son extrême gauche.
|
||||
*/
|
||||
struct Segment {
|
||||
uint16_t xd; /*!< extrême droit du segment */
|
||||
uint16_t xg; /*!< extrême gauche du segment */
|
||||
uint32_t xd; /*!< extrême droit du segment */
|
||||
uint32_t xg; /*!< extrême gauche du segment */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -108,21 +102,15 @@ struct Segment {
|
||||
|
||||
/// \brief Création d’un nouveau pixel
|
||||
Pixel *newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b);
|
||||
/// \brief Destruction d’un pointeur de pixel
|
||||
void deletePixel(Pixel *t_self);
|
||||
/// \brief Création d’une nouvelle image
|
||||
Image *newImage();
|
||||
/// \brief Destructeur d’une image
|
||||
void deleteImage(Image *t_self);
|
||||
/// \brief Constructeur d’un segment de couleur unie
|
||||
Segment *newSegment(uint16_t t_xd, uint16_t t_xg);
|
||||
/// \brief Destructeur d’un segment de couleur unie
|
||||
void deleteSegment(Segment *t_self);
|
||||
Segment *newSegment(uint32_t t_xd, uint32_t t_xg);
|
||||
/// \brief Constructeur de conteneur de zone
|
||||
Zone* newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b);
|
||||
/// \brief Destructeur de conteneur de zone
|
||||
void deleteZone(Zone *t_self);
|
||||
/// \brief Renvoie un pixel aux coordonnées `(x, y)` dans une image
|
||||
Pixel *imgAt(Image *t_img, int t_x, int t_y);
|
||||
void deleteZoneContent(Zone *t_self);
|
||||
|
||||
#endif /* UTILITIES_H */
|
||||
|
Loading…
Reference in New Issue
Block a user