Added tolerance option and result example with -t 5
This commit is contained in:
parent
88e04466f3
commit
2633662c4b
BIN
img/asterix5p.png
Normal file
BIN
img/asterix5p.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
@ -5,19 +5,39 @@
|
|||||||
|
|
||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var uint32_t tolerance
|
||||||
|
* \brief Color tolerance
|
||||||
|
*
|
||||||
|
* Cette variable est la valeur du pourcentage de tolérance couleur lors de la
|
||||||
|
* création de nouvelles zones. Cette variable contient une valeur située entre
|
||||||
|
* 0 et 100 inclus.
|
||||||
|
*/
|
||||||
|
int32_t tolerance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cette fonction permet d’évaluer si le pixel passé en argument est éligible à
|
* Cette fonction permet d’évaluer si le pixel passé en argument est éligible à
|
||||||
* la zone passée également en argument.
|
* la zone passée également en argument. Si la \ref tolerance a pour valeur 0,
|
||||||
|
* alors les couleurs doivent être strictements identiques. Sinon, leur
|
||||||
|
* différence doit être inférieure à la tolérance de couleur.
|
||||||
*
|
*
|
||||||
* \param[in] t_pixel Pointeur vers le pixel dont l’éligibilité est testée
|
* \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
|
* \param[in] t_zone Zone à laquelle le pixel est éligible ou non
|
||||||
* \return Valeur booléenne, `1` si le pixel est éligible, `0` sinon
|
* \return Valeur booléenne, `1` si le pixel est éligible, `0` sinon
|
||||||
*/
|
*/
|
||||||
int32_t sameColor(Pixel *t_pixel, Zone *t_zone) {
|
int32_t sameColor(Pixel *t_pixel, Zone *t_zone) {
|
||||||
return (t_pixel->red == t_zone->red && t_pixel->green == t_zone->green &&
|
int diff_red, diff_green, diff_blue;
|
||||||
t_pixel->blue == t_zone->blue)
|
if (tolerance == 0) {
|
||||||
? 1
|
return (t_pixel->red == t_zone->red && t_pixel->green == t_zone->green &&
|
||||||
: 0;
|
t_pixel->blue == t_zone->blue)
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
diff_red = (abs((int32_t)t_zone->red - (int32_t)t_pixel->red) * 100) / 255;
|
||||||
|
diff_green =
|
||||||
|
(abs((int32_t)t_zone->green - (int32_t)t_pixel->green) * 100) / 255;
|
||||||
|
diff_blue = (abs((int32_t)t_zone->blue - (int32_t)t_pixel->blue) * 100) / 255;
|
||||||
|
return ((diff_red + diff_green + diff_blue) / 3) <= tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,14 +192,17 @@ void write_compressed_file(Image *t_img, FILE *t_output, darray *t_zones) {
|
|||||||
*
|
*
|
||||||
* \param[in] t_input_file Nom/chemin du fichier `.ppm` d'entrée
|
* \param[in] t_input_file Nom/chemin du fichier `.ppm` d'entrée
|
||||||
* \param[in] t_output_file Nom/chemin du fichier `.su` de sortie
|
* \param[in] t_output_file Nom/chemin du fichier `.su` de sortie
|
||||||
|
* \param[in] t_tolerance Pourcentage de tolérance de couleur
|
||||||
*/
|
*/
|
||||||
void compress(const char *t_input_file, const char *t_output_file) {
|
void compress(const char *t_input_file, const char *t_output_file,
|
||||||
|
int32_t t_tolerance) {
|
||||||
Image *img;
|
Image *img;
|
||||||
darray *zones;
|
darray *zones;
|
||||||
FILE *output_file;
|
FILE *output_file;
|
||||||
if (!t_output_file) {
|
if (!t_output_file) {
|
||||||
t_output_file = DEFAULT_COMPRESSED_NAME;
|
t_output_file = DEFAULT_COMPRESSED_NAME;
|
||||||
}
|
}
|
||||||
|
tolerance = t_tolerance;
|
||||||
img = newImage();
|
img = newImage();
|
||||||
imageLoadPPM(t_input_file, img);
|
imageLoadPPM(t_input_file, img);
|
||||||
output_file = get_file(t_output_file, "wb");
|
output_file = get_file(t_output_file, "wb");
|
||||||
|
@ -23,6 +23,7 @@ void write_segments(FILE *t_output, darray *t_segments);
|
|||||||
/// Écrit les données compressées dans le fichier de sortie
|
/// Écrit les données compressées dans le fichier de sortie
|
||||||
void write_compressed_file(Image *t_img, FILE *t_output, darray *t_zones);
|
void write_compressed_file(Image *t_img, FILE *t_output, darray *t_zones);
|
||||||
/// Compresse l'image d'entrée
|
/// Compresse l'image d'entrée
|
||||||
void compress(const char *t_input_file, const char *t_output_file);
|
void compress(const char *t_input_file, const char *t_output_file,
|
||||||
|
int32_t tolerance);
|
||||||
|
|
||||||
#endif /* SRC_COMPRESS_H_ */
|
#endif /* SRC_COMPRESS_H_ */
|
||||||
|
36
src/main.c
36
src/main.c
@ -24,18 +24,21 @@
|
|||||||
*/
|
*/
|
||||||
void help(int t_exit_code) {
|
void help(int t_exit_code) {
|
||||||
puts("Usage:\n"
|
puts("Usage:\n"
|
||||||
"surfaces-unies -i path [-o path] [-options]\n\n"
|
"surfaces-unies -i path [-o path] [--options] [-t 0-100]\n\n"
|
||||||
"The default action is to compress the mandatory input image to a .su\n"
|
"The default action is to compress the mandatory input image to a .su\n"
|
||||||
"file saved in the current directory.\n"
|
"file saved in the current directory.\n"
|
||||||
"The input image MUST be saved in the ppm format.\n"
|
"The input image MUST be saved in the ppm format.\n"
|
||||||
"Options available:\n"
|
"Options available:\n"
|
||||||
"-h --help\n\tdisplay the current message\n"
|
"-h --help\n\tDisplay the current message\n"
|
||||||
"-i --input\n\tpath to the input file (MANDATORY)\n"
|
"-i --input\n\tPath to the input file (MANDATORY)\n"
|
||||||
"-o --output\n"
|
"-o --output\n"
|
||||||
"\tpath to the output file (if the file already exists, it will be\n"
|
"\tPath to the output file (if the file already exists, it will be\n"
|
||||||
"\toverwritten)\n"
|
"\toverwritten)\n"
|
||||||
"-c --compress\n\tcompress the input file\n"
|
"-t --tolerance\n"
|
||||||
"-u --uncompress\n\tuncompresses the input file to the output file.");
|
"\tColor tolerance for lossy compression. By default at 0 for lossless\n"
|
||||||
|
"\tcompression, at 100 will consider every color to be the same.\n"
|
||||||
|
"-c --compress\n\tCompress the input file\n"
|
||||||
|
"-u --uncompress\n\tUncompresses the input file to the output file.");
|
||||||
exit(t_exit_code);
|
exit(t_exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,9 +52,10 @@ void help(int t_exit_code) {
|
|||||||
* supplémentaires aux fonctions.
|
* supplémentaires aux fonctions.
|
||||||
*/
|
*/
|
||||||
struct Argres {
|
struct Argres {
|
||||||
char *input; /*!< Nom du fichier d'entrée */
|
char *input; /*!< Nom du fichier d'entrée */
|
||||||
char *output; /*!< Nom du fichier de sortie */
|
char *output; /*!< Nom du fichier de sortie */
|
||||||
char compress; /*!< Le fichier d'entrée doit-il être compressé ? */
|
char compress; /*!< Le fichier d'entrée doit-il être compressé ? */
|
||||||
|
int32_t tolerance; /*!< Tolérance en pourcentage des différences de couleur */
|
||||||
};
|
};
|
||||||
typedef struct Argres Argres;
|
typedef struct Argres Argres;
|
||||||
|
|
||||||
@ -72,6 +76,12 @@ void get_args(Argres *t_args, const int *const t_c) {
|
|||||||
case 'o': (*t_args).output = optarg; break;
|
case 'o': (*t_args).output = optarg; break;
|
||||||
case 'c': (*t_args).compress = 1; break;
|
case 'c': (*t_args).compress = 1; break;
|
||||||
case 'u': (*t_args).compress = 0; break;
|
case 'u': (*t_args).compress = 0; break;
|
||||||
|
case 't':
|
||||||
|
(*t_args).tolerance = atoi(optarg);
|
||||||
|
if(t_args->tolerance < 0 || t_args->tolerance > 100) {
|
||||||
|
help(ARGERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
default: help(ARGERROR);
|
default: help(ARGERROR);
|
||||||
}
|
}
|
||||||
@ -95,16 +105,18 @@ Argres process_args(const int t_argc, char *t_argv[]) {
|
|||||||
res.input = NULL;
|
res.input = NULL;
|
||||||
res.compress = 1;
|
res.compress = 1;
|
||||||
res.output = NULL;
|
res.output = NULL;
|
||||||
|
res.tolerance = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{"input", required_argument, NULL, 'i'},
|
{"input", required_argument, NULL, 'i'},
|
||||||
{"output", required_argument, NULL, 'o'},
|
{"output", required_argument, NULL, 'o'},
|
||||||
|
{"tolerance", required_argument, NULL, 't'},
|
||||||
{"compress", no_argument, NULL, 'c'},
|
{"compress", no_argument, NULL, 'c'},
|
||||||
{"uncompress", no_argument, NULL, 'u'},
|
{"uncompress", no_argument, NULL, 'u'},
|
||||||
{NULL, 0, NULL, 0}};
|
{NULL, 0, NULL, 0}};
|
||||||
int c = getopt_long(t_argc, t_argv, "hi:o:cu", long_options, &option_index);
|
int c = getopt_long(t_argc, t_argv, "hi:o:t:cu", long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
get_args(&res, &c);
|
get_args(&res, &c);
|
||||||
@ -129,8 +141,8 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stderr, "ERROR: no input file.");
|
fprintf(stderr, "ERROR: no input file.");
|
||||||
help(ARGERROR);
|
help(ARGERROR);
|
||||||
}
|
}
|
||||||
if(argresults.compress) {
|
if (argresults.compress) {
|
||||||
compress(argresults.input, argresults.output);
|
compress(argresults.input, argresults.output, argresults.tolerance);
|
||||||
} else {
|
} else {
|
||||||
uncompress(argresults.input, argresults.output);
|
uncompress(argresults.input, argresults.output);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user