Coverage Report

Created: 2025-10-12 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/gif.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                             GGGG  IIIII  FFFFF                              %
7
%                            G        I    F                                  %
8
%                            G  GG    I    FFF                                %
9
%                            G   G    I    F                                  %
10
%                             GGG   IIIII  F                                  %
11
%                                                                             %
12
%                                                                             %
13
%            Read/Write Compuserve Graphics Interchange Format                %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/color.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colormap.h"
50
#include "MagickCore/colormap-private.h"
51
#include "MagickCore/colorspace.h"
52
#include "MagickCore/colorspace-private.h"
53
#include "MagickCore/exception.h"
54
#include "MagickCore/exception-private.h"
55
#include "MagickCore/image.h"
56
#include "MagickCore/image-private.h"
57
#include "MagickCore/list.h"
58
#include "MagickCore/profile.h"
59
#include "MagickCore/magick.h"
60
#include "MagickCore/memory_.h"
61
#include "MagickCore/memory-private.h"
62
#include "MagickCore/monitor.h"
63
#include "MagickCore/monitor-private.h"
64
#include "MagickCore/option.h"
65
#include "MagickCore/pixel.h"
66
#include "MagickCore/pixel-accessor.h"
67
#include "MagickCore/profile-private.h"
68
#include "MagickCore/property.h"
69
#include "MagickCore/quantize.h"
70
#include "MagickCore/quantum-private.h"
71
#include "MagickCore/resource_.h"
72
#include "MagickCore/static.h"
73
#include "MagickCore/string_.h"
74
#include "MagickCore/string-private.h"
75
#include "MagickCore/module.h"
76

77
/*
78
  Define declarations.
79
*/
80
117M
#define MaximumLZWBits  12
81
117M
#define MaximumLZWCode  (1UL << MaximumLZWBits)
82

83
/*
84
  Typedef declarations.
85
*/
86
typedef struct _LZWCodeInfo
87
{
88
  unsigned char
89
    buffer[280];
90
91
  size_t
92
    count,
93
    bit;
94
95
  MagickBooleanType
96
    eof;
97
} LZWCodeInfo;
98
99
typedef struct _LZWStack
100
{
101
  size_t
102
    *codes,
103
    *index,
104
    *top;
105
} LZWStack;
106
107
typedef struct _LZWInfo
108
{
109
  Image
110
    *image;
111
112
  LZWStack
113
    *stack;
114
115
  MagickBooleanType
116
    genesis;
117
118
  size_t
119
    data_size,
120
    maximum_data_value,
121
    clear_code,
122
    end_code,
123
    bits,
124
    first_code,
125
    last_code,
126
    maximum_code,
127
    slot,
128
    *table[2];
129
130
  LZWCodeInfo
131
    code_info;
132
} LZWInfo;
133

134
/*
135
  Forward declarations.
136
*/
137
static inline int
138
  GetNextLZWCode(LZWInfo *,const size_t);
139
140
static MagickBooleanType
141
  WriteGIFImage(const ImageInfo *,Image *,ExceptionInfo *);
142
143
static ssize_t
144
  ReadBlobBlock(Image *,unsigned char *);
145

146
/*
147
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148
%                                                                             %
149
%                                                                             %
150
%                                                                             %
151
%   D e c o d e I m a g e                                                     %
152
%                                                                             %
153
%                                                                             %
154
%                                                                             %
155
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156
%
157
%  DecodeImage uncompresses an image via GIF-coding.
158
%
159
%  The format of the DecodeImage method is:
160
%
161
%      MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
162
%
163
%  A description of each parameter follows:
164
%
165
%    o image: the address of a structure of type Image.
166
%
167
%    o opacity:  The colormap index associated with the transparent color.
168
%
169
*/
170
171
static LZWInfo *RelinquishLZWInfo(LZWInfo *lzw_info)
172
10.0k
{
173
10.0k
  if (lzw_info->table[0] != (size_t *) NULL)
174
10.0k
    lzw_info->table[0]=(size_t *) RelinquishMagickMemory(
175
10.0k
      lzw_info->table[0]);
176
10.0k
  if (lzw_info->table[1] != (size_t *) NULL)
177
10.0k
    lzw_info->table[1]=(size_t *) RelinquishMagickMemory(
178
10.0k
      lzw_info->table[1]);
179
10.0k
  if (lzw_info->stack != (LZWStack *) NULL)
180
10.0k
    {
181
10.0k
      if (lzw_info->stack->codes != (size_t *) NULL)
182
10.0k
        lzw_info->stack->codes=(size_t *) RelinquishMagickMemory(
183
10.0k
          lzw_info->stack->codes);
184
10.0k
      lzw_info->stack=(LZWStack *) RelinquishMagickMemory(lzw_info->stack);
185
10.0k
    }
186
10.0k
  lzw_info=(LZWInfo *) RelinquishMagickMemory(lzw_info);
187
10.0k
  return((LZWInfo *) NULL);
188
10.0k
}
189
190
static inline void ResetLZWInfo(LZWInfo *lzw_info)
191
11.4k
{
192
11.4k
  size_t
193
11.4k
    one;
194
195
11.4k
  lzw_info->bits=lzw_info->data_size+1;
196
11.4k
  one=1;
197
11.4k
  lzw_info->maximum_code=one << lzw_info->bits;
198
11.4k
  lzw_info->slot=lzw_info->maximum_data_value+3;
199
11.4k
  lzw_info->genesis=MagickTrue;
200
11.4k
}
201
202
static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
203
10.0k
{
204
10.0k
  LZWInfo
205
10.0k
    *lzw_info;
206
207
10.0k
  ssize_t
208
10.0k
    i;
209
210
10.0k
  size_t
211
10.0k
    one;
212
213
10.0k
  lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
214
10.0k
  if (lzw_info == (LZWInfo *) NULL)
215
0
    return((LZWInfo *) NULL);
216
10.0k
  (void) memset(lzw_info,0,sizeof(*lzw_info));
217
10.0k
  lzw_info->image=image;
218
10.0k
  lzw_info->data_size=data_size;
219
10.0k
  one=1;
220
10.0k
  lzw_info->maximum_data_value=(one << data_size)-1;
221
10.0k
  lzw_info->clear_code=lzw_info->maximum_data_value+1;
222
10.0k
  lzw_info->end_code=lzw_info->maximum_data_value+2;
223
10.0k
  lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
224
10.0k
    sizeof(**lzw_info->table));
225
10.0k
  lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
226
10.0k
    sizeof(**lzw_info->table));
227
10.0k
  if ((lzw_info->table[0] == (size_t *) NULL) ||
228
10.0k
      (lzw_info->table[1] == (size_t *) NULL))
229
0
    {
230
0
      lzw_info=RelinquishLZWInfo(lzw_info);
231
0
      return((LZWInfo *) NULL);
232
0
    }
233
10.0k
  (void) memset(lzw_info->table[0],0,MaximumLZWCode*sizeof(**lzw_info->table));
234
10.0k
  (void) memset(lzw_info->table[1],0,MaximumLZWCode*sizeof(**lzw_info->table));
235
213k
  for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
236
203k
  {
237
203k
    lzw_info->table[0][i]=0;
238
203k
    lzw_info->table[1][i]=(size_t) i;
239
203k
  }
240
10.0k
  ResetLZWInfo(lzw_info);
241
10.0k
  lzw_info->code_info.buffer[0]='\0';
242
10.0k
  lzw_info->code_info.buffer[1]='\0';
243
10.0k
  lzw_info->code_info.count=2;
244
10.0k
  lzw_info->code_info.bit=8*lzw_info->code_info.count;
245
10.0k
  lzw_info->code_info.eof=MagickFalse;
246
10.0k
  lzw_info->genesis=MagickTrue;
247
10.0k
  lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
248
10.0k
  if (lzw_info->stack == (LZWStack *) NULL)
249
0
    {
250
0
      lzw_info=RelinquishLZWInfo(lzw_info);
251
0
      return((LZWInfo *) NULL);
252
0
    }
253
10.0k
  lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
254
10.0k
    MaximumLZWCode,sizeof(*lzw_info->stack->codes));
255
10.0k
  if (lzw_info->stack->codes == (size_t *) NULL)
256
0
    {
257
0
      lzw_info=RelinquishLZWInfo(lzw_info);
258
0
      return((LZWInfo *) NULL);
259
0
    }
260
10.0k
  lzw_info->stack->index=lzw_info->stack->codes;
261
10.0k
  lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
262
10.0k
  return(lzw_info);
263
10.0k
}
264
265
static inline int GetNextLZWCode(LZWInfo *lzw_info,const size_t bits)
266
192k
{
267
192k
  int
268
192k
    code;
269
270
192k
  ssize_t
271
192k
    i;
272
273
192k
  size_t
274
192k
    one;
275
276
203k
  while (((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count)) &&
277
11.8k
         (lzw_info->code_info.eof == MagickFalse))
278
11.6k
  {
279
11.6k
    ssize_t
280
11.6k
      count;
281
282
11.6k
    lzw_info->code_info.buffer[0]=lzw_info->code_info.buffer[
283
11.6k
      lzw_info->code_info.count-2];
284
11.6k
    lzw_info->code_info.buffer[1]=lzw_info->code_info.buffer[
285
11.6k
      lzw_info->code_info.count-1];
286
11.6k
    lzw_info->code_info.bit-=8*(lzw_info->code_info.count-2);
287
11.6k
    lzw_info->code_info.count=2;
288
11.6k
    count=ReadBlobBlock(lzw_info->image,&lzw_info->code_info.buffer[
289
11.6k
      lzw_info->code_info.count]);
290
11.6k
    if (count > 0)
291
11.4k
      lzw_info->code_info.count+=(size_t) count;
292
206
    else
293
206
      lzw_info->code_info.eof=MagickTrue;
294
11.6k
  }
295
192k
  if ((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count))
296
206
    return(-1);
297
192k
  code=0;
298
192k
  one=1;
299
1.86M
  for (i=0; i < (ssize_t) bits; i++)
300
1.67M
  {
301
1.67M
    code|=((lzw_info->code_info.buffer[lzw_info->code_info.bit/8] &
302
1.67M
      (one << (lzw_info->code_info.bit % 8))) != 0) << i;
303
1.67M
    lzw_info->code_info.bit++;
304
1.67M
  }
305
192k
  return(code);
306
192k
}
307
308
static inline int PopLZWStack(LZWStack *stack_info)
309
58.9M
{
310
58.9M
  if (stack_info->index <= stack_info->codes)
311
0
    return(-1);
312
58.9M
  stack_info->index--;
313
58.9M
  return((int) *stack_info->index);
314
58.9M
}
315
316
static inline void PushLZWStack(LZWStack *stack_info,const size_t value)
317
58.9M
{
318
58.9M
  if (stack_info->index >= stack_info->top)
319
0
    return;
320
58.9M
  *stack_info->index=value;
321
58.9M
  stack_info->index++;
322
58.9M
}
323
324
static int ReadBlobLZWByte(LZWInfo *lzw_info)
325
58.9M
{
326
58.9M
  int
327
58.9M
    code;
328
329
58.9M
  size_t
330
58.9M
    one,
331
58.9M
    value;
332
333
58.9M
  ssize_t
334
58.9M
    count;
335
336
58.9M
  if (lzw_info->stack->index != lzw_info->stack->codes)
337
58.7M
    return(PopLZWStack(lzw_info->stack));
338
185k
  if (lzw_info->genesis != MagickFalse)
339
11.4k
    {
340
11.4k
      lzw_info->genesis=MagickFalse;
341
11.4k
      do
342
18.7k
      {
343
18.7k
        lzw_info->first_code=(size_t) GetNextLZWCode(lzw_info,lzw_info->bits);
344
18.7k
        lzw_info->last_code=lzw_info->first_code;
345
18.7k
      } while (lzw_info->first_code == lzw_info->clear_code);
346
11.4k
      return((int) lzw_info->first_code);
347
11.4k
    }
348
173k
  code=GetNextLZWCode(lzw_info,lzw_info->bits);
349
173k
  if (code < 0)
350
132
    return(code);
351
173k
  if ((size_t) code == lzw_info->clear_code)
352
1.41k
    {
353
1.41k
      ResetLZWInfo(lzw_info);
354
1.41k
      return(ReadBlobLZWByte(lzw_info));
355
1.41k
    }
356
172k
  if ((size_t) code == lzw_info->end_code)
357
4
    return(-1);
358
172k
  if ((size_t) code < lzw_info->slot)
359
87.7k
    value=(size_t) code;
360
84.2k
  else
361
84.2k
    {
362
84.2k
      PushLZWStack(lzw_info->stack,lzw_info->first_code);
363
84.2k
      value=lzw_info->last_code;
364
84.2k
    }
365
172k
  count=0;
366
58.8M
  while (value > lzw_info->maximum_data_value)
367
58.6M
  {
368
58.6M
    if ((size_t) count > MaximumLZWCode)
369
2
      return(-1);
370
58.6M
    count++;
371
58.6M
    if ((size_t) value > MaximumLZWCode)
372
2
      return(-1);
373
58.6M
    PushLZWStack(lzw_info->stack,lzw_info->table[1][value]);
374
58.6M
    value=lzw_info->table[0][value];
375
58.6M
  }
376
172k
  lzw_info->first_code=lzw_info->table[1][value];
377
172k
  PushLZWStack(lzw_info->stack,lzw_info->first_code);
378
172k
  one=1;
379
172k
  if (lzw_info->slot < MaximumLZWCode)
380
169k
    {
381
169k
      lzw_info->table[0][lzw_info->slot]=lzw_info->last_code;
382
169k
      lzw_info->table[1][lzw_info->slot]=lzw_info->first_code;
383
169k
      lzw_info->slot++;
384
169k
      if ((lzw_info->slot >= lzw_info->maximum_code) &&
385
5.38k
          (lzw_info->bits < MaximumLZWBits))
386
5.37k
        {
387
5.37k
          lzw_info->bits++;
388
5.37k
          lzw_info->maximum_code=one << lzw_info->bits;
389
5.37k
        }
390
169k
    }
391
172k
  lzw_info->last_code=(size_t) code;
392
172k
  return(PopLZWStack(lzw_info->stack));
393
172k
}
394
395
static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity,
396
  ExceptionInfo *exception)
397
10.1k
{
398
10.1k
  int
399
10.1k
    c;
400
401
10.1k
  LZWInfo
402
10.1k
    *lzw_info;
403
404
10.1k
  size_t
405
10.1k
    pass;
406
407
10.1k
  ssize_t
408
10.1k
    index,
409
10.1k
    offset,
410
10.1k
    y;
411
412
10.1k
  unsigned char
413
10.1k
    data_size;
414
415
  /*
416
    Allocate decoder tables.
417
  */
418
10.1k
  assert(image != (Image *) NULL);
419
10.1k
  assert(image->signature == MagickCoreSignature);
420
10.1k
  if (IsEventLogging() != MagickFalse)
421
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
422
10.1k
  data_size=(unsigned char) ReadBlobByte(image);
423
10.1k
  if (data_size > MaximumLZWBits)
424
10.0k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
425
10.0k
  lzw_info=AcquireLZWInfo(image,data_size);
426
10.0k
  if (lzw_info == (LZWInfo *) NULL)
427
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
428
10.0k
      image->filename);
429
10.0k
  pass=0;
430
10.0k
  offset=0;
431
142k
  for (y=0; y < (ssize_t) image->rows; y++)
432
132k
  {
433
132k
    ssize_t
434
132k
      x;
435
436
132k
    Quantum
437
132k
      *magick_restrict q;
438
439
132k
    q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
440
132k
    if (q == (Quantum *) NULL)
441
0
      break;
442
59.0M
    for (x=0; x < (ssize_t) image->columns; )
443
58.9M
    {
444
58.9M
      c=ReadBlobLZWByte(lzw_info);
445
58.9M
      if (c < 0)
446
214
        break;
447
58.9M
      index=ConstrainColormapIndex(image,(ssize_t) c,exception);
448
58.9M
      SetPixelIndex(image,(Quantum) index,q);
449
58.9M
      SetPixelViaPixelInfo(image,image->colormap+index,q);
450
58.9M
      SetPixelAlpha(image,index == opacity ? TransparentAlpha : OpaqueAlpha,q);
451
58.9M
      x++;
452
58.9M
      q+=(ptrdiff_t) GetPixelChannels(image);
453
58.9M
    }
454
132k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
455
0
      break;
456
132k
    if (x < (ssize_t) image->columns)
457
214
      break;
458
132k
    if (image->interlace == NoInterlace)
459
72.8k
      offset++;
460
59.3k
    else
461
59.3k
      {
462
59.3k
        switch (pass)
463
59.3k
        {
464
12.1k
          case 0:
465
12.1k
          default:
466
12.1k
          {
467
12.1k
            offset+=8;
468
12.1k
            break;
469
12.1k
          }
470
7.01k
          case 1:
471
7.01k
          {
472
7.01k
            offset+=8;
473
7.01k
            break;
474
12.1k
          }
475
14.5k
          case 2:
476
14.5k
          {
477
14.5k
            offset+=4;
478
14.5k
            break;
479
12.1k
          }
480
25.5k
          case 3:
481
25.5k
          {
482
25.5k
            offset+=2;
483
25.5k
            break;
484
12.1k
          }
485
59.3k
        }
486
59.3k
      if ((pass == 0) && (offset >= (ssize_t) image->rows))
487
4.24k
        {
488
4.24k
          pass++;
489
4.24k
          offset=4;
490
4.24k
        }
491
59.3k
      if ((pass == 1) && (offset >= (ssize_t) image->rows))
492
4.23k
        {
493
4.23k
          pass++;
494
4.23k
          offset=2;
495
4.23k
        }
496
59.3k
      if ((pass == 2) && (offset >= (ssize_t) image->rows))
497
4.22k
        {
498
4.22k
          pass++;
499
4.22k
          offset=1;
500
4.22k
        }
501
59.3k
    }
502
132k
  }
503
10.0k
  lzw_info=RelinquishLZWInfo(lzw_info);
504
10.0k
  if (y < (ssize_t) image->rows)
505
9.86k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
506
9.86k
  return(MagickTrue);
507
10.0k
}
508

509
/*
510
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511
%                                                                             %
512
%                                                                             %
513
%                                                                             %
514
%   E n c o d e I m a g e                                                     %
515
%                                                                             %
516
%                                                                             %
517
%                                                                             %
518
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519
%
520
%  EncodeImage compresses an image via GIF-coding.
521
%
522
%  The format of the EncodeImage method is:
523
%
524
%      MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
525
%        const size_t data_size)
526
%
527
%  A description of each parameter follows:
528
%
529
%    o image_info: the image info.
530
%
531
%    o image: the address of a structure of type Image.
532
%
533
%    o data_size:  The number of bits in the compressed packet.
534
%
535
*/
536
static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
537
  const size_t data_size,ExceptionInfo *exception)
538
4.74k
{
539
6.21k
#define MaxCode(number_bits)  ((one << (number_bits))-1)
540
53.0M
#define MaxHashTable  5003
541
49.4M
#define MaxGIFBits  12UL
542
1.48M
#define MaxGIFTable  (1UL << MaxGIFBits)
543
1.49M
#define GIFOutputCode(code) \
544
1.49M
{ \
545
  /*  \
546
    Emit a code. \
547
  */ \
548
1.49M
  if (bits > 0) \
549
1.49M
    datum|=(size_t) (code) << bits; \
550
1.49M
  else \
551
1.49M
    datum=(size_t) (code); \
552
1.49M
  bits+=number_bits; \
553
3.57M
  while (bits >= 8) \
554
2.08M
  { \
555
    /*  \
556
      Add a character to current packet.  Maximum packet size is 255.
557
    */ \
558
2.08M
    packet[length++]=(unsigned char) (datum & 0xff); \
559
2.08M
    if (length == 255) \
560
2.08M
      { \
561
8.06k
        (void) WriteBlobByte(image,(unsigned char) length); \
562
8.06k
        (void) WriteBlob(image,length,packet); \
563
8.06k
        length=0; \
564
8.06k
      } \
565
2.08M
    datum>>=8; \
566
2.08M
    bits-=8; \
567
2.08M
  } \
568
1.49M
  if (free_code > max_code)  \
569
1.49M
    { \
570
1.50k
      number_bits++; \
571
1.50k
      if (number_bits == MaxGIFBits) \
572
1.50k
        max_code=MaxGIFTable; \
573
1.50k
      else \
574
1.50k
        max_code=MaxCode(number_bits); \
575
1.50k
    } \
576
1.49M
}
577
578
4.74k
  Quantum
579
4.74k
    index;
580
581
4.74k
  short
582
4.74k
    *hash_code,
583
4.74k
    *hash_prefix,
584
4.74k
    waiting_code;
585
586
4.74k
  size_t
587
4.74k
    bits,
588
4.74k
    clear_code,
589
4.74k
    datum,
590
4.74k
    end_of_information_code,
591
4.74k
    free_code,
592
4.74k
    length,
593
4.74k
    max_code,
594
4.74k
    next_pixel,
595
4.74k
    number_bits,
596
4.74k
    one,
597
4.74k
    pass;
598
599
4.74k
  ssize_t
600
4.74k
    displacement,
601
4.74k
    offset,
602
4.74k
    k,
603
4.74k
    y;
604
605
4.74k
  unsigned char
606
4.74k
    *packet,
607
4.74k
    *hash_suffix;
608
609
  /*
610
    Allocate encoder tables.
611
  */
612
4.74k
  assert(image != (Image *) NULL);
613
4.74k
  one=1;
614
4.74k
  packet=(unsigned char *) AcquireQuantumMemory(256,sizeof(*packet));
615
4.74k
  hash_code=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_code));
616
4.74k
  hash_prefix=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_prefix));
617
4.74k
  hash_suffix=(unsigned char *) AcquireQuantumMemory(MaxHashTable,
618
4.74k
    sizeof(*hash_suffix));
619
4.74k
  if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
620
4.74k
      (hash_prefix == (short *) NULL) ||
621
4.74k
      (hash_suffix == (unsigned char *) NULL))
622
0
    {
623
0
      if (packet != (unsigned char *) NULL)
624
0
        packet=(unsigned char *) RelinquishMagickMemory(packet);
625
0
      if (hash_code != (short *) NULL)
626
0
        hash_code=(short *) RelinquishMagickMemory(hash_code);
627
0
      if (hash_prefix != (short *) NULL)
628
0
        hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
629
0
      if (hash_suffix != (unsigned char *) NULL)
630
0
        hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
631
0
      return(MagickFalse);
632
0
    }
633
  /*
634
    Initialize GIF encoder.
635
  */
636
4.74k
  (void) memset(packet,0,256*sizeof(*packet));
637
4.74k
  (void) memset(hash_code,0,MaxHashTable*sizeof(*hash_code));
638
4.74k
  (void) memset(hash_prefix,0,MaxHashTable*sizeof(*hash_prefix));
639
4.74k
  (void) memset(hash_suffix,0,MaxHashTable*sizeof(*hash_suffix));
640
4.74k
  number_bits=data_size;
641
4.74k
  max_code=MaxCode(number_bits);
642
4.74k
  clear_code=(size_t) ((short) one << (data_size-1));
643
4.74k
  end_of_information_code=clear_code+1;
644
4.74k
  free_code=clear_code+2;
645
4.74k
  length=0;
646
4.74k
  datum=0;
647
4.74k
  bits=0;
648
4.74k
  GIFOutputCode(clear_code);
649
  /*
650
    Encode pixels.
651
  */
652
4.74k
  offset=0;
653
4.74k
  pass=0;
654
4.74k
  waiting_code=0;
655
103k
  for (y=0; y < (ssize_t) image->rows; y++)
656
99.0k
  {
657
99.0k
    const Quantum
658
99.0k
      *magick_restrict p;
659
660
99.0k
    ssize_t
661
99.0k
      x;
662
663
99.0k
    p=GetVirtualPixels(image,0,offset,image->columns,1,exception);
664
99.0k
    if (p == (const Quantum *) NULL)
665
0
      break;
666
99.0k
    if (y == 0)
667
4.74k
      {
668
4.74k
        waiting_code=(short) GetPixelIndex(image,p);
669
4.74k
        p+=(ptrdiff_t) GetPixelChannels(image);
670
4.74k
      }
671
48.0M
    for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
672
47.9M
    {
673
      /*
674
        Probe hash table.
675
      */
676
47.9M
      next_pixel=MagickFalse;
677
47.9M
      displacement=1;
678
47.9M
      index=(Quantum) ((size_t) GetPixelIndex(image,p) & 0xff);
679
47.9M
      p+=(ptrdiff_t) GetPixelChannels(image);
680
47.9M
      k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+(size_t) waiting_code);
681
47.9M
      if (k >= MaxHashTable)
682
243k
        k-=MaxHashTable;
683
47.9M
      if (k < 0)
684
0
        continue;
685
47.9M
      if (hash_code[k] > 0)
686
46.6M
        {
687
46.6M
          if ((hash_prefix[k] == waiting_code) &&
688
44.8M
              (hash_suffix[k] == (unsigned char) index))
689
44.8M
            {
690
44.8M
              waiting_code=hash_code[k];
691
44.8M
              continue;
692
44.8M
            }
693
1.85M
          if (k != 0)
694
1.85M
            displacement=MaxHashTable-k;
695
1.85M
          for ( ; ; )
696
3.18M
          {
697
3.18M
            k-=displacement;
698
3.18M
            if (k < 0)
699
1.21M
              k+=MaxHashTable;
700
3.18M
            if (hash_code[k] == 0)
701
241k
              break;
702
2.94M
            if ((hash_prefix[k] == waiting_code) &&
703
1.61M
                (hash_suffix[k] == (unsigned char) index))
704
1.61M
              {
705
1.61M
                waiting_code=hash_code[k];
706
1.61M
                next_pixel=MagickTrue;
707
1.61M
                break;
708
1.61M
              }
709
2.94M
          }
710
1.85M
          if (next_pixel != MagickFalse)
711
1.61M
            continue;
712
1.85M
        }
713
1.48M
      GIFOutputCode(waiting_code);
714
1.48M
      if (free_code < MaxGIFTable)
715
1.48M
        {
716
1.48M
          hash_code[k]=(short) free_code++;
717
1.48M
          hash_prefix[k]=waiting_code;
718
1.48M
          hash_suffix[k]=(unsigned char) index;
719
1.48M
        }
720
346
      else
721
346
        {
722
          /*
723
            Fill the hash table with empty entries.
724
          */
725
1.73M
          for (k=0; k < MaxHashTable; k++)
726
1.73M
            hash_code[k]=0;
727
          /*
728
            Reset compressor and issue a clear code.
729
          */
730
346
          free_code=clear_code+2;
731
346
          GIFOutputCode(clear_code);
732
346
          number_bits=data_size;
733
346
          max_code=MaxCode(number_bits);
734
346
        }
735
1.48M
      waiting_code=(short) index;
736
1.48M
    }
737
99.0k
    if (image_info->interlace == NoInterlace)
738
99.0k
      offset++;
739
0
    else
740
0
      switch (pass)
741
0
      {
742
0
        case 0:
743
0
        default:
744
0
        {
745
0
          offset+=8;
746
0
          if (offset >= (ssize_t) image->rows)
747
0
            {
748
0
              pass++;
749
0
              offset=4;
750
0
            }
751
0
          break;
752
0
        }
753
0
        case 1:
754
0
        {
755
0
          offset+=8;
756
0
          if (offset >= (ssize_t) image->rows)
757
0
            {
758
0
              pass++;
759
0
              offset=2;
760
0
            }
761
0
          break;
762
0
        }
763
0
        case 2:
764
0
        {
765
0
          offset+=4;
766
0
          if (offset >= (ssize_t) image->rows)
767
0
            {
768
0
              pass++;
769
0
              offset=1;
770
0
            }
771
0
          break;
772
0
        }
773
0
        case 3:
774
0
        {
775
0
          offset+=2;
776
0
          break;
777
0
        }
778
0
      }
779
99.0k
  }
780
  /*
781
    Flush out the buffered code.
782
  */
783
4.74k
  GIFOutputCode(waiting_code);
784
4.74k
  GIFOutputCode(end_of_information_code);
785
4.74k
  if (bits > 0)
786
4.28k
    {
787
      /*
788
        Add a character to current packet.  Maximum packet size is 255.
789
      */
790
4.28k
      packet[length++]=(unsigned char) (datum & 0xff);
791
4.28k
      if (length == 255)
792
1
        {
793
1
          (void) WriteBlobByte(image,(unsigned char) length);
794
1
          (void) WriteBlob(image,length,packet);
795
1
          length=0;
796
1
        }
797
4.28k
    }
798
  /*
799
    Flush accumulated data.
800
  */
801
4.74k
  if (length > 0)
802
4.73k
    {
803
4.73k
      (void) WriteBlobByte(image,(unsigned char) length);
804
4.73k
      (void) WriteBlob(image,length,packet);
805
4.73k
    }
806
  /*
807
    Free encoder memory.
808
  */
809
4.74k
  hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
810
4.74k
  hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
811
4.74k
  hash_code=(short *) RelinquishMagickMemory(hash_code);
812
4.74k
  packet=(unsigned char *) RelinquishMagickMemory(packet);
813
4.74k
  return(MagickTrue);
814
4.74k
}
815

816
/*
817
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818
%                                                                             %
819
%                                                                             %
820
%                                                                             %
821
%   I s G I F                                                                 %
822
%                                                                             %
823
%                                                                             %
824
%                                                                             %
825
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826
%
827
%  IsGIF() returns MagickTrue if the image format type, identified by the
828
%  magick string, is GIF.
829
%
830
%  The format of the IsGIF method is:
831
%
832
%      MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
833
%
834
%  A description of each parameter follows:
835
%
836
%    o magick: compare image format pattern against these bytes.
837
%
838
%    o length: Specifies the length of the magick string.
839
%
840
*/
841
static MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
842
0
{
843
0
  if (length < 4)
844
0
    return(MagickFalse);
845
0
  if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
846
0
    return(MagickTrue);
847
0
  return(MagickFalse);
848
0
}
849

850
/*
851
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852
%                                                                             %
853
%                                                                             %
854
%                                                                             %
855
+  R e a d B l o b B l o c k                                                  %
856
%                                                                             %
857
%                                                                             %
858
%                                                                             %
859
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860
%
861
%  ReadBlobBlock() reads data from the image file and returns it.  The
862
%  amount of data is determined by first reading a count byte.  The number
863
%  of bytes read is returned.
864
%
865
%  The format of the ReadBlobBlock method is:
866
%
867
%      ssize_t ReadBlobBlock(Image *image,unsigned char *data)
868
%
869
%  A description of each parameter follows:
870
%
871
%    o image: the image.
872
%
873
%    o data:  Specifies an area to place the information requested from
874
%      the file.
875
%
876
*/
877
static ssize_t ReadBlobBlock(Image *image,unsigned char *data)
878
116k
{
879
116k
  ssize_t
880
116k
    count;
881
882
116k
  unsigned char
883
116k
    block_count = 0;
884
885
116k
  assert(image != (Image *) NULL);
886
116k
  assert(image->signature == MagickCoreSignature);
887
116k
  assert(data != (unsigned char *) NULL);
888
116k
  count=ReadBlob(image,1,&block_count);
889
116k
  if (count != 1)
890
691
    return(0);
891
115k
  count=ReadBlob(image,(size_t) block_count,data);
892
115k
  if (count != (ssize_t) block_count)
893
304
    return(0);
894
115k
  return(count);
895
115k
}
896

897
/*
898
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899
%                                                                             %
900
%                                                                             %
901
%                                                                             %
902
%   R e a d G I F I m a g e                                                   %
903
%                                                                             %
904
%                                                                             %
905
%                                                                             %
906
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907
%
908
%  ReadGIFImage() reads a Compuserve Graphics image file and returns it.
909
%  It allocates the memory necessary for the new Image structure and returns a
910
%  pointer to the new image.
911
%
912
%  The format of the ReadGIFImage method is:
913
%
914
%      Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
915
%
916
%  A description of each parameter follows:
917
%
918
%    o image_info: the image info.
919
%
920
%    o exception: return any errors or warnings in this structure.
921
%
922
*/
923
924
static void *DestroyGIFProfile(void *profile)
925
4.46k
{
926
4.46k
  return((void *) DestroyStringInfo((StringInfo *) profile));
927
4.46k
}
928
929
static MagickBooleanType PingGIFImage(Image *image,ExceptionInfo *exception)
930
1.60k
{
931
1.60k
  unsigned char
932
1.60k
    buffer[256],
933
1.60k
    length,
934
1.60k
    data_size;
935
936
1.60k
  assert(image != (Image *) NULL);
937
1.60k
  assert(image->signature == MagickCoreSignature);
938
1.60k
  if (IsEventLogging() != MagickFalse)
939
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
940
1.60k
  if (ReadBlob(image,1,&data_size) != 1)
941
1.58k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
942
1.58k
  if (data_size > MaximumLZWBits)
943
1.42k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
944
1.42k
  if (ReadBlob(image,1,&length) != 1)
945
1.42k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
946
2.67k
  while (length != 0)
947
1.80k
  {
948
1.80k
    if (ReadBlob(image,length,buffer) != (ssize_t) length)
949
1.60k
      ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
950
1.60k
    if (ReadBlob(image,1,&length) != 1)
951
1.25k
      ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
952
1.25k
  }
953
870
  return(MagickTrue);
954
1.42k
}
955
956
static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
957
7.33k
{
958
43.2k
#define BitSet(byte,bit)  (((byte) & (bit)) == (bit))
959
7.33k
#define LSBFirstOrder(x,y)  (((y) << 8) | (x))
960
7.33k
#define ThrowGIFException(exception,message) \
961
520
{ \
962
520
  if (profiles != (LinkedListInfo *) NULL) \
963
520
    profiles=DestroyLinkedList(profiles,DestroyGIFProfile); \
964
520
  if (global_colormap != (unsigned char *) NULL) \
965
520
    global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap); \
966
520
  if (meta_image != (Image *) NULL) \
967
520
    meta_image=DestroyImage(meta_image); \
968
520
  ThrowReaderException((exception),(message)); \
969
0
}
970
971
7.33k
  Image
972
7.33k
    *image,
973
7.33k
    *meta_image;
974
975
7.33k
  LinkedListInfo
976
7.33k
    *profiles;
977
978
7.33k
  MagickBooleanType
979
7.33k
    status;
980
981
7.33k
  ssize_t
982
7.33k
    i;
983
984
7.33k
  unsigned char
985
7.33k
    *p;
986
987
7.33k
  size_t
988
7.33k
    duration,
989
7.33k
    global_colors,
990
7.33k
    image_count,
991
7.33k
    local_colors,
992
7.33k
    one;
993
994
7.33k
  ssize_t
995
7.33k
    count,
996
7.33k
    opacity;
997
998
7.33k
  unsigned char
999
7.33k
    background,
1000
7.33k
    buffer[257],
1001
7.33k
    c,
1002
7.33k
    flag,
1003
7.33k
    *global_colormap;
1004
1005
  /*
1006
    Open image file.
1007
  */
1008
7.33k
  assert(image_info != (const ImageInfo *) NULL);
1009
7.33k
  assert(image_info->signature == MagickCoreSignature);
1010
7.33k
  assert(exception != (ExceptionInfo *) NULL);
1011
7.33k
  assert(exception->signature == MagickCoreSignature);
1012
7.33k
  if (IsEventLogging() != MagickFalse)
1013
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1014
0
      image_info->filename);
1015
7.33k
  image=AcquireImage(image_info,exception);
1016
7.33k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1017
7.33k
  if (status == MagickFalse)
1018
112
    {
1019
112
      image=DestroyImageList(image);
1020
112
      return((Image *) NULL);
1021
112
    }
1022
  /*
1023
    Determine if this a GIF file.
1024
  */
1025
7.22k
  count=ReadBlob(image,6,buffer);
1026
7.22k
  if ((count != 6) || ((LocaleNCompare((char *) buffer,"GIF87",5) != 0) &&
1027
5.65k
      (LocaleNCompare((char *) buffer,"GIF89",5) != 0)))
1028
7.08k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1029
7.08k
  (void) memset(buffer,0,sizeof(buffer));
1030
7.08k
  meta_image=AcquireImage(image_info,exception);  /* metadata container */
1031
7.08k
  meta_image->page.width=ReadBlobLSBShort(image);
1032
7.08k
  meta_image->page.height=ReadBlobLSBShort(image);
1033
7.08k
  meta_image->iterations=1;
1034
7.08k
  flag=(unsigned char) ReadBlobByte(image);
1035
7.08k
  profiles=(LinkedListInfo *) NULL;
1036
7.08k
  background=(unsigned char) ReadBlobByte(image);
1037
7.08k
  c=(unsigned char) ReadBlobByte(image);  /* reserved */
1038
7.08k
  one=1;
1039
7.08k
  global_colors=one << (((size_t) flag & 0x07)+1);
1040
7.08k
  global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1041
7.08k
    MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
1042
7.08k
  if (global_colormap == (unsigned char *) NULL)
1043
7.08k
    ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
1044
7.08k
  (void) memset(global_colormap,0,3*MagickMax(global_colors,256)*
1045
7.08k
    sizeof(*global_colormap));
1046
7.08k
  if (BitSet((int) flag,0x80) != 0)
1047
326
    {
1048
326
      count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
1049
326
      if (count != (ssize_t) (3*global_colors))
1050
304
        ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
1051
304
    }
1052
7.06k
  duration=0;
1053
7.06k
  opacity=(-1);
1054
7.06k
  image_count=0;
1055
7.06k
  for ( ; ; )
1056
180k
  {
1057
180k
    count=ReadBlob(image,1,&c);
1058
180k
    if (count != 1)
1059
6.14k
      break;
1060
174k
    if (c == (unsigned char) ';')
1061
249
      break;  /* terminator */
1062
173k
    if (c == (unsigned char) '!')
1063
33.8k
      {
1064
        /*
1065
          GIF Extension block.
1066
        */
1067
33.8k
        (void) memset(buffer,0,sizeof(buffer));
1068
33.8k
        count=ReadBlob(image,1,&c);
1069
33.8k
        if (count != 1)
1070
33.7k
          ThrowGIFException(CorruptImageError,"UnableToReadExtensionBlock");
1071
33.7k
        switch (c)
1072
33.7k
        {
1073
1.46k
          case 0xf9:
1074
1.46k
          {
1075
            /*
1076
              Read graphics control extension.
1077
            */
1078
2.85k
            while (ReadBlobBlock(image,buffer) != 0) ;
1079
1.46k
            meta_image->dispose=(DisposeType) ((buffer[0] >> 2) & 0x07);
1080
1.46k
            meta_image->delay=((size_t) buffer[2] << 8) | buffer[1];
1081
1.46k
            if ((ssize_t) (buffer[0] & 0x01) == 0x01)
1082
715
              opacity=(ssize_t) buffer[3];
1083
1.46k
            break;
1084
0
          }
1085
2.84k
          case 0xfe:
1086
2.84k
          {
1087
2.84k
            char
1088
2.84k
              *comments;
1089
1090
2.84k
            size_t
1091
2.84k
              extent,
1092
2.84k
              offset;
1093
1094
2.84k
            comments=AcquireString((char *) NULL);
1095
2.84k
            extent=MagickPathExtent;
1096
4.31k
            for (offset=0; ; offset+=(size_t) count)
1097
7.15k
            {
1098
7.15k
              count=ReadBlobBlock(image,buffer);
1099
7.15k
              if (count == 0)
1100
2.84k
                break;
1101
4.31k
              buffer[count]='\0';
1102
4.31k
              if ((count+(ssize_t) offset+MagickPathExtent) >= (ssize_t) extent)
1103
850
                {
1104
850
                  extent<<=1;
1105
850
                  comments=(char *) ResizeQuantumMemory(comments,
1106
850
                    OverAllocateMemory(extent+MagickPathExtent),
1107
850
                    sizeof(*comments));
1108
850
                  if (comments == (char *) NULL)
1109
0
                    ThrowGIFException(ResourceLimitError,
1110
850
                      "MemoryAllocationFailed");
1111
850
                }
1112
4.31k
              (void) CopyMagickString(&comments[offset],(char *) buffer,extent-
1113
4.31k
                offset);
1114
4.31k
            }
1115
2.84k
            (void) SetImageProperty(meta_image,"comment",comments,exception);
1116
2.84k
            comments=DestroyString(comments);
1117
2.84k
            break;
1118
2.84k
          }
1119
28.5k
          case 0xff:
1120
28.5k
          {
1121
28.5k
            MagickBooleanType
1122
28.5k
              loop;
1123
1124
            /*
1125
              Read Netscape Loop extension.
1126
            */
1127
28.5k
            loop=MagickFalse;
1128
28.5k
            if (ReadBlobBlock(image,buffer) != 0)
1129
22.5k
              loop=LocaleNCompare((char *) buffer,"NETSCAPE2.0",11) == 0 ?
1130
22.1k
                MagickTrue : MagickFalse;
1131
28.5k
            if (loop != MagickFalse)
1132
1.55k
              while (ReadBlobBlock(image,buffer) != 0)
1133
1.11k
              {
1134
1.11k
                meta_image->iterations=((size_t) buffer[2] << 8) | buffer[1];
1135
1.11k
                if (meta_image->iterations != 0)
1136
740
                  meta_image->iterations++;
1137
1.11k
              }
1138
28.0k
            else
1139
28.0k
              {
1140
28.0k
                char
1141
28.0k
                  name[MagickPathExtent];
1142
1143
28.0k
                int
1144
28.0k
                  block_length,
1145
28.0k
                  info_length,
1146
28.0k
                  reserved_length;
1147
1148
28.0k
                MagickBooleanType
1149
28.0k
                  magick = MagickFalse;
1150
1151
28.0k
                unsigned char
1152
28.0k
                  *info;
1153
1154
                /*
1155
                  Store GIF application extension as a generic profile.
1156
                */
1157
28.0k
                if (LocaleNCompare((char *) buffer,"ImageMagick",11) == 0)
1158
947
                  magick=MagickTrue;
1159
27.1k
                else if (LocaleNCompare((char *) buffer,"ICCRGBG1012",11) == 0)
1160
7.71k
                  (void) CopyMagickString(name,"icc",sizeof(name));
1161
19.4k
                else if (LocaleNCompare((char *) buffer,"MGK8BIM0000",11) == 0)
1162
11.1k
                  (void) CopyMagickString(name,"8bim",sizeof(name));
1163
8.31k
                else if (LocaleNCompare((char *) buffer,"MGKIPTC0000",11) == 0)
1164
677
                  (void) CopyMagickString(name,"iptc",sizeof(name));
1165
7.64k
                else
1166
7.64k
                  (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
1167
7.64k
                    buffer);
1168
28.0k
                reserved_length=255;
1169
28.0k
                info=(unsigned char *) AcquireQuantumMemory((size_t)
1170
28.0k
                  reserved_length,sizeof(*info));
1171
28.0k
                if (info == (unsigned char *) NULL)
1172
0
                  ThrowGIFException(ResourceLimitError,
1173
28.0k
                    "MemoryAllocationFailed");
1174
28.0k
                (void) memset(info,0,(size_t) reserved_length*sizeof(*info));
1175
28.0k
                for (info_length=0; ; )
1176
63.3k
                {
1177
63.3k
                  block_length=(int) ReadBlobBlock(image,info+info_length);
1178
63.3k
                  if (block_length == 0)
1179
28.0k
                    break;
1180
35.2k
                  info_length+=block_length;
1181
35.2k
                  if (info_length > (reserved_length-255))
1182
22.0k
                    {
1183
22.0k
                      reserved_length+=4096;
1184
22.0k
                      info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
1185
22.0k
                        reserved_length,sizeof(*info));
1186
22.0k
                      if (info == (unsigned char *) NULL)
1187
0
                        {
1188
0
                          info=(unsigned char *) RelinquishMagickMemory(info);
1189
0
                          ThrowGIFException(ResourceLimitError,
1190
0
                            "MemoryAllocationFailed");
1191
0
                        }
1192
22.0k
                    }
1193
35.2k
                }
1194
28.0k
                if (magick != MagickFalse)
1195
947
                  meta_image->gamma=StringToDouble((char *) info+6,
1196
947
                      (char **) NULL);
1197
27.1k
                else
1198
27.1k
                  {
1199
27.1k
                    StringInfo
1200
27.1k
                      *profile;
1201
1202
27.1k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1203
27.1k
                      "      profile name=%s",name);
1204
27.1k
                    profile=BlobToProfileStringInfo(name,info,(size_t) info_length,
1205
27.1k
                      exception);
1206
27.1k
                    if (profile != (StringInfo *) NULL)
1207
27.1k
                      {
1208
27.1k
                        if (profiles == (LinkedListInfo *) NULL)
1209
9.62k
                          profiles=NewLinkedList(0);
1210
27.1k
                        (void) AppendValueToLinkedList(profiles,profile);
1211
27.1k
                      }
1212
27.1k
                  }
1213
28.0k
                info=(unsigned char *) RelinquishMagickMemory(info);
1214
28.0k
              }
1215
28.5k
            break;
1216
28.5k
          }
1217
28.5k
          default:
1218
950
          {
1219
1.57k
            while (ReadBlobBlock(image,buffer) != 0) ;
1220
950
            break;
1221
28.5k
          }
1222
33.7k
        }
1223
33.7k
      }
1224
173k
    if (c != (unsigned char) ',')
1225
161k
      continue;
1226
12.0k
    image_count++;
1227
12.0k
    if (image_count != 1)
1228
5.58k
      {
1229
        /*
1230
          Allocate next image structure.
1231
        */
1232
5.58k
        AcquireNextImage(image_info,image,exception);
1233
5.58k
        if (GetNextImageInList(image) == (Image *) NULL)
1234
0
          {
1235
0
            status=MagickFalse;
1236
0
            break;
1237
0
          }
1238
5.58k
        image=SyncNextImageInList(image);
1239
5.58k
      }
1240
    /*
1241
      Read image attributes.
1242
    */
1243
12.0k
    meta_image->page.x=(ssize_t) ReadBlobLSBShort(image);
1244
12.0k
    meta_image->page.y=(ssize_t) ReadBlobLSBShort(image);
1245
12.0k
    meta_image->scene=image->scene;
1246
12.0k
    (void) CloneImageProperties(image,meta_image);
1247
12.0k
    DestroyImageProperties(meta_image);
1248
12.0k
    image->storage_class=PseudoClass;
1249
12.0k
    image->compression=LZWCompression;
1250
12.0k
    image->columns=ReadBlobLSBShort(image);
1251
12.0k
    image->rows=ReadBlobLSBShort(image);
1252
12.0k
    image->depth=8;
1253
12.0k
    flag=(unsigned char) ReadBlobByte(image);
1254
12.0k
    image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace : NoInterlace;
1255
12.0k
    local_colors=BitSet((int) flag,0x80) == 0 ? global_colors : one <<
1256
300
      ((size_t) (flag & 0x07)+1);
1257
12.0k
    image->colors=local_colors;
1258
12.0k
    if (opacity == (ssize_t) image->colors)
1259
74
      image->colors++;
1260
12.0k
    else if (opacity > (ssize_t) image->colors)
1261
60
      opacity=(-1);
1262
12.0k
    image->ticks_per_second=100;
1263
12.0k
    image->alpha_trait=opacity >= 0 ? BlendPixelTrait : UndefinedPixelTrait;
1264
12.0k
    if ((image->columns == 0) || (image->rows == 0))
1265
12.0k
      ThrowGIFException(CorruptImageError,"NegativeOrZeroImageSize");
1266
    /*
1267
      Initialize colormap.
1268
    */
1269
12.0k
    if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1270
12.0k
      ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
1271
12.0k
    if (BitSet((int) flag,0x80) == 0)
1272
11.7k
      {
1273
        /*
1274
          Use global colormap.
1275
        */
1276
11.7k
        p=global_colormap;
1277
372k
        for (i=0; i < (ssize_t) image->colors; i++)
1278
360k
        {
1279
360k
          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1280
360k
          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1281
360k
          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1282
360k
          if (i == opacity)
1283
182
            {
1284
182
              image->colormap[i].alpha=(double) TransparentAlpha;
1285
182
              image->transparent_color=image->colormap[opacity];
1286
182
            }
1287
360k
        }
1288
11.7k
        if (image->colors > 0)
1289
11.7k
          image->background_color=image->colormap[MagickMin((ssize_t)
1290
11.7k
            background,(ssize_t) image->colors-1)];
1291
11.7k
      }
1292
215
    else
1293
215
      {
1294
215
        unsigned char
1295
215
          *colormap;
1296
1297
        /*
1298
          Read local colormap.
1299
        */
1300
215
        colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1301
215
          MagickMax(local_colors,256),3UL*sizeof(*colormap));
1302
215
        if (colormap == (unsigned char *) NULL)
1303
215
          ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
1304
215
        (void) memset(colormap,0,3*MagickMax(local_colors,256)*
1305
215
          sizeof(*colormap));
1306
215
        count=ReadBlob(image,(3*local_colors)*sizeof(*colormap),colormap);
1307
215
        if (count != (ssize_t) (3*local_colors))
1308
40
          {
1309
40
            colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1310
40
            ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
1311
0
          }
1312
175
        p=colormap;
1313
2.03k
        for (i=0; i < (ssize_t) image->colors; i++)
1314
1.85k
        {
1315
1.85k
          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1316
1.85k
          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1317
1.85k
          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1318
1.85k
          if (i == opacity)
1319
56
            image->colormap[i].alpha=(double) TransparentAlpha;
1320
1.85k
        }
1321
175
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1322
175
      }
1323
11.9k
    if (image->gamma == 1.0)
1324
201
      {
1325
2.01k
        for (i=0; i < (ssize_t) image->colors; i++)
1326
1.91k
          if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
1327
107
            break;
1328
201
        (void) SetImageColorspace(image,i == (ssize_t) image->colors ?
1329
107
          GRAYColorspace : RGBColorspace,exception);
1330
201
      }
1331
11.9k
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1332
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1333
0
        break;
1334
11.9k
    status=SetImageExtent(image,image->columns,image->rows,exception);
1335
11.9k
    if (status == MagickFalse)
1336
172
      {
1337
172
        if (profiles != (LinkedListInfo *) NULL)
1338
6
          profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
1339
172
        global_colormap=(unsigned char *) RelinquishMagickMemory(
1340
172
          global_colormap);
1341
172
        meta_image=DestroyImage(meta_image);
1342
172
        return(DestroyImageList(image));
1343
172
      }
1344
    /*
1345
      Decode image.
1346
    */
1347
11.7k
    if (image_info->ping != MagickFalse)
1348
1.60k
      status=PingGIFImage(image,exception);
1349
10.1k
    else
1350
10.1k
      status=DecodeImage(image,opacity,exception);
1351
11.7k
    if ((image_info->ping == MagickFalse) && (status == MagickFalse))
1352
11.4k
      ThrowGIFException(CorruptImageError,"CorruptImage");
1353
11.4k
    if (profiles != (LinkedListInfo *) NULL)
1354
9.23k
      {
1355
9.23k
        StringInfo
1356
9.23k
          *profile;
1357
1358
        /*
1359
          Set image profiles.
1360
        */
1361
9.23k
        ResetLinkedListIterator(profiles);
1362
9.23k
        profile=(StringInfo *) GetNextValueInLinkedList(profiles);
1363
31.9k
        while (profile != (StringInfo *) NULL)
1364
22.6k
        {
1365
22.6k
          (void) SetImageProfilePrivate(image,profile,exception);
1366
22.6k
          profile=(StringInfo *) GetNextValueInLinkedList(profiles);
1367
22.6k
        }
1368
9.23k
        profiles=DestroyLinkedList(profiles,(void *(*)(void *)) NULL);
1369
9.23k
      }
1370
11.4k
    duration+=image->delay*image->iterations;
1371
11.4k
    if (image_info->number_scenes != 0)
1372
168
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1373
1
        break;
1374
11.4k
    opacity=(-1);
1375
11.4k
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1376
11.4k
      image->scene-1,image->scene);
1377
11.4k
    if (status == MagickFalse)
1378
0
      break;
1379
11.4k
  }
1380
6.39k
  image->duration=duration;
1381
6.39k
  if (profiles != (LinkedListInfo *) NULL)
1382
366
    profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
1383
6.39k
  meta_image=DestroyImage(meta_image);
1384
6.39k
  global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1385
6.39k
  if ((image->columns == 0) || (image->rows == 0))
1386
5.84k
    ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1387
5.84k
  if (CloseBlob(image) == MagickFalse)
1388
0
    status=MagickFalse;
1389
5.84k
  if (status == MagickFalse)
1390
0
    return(DestroyImageList(image));
1391
5.84k
  return(GetFirstImageInList(image));
1392
5.84k
}
1393

1394
/*
1395
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396
%                                                                             %
1397
%                                                                             %
1398
%                                                                             %
1399
%   R e g i s t e r G I F I m a g e                                           %
1400
%                                                                             %
1401
%                                                                             %
1402
%                                                                             %
1403
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404
%
1405
%  RegisterGIFImage() adds properties for the GIF image format to
1406
%  the list of supported formats.  The properties include the image format
1407
%  tag, a method to read and/or write the format, whether the format
1408
%  supports the saving of more than one frame to the same file or blob,
1409
%  whether the format supports native in-memory I/O, and a brief
1410
%  description of the format.
1411
%
1412
%  The format of the RegisterGIFImage method is:
1413
%
1414
%      size_t RegisterGIFImage(void)
1415
%
1416
*/
1417
ModuleExport size_t RegisterGIFImage(void)
1418
10
{
1419
10
  MagickInfo
1420
10
    *entry;
1421
1422
10
  entry=AcquireMagickInfo("GIF","GIF",
1423
10
    "CompuServe graphics interchange format");
1424
10
  entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1425
10
  entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1426
10
  entry->magick=(IsImageFormatHandler *) IsGIF;
1427
10
  entry->mime_type=ConstantString("image/gif");
1428
10
  (void) RegisterMagickInfo(entry);
1429
10
  entry=AcquireMagickInfo("GIF","GIF87",
1430
10
    "CompuServe graphics interchange format");
1431
10
  entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1432
10
  entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1433
10
  entry->magick=(IsImageFormatHandler *) IsGIF;
1434
10
  entry->flags^=CoderAdjoinFlag;
1435
10
  entry->version=ConstantString("version 87a");
1436
10
  entry->mime_type=ConstantString("image/gif");
1437
10
  (void) RegisterMagickInfo(entry);
1438
10
  return(MagickImageCoderSignature);
1439
10
}
1440

1441
/*
1442
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443
%                                                                             %
1444
%                                                                             %
1445
%                                                                             %
1446
%   U n r e g i s t e r G I F I m a g e                                       %
1447
%                                                                             %
1448
%                                                                             %
1449
%                                                                             %
1450
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451
%
1452
%  UnregisterGIFImage() removes format registrations made by the
1453
%  GIF module from the list of supported formats.
1454
%
1455
%  The format of the UnregisterGIFImage method is:
1456
%
1457
%      UnregisterGIFImage(void)
1458
%
1459
*/
1460
ModuleExport void UnregisterGIFImage(void)
1461
0
{
1462
0
  (void) UnregisterMagickInfo("GIF");
1463
0
  (void) UnregisterMagickInfo("GIF87");
1464
0
}
1465

1466
/*
1467
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468
%                                                                             %
1469
%                                                                             %
1470
%                                                                             %
1471
%   W r i t e G I F I m a g e                                                 %
1472
%                                                                             %
1473
%                                                                             %
1474
%                                                                             %
1475
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476
%
1477
%  WriteGIFImage() writes an image to a file in the Compuserve Graphics
1478
%  image format.
1479
%
1480
%  The format of the WriteGIFImage method is:
1481
%
1482
%      MagickBooleanType WriteGIFImage(const ImageInfo *image_info,
1483
%        Image *image,ExceptionInfo *exception)
1484
%
1485
%  A description of each parameter follows.
1486
%
1487
%    o image_info: the image info.
1488
%
1489
%    o image:  The image.
1490
%
1491
%    o exception: return any errors or warnings in this structure.
1492
%
1493
*/
1494
static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
1495
  ExceptionInfo *exception)
1496
4.74k
{
1497
4.74k
  ImageInfo
1498
4.74k
    *write_info;
1499
1500
4.74k
  int
1501
4.74k
    c;
1502
1503
4.74k
  MagickBooleanType
1504
4.74k
    status;
1505
1506
4.74k
  MagickOffsetType
1507
4.74k
    scene;
1508
1509
4.74k
  RectangleInfo
1510
4.74k
    page;
1511
1512
4.74k
  size_t
1513
4.74k
    bits_per_pixel,
1514
4.74k
    delay,
1515
4.74k
    length,
1516
4.74k
    number_scenes,
1517
4.74k
    one;
1518
1519
4.74k
  ssize_t
1520
4.74k
    i,
1521
4.74k
    j,
1522
4.74k
    opacity;
1523
1524
4.74k
  unsigned char
1525
4.74k
    *colormap,
1526
4.74k
    *global_colormap,
1527
4.74k
    *q;
1528
1529
  /*
1530
    Open output image file.
1531
  */
1532
4.74k
  assert(image_info != (const ImageInfo *) NULL);
1533
4.74k
  assert(image_info->signature == MagickCoreSignature);
1534
4.74k
  assert(image != (Image *) NULL);
1535
4.74k
  assert(image->signature == MagickCoreSignature);
1536
4.74k
  assert(exception != (ExceptionInfo *) NULL);
1537
4.74k
  assert(exception->signature == MagickCoreSignature);
1538
4.74k
  if (IsEventLogging() != MagickFalse)
1539
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1540
4.74k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1541
4.74k
  if (status == MagickFalse)
1542
0
    return(status);
1543
  /*
1544
    Allocate colormap.
1545
  */
1546
4.74k
  global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
1547
4.74k
    sizeof(*global_colormap));
1548
4.74k
  colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
1549
4.74k
  if ((global_colormap == (unsigned char *) NULL) ||
1550
4.74k
      (colormap == (unsigned char *) NULL))
1551
0
    {
1552
0
      if (global_colormap != (unsigned char *) NULL)
1553
0
        global_colormap=(unsigned char *) RelinquishMagickMemory(
1554
0
          global_colormap);
1555
0
      if (colormap != (unsigned char *) NULL)
1556
0
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1557
0
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1558
0
    }
1559
3.64M
  for (i=0; i < 768; i++)
1560
3.64M
    colormap[i]=(unsigned char) 0;
1561
  /*
1562
    Write GIF header.
1563
  */
1564
4.74k
  write_info=CloneImageInfo(image_info);
1565
4.74k
  if (LocaleCompare(write_info->magick,"GIF87") != 0)
1566
4.74k
    (void) WriteBlob(image,6,(unsigned char *) "GIF89a");
1567
0
  else
1568
0
    {
1569
0
      (void) WriteBlob(image,6,(unsigned char *) "GIF87a");
1570
0
      write_info->adjoin=MagickFalse;
1571
0
    }
1572
  /*
1573
    Determine image bounding box.
1574
  */
1575
4.74k
  page.width=image->columns;
1576
4.74k
  if (image->page.width > page.width)
1577
4.16k
    page.width=image->page.width;
1578
4.74k
  page.height=image->rows;
1579
4.74k
  if (image->page.height > page.height)
1580
3.85k
    page.height=image->page.height;
1581
4.74k
  page.x=image->page.x;
1582
4.74k
  page.y=image->page.y;
1583
4.74k
  (void) WriteBlobLSBShort(image,(unsigned short) page.width);
1584
4.74k
  (void) WriteBlobLSBShort(image,(unsigned short) page.height);
1585
  /*
1586
    Write images to file.
1587
  */
1588
4.74k
  scene=0;
1589
4.74k
  one=1;
1590
4.74k
  number_scenes=GetImageListLength(image);
1591
4.74k
  do
1592
4.74k
  {
1593
4.74k
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1594
0
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
1595
4.74k
    opacity=(-1);
1596
4.74k
    if (IsImageOpaque(image,exception) != MagickFalse)
1597
4.70k
      {
1598
4.70k
        if ((image->storage_class == DirectClass) || (image->colors > 256))
1599
0
          (void) SetImageType(image,PaletteType,exception);
1600
4.70k
      }
1601
31
    else
1602
31
      {
1603
31
        double
1604
31
          alpha,
1605
31
          beta;
1606
1607
        /*
1608
          Identify transparent colormap index.
1609
        */
1610
31
        if ((image->storage_class == DirectClass) || (image->colors > 256))
1611
0
          (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1612
3.43k
        for (i=0; i < (ssize_t) image->colors; i++)
1613
3.40k
          if (image->colormap[i].alpha != (double) OpaqueAlpha)
1614
31
            {
1615
31
              if (opacity < 0)
1616
31
                {
1617
31
                  opacity=i;
1618
31
                  continue;
1619
31
                }
1620
0
              alpha=fabs(image->colormap[i].alpha-(double) TransparentAlpha);
1621
0
              beta=fabs(image->colormap[opacity].alpha-(double)
1622
0
                TransparentAlpha);
1623
0
              if (alpha < beta)
1624
0
                opacity=i;
1625
0
            }
1626
31
        if (opacity == -1)
1627
0
          {
1628
0
            (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1629
0
            for (i=0; i < (ssize_t) image->colors; i++)
1630
0
              if (image->colormap[i].alpha != (double) OpaqueAlpha)
1631
0
                {
1632
0
                  if (opacity < 0)
1633
0
                    {
1634
0
                      opacity=i;
1635
0
                      continue;
1636
0
                    }
1637
0
                  alpha=fabs(image->colormap[i].alpha-(double)
1638
0
                    TransparentAlpha);
1639
0
                  beta=fabs(image->colormap[opacity].alpha-(double)
1640
0
                    TransparentAlpha);
1641
0
                  if (alpha < beta)
1642
0
                    opacity=i;
1643
0
                }
1644
0
          }
1645
31
        if (opacity >= 0)
1646
31
          {
1647
31
            image->colormap[opacity].red=image->transparent_color.red;
1648
31
            image->colormap[opacity].green=image->transparent_color.green;
1649
31
            image->colormap[opacity].blue=image->transparent_color.blue;
1650
31
          }
1651
31
      }
1652
4.74k
    if ((image->storage_class == DirectClass) || (image->colors > 256))
1653
4.74k
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1654
13.9k
    for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1655
13.5k
      if ((one << bits_per_pixel) >= image->colors)
1656
4.37k
        break;
1657
4.74k
    q=colormap;
1658
177k
    for (i=0; i < (ssize_t) image->colors; i++)
1659
172k
    {
1660
172k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1661
172k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1662
172k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1663
172k
    }
1664
4.98k
    for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
1665
247
    {
1666
247
      *q++=(unsigned char) 0x0;
1667
247
      *q++=(unsigned char) 0x0;
1668
247
      *q++=(unsigned char) 0x0;
1669
247
    }
1670
4.74k
    if ((GetPreviousImageInList(image) == (Image *) NULL) ||
1671
0
        (write_info->adjoin == MagickFalse))
1672
4.74k
      {
1673
        /*
1674
          Write global colormap.
1675
        */
1676
4.74k
        c=0x80;
1677
4.74k
        c|=(8-1) << 4;  /* color resolution */
1678
4.74k
        c|=(int) (bits_per_pixel-1);   /* size of global colormap */
1679
4.74k
        (void) WriteBlobByte(image,(unsigned char) c);
1680
7.30k
        for (j=0; j < (ssize_t) image->colors; j++)
1681
7.29k
          if (IsPixelInfoEquivalent(&image->background_color,image->colormap+j))
1682
4.72k
            break;
1683
4.74k
        (void) WriteBlobByte(image,(unsigned char)
1684
4.74k
          (j == (ssize_t) image->colors ? 0 : j));  /* background color */
1685
4.74k
        (void) WriteBlobByte(image,(unsigned char) 0x00);  /* reserved */
1686
4.74k
        length=(size_t) (3*(one << bits_per_pixel));
1687
4.74k
        (void) WriteBlob(image,length,colormap);
1688
3.64M
        for (j=0; j < 768; j++)
1689
3.64M
          global_colormap[j]=colormap[j];
1690
4.74k
      }
1691
4.74k
    if (LocaleCompare(write_info->magick,"GIF87") != 0)
1692
4.74k
      {
1693
4.74k
        const char
1694
4.74k
          *value;
1695
1696
4.74k
        if ((GetPreviousImageInList(image) == (Image *) NULL) &&
1697
4.74k
            (GetNextImageInList(image) != (Image *) NULL) &&
1698
0
            (image->iterations != 1))
1699
0
          {
1700
            /*
1701
              Write Netscape Loop extension.
1702
            */
1703
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1704
0
               "  Writing GIF Extension %s","NETSCAPE2.0");
1705
0
            (void) WriteBlobByte(image,(unsigned char) 0x21);
1706
0
            (void) WriteBlobByte(image,(unsigned char) 0xff);
1707
0
            (void) WriteBlobByte(image,(unsigned char) 0x0b);
1708
0
            (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0");
1709
0
            (void) WriteBlobByte(image,(unsigned char) 0x03);
1710
0
            (void) WriteBlobByte(image,(unsigned char) 0x01);
1711
0
            (void) WriteBlobLSBShort(image,(unsigned short) (image->iterations ?
1712
0
              image->iterations-1 : 0));
1713
0
            (void) WriteBlobByte(image,(unsigned char) 0x00);
1714
0
          }
1715
        /*
1716
          Write graphics control extension.
1717
        */
1718
4.74k
        (void) WriteBlobByte(image,(unsigned char) 0x21);
1719
4.74k
        (void) WriteBlobByte(image,(unsigned char) 0xf9);
1720
4.74k
        (void) WriteBlobByte(image,(unsigned char) 0x04);
1721
4.74k
        c=(int) (image->dispose << 2);
1722
4.74k
        if (opacity >= 0)
1723
31
          c|=0x01;
1724
4.74k
        (void) WriteBlobByte(image,(unsigned char) c);
1725
4.74k
        delay=(size_t) (100*image->delay/MagickMax((size_t)
1726
4.74k
          image->ticks_per_second,1));
1727
4.74k
        (void) WriteBlobLSBShort(image,(unsigned short) delay);
1728
4.74k
        (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
1729
4.74k
          0));
1730
4.74k
        (void) WriteBlobByte(image,(unsigned char) 0x00);
1731
4.74k
        if (fabs(image->gamma-1.0/2.2) > MagickEpsilon)
1732
2
          {
1733
2
            char
1734
2
              attributes[MagickPathExtent];
1735
1736
2
            ssize_t
1737
2
              count;
1738
1739
            /*
1740
              Write ImageMagick extension.
1741
            */
1742
2
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1743
2
               "  Writing GIF Extension %s","ImageMagick");
1744
2
            (void) WriteBlobByte(image,(unsigned char) 0x21);
1745
2
            (void) WriteBlobByte(image,(unsigned char) 0xff);
1746
2
            (void) WriteBlobByte(image,(unsigned char) 0x0b);
1747
2
            (void) WriteBlob(image,11,(unsigned char *) "ImageMagick");
1748
2
            count=FormatLocaleString(attributes,MagickPathExtent,"gamma=%g",
1749
2
              image->gamma);
1750
2
            (void) WriteBlobByte(image,(unsigned char) count);
1751
2
            (void) WriteBlob(image,(size_t) count,(unsigned char *) attributes);
1752
2
            (void) WriteBlobByte(image,(unsigned char) 0x00);
1753
2
          }
1754
4.74k
        value=GetImageProperty(image,"comment",exception);
1755
4.74k
        if (value != (const char *) NULL)
1756
104
          {
1757
104
            const char
1758
104
              *p;
1759
1760
104
            size_t
1761
104
              count;
1762
1763
            /*
1764
              Write comment extension.
1765
            */
1766
104
            (void) WriteBlobByte(image,(unsigned char) 0x21);
1767
104
            (void) WriteBlobByte(image,(unsigned char) 0xfe);
1768
278
            for (p=value; *p != '\0'; )
1769
174
            {
1770
174
              count=MagickMin(strlen(p),255);
1771
174
              (void) WriteBlobByte(image,(unsigned char) count);
1772
36.8k
              for (i=0; i < (ssize_t) count; i++)
1773
36.6k
                (void) WriteBlobByte(image,(unsigned char) *p++);
1774
174
            }
1775
104
            (void) WriteBlobByte(image,(unsigned char) 0x00);
1776
104
          }
1777
4.74k
        ResetImageProfileIterator(image);
1778
4.74k
        for ( ; ; )
1779
11.7k
        {
1780
11.7k
          char
1781
11.7k
            *name;
1782
1783
11.7k
          const StringInfo
1784
11.7k
            *profile;
1785
1786
11.7k
          name=GetNextImageProfile(image);
1787
11.7k
          if (name == (const char *) NULL)
1788
4.74k
            break;
1789
6.96k
          profile=GetImageProfile(image,name);
1790
6.96k
          if (profile != (StringInfo *) NULL)
1791
6.96k
          {
1792
6.96k
            if ((LocaleCompare(name,"ICC") == 0) ||
1793
5.44k
                (LocaleCompare(name,"ICM") == 0) ||
1794
5.44k
                (LocaleCompare(name,"IPTC") == 0) ||
1795
5.41k
                (LocaleCompare(name,"8BIM") == 0) ||
1796
2.72k
                (LocaleNCompare(name,"gif:",4) == 0))
1797
4.82k
            {
1798
4.82k
               ssize_t
1799
4.82k
                 offset;
1800
1801
4.82k
               unsigned char
1802
4.82k
                 *datum;
1803
1804
4.82k
               datum=GetStringInfoDatum(profile);
1805
4.82k
               length=GetStringInfoLength(profile);
1806
4.82k
               (void) WriteBlobByte(image,(unsigned char) 0x21);
1807
4.82k
               (void) WriteBlobByte(image,(unsigned char) 0xff);
1808
4.82k
               (void) WriteBlobByte(image,(unsigned char) 0x0b);
1809
4.82k
               if ((LocaleCompare(name,"ICC") == 0) ||
1810
3.30k
                   (LocaleCompare(name,"ICM") == 0))
1811
1.51k
                 {
1812
                   /*
1813
                     Write ICC extension.
1814
                   */
1815
1.51k
                   (void) WriteBlob(image,11,(unsigned char *) "ICCRGBG1012");
1816
1.51k
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1817
1.51k
                     "  Writing GIF Extension %s","ICCRGBG1012");
1818
1.51k
                 }
1819
3.30k
               else
1820
3.30k
                 if ((LocaleCompare(name,"IPTC") == 0))
1821
37
                   {
1822
                     /*
1823
                       Write IPTC extension.
1824
                     */
1825
37
                     (void) WriteBlob(image,11,(unsigned char *) "MGKIPTC0000");
1826
37
                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1827
37
                       "  Writing GIF Extension %s","MGKIPTC0000");
1828
37
                   }
1829
3.26k
                 else
1830
3.26k
                   if ((LocaleCompare(name,"8BIM") == 0))
1831
2.69k
                     {
1832
                       /*
1833
                         Write 8BIM extension.
1834
                       */
1835
2.69k
                        (void) WriteBlob(image,11,(unsigned char *)
1836
2.69k
                          "MGK8BIM0000");
1837
2.69k
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1838
2.69k
                          "  Writing GIF Extension %s","MGK8BIM0000");
1839
2.69k
                     }
1840
575
                   else
1841
575
                     {
1842
575
                       char
1843
575
                         extension[MagickPathExtent];
1844
1845
                       /*
1846
                         Write generic extension.
1847
                       */
1848
575
                       (void) memset(extension,0,sizeof(extension));
1849
575
                       (void) CopyMagickString(extension,name+4,
1850
575
                         sizeof(extension));
1851
575
                       (void) WriteBlob(image,11,(unsigned char *) extension);
1852
575
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1853
575
                         "  Writing GIF Extension %s",name);
1854
575
                     }
1855
4.82k
               offset=0;
1856
12.0k
               while ((ssize_t) length > offset)
1857
7.23k
               {
1858
7.23k
                 size_t
1859
7.23k
                   block_length;
1860
1861
7.23k
                 if (((ssize_t) length-offset) < 255)
1862
4.80k
                   block_length=(size_t) ((ssize_t) length-offset);
1863
2.43k
                 else
1864
2.43k
                   block_length=255;
1865
7.23k
                 (void) WriteBlobByte(image,(unsigned char) block_length);
1866
7.23k
                 (void) WriteBlob(image,(size_t) block_length,datum+offset);
1867
7.23k
                 offset+=(ssize_t) block_length;
1868
7.23k
               }
1869
4.82k
               (void) WriteBlobByte(image,(unsigned char) 0x00);
1870
4.82k
            }
1871
6.96k
          }
1872
6.96k
        }
1873
4.74k
      }
1874
4.74k
    (void) WriteBlobByte(image,',');  /* image separator */
1875
    /*
1876
      Write the image header.
1877
    */
1878
4.74k
    page.x=image->page.x;
1879
4.74k
    page.y=image->page.y;
1880
4.74k
    if ((image->page.width != 0) && (image->page.height != 0))
1881
4.74k
      page=image->page;
1882
4.74k
    (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
1883
4.74k
    (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
1884
4.74k
    (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
1885
4.74k
    (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
1886
4.74k
    c=0x00;
1887
4.74k
    if (write_info->interlace != NoInterlace)
1888
0
      c|=0x40;  /* pixel data is interlaced */
1889
523k
    for (j=0; j < (ssize_t) (3*image->colors); j++)
1890
518k
      if (colormap[j] != global_colormap[j])
1891
0
        break;
1892
4.74k
    if (j == (ssize_t) (3*image->colors))
1893
4.74k
      (void) WriteBlobByte(image,(unsigned char) c);
1894
0
    else
1895
0
      {
1896
0
        c|=0x80;
1897
0
        c|=(int) (bits_per_pixel-1);   /* size of local colormap */
1898
0
        (void) WriteBlobByte(image,(unsigned char) c);
1899
0
        length=(size_t) (3*(one << bits_per_pixel));
1900
0
        (void) WriteBlob(image,length,colormap);
1901
0
      }
1902
    /*
1903
      Write the image data.
1904
    */
1905
4.74k
    c=(int) MagickMax(bits_per_pixel,2);
1906
4.74k
    (void) WriteBlobByte(image,(unsigned char) c);
1907
4.74k
    status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1,
1908
4.74k
      exception);
1909
4.74k
    if (status == MagickFalse)
1910
0
      {
1911
0
        global_colormap=(unsigned char *) RelinquishMagickMemory(
1912
0
          global_colormap);
1913
0
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1914
0
        write_info=DestroyImageInfo(write_info);
1915
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1916
0
      }
1917
4.74k
    (void) WriteBlobByte(image,(unsigned char) 0x00);
1918
4.74k
    if (GetNextImageInList(image) == (Image *) NULL)
1919
4.74k
      break;
1920
0
    image=SyncNextImageInList(image);
1921
0
    scene++;
1922
0
    status=SetImageProgress(image,SaveImagesTag,scene,number_scenes);
1923
0
    if (status == MagickFalse)
1924
0
      break;
1925
0
  } while (write_info->adjoin != MagickFalse);
1926
4.74k
  (void) WriteBlobByte(image,';'); /* terminator */
1927
4.74k
  global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1928
4.74k
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1929
4.74k
  write_info=DestroyImageInfo(write_info);
1930
4.74k
  if (CloseBlob(image) == MagickFalse)
1931
0
    status=MagickFalse;
1932
4.74k
  return(status);
1933
4.74k
}