diff --git a/src/fileformats.c b/src/fileformats.c index 981837fa..6ca3bdca 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -4065,97 +4065,97 @@ void Test_GIF(T_IO_Context * context, FILE * file) // -- Lire un fichier au format GIF ----------------------------------------- -/// @todo avoid using global variables, define a "GIF context" instead -// Définition de quelques variables globales au chargement du GIF87a -word GIF_nb_bits; // Nb de bits composants un code complet -word GIF_remainder_bits; // Nb de bits encore dispos dans GIF_last_byte -byte GIF_remainder_byte; // Nb d'octets avant le prochain bloc de Raster Data -word GIF_current_code; // Code traité (qui vient d'être lu en général) -byte GIF_last_byte; // Octet de lecture des bits -word GIF_pos_X; // Coordonnées d'affichage de l'image -word GIF_pos_Y; -word GIF_interlaced; // L'image est entrelacée -word GIF_finished_interlaced_image; // L'image entrelacée est finie de charger -word GIF_pass; // index de passe de l'image entrelacée -FILE *GIF_file; // L'handle du fichier +typedef struct { + word nb_bits; // Nb de bits composants un code complet + word remainder_bits; // Nb de bits encore dispos dans GIF_last_byte + byte remainder_byte; // Nb d'octets avant le prochain bloc de Raster Data + word current_code; // Code traité (qui vient d'être lu en général) + byte last_byte; // Octet de lecture des bits + word pos_X; // Coordonnées d'affichage de l'image + word pos_Y; + word interlaced; // L'image est entrelacée + word finished_interlaced_image; // L'image entrelacée est finie de charger + word pass; // index de passe de l'image entrelacée + word stop; +} T_GIF_context; -/// Reads the next code (GIF_nb_bits bits) -static word GIF_get_next_code(void) + +/// Reads the next code (GIF.nb_bits bits) +static word GIF_get_next_code(FILE * GIF_file, T_GIF_context * gif) { - word nb_bits_to_process=GIF_nb_bits; - word nb_bits_processed =0; + word nb_bits_to_process = gif->nb_bits; + word nb_bits_processed = 0; word current_nb_bits; - GIF_current_code=0; + gif->current_code = 0; while (nb_bits_to_process) { - if (GIF_remainder_bits==0) // Il ne reste plus de bits... + if (gif->remainder_bits==0) // Il ne reste plus de bits... { // Lire l'octet suivant: // Si on a atteint la fin du bloc de Raster Data - if (GIF_remainder_byte==0) + if (gif->remainder_byte==0) // Lire l'octet nous donnant la taille du bloc de Raster Data suivant - if(Read_byte(GIF_file, &GIF_remainder_byte)!=1) + if(Read_byte(GIF_file, &gif->remainder_byte)!=1) File_error=2; - if(Read_byte(GIF_file,&GIF_last_byte)!=1) + if(Read_byte(GIF_file,&gif->last_byte)!=1) File_error = 2; - GIF_remainder_byte--; - GIF_remainder_bits=8; + gif->remainder_byte--; + gif->remainder_bits=8; } - current_nb_bits=(nb_bits_to_process<=GIF_remainder_bits)?nb_bits_to_process:GIF_remainder_bits; + current_nb_bits=(nb_bits_to_process<=gif->remainder_bits)?nb_bits_to_process:gif->remainder_bits; - GIF_current_code|=(GIF_last_byte & ((1<>=current_nb_bits; - nb_bits_processed +=current_nb_bits; - nb_bits_to_process-=current_nb_bits; - GIF_remainder_bits -=current_nb_bits; + gif->current_code |= (gif->last_byte & ((1<last_byte >>= current_nb_bits; + nb_bits_processed += current_nb_bits; + nb_bits_to_process -= current_nb_bits; + gif->remainder_bits -= current_nb_bits; } - return GIF_current_code; + return gif->current_code; } /// Put a new pixel -static void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, int is_transparent, byte color) +static void GIF_new_pixel(T_IO_Context * context, T_GIF_context * gif, T_GIF_IDB *idb, int is_transparent, byte color) { if (!is_transparent || color!=context->Transparent_color) - Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); + Set_pixel(context, idb->Pos_X+gif->pos_X, idb->Pos_Y+gif->pos_Y,color); - GIF_pos_X++; + gif->pos_X++; - if (GIF_pos_X>=idb->Image_width) + if (gif->pos_X >= idb->Image_width) { - GIF_pos_X=0; + gif->pos_X=0; - if (!GIF_interlaced) - GIF_pos_Y++; + if (!gif->interlaced) + gif->pos_Y++; else { - switch (GIF_pass) + switch (gif->pass) { - case 0 : GIF_pos_Y+=8; + case 0 : + case 1 : gif->pos_Y+=8; break; - case 1 : GIF_pos_Y+=8; + case 2 : gif->pos_Y+=4; break; - case 2 : GIF_pos_Y+=4; - break; - default: GIF_pos_Y+=2; + default: gif->pos_Y+=2; } - if (GIF_pos_Y>=idb->Image_height) + if (gif->pos_Y >= idb->Image_height) { - switch(++GIF_pass) + switch(++(gif->pass)) { - case 1 : GIF_pos_Y=4; + case 1 : gif->pos_Y=4; break; - case 2 : GIF_pos_Y=2; + case 2 : gif->pos_Y=2; break; - case 3 : GIF_pos_Y=1; + case 3 : gif->pos_Y=1; break; - case 4 : GIF_finished_interlaced_image=1; + case 4 : gif->finished_interlaced_image=1; } } } @@ -4166,6 +4166,7 @@ static void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, int is_transpa /// Load GIF file void Load_GIF(T_IO_Context * context) { + FILE *GIF_file; int image_mode = -1; char signature[6]; @@ -4176,6 +4177,7 @@ void Load_GIF(T_IO_Context * context) word alphabet_max; // Nombre d'entrées possibles dans l'alphabet word alphabet_stack_pos; // Position dans la pile de décodage d'un chaîne + T_GIF_context GIF; T_GIF_LSDB LSDB; T_GIF_IDB IDB; T_GIF_GCE GCE; @@ -4314,6 +4316,7 @@ void Load_GIF(T_IO_Context * context) last_delay = GCE.Delay_time; context->Transparent_color= GCE.Transparent_color; is_transparent = GCE.Packed_fields & 1; + GFX2_Log(GFX2_DEBUG, "GIF Graphics Control Extension : transp=%d (color #%u) delay=%ums disposal_method=%d\n", is_transparent, GCE.Transparent_color, 10*GCE.Delay_time, disposal_method); if (number_LID == 0) context->Background_transparent = is_transparent; is_transparent &= is_looping; @@ -4564,67 +4567,67 @@ void Load_GIF(T_IO_Context * context) value_eof =(1<value_clr) + while (GIF.current_code>value_clr) { - alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF_current_code]; - GIF_current_code=alphabet_prefix[GIF_current_code]; + alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF.current_code]; + GIF.current_code=alphabet_prefix[GIF.current_code]; } - special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; + special_case=alphabet_stack[alphabet_stack_pos++]=GIF.current_code; do - GIF_new_pixel(context, &IDB, is_transparent, alphabet_stack[--alphabet_stack_pos]); + GIF_new_pixel(context, &GIF, &IDB, is_transparent, alphabet_stack[--alphabet_stack_pos]); while (alphabet_stack_pos!=0); alphabet_prefix[alphabet_free ]=old_code; - alphabet_suffix[alphabet_free++]=GIF_current_code; + alphabet_suffix[alphabet_free++]=GIF.current_code; old_code=byte_read; if (alphabet_free>alphabet_max) { - if (GIF_nb_bits<12) - alphabet_max =((1 << (++GIF_nb_bits))-1); + if (GIF.nb_bits<12) + alphabet_max =((1 << (++GIF.nb_bits))-1); } } else // Code Clear rencontré { - GIF_nb_bits =initial_nb_bits + 1; - alphabet_max =((1 << GIF_nb_bits)-1); - alphabet_free =(1<=0) if ( /* (GIF_pos_X!=0) || */ - ( ( (!GIF_interlaced) && (GIF_pos_Y!=IDB.Image_height) && (GIF_pos_X!=0)) || - ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) + ( ( (!GIF.interlaced) && (GIF.pos_Y!=IDB.Image_height) && (GIF.pos_X!=0)) || + ( (GIF.interlaced) && (!GIF.finished_interlaced_image) ) ) ) File_error=2; @@ -4695,80 +4698,81 @@ void Load_GIF(T_IO_Context * context) // -- Sauver un fichier au format GIF --------------------------------------- - int GIF_stop; // "On peut arrêter la sauvegarde du fichier" - byte GIF_buffer[256]; // buffer d'écriture de bloc de données compilées +/// Flush ::GIF_buffer +static void GIF_empty_buffer(FILE * file, T_GIF_context *gif, byte * GIF_buffer) +{ + word index; - /// Flush ::GIF_buffer - static void GIF_empty_buffer(void) + if (gif->remainder_byte) { - word index; + GIF_buffer[0] = gif->remainder_byte; - if (GIF_remainder_byte) + for (index = 0; index <= gif->remainder_byte; index++) + Write_one_byte(file, GIF_buffer[index]); + + gif->remainder_byte=0; + } +} + +/// Write a code (GIF_nb_bits bits) +static void GIF_set_code(FILE * GIF_file, T_GIF_context * gif, byte * GIF_buffer, word Code) +{ + word nb_bits_to_process = gif->nb_bits; + word nb_bits_processed =0; + word current_nb_bits; + + while (nb_bits_to_process) + { + current_nb_bits = (nb_bits_to_process <= (8-gif->remainder_bits)) ? + nb_bits_to_process: (8-gif->remainder_bits); + + gif->last_byte |= (Code & ((1<remainder_bits; + Code>>=current_nb_bits; + gif->remainder_bits +=current_nb_bits; + nb_bits_processed +=current_nb_bits; + nb_bits_to_process-=current_nb_bits; + + if (gif->remainder_bits==8) // Il ne reste plus de bits à coder sur l'octet courant { - GIF_buffer[0]=GIF_remainder_byte; + // Ecrire l'octet à balancer: + GIF_buffer[++(gif->remainder_byte)] = gif->last_byte; - for (index=0;index<=GIF_remainder_byte;index++) - Write_one_byte(GIF_file,GIF_buffer[index]); + // Si on a atteint la fin du bloc de Raster Data + if (gif->remainder_byte==255) + // On doit vider le buffer qui est maintenant plein + GIF_empty_buffer(GIF_file, gif, GIF_buffer); - GIF_remainder_byte=0; + gif->last_byte=0; + gif->remainder_bits=0; } } +} - /// Write a code (GIF_nb_bits bits) - static void GIF_set_code(word Code) + +/// Read the next pixel +static byte GIF_next_pixel(T_IO_Context *context, T_GIF_context *gif, T_GIF_IDB *idb) +{ + byte temp; + + temp = Get_pixel(context, gif->pos_X, gif->pos_Y); + + if (++gif->pos_X >= (idb->Image_width + idb->Pos_X)) { - word nb_bits_to_process=GIF_nb_bits; - word nb_bits_processed =0; - word current_nb_bits; - - while (nb_bits_to_process) - { - current_nb_bits=(nb_bits_to_process<=(8-GIF_remainder_bits))?nb_bits_to_process:(8-GIF_remainder_bits); - - GIF_last_byte|=(Code & ((1<>=current_nb_bits; - GIF_remainder_bits +=current_nb_bits; - nb_bits_processed +=current_nb_bits; - nb_bits_to_process-=current_nb_bits; - - if (GIF_remainder_bits==8) // Il ne reste plus de bits à coder sur l'octet courant - { - // Ecrire l'octet à balancer: - GIF_buffer[++GIF_remainder_byte]=GIF_last_byte; - - // Si on a atteint la fin du bloc de Raster Data - if (GIF_remainder_byte==255) - // On doit vider le buffer qui est maintenant plein - GIF_empty_buffer(); - - GIF_last_byte=0; - GIF_remainder_bits=0; - } - } + gif->pos_X = idb->Pos_X; + if (++gif->pos_Y >= (idb->Image_height + idb->Pos_Y)) + gif->stop = 1; } - - /// Read the next pixel - static byte GIF_next_pixel(T_IO_Context *context, T_GIF_IDB *idb) - { - byte temp; - - temp=Get_pixel(context, GIF_pos_X,GIF_pos_Y); - - if (++GIF_pos_X >= (idb->Image_width + idb->Pos_X)) - { - GIF_pos_X = idb->Pos_X; - if (++GIF_pos_Y >= (idb->Image_height + idb->Pos_Y)) - GIF_stop=1; - } - - return temp; - } + return temp; +} /// Save a GIF file void Save_GIF(T_IO_Context * context) { + FILE * GIF_file; + byte GIF_buffer[256]; // buffer d'écriture de bloc de données compilées + word * alphabet_prefix; // Table des préfixes des codes word * alphabet_suffix; // Table des suffixes des codes word * alphabet_daughter; // Table des chaînes filles (plus longues) @@ -4778,6 +4782,7 @@ void Save_GIF(T_IO_Context * context) word start; // Code précédent (sert au linkage des chaînes) int descend; // Booléen "On vient de descendre" + T_GIF_context GIF; T_GIF_LSDB LSDB; T_GIF_IDB IDB; @@ -5017,17 +5022,17 @@ void Save_GIF(T_IO_Context * context) // find bounding box of changes for Animated GIFs min_X = min_Y = 0xffff; max_X = max_Y = 0; - for(GIF_pos_Y = 0; GIF_pos_Y < context->Height; GIF_pos_Y++) { - for(GIF_pos_X = 0; GIF_pos_X < context->Width; GIF_pos_X++) { - if (GIF_pos_X >= min_X && GIF_pos_X <= max_X && GIF_pos_Y >= min_Y && GIF_pos_Y <= max_Y) + for(GIF.pos_Y = 0; GIF.pos_Y < context->Height; GIF.pos_Y++) { + for(GIF.pos_X = 0; GIF.pos_X < context->Width; GIF.pos_X++) { + if (GIF.pos_X >= min_X && GIF.pos_X <= max_X && GIF.pos_Y >= min_Y && GIF.pos_Y <= max_Y) continue; // already in the box if(disposal_method == DISPOSAL_METHOD_DO_NOT_DISPOSE) { // if that pixel has same value in previous layer, no need to save it Set_saving_layer(context, current_layer - 1); - temp = Get_pixel(context, GIF_pos_X, GIF_pos_Y); + temp = Get_pixel(context, GIF.pos_X, GIF.pos_Y); Set_saving_layer(context, current_layer); - if(temp == Get_pixel(context, GIF_pos_X, GIF_pos_Y)) + if(temp == Get_pixel(context, GIF.pos_X, GIF.pos_Y)) continue; } if (disposal_method == DISPOSAL_METHOD_RESTORE_BGCOLOR @@ -5035,13 +5040,13 @@ void Save_GIF(T_IO_Context * context) || Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // if that pixel is Backcol, no need to save it - if (LSDB.Backcol == Get_pixel(context, GIF_pos_X, GIF_pos_Y)) + if (LSDB.Backcol == Get_pixel(context, GIF.pos_X, GIF.pos_Y)) continue; } - if(GIF_pos_X < min_X) min_X = GIF_pos_X; - if(GIF_pos_X > max_X) max_X = GIF_pos_X; - if(GIF_pos_Y < min_Y) min_Y = GIF_pos_Y; - if(GIF_pos_Y > max_Y) max_Y = GIF_pos_Y; + if(GIF.pos_X < min_X) min_X = GIF.pos_X; + if(GIF.pos_X > max_X) max_X = GIF.pos_X; + if(GIF.pos_Y < min_Y) min_Y = GIF.pos_Y; + if(GIF.pos_Y > max_Y) max_Y = GIF.pos_Y; } } if((min_X <= max_X) && (min_Y <= max_Y)) @@ -5061,9 +5066,9 @@ void Save_GIF(T_IO_Context * context) // look for the maximum pixel value // to decide how many bit per pixel are needed. - for(GIF_pos_Y = IDB.Pos_Y; GIF_pos_Y < IDB.Image_height + IDB.Pos_Y; GIF_pos_Y++) { - for(GIF_pos_X = IDB.Pos_X; GIF_pos_X < IDB.Image_width + IDB.Pos_X; GIF_pos_X++) { - temp=Get_pixel(context, GIF_pos_X, GIF_pos_Y); + for(GIF.pos_Y = IDB.Pos_Y; GIF.pos_Y < IDB.Image_height + IDB.Pos_Y; GIF.pos_Y++) { + for(GIF.pos_X = IDB.Pos_X; GIF.pos_X < IDB.Image_width + IDB.Pos_X; GIF.pos_X++) { + temp=Get_pixel(context, GIF.pos_X, GIF.pos_Y); if(temp > max) max = temp; } } @@ -5092,22 +5097,22 @@ void Save_GIF(T_IO_Context * context) // Le block indicateur d'IDB et l'IDB ont étés correctements // écrits. - GIF_pos_X=IDB.Pos_X; - GIF_pos_Y=IDB.Pos_Y; - GIF_last_byte=0; - GIF_remainder_bits=0; - GIF_remainder_byte=0; + GIF.pos_X=IDB.Pos_X; + GIF.pos_Y=IDB.Pos_Y; + GIF.last_byte=0; + GIF.remainder_bits=0; + GIF.remainder_byte=0; #define GIF_INVALID_CODE (65535) index=GIF_INVALID_CODE; File_error=0; - GIF_stop=0; + GIF.stop=0; // Réintialisation de la table: alphabet_free=clear + 2; // 258 for 8bpp - GIF_nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8 bpp + GIF.nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8 bpp alphabet_max =clear+clear-1; // 511 for 8bpp - GIF_set_code(clear); //256 for 8bpp + GIF_set_code(GIF_file, &GIF, GIF_buffer, clear); //256 for 8bpp for (start=0;start<4096;start++) { alphabet_daughter[start] = GIF_INVALID_CODE; @@ -5116,12 +5121,12 @@ void Save_GIF(T_IO_Context * context) ////////////////////////////////////////////// COMPRESSION LZW // - start=current_string=GIF_next_pixel(context, &IDB); + start=current_string=GIF_next_pixel(context, &GIF, &IDB); descend=1; - while ((!GIF_stop) && (!File_error)) + while ((!GIF.stop) && (!File_error)) { - current_char=GIF_next_pixel(context, &IDB); + current_char=GIF_next_pixel(context, &GIF, &IDB); // look for (current_string,current_char) in the alphabet while ( (index != GIF_INVALID_CODE) && @@ -5147,7 +5152,7 @@ void Save_GIF(T_IO_Context * context) { // (current_string,current_char) was not found in the alphabet // so write current_string to the Gif stream - GIF_set_code(current_string); + GIF_set_code(GIF_file, &GIF, GIF_buffer, current_string); if(alphabet_free < 4096) { // link current_string and the new one @@ -5165,9 +5170,9 @@ void Save_GIF(T_IO_Context * context) if (alphabet_free >= 4096) { // clear alphabet - GIF_set_code(clear); // 256 for 8bpp + GIF_set_code(GIF_file, &GIF, GIF_buffer, clear); // 256 for 8bpp alphabet_free=clear+2; // 258 for 8bpp - GIF_nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8bpp + GIF.nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8bpp alphabet_max =clear+clear-1; // 511 for 8bpp for (start=0;start<4096;start++) { @@ -5179,8 +5184,8 @@ void Save_GIF(T_IO_Context * context) { // On augmente le nb de bits - GIF_nb_bits++; - alphabet_max=(1<