From a27a31a0aebd8df097fc0d92c1cc3baedc97118c Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Sat, 24 Nov 2018 21:33:47 +0100 Subject: [PATCH] I think I fixed zones detection, still got memory leak --- .gitignore | 2 ++ src/compress.c | 83 ++++++++++++++++++++++++------------------------ src/compress.h | 4 +-- src/darray.c | 11 ++++--- src/errorcodes.h | 1 + src/main.c | 13 ++++---- src/ppm.c | 3 +- src/utilities.c | 46 ++++----------------------- src/utilities.h | 22 +++---------- 9 files changed, 74 insertions(+), 111 deletions(-) diff --git a/.gitignore b/.gitignore index 0314b4d..91c798f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ build debug !.gitignore *.out +\.idea/ +cmake-build-debug/ diff --git a/src/compress.c b/src/compress.c index b442d49..fc4d111 100644 --- a/src/compress.c +++ b/src/compress.c @@ -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); - if(!sameColor(current_pixel, t_zone)) { - break; - } - (*current_pixel).visited = true; + current_pixel = darrayGet(t_img->pixels, (size_t)t_idx); + if (current_pixel->visited || !sameColor(current_pixel, t_zone)) { + return; } - 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)) { + (*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 (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 = 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); } diff --git a/src/compress.h b/src/compress.h index 465e133..b6113e8 100644 --- a/src/compress.h +++ b/src/compress.h @@ -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 diff --git a/src/darray.c b/src/darray.c index 5cf2cc3..cd8b77a 100644 --- a/src/darray.c +++ b/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; diff --git a/src/errorcodes.h b/src/errorcodes.h index 205ac28..1c8c575 100644 --- a/src/errorcodes.h +++ b/src/errorcodes.h @@ -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 */ diff --git a/src/main.c b/src/main.c index c41c88b..3da6ffc 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,7 @@ * des fonctions cœures du programme. */ -#include "common.h" +#include "compress.h" #include #include @@ -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'}, diff --git a/src/ppm.c b/src/ppm.c index 54119ba..57937fa 100644 --- a/src/ppm.c +++ b/src/ppm.c @@ -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; } diff --git a/src/utilities.c b/src/utilities.c index 8e10871..0d48603 100644 --- a/src/utilities.c +++ b/src/utilities.c @@ -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 diff --git a/src/utilities.h b/src/utilities.h index 680bad0..fdc7381 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -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 */