I think I fixed zones detection, still got memory leak

parent 0f1b59b1
Pipeline #63 passed with stage
in 1 minute and 18 seconds
......@@ -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 = darrayGet(t_img->pixels, (size_t)t_idx);
if (current_pixel->visited || !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)) {
(*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);
if(current_pixel->visited || !sameColor(current_pixel, t_zone)) {
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) {
Zone* current_zone;
Pixel* pixel;
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);
......@@ -103,14 +114,14 @@ void chooseZoneForPixel(Image* t_img, int t_idx, darray *zones) {
* \param t_img Image à convertir en zones
* \return Pointeur vers un \ref darray de structures \ref Zone
*/
darray* imgToZones(Image* t_img) {
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
......
......@@ -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 */
......@@ -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);
}
}
\ No newline at end of file
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment