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,20 +5,40 @@
|
||||
|
||||
#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 à
|
||||
* 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_zone Zone à laquelle le pixel est éligible ou non
|
||||
* \return Valeur booléenne, `1` si le pixel est éligible, `0` sinon
|
||||
*/
|
||||
int32_t sameColor(Pixel *t_pixel, Zone *t_zone) {
|
||||
int diff_red, diff_green, diff_blue;
|
||||
if (tolerance == 0) {
|
||||
return (t_pixel->red == t_zone->red && t_pixel->green == t_zone->green &&
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute un pixel à la zone passé en argument si le pixel à l’index passé en
|
||||
@ -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_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;
|
||||
darray *zones;
|
||||
FILE *output_file;
|
||||
if (!t_output_file) {
|
||||
t_output_file = DEFAULT_COMPRESSED_NAME;
|
||||
}
|
||||
tolerance = t_tolerance;
|
||||
img = newImage();
|
||||
imageLoadPPM(t_input_file, img);
|
||||
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
|
||||
void write_compressed_file(Image *t_img, FILE *t_output, darray *t_zones);
|
||||
/// 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_ */
|
||||
|
28
src/main.c
28
src/main.c
@ -24,18 +24,21 @@
|
||||
*/
|
||||
void help(int t_exit_code) {
|
||||
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"
|
||||
"file saved in the current directory.\n"
|
||||
"The input image MUST be saved in the ppm format.\n"
|
||||
"Options available:\n"
|
||||
"-h --help\n\tdisplay the current message\n"
|
||||
"-i --input\n\tpath to the input file (MANDATORY)\n"
|
||||
"-h --help\n\tDisplay the current message\n"
|
||||
"-i --input\n\tPath to the input file (MANDATORY)\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"
|
||||
"-c --compress\n\tcompress the input file\n"
|
||||
"-u --uncompress\n\tuncompresses the input file to the output file.");
|
||||
"-t --tolerance\n"
|
||||
"\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);
|
||||
}
|
||||
|
||||
@ -52,6 +55,7 @@ struct Argres {
|
||||
char *input; /*!< Nom du fichier d'entrée */
|
||||
char *output; /*!< Nom du fichier de sortie */
|
||||
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;
|
||||
|
||||
@ -72,6 +76,12 @@ void get_args(Argres *t_args, const int *const t_c) {
|
||||
case 'o': (*t_args).output = optarg; break;
|
||||
case 'c': (*t_args).compress = 1; 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 '?':
|
||||
default: help(ARGERROR);
|
||||
}
|
||||
@ -95,16 +105,18 @@ Argres process_args(const int t_argc, char *t_argv[]) {
|
||||
res.input = NULL;
|
||||
res.compress = 1;
|
||||
res.output = NULL;
|
||||
res.tolerance = 0;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"input", required_argument, NULL, 'i'},
|
||||
{"output", required_argument, NULL, 'o'},
|
||||
{"tolerance", required_argument, NULL, 't'},
|
||||
{"compress", no_argument, NULL, 'c'},
|
||||
{"uncompress", no_argument, NULL, 'u'},
|
||||
{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)
|
||||
break;
|
||||
get_args(&res, &c);
|
||||
@ -130,7 +142,7 @@ int main(int argc, char **argv) {
|
||||
help(ARGERROR);
|
||||
}
|
||||
if (argresults.compress) {
|
||||
compress(argresults.input, argresults.output);
|
||||
compress(argresults.input, argresults.output, argresults.tolerance);
|
||||
} else {
|
||||
uncompress(argresults.input, argresults.output);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user