1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 
21 ///@file giformat.c
22 /// Saving and loading GIF
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include "struct.h"
27 #include "global.h"
28 #include "oldies.h"
29 #include "io.h"
30 #include "loadsave.h"
31 #include "loadsavefuncs.h"
32 #include "gfx2mem.h"
33 #include "gfx2log.h"
34 
35 #ifndef MIN
36 #define MIN(a,b) ((a)<(b)?(a):(b))
37 #endif
38 #ifndef MAX
39 #define MAX(a,b) ((a)>(b)?(a):(b))
40 #endif
41 
42 /**
43  * @defgroup GIF GIF format
44  * @ingroup loadsaveformats
45  * Graphics Interchange Format
46  *
47  * The GIF format uses LZW compression and stores indexed color pictures
48  * up to 256 colors. It has the ability to store several pictures in the same
49  * file : GrafX2 takes advantage of this feature for storing layered images
50  * and animations.
51  *
52  * GrafX2 implements GIF89a :
53  * https://www.w3.org/Graphics/GIF/spec-gif89a.txt
54  *
55  * @{
56  */
57 
58 /// Logical Screen Descriptor Block
59 typedef struct
60 {
61   word Width;   ///< Width of the complete image area
62   word Height;  ///< Height of the complete image area
63   byte Resol;   ///< Informations about the resolution (and other)
64   byte Backcol; ///< Proposed background color
65   byte Aspect;  ///< Informations about aspect ratio. Ratio = (Aspect + 15) / 64
66 } T_GIF_LSDB;
67 
68 /// Image Descriptor Block
69 typedef struct
70 {
71   word Pos_X;         ///< X offset where the image should be pasted
72   word Pos_Y;         ///< Y offset where the image should be pasted
73   word Image_width;   ///< Width of image
74   word Image_height;  ///< Height of image
75   byte Indicator;     ///< Misc image information
76   byte Nb_bits_pixel; ///< Nb de bits par pixel
77 } T_GIF_IDB;
78 
79 /// Graphic Control Extension
80 typedef struct
81 {
82   byte Block_identifier;  ///< 0x21
83   byte Function;          ///< 0xF9
84   byte Block_size;        ///< 4
85   byte Packed_fields;     ///< 11100000 : Reserved
86                           ///< 00011100 : Disposal method
87                           ///< 00000010 : User input flag
88                           ///< 00000001 : Transparent flag
89   word Delay_time;        ///< Time for this frame to stay displayed
90   byte Transparent_color; ///< Which color index acts as transparent
91   word Block_terminator;  ///< 0x00
92 } T_GIF_GCE;
93 
94 enum DISPOSAL_METHOD
95 {
96   DISPOSAL_METHOD_UNDEFINED = 0,
97   DISPOSAL_METHOD_DO_NOT_DISPOSE = 1,
98   DISPOSAL_METHOD_RESTORE_BGCOLOR = 2,
99   DISPOSAL_METHOD_RESTORE_PREVIOUS = 3,
100 };
101 
102 
103 /// Test if a file is GIF format
Test_GIF(T_IO_Context * context,FILE * file)104 void Test_GIF(T_IO_Context * context, FILE * file)
105 {
106   char signature[6];
107 
108   (void)context;
109   File_error=1;
110 
111   if (Read_bytes(file,signature,6))
112   {
113     /// checks if the signature (6 first bytes) is either GIF87a or GIF89a
114     if ((!memcmp(signature,"GIF87a",6))||(!memcmp(signature,"GIF89a",6)))
115       File_error=0;
116   }
117 }
118 
119 
120 // -- Lire un fichier au format GIF -----------------------------------------
121 
122 typedef struct {
123   word nb_bits;        ///< bits for a code
124   word remainder_bits; ///< available bits in @ref last_byte field
125   byte remainder_byte; ///< Remaining bytes in current block
126   word current_code;   ///< current code (generally the one just read)
127   byte last_byte;      ///< buffer byte for reading bits for codes
128   word pos_X;          ///< Current coordinates
129   word pos_Y;
130   word interlaced;     ///< interlaced flag
131   word pass;           ///< current pass in interlaced decoding
132   word stop;           ///< Stop flag (end of picture)
133 } T_GIF_context;
134 
135 
136 /// Reads the next code (GIF.nb_bits bits)
GIF_get_next_code(FILE * GIF_file,T_GIF_context * gif)137 static word GIF_get_next_code(FILE * GIF_file, T_GIF_context * gif)
138 {
139   word nb_bits_to_process = gif->nb_bits;
140   word nb_bits_processed = 0;
141   word current_nb_bits;
142 
143   gif->current_code = 0;
144 
145   while (nb_bits_to_process)
146   {
147     if (gif->remainder_bits == 0) // Il ne reste plus de bits...
148     {
149       // Lire l'octet suivant:
150 
151       // Si on a atteint la fin du bloc de Raster Data
152       if (gif->remainder_byte == 0)
153       {
154         // Lire l'octet nous donnant la taille du bloc de Raster Data suivant
155         if(Read_byte(GIF_file, &gif->remainder_byte)!=1)
156         {
157           File_error=2;
158           return 0;
159         }
160         if (gif->remainder_byte == 0) // still nothing ? That is the end data block
161         {
162           File_error = 2;
163           GFX2_Log(GFX2_WARNING, "GIF 0 sized data block\n");
164           return gif->current_code;
165         }
166       }
167       if(Read_byte(GIF_file,&gif->last_byte)!=1)
168       {
169         File_error = 2;
170         GFX2_Log(GFX2_ERROR, "GIF failed to load data byte\n");
171         return 0;
172       }
173       gif->remainder_byte--;
174       gif->remainder_bits=8;
175     }
176 
177     current_nb_bits=(nb_bits_to_process<=gif->remainder_bits)?nb_bits_to_process:gif->remainder_bits;
178 
179     gif->current_code |= (gif->last_byte & ((1<<current_nb_bits)-1))<<nb_bits_processed;
180     gif->last_byte >>= current_nb_bits;
181     nb_bits_processed += current_nb_bits;
182     nb_bits_to_process -= current_nb_bits;
183     gif->remainder_bits -= current_nb_bits;
184   }
185 
186   return gif->current_code;
187 }
188 
189 /// Put a new pixel
GIF_new_pixel(T_IO_Context * context,T_GIF_context * gif,T_GIF_IDB * idb,int is_transparent,byte color)190 static void GIF_new_pixel(T_IO_Context * context, T_GIF_context * gif, T_GIF_IDB *idb, int is_transparent, byte color)
191 {
192   if (!is_transparent || color!=context->Transparent_color)
193     Set_pixel(context, idb->Pos_X+gif->pos_X, idb->Pos_Y+gif->pos_Y,color);
194 
195   gif->pos_X++;
196 
197   if (gif->pos_X >= idb->Image_width)
198   {
199     gif->pos_X=0;
200 
201     if (!gif->interlaced)
202     {
203       gif->pos_Y++;
204       if (gif->pos_Y >= idb->Image_height)
205         gif->stop = 1;
206     }
207     else
208     {
209       switch (gif->pass)
210       {
211         case 0 :
212         case 1 : gif->pos_Y+=8;
213                  break;
214         case 2 : gif->pos_Y+=4;
215                  break;
216         default: gif->pos_Y+=2;
217       }
218 
219       if (gif->pos_Y >= idb->Image_height)
220       {
221         switch(++(gif->pass))
222         {
223         case 1 : gif->pos_Y=4;
224                  break;
225         case 2 : gif->pos_Y=2;
226                  break;
227         case 3 : gif->pos_Y=1;
228                  break;
229         case 4 : gif->stop = 1;
230         }
231       }
232     }
233   }
234 }
235 
236 
237 /// Load GIF file
Load_GIF(T_IO_Context * context)238 void Load_GIF(T_IO_Context * context)
239 {
240   FILE *GIF_file;
241   int image_mode = -1;
242   char signature[6];
243 
244   word * alphabet_stack;     // Pile de décodage d'une chaîne
245   word * alphabet_prefix;  // Table des préfixes des codes
246   word * alphabet_suffix;  // Table des suffixes des codes
247   word   alphabet_free;     // Position libre dans l'alphabet
248   word   alphabet_max;      // Nombre d'entrées possibles dans l'alphabet
249   word   alphabet_stack_pos; // Position dans la pile de décodage d'un chaîne
250 
251   T_GIF_context GIF;
252   T_GIF_LSDB LSDB;
253   T_GIF_IDB IDB;
254   T_GIF_GCE GCE;
255 
256   word nb_colors;       // Nombre de couleurs dans l'image
257   word color_index; // index de traitement d'une couleur
258   byte size_to_read; // Nombre de données à lire      (divers)
259   byte block_identifier;  // Code indicateur du type de bloc en cours
260   byte initial_nb_bits;   // Nb de bits au début du traitement LZW
261   word special_case=0;       // Mémoire pour le cas spécial
262   word old_code=0;       // Code précédent
263   word byte_read;         // Sauvegarde du code en cours de lecture
264   word value_clr;        // Valeur <=> Clear tables
265   word value_eof;        // Valeur <=> End d'image
266   long file_size;
267   int number_LID; // Nombre d'images trouvées dans le fichier
268   int current_layer = 0;
269   int last_delay = 0;
270   byte is_transparent = 0;
271   byte is_looping=0;
272   enum PIXEL_RATIO ratio;
273   byte disposal_method = DISPOSAL_METHOD_RESTORE_BGCOLOR;
274 
275   byte previous_disposal_method = DISPOSAL_METHOD_RESTORE_BGCOLOR;
276   word previous_width=0;
277   word previous_height=0;
278   word previous_pos_x=0;
279   word previous_pos_y=0;
280 
281   /////////////////////////////////////////////////// FIN DES DECLARATIONS //
282 
283 
284   number_LID=0;
285 
286   if ((GIF_file=Open_file_read(context)))
287   {
288     file_size=File_length_file(GIF_file);
289     if ( (Read_bytes(GIF_file,signature,6)) &&
290          ( (memcmp(signature,"GIF87a",6)==0) ||
291            (memcmp(signature,"GIF89a",6)==0) ) )
292     {
293 
294       // Allocation de mémoire pour les tables & piles de traitement:
295       alphabet_stack  = (word *)GFX2_malloc(4096*sizeof(word));
296       alphabet_prefix = (word *)GFX2_malloc(4096*sizeof(word));
297       alphabet_suffix = (word *)GFX2_malloc(4096*sizeof(word));
298 
299       if (Read_word_le(GIF_file,&(LSDB.Width))
300       && Read_word_le(GIF_file,&(LSDB.Height))
301       && Read_byte(GIF_file,&(LSDB.Resol))
302       && Read_byte(GIF_file,&(LSDB.Backcol))
303       && Read_byte(GIF_file,&(LSDB.Aspect))
304         )
305       {
306         // Lecture du Logical Screen Descriptor Block réussie:
307 
308         Original_screen_X=LSDB.Width;
309         Original_screen_Y=LSDB.Height;
310 
311         ratio=PIXEL_SIMPLE;          //  (49 + 15) / 64 = 1:1
312         if (LSDB.Aspect != 0) {
313           if (LSDB.Aspect < 25)      //  (17 + 15) / 64 = 1:2
314             ratio=PIXEL_TALL;
315           else if (LSDB.Aspect < 41) //  (33 + 15) / 64 = 3:4
316             ratio=PIXEL_TALL3;
317           else if (LSDB.Aspect > 82) // (113 + 15) / 64 = 2:1
318             ratio=PIXEL_WIDE;
319         }
320 
321         Pre_load(context, LSDB.Width,LSDB.Height,file_size,FORMAT_GIF,ratio,(LSDB.Resol&7)+1);
322 
323         // Palette globale dispo = (LSDB.Resol  and $80)
324         // Profondeur de couleur =((LSDB.Resol  and $70) shr 4)+1
325         // Nombre de bits/pixel  = (LSDB.Resol  and $07)+1
326         // Ordre de Classement   = (LSDB.Aspect and $80)
327 
328         nb_colors=(1 << ((LSDB.Resol & 0x07)+1));
329         if (LSDB.Resol & 0x80)
330         {
331           // Palette globale dispo:
332 
333           if (Config.Clear_palette)
334             memset(context->Palette,0,sizeof(T_Palette));
335 
336           // Load the palette
337           for(color_index=0;color_index<nb_colors;color_index++)
338           {
339             Read_byte(GIF_file,&(context->Palette[color_index].R));
340             Read_byte(GIF_file,&(context->Palette[color_index].G));
341             Read_byte(GIF_file,&(context->Palette[color_index].B));
342           }
343         }
344 
345         // On lit un indicateur de block
346         Read_byte(GIF_file,&block_identifier);
347         while (block_identifier!=0x3B && !File_error)
348         {
349           switch (block_identifier)
350           {
351             case 0x21: // Bloc d'extension
352             {
353               byte function_code;
354               // Lecture du code de fonction:
355               Read_byte(GIF_file,&function_code);
356               // Lecture de la taille du bloc:
357               Read_byte(GIF_file,&size_to_read);
358               while (size_to_read!=0 && !File_error)
359               {
360                 switch(function_code)
361                 {
362                   case 0xFE: // Comment Block Extension
363                     // On récupère le premier commentaire non-vide,
364                     // on jette les autres.
365                     if (context->Comment[0]=='\0')
366                     {
367                       int nb_char_to_keep = MIN(size_to_read, COMMENT_SIZE);
368 
369                       Read_bytes(GIF_file,context->Comment,nb_char_to_keep);
370                       context->Comment[nb_char_to_keep+1]='\0';
371                       // Si le commentaire etait trop long, on fait avance-rapide
372                       // sur la suite.
373                       if (size_to_read>nb_char_to_keep)
374                         fseek(GIF_file,size_to_read-nb_char_to_keep,SEEK_CUR);
375                     }
376                     // Lecture de la taille du bloc suivant:
377                     Read_byte(GIF_file,&size_to_read);
378                     break;
379                   case 0xF9: // Graphics Control Extension
380                     // Prévu pour la transparence
381                     if ( Read_byte(GIF_file,&(GCE.Packed_fields))
382                       && Read_word_le(GIF_file,&(GCE.Delay_time))
383                       && Read_byte(GIF_file,&(GCE.Transparent_color)))
384                     {
385                       previous_disposal_method = disposal_method;
386                       disposal_method = (GCE.Packed_fields >> 2) & 7;
387                       last_delay = GCE.Delay_time;
388                       context->Transparent_color= GCE.Transparent_color;
389                       is_transparent = GCE.Packed_fields & 1;
390                       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);
391                       if (number_LID == 0)
392                         context->Background_transparent = is_transparent;
393                       is_transparent &= is_looping;
394                     }
395                     else
396                       File_error=2;
397                     // Lecture de la taille du bloc suivant:
398                     Read_byte(GIF_file,&size_to_read);
399                     break;
400 
401                   case 0xFF: // Application Extension
402                     // Normally, always a 11-byte block
403                     if (size_to_read == 0x0B)
404                     {
405                       char aeb[0x0B];
406                       Read_bytes(GIF_file,aeb, 0x0B);
407                       GFX2_Log(GFX2_DEBUG, "GIF extension \"%.11s\"\n", aeb);
408                       if (File_error)
409                         ;
410                       else if (!memcmp(aeb,"NETSCAPE2.0",0x0B))
411                       {
412                         is_looping=1;
413                         // The well-known Netscape extension.
414                         // Load as an animation
415                         Set_image_mode(context, IMAGE_MODE_ANIMATION);
416                         // Skip sub-block
417                         do
418                         {
419                           if (! Read_byte(GIF_file,&size_to_read))
420                             File_error=1;
421                           fseek(GIF_file,size_to_read,SEEK_CUR);
422                         } while (!File_error && size_to_read!=0);
423                       }
424                       else if (!memcmp(aeb,"GFX2PATH\x00\x00\x00",0x0B))
425                       {
426                         // Original file path
427                         Read_byte(GIF_file,&size_to_read);
428                         if (!File_error && size_to_read > 0)
429                         {
430                           free(context->Original_file_directory);
431                           context->Original_file_directory = GFX2_malloc(size_to_read);
432                           Read_bytes(GIF_file, context->Original_file_directory, size_to_read);
433                           Read_byte(GIF_file, &size_to_read);
434                           if (!File_error && size_to_read > 0)
435                           {
436                             free(context->Original_file_name);
437                             context->Original_file_name = GFX2_malloc(size_to_read);
438                             Read_bytes(GIF_file, context->Original_file_name, size_to_read);
439                             Read_byte(GIF_file, &size_to_read); // Normally 0
440                           }
441                         }
442                       }
443                       else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B))
444                       {
445                         // Color animation. Similar to a CRNG chunk in IFF file format.
446                         word rate;
447                         word flags;
448                         byte col1;
449                         byte col2;
450                         //
451                         Read_byte(GIF_file,&size_to_read);
452                         for(;size_to_read>0 && !File_error;size_to_read-=6)
453                         {
454                           if ( (Read_word_be(GIF_file, &rate))
455                             && (Read_word_be(GIF_file, &flags))
456                             && (Read_byte(GIF_file, &col1))
457                             && (Read_byte(GIF_file, &col2)))
458                           {
459                             if (col1 != col2)
460                             {
461                               // Valid cycling range
462                               context->Cycle_range[context->Color_cycles].Start = MIN(col1, col2);
463                               context->Cycle_range[context->Color_cycles].End = MAX(col1, col2);
464                               context->Cycle_range[context->Color_cycles].Inverse = (flags&2)?1:0;
465                               context->Cycle_range[context->Color_cycles].Speed = (flags&1)?rate/78:0;
466 
467                               context->Color_cycles++;
468                             }
469                           }
470                           else
471                           {
472                             File_error=1;
473                           }
474                         }
475                         // Read end-of-block delimiter
476                         if (!File_error)
477                           Read_byte(GIF_file,&size_to_read);
478                         if (size_to_read!=0)
479                           File_error=1;
480                       }
481                       else if (0 == memcmp(aeb, "GFX2MODE", 8))
482                       {
483                         Read_byte(GIF_file,&size_to_read);
484                         if (size_to_read > 0)
485                         { // read the image mode. We'll set it after having loaded all layers.
486                           char * label = GFX2_malloc((size_t)size_to_read + 1);
487                           Read_bytes(GIF_file, label, size_to_read);
488                           label[size_to_read] = '\0';
489                           image_mode = Constraint_mode_from_label(label);
490                           GFX2_Log(GFX2_DEBUG, "    mode = %s (%d)\n", label, image_mode);
491                           free(label);
492                           Read_byte(GIF_file,&size_to_read);
493                           // be future proof, skip following sub-blocks :
494                           while (size_to_read!=0 && !File_error)
495                           {
496                             if (fseek(GIF_file,size_to_read,SEEK_CUR) < 0)
497                               File_error = 1;
498                             if (!Read_byte(GIF_file,&size_to_read))
499                               File_error = 1;
500                           }
501                         }
502                       }
503                       else
504                       {
505                         // Unknown extension, skip.
506                         Read_byte(GIF_file,&size_to_read);
507                         while (size_to_read!=0 && !File_error)
508                         {
509                           if (fseek(GIF_file,size_to_read,SEEK_CUR) < 0)
510                             File_error = 1;
511                           if (!Read_byte(GIF_file,&size_to_read))
512                             File_error = 1;
513                         }
514                       }
515                     }
516                     else
517                     {
518                       fseek(GIF_file,size_to_read,SEEK_CUR);
519                       // Lecture de la taille du bloc suivant:
520                       Read_byte(GIF_file,&size_to_read);
521                     }
522                     break;
523 
524                   default:
525                     // On saute le bloc:
526                     fseek(GIF_file,size_to_read,SEEK_CUR);
527                     // Lecture de la taille du bloc suivant:
528                     Read_byte(GIF_file,&size_to_read);
529                     break;
530                 }
531               }
532             }
533             break;
534             case 0x2C: // Local Image Descriptor
535             {
536               if (number_LID!=0)
537               {
538                 // This a second layer/frame, or more.
539                 // Attempt to add a layer to current image
540                 current_layer++;
541                 Set_loading_layer(context, current_layer);
542                 if (context->Type == CONTEXT_MAIN_IMAGE && Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
543                 {
544                   // Copy the content of previous layer.
545                   memcpy(
546                     Main.backups->Pages->Image[Main.current_layer].Pixels,
547                     Main.backups->Pages->Image[Main.current_layer-1].Pixels,
548                     Main.backups->Pages->Width*Main.backups->Pages->Height);
549                 }
550                 else
551                 {
552                   Fill_canvas(context, is_transparent ? context->Transparent_color : LSDB.Backcol);
553                 }
554               }
555               else
556               {
557                 // First frame/layer, fill canvas with backcolor
558                 Fill_canvas(context, is_transparent ? context->Transparent_color : LSDB.Backcol);
559               }
560               // Duration was set in the previously loaded GCE
561               Set_frame_duration(context, last_delay*10);
562               number_LID++;
563 
564               // lecture de 10 derniers octets
565               if ( Read_word_le(GIF_file,&(IDB.Pos_X))
566                 && Read_word_le(GIF_file,&(IDB.Pos_Y))
567                 && Read_word_le(GIF_file,&(IDB.Image_width))
568                 && Read_word_le(GIF_file,&(IDB.Image_height))
569                 && Read_byte(GIF_file,&(IDB.Indicator))
570                 && IDB.Image_width && IDB.Image_height)
571               {
572                 GFX2_Log(GFX2_DEBUG, "GIF Image descriptor %u Pos (%u,%u) %ux%u %s%slocal palette(%ubpp)\n",
573                          number_LID, IDB.Pos_X, IDB.Pos_Y, IDB.Image_width, IDB.Image_height,
574                          (IDB.Indicator & 0x40) ? "interlaced " : "", (IDB.Indicator & 0x80) ? "" : "no ",
575                          (IDB.Indicator & 7) + 1);
576                 // Palette locale dispo = (IDB.Indicator and $80)
577                 // Image entrelacée     = (IDB.Indicator and $40)
578                 // Ordre de classement  = (IDB.Indicator and $20)
579                 // Nombre de bits/pixel = (IDB.Indicator and $07)+1 (si palette locale dispo)
580 
581                 if (IDB.Indicator & 0x80)
582                 {
583                   // Palette locale dispo
584 
585                   if (Config.Clear_palette)
586                     memset(context->Palette,0,sizeof(T_Palette));
587 
588                   nb_colors=(1 << ((IDB.Indicator & 0x07)+1));
589                   // Load the palette
590                   for(color_index=0;color_index<nb_colors;color_index++)
591                   {
592                     Read_byte(GIF_file,&(context->Palette[color_index].R));
593                     Read_byte(GIF_file,&(context->Palette[color_index].G));
594                     Read_byte(GIF_file,&(context->Palette[color_index].B));
595                   }
596 
597                 }
598                 if (number_LID!=1)
599                 {
600                   // This a second layer/frame, or more.
601                   if (context->Type == CONTEXT_MAIN_IMAGE && Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
602                   {
603                     // Need to clear previous image to back-color.
604                     if (previous_disposal_method==DISPOSAL_METHOD_RESTORE_BGCOLOR)
605                     {
606                       int y;
607                       for (y=0; y<previous_height; y++)
608                         memset(
609                           Main.backups->Pages->Image[Main.current_layer].Pixels
610                            + (previous_pos_y+y)* Main.backups->Pages->Width+previous_pos_x,
611                           is_transparent ? context->Transparent_color : LSDB.Backcol,
612                           previous_width);
613                     }
614                   }
615                 }
616                 previous_height=IDB.Image_height;
617                 previous_width=IDB.Image_width;
618                 previous_pos_x=IDB.Pos_X;
619                 previous_pos_y=IDB.Pos_Y;
620 
621                 File_error=0;
622                 if (!Read_byte(GIF_file,&(initial_nb_bits)))
623                   File_error=1;
624 
625                 value_clr    =(1<<initial_nb_bits)+0;
626                 value_eof    =(1<<initial_nb_bits)+1;
627                 alphabet_free=(1<<initial_nb_bits)+2;
628 
629                 GIF.nb_bits  =initial_nb_bits + 1;
630                 alphabet_max      =((1 <<  GIF.nb_bits)-1);
631                 GIF.interlaced    =(IDB.Indicator & 0x40);
632                 GIF.pass         =0;
633 
634                 /*Init_lecture();*/
635 
636 
637                 GIF.stop = 0;
638 
639                 //////////////////////////////////////////// DECOMPRESSION LZW //
640 
641                 GIF.pos_X=0;
642                 GIF.pos_Y=0;
643                 alphabet_stack_pos=0;
644                 GIF.last_byte    =0;
645                 GIF.remainder_bits    =0;
646                 GIF.remainder_byte    =0;
647 
648                 while ( (GIF_get_next_code(GIF_file, &GIF)!=value_eof) && (!File_error) )
649                 {
650                   if (GIF.current_code > alphabet_free)
651                   {
652                     GFX2_Log(GFX2_INFO, "Load_GIF() Invalid code %u (should be <=%u)\n", GIF.current_code, alphabet_free);
653                     File_error=2;
654                     break;
655                   }
656                   else if (GIF.current_code != value_clr)
657                   {
658                     byte_read = GIF.current_code;
659                     if (alphabet_free == GIF.current_code)
660                     {
661                       GIF.current_code=old_code;
662                       alphabet_stack[alphabet_stack_pos++]=special_case;
663                     }
664 
665                     while (GIF.current_code > value_clr)
666                     {
667                       if (GIF.current_code >= 4096)
668                       {
669                         GFX2_Log(GFX2_ERROR, "Load_GIF() GIF.current_code = %u >= 4096\n", GIF.current_code);
670                         File_error = 2;
671                         break;
672                       }
673                       alphabet_stack[alphabet_stack_pos++] = alphabet_suffix[GIF.current_code];
674                       GIF.current_code = alphabet_prefix[GIF.current_code];
675                     }
676 
677                     special_case = alphabet_stack[alphabet_stack_pos++] = GIF.current_code;
678 
679                     do
680                       GIF_new_pixel(context, &GIF, &IDB, is_transparent, alphabet_stack[--alphabet_stack_pos]);
681                     while (alphabet_stack_pos!=0);
682 
683                     alphabet_prefix[alphabet_free  ]=old_code;
684                     alphabet_suffix[alphabet_free++]=GIF.current_code;
685                     old_code=byte_read;
686 
687                     if (alphabet_free>alphabet_max)
688                     {
689                       if (GIF.nb_bits<12)
690                         alphabet_max      =((1 << (++GIF.nb_bits))-1);
691                     }
692                   }
693                   else // Clear code
694                   {
695                     GIF.nb_bits   = initial_nb_bits + 1;
696                     alphabet_max  = ((1 <<  GIF.nb_bits)-1);
697                     alphabet_free = (1<<initial_nb_bits)+2;
698                     special_case  = GIF_get_next_code(GIF_file, &GIF);
699                     if (GIF.current_code >= value_clr)
700                     {
701                       GFX2_Log(GFX2_INFO, "Load_GIF() Invalid code %u just after clear (=%u)!\n",
702                                GIF.current_code, value_clr);
703                       File_error = 2;
704                       break;
705                     }
706                     old_code      = GIF.current_code;
707                     GIF_new_pixel(context, &GIF, &IDB, is_transparent, GIF.current_code);
708                   }
709                 }
710 
711                 if (File_error == 2 && GIF.pos_X == 0 && GIF.pos_Y == IDB.Image_height)
712                   File_error=0;
713 
714                 if (File_error >= 0 && !GIF.stop)
715                   File_error=2;
716 
717                 // No need to read more than one frame in animation preview mode
718                 if (context->Type == CONTEXT_PREVIEW && is_looping)
719                 {
720                   goto early_exit;
721                 }
722                 // Same with brush
723                 if (context->Type == CONTEXT_BRUSH && is_looping)
724                 {
725                   goto early_exit;
726                 }
727 
728               } // Le fichier contenait un IDB
729               else
730                 File_error=2;
731             }
732             default:
733             break;
734           }
735           // Lecture du code de fonction suivant:
736           if (!Read_byte(GIF_file,&block_identifier))
737             File_error=2;
738         }
739 
740         // set the mode that have been read previously.
741         if (image_mode > 0)
742           Set_image_mode(context, image_mode);
743       } // Le fichier contenait un LSDB
744       else
745         File_error=1;
746 
747       early_exit:
748 
749       // Libération de la mémoire utilisée par les tables & piles de traitement:
750       free(alphabet_suffix);
751       free(alphabet_prefix);
752       free(alphabet_stack);
753       alphabet_suffix = alphabet_prefix = alphabet_stack = NULL;
754     } // Le fichier contenait au moins la signature GIF87a ou GIF89a
755     else
756       File_error=1;
757 
758     fclose(GIF_file);
759 
760   } // Le fichier était ouvrable
761   else
762     File_error=1;
763 }
764 
765 
766 // -- Sauver un fichier au format GIF ---------------------------------------
767 
768 /// Flush the buffer
GIF_empty_buffer(FILE * file,T_GIF_context * gif,byte * GIF_buffer)769 static void GIF_empty_buffer(FILE * file, T_GIF_context *gif, byte * GIF_buffer)
770 {
771   if (gif->remainder_byte)
772   {
773     GIF_buffer[0] = gif->remainder_byte;
774 
775     if (!Write_bytes(file, GIF_buffer, (size_t)gif->remainder_byte + 1))
776       File_error = 1;
777 
778     gif->remainder_byte = 0;
779   }
780 }
781 
782 /// Write a code (GIF_nb_bits bits)
GIF_set_code(FILE * GIF_file,T_GIF_context * gif,byte * GIF_buffer,word Code)783 static void GIF_set_code(FILE * GIF_file, T_GIF_context * gif, byte * GIF_buffer, word Code)
784 {
785   word nb_bits_to_process = gif->nb_bits;
786   word nb_bits_processed  =0;
787   word current_nb_bits;
788 
789   while (nb_bits_to_process)
790   {
791     current_nb_bits = (nb_bits_to_process <= (8-gif->remainder_bits)) ?
792                           nb_bits_to_process: (8-gif->remainder_bits);
793 
794     gif->last_byte |= (Code & ((1<<current_nb_bits)-1))<<gif->remainder_bits;
795     Code>>=current_nb_bits;
796     gif->remainder_bits    +=current_nb_bits;
797     nb_bits_processed  +=current_nb_bits;
798     nb_bits_to_process-=current_nb_bits;
799 
800     if (gif->remainder_bits==8) // Il ne reste plus de bits à coder sur l'octet courant
801     {
802       // Ecrire l'octet à balancer:
803       GIF_buffer[++(gif->remainder_byte)] = gif->last_byte;
804 
805       // Si on a atteint la fin du bloc de Raster Data
806       if (gif->remainder_byte==255)
807         // On doit vider le buffer qui est maintenant plein
808         GIF_empty_buffer(GIF_file, gif, GIF_buffer);
809 
810       gif->last_byte=0;
811       gif->remainder_bits=0;
812     }
813   }
814 }
815 
816 
817 /// Read the next pixel
GIF_next_pixel(T_IO_Context * context,T_GIF_context * gif,T_GIF_IDB * idb)818 static byte GIF_next_pixel(T_IO_Context *context, T_GIF_context *gif, T_GIF_IDB *idb)
819 {
820   byte temp;
821 
822   temp = Get_pixel(context, gif->pos_X, gif->pos_Y);
823 
824   if (++gif->pos_X >= (idb->Image_width + idb->Pos_X))
825   {
826     gif->pos_X = idb->Pos_X;
827     if (++gif->pos_Y >= (idb->Image_height + idb->Pos_Y))
828       gif->stop = 1;
829   }
830 
831   return temp;
832 }
833 
834 struct gif_alphabet {
835   word prefix[4096];    // code prefix array
836   word suffix[4096];    // code suffix array
837   word daughter[4096];  // daughter strings array (greater length)
838   word sister[4096];    // sister strings array (same length)
839   word free;            // first free slot in the alphabet
840   word max;             // maximum number of entry in the alphabet
841 };
842 
843 /// Save a GIF file
Save_GIF(T_IO_Context * context)844 void Save_GIF(T_IO_Context * context)
845 {
846   FILE * GIF_file;
847   byte GIF_buffer[256];   // buffer d'écriture de bloc de données compilées
848 
849   struct gif_alphabet * alphabet;
850   word   start;            // Code précédent (sert au linkage des chaînes)
851   int    descend;          // Booléen "On vient de descendre"
852 
853   T_GIF_context GIF;
854   T_GIF_LSDB LSDB;
855   T_GIF_IDB IDB;
856 
857 
858   byte block_identifier;  // Code indicateur du type de bloc en cours
859   word current_string;   // Code de la chaîne en cours de traitement
860   byte current_char;         // Caractère à coder
861   word index;            // index de recherche de chaîne
862   int current_layer;
863 
864   word clear;   // LZW clear code
865   word eof;     // End of image code
866 
867   /////////////////////////////////////////////////// FIN DES DECLARATIONS //
868 
869   File_error=0;
870 
871   if ((GIF_file=Open_file_write(context)))
872   {
873     // On écrit la signature du fichier
874     if (Write_bytes(GIF_file,"GIF89a",6))
875     {
876       // La signature du fichier a été correctement écrite.
877 
878       // Allocation de mémoire pour les tables
879       alphabet = (struct gif_alphabet *)GFX2_malloc(sizeof(struct gif_alphabet));
880       if (alphabet == NULL)
881       {
882         File_error = 1;
883         fclose(GIF_file);
884         return;
885       }
886 
887       // On initialise le LSDB du fichier
888       if (Config.Screen_size_in_GIF && Screen_width >= context->Width && Screen_height >= context->Height)
889       {
890         // Canvas bigger than the image
891         LSDB.Width=Screen_width;
892         LSDB.Height=Screen_height;
893       }
894       else
895       {
896         LSDB.Width=context->Width;
897         LSDB.Height=context->Height;
898       }
899       LSDB.Resol  = 0xF7;  // Global palette of 256 entries, 256 color image
900       // 0xF7 = 1111 0111
901       // <Packed Fields>  =      Global Color Table Flag       1 Bit
902       //                         Color Resolution              3 Bits
903       //                         Sort Flag                     1 Bit
904       //                         Size of Global Color Table    3 Bits
905       LSDB.Backcol=context->Transparent_color;
906       switch(context->Ratio)
907       {
908         case PIXEL_TALL:
909         case PIXEL_TALL2:
910           LSDB.Aspect = 17; // 1:2 = 2:4
911           break;
912         case PIXEL_TALL3:
913           LSDB.Aspect = 33; // 3:4
914           break;
915         case PIXEL_WIDE:
916         case PIXEL_WIDE2:
917           LSDB.Aspect = 113; // 2:1 = 4:2
918           break;
919         default:
920           LSDB.Aspect = 0; // undefined, which is most frequent.
921           // 49 would be 1:1 ratio
922       }
923 
924       // On sauve le LSDB dans le fichier
925 
926       if (Write_word_le(GIF_file,LSDB.Width) &&
927           Write_word_le(GIF_file,LSDB.Height) &&
928           Write_byte(GIF_file,LSDB.Resol) &&
929           Write_byte(GIF_file,LSDB.Backcol) &&
930           Write_byte(GIF_file,LSDB.Aspect) )
931       {
932         // Le LSDB a été correctement écrit.
933         int i;
934         // On sauve la palette
935         for(i=0;i<256 && !File_error;i++)
936         {
937           if (!Write_byte(GIF_file,context->Palette[i].R)
938             ||!Write_byte(GIF_file,context->Palette[i].G)
939             ||!Write_byte(GIF_file,context->Palette[i].B))
940             File_error=1;
941         }
942         if (!File_error)
943         {
944           // La palette a été correctement écrite.
945 
946           /// - "Netscape" animation extension :
947           /// <pre>
948           ///   0x21       Extension Label
949           ///   0xFF       Application Extension Label
950           ///   0x0B       Block Size
951           ///   "NETSCAPE" Application Identifier (8 bytes)
952           ///   "2.0"      Application Authentication Code (3 bytes)
953           ///   0x03       Sub-block Data Size
954           ///   0xLL       01 to loop
955           ///   0xSSSS     (little endian) number of loops, 0 means infinite loop
956           ///   0x00 Block terminator </pre>
957           /// see http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
958           if (context->Type == CONTEXT_MAIN_IMAGE && Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
959           {
960             if (context->Nb_layers>1)
961               Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00",19);
962           }
963           else if (context->Type == CONTEXT_MAIN_IMAGE && Main.backups->Pages->Image_mode > IMAGE_MODE_ANIMATION)
964           {
965             /// - GrafX2 extension to store ::IMAGE_MODES :
966             /// <pre>
967             ///   0x21       Extension Label
968             ///   0xFF       Application Extension Label
969             ///   0x0B       Block Size
970             ///   "GFX2MODE" Application Identifier (8 bytes)
971             ///   "2.6"      Application Authentication Code (3 bytes)
972             ///   0xll       Sub-block Data Size
973             ///   string     label
974             ///   0x00 Block terminator </pre>
975             /// @see Constraint_mode_label()
976             const char * label = Constraint_mode_label(Main.backups->Pages->Image_mode);
977             if (label != NULL)
978             {
979               size_t len = strlen(label);
980               // Write extension for storing IMAGE_MODE
981               Write_byte(GIF_file,0x21);  // Extension Introducer
982               Write_byte(GIF_file,0xff);  // Extension Label
983               Write_byte(GIF_file,  11);  // Block size
984               Write_bytes(GIF_file, "GFX2MODE2.6", 11); // Application Identifier + Appl. Authentication Code
985               Write_byte(GIF_file, (byte)len);    // Block size
986               Write_bytes(GIF_file, label, len);  // Data
987               Write_byte(GIF_file, 0);    // Block terminator
988             }
989           }
990 
991           // Ecriture du commentaire
992           if (context->Comment[0])
993           {
994             Write_bytes(GIF_file,"\x21\xFE",2);
995             Write_byte(GIF_file, (byte)strlen(context->Comment));
996             Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1);
997           }
998           /// - "CRNG" Color cycing extension :
999           /// <pre>
1000           ///   0x21       Extension Label
1001           ///   0xFF       Application Extension Label
1002           ///   0x0B       Block Size
1003           ///   "CRNG\0\0\0\0" "CRNG" Application Identifier (8 bytes)
1004           ///   "1.0"      Application Authentication Code (3 bytes)
1005           ///   0xll       Sub-block Data Size (6 bytes per color cycle)
1006           ///   For each color cycle :
1007           ///     0xRRRR   (big endian) Rate
1008           ///     0xFFFF   (big endian) Flags
1009           ///     0xSS     start (lower color index)
1010           ///     0xEE     end (higher color index)
1011           ///   0x00       Block terminator </pre>
1012           if (context->Color_cycles)
1013           {
1014             int i;
1015 
1016             Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14);
1017             Write_byte(GIF_file,context->Color_cycles*6);
1018             for (i=0; i<context->Color_cycles; i++)
1019             {
1020               word flags=0;
1021               flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not
1022               flags|= context->Cycle_range[i].Inverse?2:0; // Inverted
1023 
1024               Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate
1025               Write_word_be(GIF_file,flags); // Flags
1026               Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color
1027               Write_byte(GIF_file,context->Cycle_range[i].End); // Max color
1028             }
1029             Write_byte(GIF_file,0);
1030           }
1031 
1032           // Loop on all layers
1033           for (current_layer=0;
1034             current_layer < context->Nb_layers && !File_error;
1035             current_layer++)
1036           {
1037             // Write a Graphic Control Extension
1038             T_GIF_GCE GCE;
1039             byte disposal_method;
1040 
1041             Set_saving_layer(context, current_layer);
1042 
1043             GCE.Block_identifier = 0x21;
1044             GCE.Function = 0xF9;
1045             GCE.Block_size=4;
1046 
1047             if (context->Type == CONTEXT_MAIN_IMAGE && Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
1048             {
1049               // Animation frame
1050               int duration;
1051               if(context->Background_transparent)
1052                 disposal_method = DISPOSAL_METHOD_RESTORE_BGCOLOR;
1053               else
1054                 disposal_method = DISPOSAL_METHOD_DO_NOT_DISPOSE;
1055               GCE.Packed_fields=(disposal_method<<2)|(context->Background_transparent);
1056               duration=Get_frame_duration(context)/10;
1057               GCE.Delay_time=duration<0xFFFF?duration:0xFFFF;
1058             }
1059             else
1060             {
1061               // Layered image or brush
1062               disposal_method = DISPOSAL_METHOD_DO_NOT_DISPOSE;
1063               if (current_layer==0)
1064                 GCE.Packed_fields=(disposal_method<<2)|(context->Background_transparent);
1065               else
1066                 GCE.Packed_fields=(disposal_method<<2)|(1);
1067               GCE.Delay_time=5; // Duration 5/100s (minimum viable value for current web browsers)
1068               if (current_layer == context->Nb_layers -1)
1069                 GCE.Delay_time=0xFFFF; // Infinity (10 minutes)
1070             }
1071             GCE.Transparent_color=context->Transparent_color;
1072             GCE.Block_terminator=0x00;
1073 
1074             if (Write_byte(GIF_file,GCE.Block_identifier)
1075              && Write_byte(GIF_file,GCE.Function)
1076              && Write_byte(GIF_file,GCE.Block_size)
1077              && Write_byte(GIF_file,GCE.Packed_fields)
1078              && Write_word_le(GIF_file,GCE.Delay_time)
1079              && Write_byte(GIF_file,GCE.Transparent_color)
1080              && Write_byte(GIF_file,GCE.Block_terminator)
1081              )
1082             {
1083               byte temp, max = 0;
1084 
1085               IDB.Pos_X=0;
1086               IDB.Pos_Y=0;
1087               IDB.Image_width=context->Width;
1088               IDB.Image_height=context->Height;
1089               if(current_layer > 0)
1090               {
1091                 word min_X, max_X, min_Y, max_Y;
1092                 // find bounding box of changes for Animated GIFs
1093                 min_X = min_Y = 0xffff;
1094                 max_X = max_Y = 0;
1095                 for(GIF.pos_Y = 0; GIF.pos_Y < context->Height; GIF.pos_Y++) {
1096                   for(GIF.pos_X = 0; GIF.pos_X < context->Width; GIF.pos_X++) {
1097                     if (GIF.pos_X >= min_X && GIF.pos_X <= max_X && GIF.pos_Y >= min_Y && GIF.pos_Y <= max_Y)
1098                       continue; // already in the box
1099                     if(disposal_method == DISPOSAL_METHOD_DO_NOT_DISPOSE)
1100                     {
1101                       // if that pixel has same value in previous layer, no need to save it
1102                       Set_saving_layer(context, current_layer - 1);
1103                       temp = Get_pixel(context, GIF.pos_X, GIF.pos_Y);
1104                       Set_saving_layer(context, current_layer);
1105                       if(temp == Get_pixel(context, GIF.pos_X, GIF.pos_Y))
1106                         continue;
1107                     }
1108                     if (disposal_method == DISPOSAL_METHOD_RESTORE_BGCOLOR
1109                       || context->Background_transparent
1110                       || Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
1111                     {
1112                       // if that pixel is Backcol, no need to save it
1113                       if (LSDB.Backcol == Get_pixel(context, GIF.pos_X, GIF.pos_Y))
1114                         continue;
1115                     }
1116                     if(GIF.pos_X < min_X) min_X = GIF.pos_X;
1117                     if(GIF.pos_X > max_X) max_X = GIF.pos_X;
1118                     if(GIF.pos_Y < min_Y) min_Y = GIF.pos_Y;
1119                     if(GIF.pos_Y > max_Y) max_Y = GIF.pos_Y;
1120                   }
1121                 }
1122                 if((min_X <= max_X) && (min_Y <= max_Y))
1123                 {
1124                   IDB.Pos_X = min_X;
1125                   IDB.Pos_Y = min_Y;
1126                   IDB.Image_width = max_X + 1 - min_X;
1127                   IDB.Image_height = max_Y + 1 - min_Y;
1128                 }
1129                 else
1130                 {
1131                   // if no pixel changes, store a 1 pixel image
1132                   IDB.Image_width = 1;
1133                   IDB.Image_height = 1;
1134                 }
1135               }
1136 
1137               // look for the maximum pixel value
1138               // to decide how many bit per pixel are needed.
1139               for(GIF.pos_Y = IDB.Pos_Y; GIF.pos_Y < IDB.Image_height + IDB.Pos_Y; GIF.pos_Y++) {
1140                 for(GIF.pos_X = IDB.Pos_X; GIF.pos_X < IDB.Image_width + IDB.Pos_X; GIF.pos_X++) {
1141                   temp=Get_pixel(context, GIF.pos_X, GIF.pos_Y);
1142                   if(temp > max) max = temp;
1143                 }
1144               }
1145               IDB.Nb_bits_pixel=2;  // Find the minimum bpp value to fit all pixels
1146               while((int)max >= (1 << IDB.Nb_bits_pixel)) {
1147                 IDB.Nb_bits_pixel++;
1148               }
1149               GFX2_Log(GFX2_DEBUG, "GIF image #%d %ubits (%u,%u) %ux%u\n",
1150                        current_layer, IDB.Nb_bits_pixel, IDB.Pos_X, IDB.Pos_Y,
1151                        IDB.Image_width, IDB.Image_height);
1152 
1153               // On va écrire un block indicateur d'IDB et l'IDB du fichier
1154               block_identifier=0x2C;
1155               IDB.Indicator=0x07;    // Image non entrelacée, pas de palette locale.
1156               clear = 1 << IDB.Nb_bits_pixel; // Clear Code
1157               eof = clear + 1;                // End of Picture Code
1158 
1159               if ( Write_byte(GIF_file,block_identifier) &&
1160                    Write_word_le(GIF_file,IDB.Pos_X) &&
1161                    Write_word_le(GIF_file,IDB.Pos_Y) &&
1162                    Write_word_le(GIF_file,IDB.Image_width) &&
1163                    Write_word_le(GIF_file,IDB.Image_height) &&
1164                    Write_byte(GIF_file,IDB.Indicator) &&
1165                    Write_byte(GIF_file,IDB.Nb_bits_pixel))
1166               {
1167                 //   Le block indicateur d'IDB et l'IDB ont étés correctements
1168                 // écrits.
1169 
1170                 GIF.pos_X=IDB.Pos_X;
1171                 GIF.pos_Y=IDB.Pos_Y;
1172                 GIF.last_byte=0;
1173                 GIF.remainder_bits=0;
1174                 GIF.remainder_byte=0;
1175 
1176 #define GIF_INVALID_CODE (65535)
1177                 index=GIF_INVALID_CODE;
1178                 File_error=0;
1179                 GIF.stop=0;
1180 
1181                 // Réintialisation de la table:
1182                 alphabet->free = clear + 2;  // 258 for 8bpp
1183                 GIF.nb_bits = IDB.Nb_bits_pixel + 1; // 9 for 8 bpp
1184                 alphabet->max = clear+clear-1;  // 511 for 8bpp
1185                 GIF_set_code(GIF_file, &GIF, GIF_buffer, clear);  //256 for 8bpp
1186                 for (start=0; start<4096; start++)
1187                 {
1188                   alphabet->daughter[start] = GIF_INVALID_CODE;
1189                   alphabet->sister[start] = GIF_INVALID_CODE;
1190                 }
1191 
1192                 ////////////////////////////////////////////// COMPRESSION LZW //
1193 
1194                 start=current_string=GIF_next_pixel(context, &GIF, &IDB);
1195                 descend=1;
1196 
1197                 while ((!GIF.stop) && (!File_error))
1198                 {
1199                   current_char=GIF_next_pixel(context, &GIF, &IDB);
1200 
1201                   // look for (current_string,current_char) in the alphabet
1202                   while ( (index != GIF_INVALID_CODE) &&
1203                           ( (current_string != alphabet->prefix[index]) ||
1204                             (current_char   != alphabet->suffix[index]) ) )
1205                   {
1206                     descend = 0;
1207                     start = index;
1208                     index = alphabet->sister[index];
1209                   }
1210 
1211                   if (index != GIF_INVALID_CODE)
1212                   {
1213                     // (current_string,current_char) == (alphabet_prefix,alphabet_suffix)[index]
1214                     // We have found (current_string,current_char) in the alphabet
1215                     // at the index position. So go on and prepare for then next character
1216 
1217                     descend = 1;
1218                     start = current_string = index;
1219                     index = alphabet->daughter[index];
1220                   }
1221                   else
1222                   {
1223                     // (current_string,current_char) was not found in the alphabet
1224                     // so write current_string to the Gif stream
1225                     GIF_set_code(GIF_file, &GIF, GIF_buffer, current_string);
1226 
1227                     if(alphabet->free < 4096) {
1228                       // link current_string and the new one
1229                       if (descend)
1230                         alphabet->daughter[start] = alphabet->free;
1231                       else
1232                         alphabet->sister[start] = alphabet->free;
1233 
1234                       // add (current_string,current_char) to the alphabet
1235                       alphabet->prefix[alphabet->free] = current_string;
1236                       alphabet->suffix[alphabet->free] = current_char;
1237                       alphabet->free++;
1238                     }
1239 
1240                     if (alphabet->free >= 4096)
1241                     {
1242                       // clear alphabet
1243                       GIF_set_code(GIF_file, &GIF, GIF_buffer, clear);    // 256 for 8bpp
1244                       alphabet->free=clear+2;  // 258 for 8bpp
1245                       GIF.nb_bits = IDB.Nb_bits_pixel + 1;  // 9 for 8bpp
1246                       alphabet->max = clear+clear-1;    // 511 for 8bpp
1247                       for (start=0;start<4096;start++)
1248                       {
1249                         alphabet->daughter[start] = GIF_INVALID_CODE;
1250                         alphabet->sister[start] = GIF_INVALID_CODE;
1251                       }
1252                     }
1253                     else if (alphabet->free > (alphabet->max + 1))
1254                     {
1255                       // On augmente le nb de bits
1256 
1257                       GIF.nb_bits++;
1258                       alphabet->max = (1<<GIF.nb_bits)-1;
1259                     }
1260 
1261                     // initialize current_string as the string "current_char"
1262                     index = alphabet->daughter[current_char];
1263                     start = current_string = current_char;
1264                     descend = 1;
1265                   }
1266                 }
1267 
1268                 if (!File_error)
1269                 {
1270                   // Write the last code (before EOF)
1271                   GIF_set_code(GIF_file, &GIF, GIF_buffer, current_string);
1272 
1273                   // we need to update alphabet->free / GIF.nb_bits here because
1274                   // the decoder will update them after each code,
1275                   // so in very rare cases there might be a problem if we
1276                   // don't do it.
1277                   // see http://pulkomandy.tk/projects/GrafX2/ticket/125
1278                   if(alphabet->free < 4096)
1279                   {
1280                     alphabet->free++;
1281                     if ((alphabet->free > alphabet->max+1) && (GIF.nb_bits < 12))
1282                     {
1283                       GIF.nb_bits++;
1284                       alphabet->max = (1 << GIF.nb_bits) - 1;
1285                     }
1286                   }
1287 
1288                   GIF_set_code(GIF_file, &GIF, GIF_buffer, eof);  // 257 for 8bpp    // Code de End d'image
1289                   if (GIF.remainder_bits!=0)
1290                   {
1291                     // Write last byte (this is an incomplete byte)
1292                     GIF_buffer[++GIF.remainder_byte]=GIF.last_byte;
1293                     GIF.last_byte=0;
1294                     GIF.remainder_bits=0;
1295                   }
1296                   GIF_empty_buffer(GIF_file, &GIF, GIF_buffer); // On envoie les dernières données du buffer GIF dans le buffer KM
1297 
1298                   // On écrit un \0
1299                   if (! Write_byte(GIF_file,'\x00'))
1300                     File_error=1;
1301                 }
1302 
1303               } // On a pu écrire l'IDB
1304               else
1305                 File_error=1;
1306             }
1307             else
1308               File_error=1;
1309           }
1310 
1311           // After writing all layers
1312           if (!File_error)
1313           {
1314             /// - If requested, write a specific extension for storing
1315             /// original file path.
1316             /// This is used by the backup system.
1317             /// The format is :
1318             /// <pre>
1319             ///   0x21       Extension Label
1320             ///   0xFF       Application Extension Label
1321             ///   0x0B       Block Size
1322             ///   "GFX2PATH" "GFX2PATH" Application Identifier (8 bytes)
1323             ///   "\0\0\0"   Application Authentication Code (3 bytes)
1324             ///   0xll       Sub-block Data Size : path size (including null)
1325             ///   "..path.." path (null-terminated)
1326             ///   0xll       Sub-block Data Size : filename size (including null)
1327             ///   "..file.." file name (null-terminated)
1328             ///   0x00       Block terminator </pre>
1329             if (context->Original_file_name != NULL
1330              && context->Original_file_directory != NULL)
1331             {
1332               long name_size = 1+strlen(context->Original_file_name);
1333               long dir_size = 1+strlen(context->Original_file_directory);
1334               if (name_size<256 && dir_size<256)
1335               {
1336                 if (! Write_bytes(GIF_file,"\x21\xFF\x0BGFX2PATH\x00\x00\x00", 14)
1337                 || ! Write_byte(GIF_file,dir_size)
1338                 || ! Write_bytes(GIF_file, context->Original_file_directory, dir_size)
1339                 || ! Write_byte(GIF_file,name_size)
1340                 || ! Write_bytes(GIF_file, context->Original_file_name, name_size)
1341                 || ! Write_byte(GIF_file,0))
1342                   File_error=1;
1343               }
1344             }
1345 
1346             // On écrit un GIF TERMINATOR, exigé par SVGA et SEA.
1347             if (! Write_byte(GIF_file,'\x3B'))
1348               File_error=1;
1349           }
1350 
1351         } // On a pu écrire la palette
1352         else
1353           File_error=1;
1354 
1355       } // On a pu écrire le LSDB
1356       else
1357         File_error=1;
1358 
1359       // Libération de la mémoire utilisée par les tables
1360       free(alphabet);
1361 
1362     } // On a pu écrire la signature du fichier
1363     else
1364       File_error=1;
1365 
1366     fclose(GIF_file);
1367     if (File_error)
1368       Remove_file(context);
1369 
1370   } // On a pu ouvrir le fichier en écriture
1371   else
1372     File_error=1;
1373 
1374 }
1375 
1376 /** @} */
1377