Coverage Report

Created: 2026-03-31 06:56

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/license/                                         %
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
145M
#define MaximumLZWBits  12
81
145M
#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.1k
{
173
10.1k
  if (lzw_info->table[0] != (size_t *) NULL)
174
10.1k
    lzw_info->table[0]=(size_t *) RelinquishMagickMemory(
175
10.1k
      lzw_info->table[0]);
176
10.1k
  if (lzw_info->table[1] != (size_t *) NULL)
177
10.1k
    lzw_info->table[1]=(size_t *) RelinquishMagickMemory(
178
10.1k
      lzw_info->table[1]);
179
10.1k
  if (lzw_info->stack != (LZWStack *) NULL)
180
10.1k
    {
181
10.1k
      if (lzw_info->stack->codes != (size_t *) NULL)
182
10.1k
        lzw_info->stack->codes=(size_t *) RelinquishMagickMemory(
183
10.1k
          lzw_info->stack->codes);
184
10.1k
      lzw_info->stack=(LZWStack *) RelinquishMagickMemory(lzw_info->stack);
185
10.1k
    }
186
10.1k
  lzw_info=(LZWInfo *) RelinquishMagickMemory(lzw_info);
187
10.1k
  return((LZWInfo *) NULL);
188
10.1k
}
189
190
static inline void ResetLZWInfo(LZWInfo *lzw_info)
191
11.9k
{
192
11.9k
  size_t
193
11.9k
    one;
194
195
11.9k
  lzw_info->bits=lzw_info->data_size+1;
196
11.9k
  one=1;
197
11.9k
  lzw_info->maximum_code=one << lzw_info->bits;
198
11.9k
  lzw_info->slot=lzw_info->maximum_data_value+3;
199
11.9k
  lzw_info->genesis=MagickTrue;
200
11.9k
}
201
202
static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
203
10.1k
{
204
10.1k
  LZWInfo
205
10.1k
    *lzw_info;
206
207
10.1k
  ssize_t
208
10.1k
    i;
209
210
10.1k
  size_t
211
10.1k
    one;
212
213
10.1k
  lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
214
10.1k
  if (lzw_info == (LZWInfo *) NULL)
215
0
    return((LZWInfo *) NULL);
216
10.1k
  (void) memset(lzw_info,0,sizeof(*lzw_info));
217
10.1k
  lzw_info->image=image;
218
10.1k
  lzw_info->data_size=data_size;
219
10.1k
  one=1;
220
10.1k
  lzw_info->maximum_data_value=(one << data_size)-1;
221
10.1k
  lzw_info->clear_code=lzw_info->maximum_data_value+1;
222
10.1k
  lzw_info->end_code=lzw_info->maximum_data_value+2;
223
10.1k
  lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
224
10.1k
    sizeof(**lzw_info->table));
225
10.1k
  lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
226
10.1k
    sizeof(**lzw_info->table));
227
10.1k
  if ((lzw_info->table[0] == (size_t *) NULL) ||
228
10.1k
      (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.1k
  (void) memset(lzw_info->table[0],0,MaximumLZWCode*sizeof(**lzw_info->table));
234
10.1k
  (void) memset(lzw_info->table[1],0,MaximumLZWCode*sizeof(**lzw_info->table));
235
228k
  for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
236
218k
  {
237
218k
    lzw_info->table[0][i]=0;
238
218k
    lzw_info->table[1][i]=(size_t) i;
239
218k
  }
240
10.1k
  ResetLZWInfo(lzw_info);
241
10.1k
  lzw_info->code_info.buffer[0]='\0';
242
10.1k
  lzw_info->code_info.buffer[1]='\0';
243
10.1k
  lzw_info->code_info.count=2;
244
10.1k
  lzw_info->code_info.bit=8*lzw_info->code_info.count;
245
10.1k
  lzw_info->code_info.eof=MagickFalse;
246
10.1k
  lzw_info->genesis=MagickTrue;
247
10.1k
  lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
248
10.1k
  if (lzw_info->stack == (LZWStack *) NULL)
249
0
    {
250
0
      lzw_info=RelinquishLZWInfo(lzw_info);
251
0
      return((LZWInfo *) NULL);
252
0
    }
253
10.1k
  lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
254
10.1k
    MaximumLZWCode,sizeof(*lzw_info->stack->codes));
255
10.1k
  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.1k
  lzw_info->stack->index=lzw_info->stack->codes;
261
10.1k
  lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
262
10.1k
  return(lzw_info);
263
10.1k
}
264
265
static inline int GetNextLZWCode(LZWInfo *lzw_info,const size_t bits)
266
224k
{
267
224k
  int
268
224k
    code;
269
270
224k
  ssize_t
271
224k
    i;
272
273
224k
  size_t
274
224k
    one;
275
276
236k
  while (((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count)) &&
277
12.2k
         (lzw_info->code_info.eof == MagickFalse))
278
12.0k
  {
279
12.0k
    ssize_t
280
12.0k
      count;
281
282
12.0k
    lzw_info->code_info.buffer[0]=lzw_info->code_info.buffer[
283
12.0k
      lzw_info->code_info.count-2];
284
12.0k
    lzw_info->code_info.buffer[1]=lzw_info->code_info.buffer[
285
12.0k
      lzw_info->code_info.count-1];
286
12.0k
    lzw_info->code_info.bit-=8*(lzw_info->code_info.count-2);
287
12.0k
    lzw_info->code_info.count=2;
288
12.0k
    count=ReadBlobBlock(lzw_info->image,&lzw_info->code_info.buffer[
289
12.0k
      lzw_info->code_info.count]);
290
12.0k
    if (count > 0)
291
11.8k
      lzw_info->code_info.count+=(size_t) count;
292
212
    else
293
212
      lzw_info->code_info.eof=MagickTrue;
294
12.0k
  }
295
224k
  if ((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count))
296
212
    return(-1);
297
224k
  code=0;
298
224k
  one=1;
299
2.22M
  for (i=0; i < (ssize_t) bits; i++)
300
1.99M
  {
301
1.99M
    code|=((lzw_info->code_info.buffer[lzw_info->code_info.bit/8] &
302
1.99M
      (one << (lzw_info->code_info.bit % 8))) != 0) << i;
303
1.99M
    lzw_info->code_info.bit++;
304
1.99M
  }
305
224k
  return(code);
306
224k
}
307
308
static inline int PopLZWStack(LZWStack *stack_info)
309
72.8M
{
310
72.8M
  if (stack_info->index <= stack_info->codes)
311
0
    return(-1);
312
72.8M
  stack_info->index--;
313
72.8M
  return((int) *stack_info->index);
314
72.8M
}
315
316
static inline void PushLZWStack(LZWStack *stack_info,const size_t value)
317
72.9M
{
318
72.9M
  if (stack_info->index >= stack_info->top)
319
0
    return;
320
72.9M
  *stack_info->index=value;
321
72.9M
  stack_info->index++;
322
72.9M
}
323
324
static int ReadBlobLZWByte(LZWInfo *lzw_info)
325
72.8M
{
326
72.8M
  int
327
72.8M
    code;
328
329
72.8M
  size_t
330
72.8M
    one,
331
72.8M
    value;
332
333
72.8M
  ssize_t
334
72.8M
    count;
335
336
72.8M
  if (lzw_info->stack->index != lzw_info->stack->codes)
337
72.6M
    return(PopLZWStack(lzw_info->stack));
338
216k
  if (lzw_info->genesis != MagickFalse)
339
11.9k
    {
340
11.9k
      lzw_info->genesis=MagickFalse;
341
11.9k
      do
342
19.6k
      {
343
19.6k
        lzw_info->first_code=(size_t) GetNextLZWCode(lzw_info,lzw_info->bits);
344
19.6k
        lzw_info->last_code=lzw_info->first_code;
345
19.6k
      } while (lzw_info->first_code == lzw_info->clear_code);
346
11.9k
      return((int) lzw_info->first_code);
347
11.9k
    }
348
204k
  code=GetNextLZWCode(lzw_info,lzw_info->bits);
349
204k
  if (code < 0)
350
131
    return(code);
351
204k
  if ((size_t) code == lzw_info->clear_code)
352
1.80k
    {
353
1.80k
      ResetLZWInfo(lzw_info);
354
1.80k
      return(ReadBlobLZWByte(lzw_info));
355
1.80k
    }
356
202k
  if ((size_t) code == lzw_info->end_code)
357
6
    return(-1);
358
202k
  if ((size_t) code < lzw_info->slot)
359
103k
    value=(size_t) code;
360
99.5k
  else
361
99.5k
    {
362
99.5k
      PushLZWStack(lzw_info->stack,lzw_info->first_code);
363
99.5k
      value=lzw_info->last_code;
364
99.5k
    }
365
202k
  count=0;
366
72.8M
  while (value > lzw_info->maximum_data_value)
367
72.6M
  {
368
72.6M
    if ((size_t) count > MaximumLZWCode)
369
1
      return(-1);
370
72.6M
    count++;
371
72.6M
    if ((size_t) value > MaximumLZWCode)
372
3
      return(-1);
373
72.6M
    PushLZWStack(lzw_info->stack,lzw_info->table[1][value]);
374
72.6M
    value=lzw_info->table[0][value];
375
72.6M
  }
376
202k
  lzw_info->first_code=lzw_info->table[1][value];
377
202k
  PushLZWStack(lzw_info->stack,lzw_info->first_code);
378
202k
  one=1;
379
202k
  if (lzw_info->slot < MaximumLZWCode)
380
199k
    {
381
199k
      lzw_info->table[0][lzw_info->slot]=lzw_info->last_code;
382
199k
      lzw_info->table[1][lzw_info->slot]=lzw_info->first_code;
383
199k
      lzw_info->slot++;
384
199k
      if ((lzw_info->slot >= lzw_info->maximum_code) &&
385
5.85k
          (lzw_info->bits < MaximumLZWBits))
386
5.84k
        {
387
5.84k
          lzw_info->bits++;
388
5.84k
          lzw_info->maximum_code=one << lzw_info->bits;
389
5.84k
        }
390
199k
    }
391
202k
  lzw_info->last_code=(size_t) code;
392
202k
  return(PopLZWStack(lzw_info->stack));
393
202k
}
394
395
static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity,
396
  ExceptionInfo *exception)
397
10.2k
{
398
10.2k
  int
399
10.2k
    c;
400
401
10.2k
  LZWInfo
402
10.2k
    *lzw_info;
403
404
10.2k
  size_t
405
10.2k
    pass;
406
407
10.2k
  ssize_t
408
10.2k
    index,
409
10.2k
    offset,
410
10.2k
    y;
411
412
10.2k
  unsigned char
413
10.2k
    data_size;
414
415
  /*
416
    Allocate decoder tables.
417
  */
418
10.2k
  assert(image != (Image *) NULL);
419
10.2k
  assert(image->signature == MagickCoreSignature);
420
10.2k
  if (IsEventLogging() != MagickFalse)
421
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
422
10.2k
  data_size=(unsigned char) ReadBlobByte(image);
423
10.2k
  if (data_size > MaximumLZWBits)
424
10.1k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
425
10.1k
  lzw_info=AcquireLZWInfo(image,data_size);
426
10.1k
  if (lzw_info == (LZWInfo *) NULL)
427
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
428
10.1k
      image->filename);
429
10.1k
  pass=0;
430
10.1k
  offset=0;
431
143k
  for (y=0; y < (ssize_t) image->rows; y++)
432
133k
  {
433
133k
    ssize_t
434
133k
      x;
435
436
133k
    Quantum
437
133k
      *magick_restrict q;
438
439
133k
    q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
440
133k
    if (q == (Quantum *) NULL)
441
0
      break;
442
73.0M
    for (x=0; x < (ssize_t) image->columns; )
443
72.8M
    {
444
72.8M
      c=ReadBlobLZWByte(lzw_info);
445
72.8M
      if (c < 0)
446
222
        break;
447
72.8M
      index=ConstrainColormapIndex(image,(ssize_t) c,exception);
448
72.8M
      SetPixelIndex(image,(Quantum) index,q);
449
72.8M
      SetPixelViaPixelInfo(image,image->colormap+index,q);
450
72.8M
      SetPixelAlpha(image,index == opacity ? TransparentAlpha : OpaqueAlpha,q);
451
72.8M
      x++;
452
72.8M
      q+=(ptrdiff_t) GetPixelChannels(image);
453
72.8M
    }
454
133k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
455
0
      break;
456
133k
    if (x < (ssize_t) image->columns)
457
222
      break;
458
133k
    if (image->interlace == NoInterlace)
459
79.4k
      offset++;
460
54.2k
    else
461
54.2k
      {
462
54.2k
        switch (pass)
463
54.2k
        {
464
11.5k
          case 0:
465
11.5k
          default:
466
11.5k
          {
467
11.5k
            offset+=8;
468
11.5k
            break;
469
11.5k
          }
470
6.35k
          case 1:
471
6.35k
          {
472
6.35k
            offset+=8;
473
6.35k
            break;
474
11.5k
          }
475
13.2k
          case 2:
476
13.2k
          {
477
13.2k
            offset+=4;
478
13.2k
            break;
479
11.5k
          }
480
23.0k
          case 3:
481
23.0k
          {
482
23.0k
            offset+=2;
483
23.0k
            break;
484
11.5k
          }
485
54.2k
        }
486
54.2k
      if ((pass == 0) && (offset >= (ssize_t) image->rows))
487
4.46k
        {
488
4.46k
          pass++;
489
4.46k
          offset=4;
490
4.46k
        }
491
54.2k
      if ((pass == 1) && (offset >= (ssize_t) image->rows))
492
4.45k
        {
493
4.45k
          pass++;
494
4.45k
          offset=2;
495
4.45k
        }
496
54.2k
      if ((pass == 2) && (offset >= (ssize_t) image->rows))
497
4.44k
        {
498
4.44k
          pass++;
499
4.44k
          offset=1;
500
4.44k
        }
501
54.2k
    }
502
133k
  }
503
10.1k
  lzw_info=RelinquishLZWInfo(lzw_info);
504
10.1k
  if (y < (ssize_t) image->rows)
505
9.96k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
506
9.96k
  return(MagickTrue);
507
10.1k
}
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.83k
{
539
6.83k
#define MaxCode(number_bits)  ((one << (number_bits))-1)
540
74.2M
#define MaxHashTable  5003
541
69.2M
#define MaxGIFBits  12UL
542
2.15M
#define MaxGIFTable  (1UL << MaxGIFBits)
543
2.16M
#define GIFOutputCode(code) \
544
2.16M
{ \
545
  /*  \
546
    Emit a code. \
547
  */ \
548
2.16M
  if (bits > 0) \
549
2.16M
    datum|=(size_t) (code) << bits; \
550
2.16M
  else \
551
2.16M
    datum=(size_t) (code); \
552
2.16M
  bits+=number_bits; \
553
5.18M
  while (bits >= 8) \
554
3.01M
  { \
555
    /*  \
556
      Add a character to current packet.  Maximum packet size is 255.
557
    */ \
558
3.01M
    packet[length++]=(unsigned char) (datum & 0xff); \
559
3.01M
    if (length == 255) \
560
3.01M
      { \
561
11.7k
        (void) WriteBlobByte(image,(unsigned char) length); \
562
11.7k
        (void) WriteBlob(image,length,packet); \
563
11.7k
        length=0; \
564
11.7k
      } \
565
3.01M
    datum>>=8; \
566
3.01M
    bits-=8; \
567
3.01M
  } \
568
2.16M
  if (free_code > max_code)  \
569
2.16M
    { \
570
2.04k
      number_bits++; \
571
2.04k
      if (number_bits == MaxGIFBits) \
572
2.04k
        max_code=MaxGIFTable; \
573
2.04k
      else \
574
2.04k
        max_code=MaxCode(number_bits); \
575
2.04k
    } \
576
2.16M
}
577
578
4.83k
  Quantum
579
4.83k
    index;
580
581
4.83k
  short
582
4.83k
    *hash_code,
583
4.83k
    *hash_prefix,
584
4.83k
    waiting_code;
585
586
4.83k
  size_t
587
4.83k
    bits,
588
4.83k
    clear_code,
589
4.83k
    datum,
590
4.83k
    end_of_information_code,
591
4.83k
    free_code,
592
4.83k
    length,
593
4.83k
    max_code,
594
4.83k
    next_pixel,
595
4.83k
    number_bits,
596
4.83k
    one,
597
4.83k
    pass;
598
599
4.83k
  ssize_t
600
4.83k
    displacement,
601
4.83k
    offset,
602
4.83k
    k,
603
4.83k
    y;
604
605
4.83k
  unsigned char
606
4.83k
    *packet,
607
4.83k
    *hash_suffix;
608
609
  /*
610
    Allocate encoder tables.
611
  */
612
4.83k
  assert(image != (Image *) NULL);
613
4.83k
  one=1;
614
4.83k
  packet=(unsigned char *) AcquireQuantumMemory(256,sizeof(*packet));
615
4.83k
  hash_code=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_code));
616
4.83k
  hash_prefix=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_prefix));
617
4.83k
  hash_suffix=(unsigned char *) AcquireQuantumMemory(MaxHashTable,
618
4.83k
    sizeof(*hash_suffix));
619
4.83k
  if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
620
4.83k
      (hash_prefix == (short *) NULL) ||
621
4.83k
      (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.83k
  (void) memset(packet,0,256*sizeof(*packet));
637
4.83k
  (void) memset(hash_code,0,MaxHashTable*sizeof(*hash_code));
638
4.83k
  (void) memset(hash_prefix,0,MaxHashTable*sizeof(*hash_prefix));
639
4.83k
  (void) memset(hash_suffix,0,MaxHashTable*sizeof(*hash_suffix));
640
4.83k
  number_bits=data_size;
641
4.83k
  max_code=MaxCode(number_bits);
642
4.83k
  clear_code=(size_t) ((short) one << (data_size-1));
643
4.83k
  end_of_information_code=clear_code+1;
644
4.83k
  free_code=clear_code+2;
645
4.83k
  length=0;
646
4.83k
  datum=0;
647
4.83k
  bits=0;
648
4.83k
  GIFOutputCode(clear_code);
649
  /*
650
    Encode pixels.
651
  */
652
4.83k
  offset=0;
653
4.83k
  pass=0;
654
4.83k
  waiting_code=0;
655
108k
  for (y=0; y < (ssize_t) image->rows; y++)
656
103k
  {
657
103k
    const Quantum
658
103k
      *magick_restrict p;
659
660
103k
    ssize_t
661
103k
      x;
662
663
103k
    p=GetVirtualPixels(image,0,offset,image->columns,1,exception);
664
103k
    if (p == (const Quantum *) NULL)
665
0
      break;
666
103k
    if (y == 0)
667
4.83k
      {
668
4.83k
        waiting_code=(short) GetPixelIndex(image,p);
669
4.83k
        p+=(ptrdiff_t) GetPixelChannels(image);
670
4.83k
      }
671
67.1M
    for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
672
67.0M
    {
673
      /*
674
        Probe hash table.
675
      */
676
67.0M
      next_pixel=MagickFalse;
677
67.0M
      displacement=1;
678
67.0M
      index=(Quantum) ((size_t) GetPixelIndex(image,p) & 0xff);
679
67.0M
      p+=(ptrdiff_t) GetPixelChannels(image);
680
67.0M
      k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+(size_t) waiting_code);
681
67.0M
      if (k >= MaxHashTable)
682
502k
        k-=MaxHashTable;
683
67.0M
      if (k < 0)
684
0
        continue;
685
67.0M
      if (hash_code[k] > 0)
686
65.2M
        {
687
65.2M
          if ((hash_prefix[k] == waiting_code) &&
688
62.8M
              (hash_suffix[k] == (unsigned char) index))
689
62.8M
            {
690
62.8M
              waiting_code=hash_code[k];
691
62.8M
              continue;
692
62.8M
            }
693
2.42M
          if (k != 0)
694
2.42M
            displacement=MaxHashTable-k;
695
2.42M
          for ( ; ; )
696
4.23M
          {
697
4.23M
            k-=displacement;
698
4.23M
            if (k < 0)
699
1.64M
              k+=MaxHashTable;
700
4.23M
            if (hash_code[k] == 0)
701
352k
              break;
702
3.88M
            if ((hash_prefix[k] == waiting_code) &&
703
2.07M
                (hash_suffix[k] == (unsigned char) index))
704
2.07M
              {
705
2.07M
                waiting_code=hash_code[k];
706
2.07M
                next_pixel=MagickTrue;
707
2.07M
                break;
708
2.07M
              }
709
3.88M
          }
710
2.42M
          if (next_pixel != MagickFalse)
711
2.07M
            continue;
712
2.42M
        }
713
2.15M
      GIFOutputCode(waiting_code);
714
2.15M
      if (free_code < MaxGIFTable)
715
2.14M
        {
716
2.14M
          hash_code[k]=(short) free_code++;
717
2.14M
          hash_prefix[k]=waiting_code;
718
2.14M
          hash_suffix[k]=(unsigned char) index;
719
2.14M
        }
720
507
      else
721
507
        {
722
          /*
723
            Fill the hash table with empty entries.
724
          */
725
2.53M
          for (k=0; k < MaxHashTable; k++)
726
2.53M
            hash_code[k]=0;
727
          /*
728
            Reset compressor and issue a clear code.
729
          */
730
507
          free_code=clear_code+2;
731
507
          GIFOutputCode(clear_code);
732
507
          number_bits=data_size;
733
507
          max_code=MaxCode(number_bits);
734
507
        }
735
2.15M
      waiting_code=(short) index;
736
2.15M
    }
737
103k
    if (image_info->interlace == NoInterlace)
738
103k
      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
103k
  }
780
  /*
781
    Flush out the buffered code.
782
  */
783
4.83k
  GIFOutputCode(waiting_code);
784
4.83k
  GIFOutputCode(end_of_information_code);
785
4.83k
  if (bits > 0)
786
4.35k
    {
787
      /*
788
        Add a character to current packet.  Maximum packet size is 255.
789
      */
790
4.35k
      packet[length++]=(unsigned char) (datum & 0xff);
791
4.35k
      if (length == 255)
792
2
        {
793
2
          (void) WriteBlobByte(image,(unsigned char) length);
794
2
          (void) WriteBlob(image,length,packet);
795
2
          length=0;
796
2
        }
797
4.35k
    }
798
  /*
799
    Flush accumulated data.
800
  */
801
4.83k
  if (length > 0)
802
4.83k
    {
803
4.83k
      (void) WriteBlobByte(image,(unsigned char) length);
804
4.83k
      (void) WriteBlob(image,length,packet);
805
4.83k
    }
806
  /*
807
    Free encoder memory.
808
  */
809
4.83k
  hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
810
4.83k
  hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
811
4.83k
  hash_code=(short *) RelinquishMagickMemory(hash_code);
812
4.83k
  packet=(unsigned char *) RelinquishMagickMemory(packet);
813
4.83k
  return(MagickTrue);
814
4.83k
}
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
118k
{
879
118k
  ssize_t
880
118k
    count;
881
882
118k
  unsigned char
883
118k
    block_count = 0;
884
885
118k
  assert(image != (Image *) NULL);
886
118k
  assert(image->signature == MagickCoreSignature);
887
118k
  assert(data != (unsigned char *) NULL);
888
118k
  count=ReadBlob(image,1,&block_count);
889
118k
  if (count != 1)
890
677
    return(0);
891
117k
  count=ReadBlob(image,(size_t) block_count,data);
892
117k
  if (count != (ssize_t) block_count)
893
490
    return(0);
894
117k
  return(count);
895
117k
}
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.28k
{
926
4.28k
  return((void *) DestroyStringInfo((StringInfo *) profile));
927
4.28k
}
928
929
static MagickBooleanType PingGIFImage(Image *image,ExceptionInfo *exception)
930
1.56k
{
931
1.56k
  unsigned char
932
1.56k
    buffer[256],
933
1.56k
    length,
934
1.56k
    data_size;
935
936
1.56k
  assert(image != (Image *) NULL);
937
1.56k
  assert(image->signature == MagickCoreSignature);
938
1.56k
  if (IsEventLogging() != MagickFalse)
939
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
940
1.56k
  if (ReadBlob(image,1,&data_size) != 1)
941
1.55k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
942
1.55k
  if (data_size > MaximumLZWBits)
943
1.37k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
944
1.37k
  if (ReadBlob(image,1,&length) != 1)
945
1.37k
    ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
946
2.79k
  while (length != 0)
947
1.92k
  {
948
1.92k
    if (ReadBlob(image,length,buffer) != (ssize_t) length)
949
1.73k
      ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
950
1.73k
    if (ReadBlob(image,1,&length) != 1)
951
1.42k
      ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
952
1.42k
  }
953
875
  return(MagickTrue);
954
1.37k
}
955
956
static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
957
7.23k
{
958
43.4k
#define BitSet(byte,bit)  (((byte) & (bit)) == (bit))
959
7.23k
#define LSBFirstOrder(x,y)  (((y) << 8) | (x))
960
7.23k
#define ThrowGIFException(exception,message) \
961
508
{ \
962
508
  if (profiles != (LinkedListInfo *) NULL) \
963
508
    profiles=DestroyLinkedList(profiles,DestroyGIFProfile); \
964
508
  if (global_colormap != (unsigned char *) NULL) \
965
508
    global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap); \
966
508
  if (meta_image != (Image *) NULL) \
967
508
    meta_image=DestroyImage(meta_image); \
968
508
  ThrowReaderException((exception),(message)); \
969
0
}
970
971
7.23k
  Image
972
7.23k
    *image,
973
7.23k
    *meta_image;
974
975
7.23k
  LinkedListInfo
976
7.23k
    *profiles;
977
978
7.23k
  MagickBooleanType
979
7.23k
    status;
980
981
7.23k
  ssize_t
982
7.23k
    i;
983
984
7.23k
  unsigned char
985
7.23k
    *p;
986
987
7.23k
  size_t
988
7.23k
    duration,
989
7.23k
    global_colors,
990
7.23k
    image_count,
991
7.23k
    local_colors,
992
7.23k
    one;
993
994
7.23k
  ssize_t
995
7.23k
    count,
996
7.23k
    opacity;
997
998
7.23k
  unsigned char
999
7.23k
    background,
1000
7.23k
    buffer[257],
1001
7.23k
    c,
1002
7.23k
    flag,
1003
7.23k
    *global_colormap;
1004
1005
  /*
1006
    Open image file.
1007
  */
1008
7.23k
  assert(image_info != (const ImageInfo *) NULL);
1009
7.23k
  assert(image_info->signature == MagickCoreSignature);
1010
7.23k
  assert(exception != (ExceptionInfo *) NULL);
1011
7.23k
  assert(exception->signature == MagickCoreSignature);
1012
7.23k
  if (IsEventLogging() != MagickFalse)
1013
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1014
0
      image_info->filename);
1015
7.23k
  image=AcquireImage(image_info,exception);
1016
7.23k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1017
7.23k
  if (status == MagickFalse)
1018
42
    {
1019
42
      image=DestroyImageList(image);
1020
42
      return((Image *) NULL);
1021
42
    }
1022
  /*
1023
    Determine if this a GIF file.
1024
  */
1025
7.19k
  count=ReadBlob(image,6,buffer);
1026
7.19k
  if ((count != 6) || ((LocaleNCompare((char *) buffer,"GIF87",5) != 0) &&
1027
5.69k
      (LocaleNCompare((char *) buffer,"GIF89",5) != 0)))
1028
7.11k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1029
7.11k
  (void) memset(buffer,0,sizeof(buffer));
1030
7.11k
  meta_image=AcquireImage(image_info,exception);  /* metadata container */
1031
7.11k
  meta_image->page.width=ReadBlobLSBShort(image);
1032
7.11k
  meta_image->page.height=ReadBlobLSBShort(image);
1033
7.11k
  meta_image->iterations=1;
1034
7.11k
  flag=(unsigned char) ReadBlobByte(image);
1035
7.11k
  profiles=(LinkedListInfo *) NULL;
1036
7.11k
  background=(unsigned char) ReadBlobByte(image);
1037
7.11k
  c=(unsigned char) ReadBlobByte(image);  /* reserved */
1038
7.11k
  one=1;
1039
7.11k
  global_colors=one << (((size_t) flag & 0x07)+1);
1040
7.11k
  global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1041
7.11k
    MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
1042
7.11k
  if (global_colormap == (unsigned char *) NULL)
1043
7.11k
    ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
1044
7.11k
  (void) memset(global_colormap,0,3*MagickMax(global_colors,256)*
1045
7.11k
    sizeof(*global_colormap));
1046
7.11k
  if (BitSet((int) flag,0x80) != 0)
1047
360
    {
1048
360
      count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
1049
360
      if (count != (ssize_t) (3*global_colors))
1050
340
        ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
1051
340
    }
1052
7.09k
  duration=0;
1053
7.09k
  opacity=(-1);
1054
7.09k
  image_count=0;
1055
7.09k
  for ( ; ; )
1056
199k
  {
1057
199k
    count=ReadBlob(image,1,&c);
1058
199k
    if (count != 1)
1059
6.17k
      break;
1060
193k
    if (c == (unsigned char) ';')
1061
267
      break;  /* terminator */
1062
193k
    if (c == (unsigned char) '!')
1063
33.6k
      {
1064
        /*
1065
          GIF Extension block.
1066
        */
1067
33.6k
        (void) memset(buffer,0,sizeof(buffer));
1068
33.6k
        count=ReadBlob(image,1,&c);
1069
33.6k
        if (count != 1)
1070
33.6k
          ThrowGIFException(CorruptImageError,"UnableToReadExtensionBlock");
1071
33.6k
        switch (c)
1072
33.6k
        {
1073
1.37k
          case 0xf9:
1074
1.37k
          {
1075
            /*
1076
              Read graphics control extension.
1077
            */
1078
2.82k
            while (ReadBlobBlock(image,buffer) != 0) ;
1079
1.37k
            meta_image->dispose=(DisposeType) ((buffer[0] >> 2) & 0x07);
1080
1.37k
            meta_image->delay=((size_t) buffer[2] << 8) | buffer[1];
1081
1.37k
            if ((ssize_t) (buffer[0] & 0x01) == 0x01)
1082
627
              opacity=(ssize_t) buffer[3];
1083
1.37k
            break;
1084
0
          }
1085
2.54k
          case 0xfe:
1086
2.54k
          {
1087
2.54k
            char
1088
2.54k
              *comments;
1089
1090
2.54k
            size_t
1091
2.54k
              extent,
1092
2.54k
              offset;
1093
1094
2.54k
            comments=AcquireString((char *) NULL);
1095
2.54k
            extent=MagickPathExtent;
1096
4.05k
            for (offset=0; ; offset+=(size_t) count)
1097
6.59k
            {
1098
6.59k
              count=ReadBlobBlock(image,buffer);
1099
6.59k
              if (count == 0)
1100
2.54k
                break;
1101
4.05k
              buffer[count]='\0';
1102
4.05k
              if ((count+(ssize_t) offset+MagickPathExtent) >= (ssize_t) extent)
1103
702
                {
1104
702
                  extent<<=1;
1105
702
                  comments=(char *) ResizeQuantumMemory(comments,
1106
702
                    OverAllocateMemory(extent+MagickPathExtent),
1107
702
                    sizeof(*comments));
1108
702
                  if (comments == (char *) NULL)
1109
0
                    ThrowGIFException(ResourceLimitError,
1110
702
                      "MemoryAllocationFailed");
1111
702
                }
1112
4.05k
              (void) CopyMagickString(&comments[offset],(char *) buffer,extent-
1113
4.05k
                offset);
1114
4.05k
            }
1115
2.54k
            (void) SetImageProperty(meta_image,"comment",comments,exception);
1116
2.54k
            comments=DestroyString(comments);
1117
2.54k
            break;
1118
2.54k
          }
1119
28.7k
          case 0xff:
1120
28.7k
          {
1121
28.7k
            MagickBooleanType
1122
28.7k
              loop;
1123
1124
            /*
1125
              Read Netscape Loop extension.
1126
            */
1127
28.7k
            loop=MagickFalse;
1128
28.7k
            if (ReadBlobBlock(image,buffer) != 0)
1129
23.4k
              loop=LocaleNCompare((char *) buffer,"NETSCAPE2.0",11) == 0 ?
1130
22.9k
                MagickTrue : MagickFalse;
1131
28.7k
            if (loop != MagickFalse)
1132
1.74k
              while (ReadBlobBlock(image,buffer) != 0)
1133
1.26k
              {
1134
1.26k
                meta_image->iterations=((size_t) buffer[2] << 8) | buffer[1];
1135
1.26k
                if (meta_image->iterations != 0)
1136
853
                  meta_image->iterations++;
1137
1.26k
              }
1138
28.3k
            else
1139
28.3k
              {
1140
28.3k
                char
1141
28.3k
                  name[MagickPathExtent];
1142
1143
28.3k
                int
1144
28.3k
                  block_length,
1145
28.3k
                  info_length,
1146
28.3k
                  reserved_length;
1147
1148
28.3k
                MagickBooleanType
1149
28.3k
                  magick = MagickFalse;
1150
1151
28.3k
                unsigned char
1152
28.3k
                  *info;
1153
1154
                /*
1155
                  Store GIF application extension as a generic profile.
1156
                */
1157
28.3k
                if (LocaleNCompare((char *) buffer,"ImageMagick",11) == 0)
1158
814
                  magick=MagickTrue;
1159
27.4k
                else if (LocaleNCompare((char *) buffer,"ICCRGBG1012",11) == 0)
1160
8.24k
                  (void) CopyMagickString(name,"icc",sizeof(name));
1161
19.2k
                else if (LocaleNCompare((char *) buffer,"MGK8BIM0000",11) == 0)
1162
11.0k
                  (void) CopyMagickString(name,"8bim",sizeof(name));
1163
8.18k
                else if (LocaleNCompare((char *) buffer,"MGKIPTC0000",11) == 0)
1164
805
                  (void) CopyMagickString(name,"iptc",sizeof(name));
1165
7.38k
                else
1166
7.38k
                  (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
1167
7.38k
                    buffer);
1168
28.3k
                reserved_length=255;
1169
28.3k
                info=(unsigned char *) AcquireQuantumMemory((size_t)
1170
28.3k
                  reserved_length,sizeof(*info));
1171
28.3k
                if (info == (unsigned char *) NULL)
1172
0
                  ThrowGIFException(ResourceLimitError,
1173
28.3k
                    "MemoryAllocationFailed");
1174
28.3k
                (void) memset(info,0,(size_t) reserved_length*sizeof(*info));
1175
28.3k
                for (info_length=0; ; )
1176
64.8k
                {
1177
64.8k
                  block_length=(int) ReadBlobBlock(image,info+info_length);
1178
64.8k
                  if (block_length == 0)
1179
28.3k
                    break;
1180
36.5k
                  info_length+=block_length;
1181
36.5k
                  if (info_length > (reserved_length-255))
1182
22.5k
                    {
1183
22.5k
                      reserved_length+=4096;
1184
22.5k
                      info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
1185
22.5k
                        reserved_length,sizeof(*info));
1186
22.5k
                      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.5k
                    }
1193
36.5k
                }
1194
28.3k
                if (magick != MagickFalse)
1195
814
                  meta_image->gamma=StringToDouble((char *) info+6,
1196
814
                      (char **) NULL);
1197
27.4k
                else
1198
27.4k
                  {
1199
27.4k
                    StringInfo
1200
27.4k
                      *profile;
1201
1202
27.4k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1203
27.4k
                      "      profile name=%s",name);
1204
27.4k
                    profile=BlobToProfileStringInfo(name,info,(size_t) info_length,
1205
27.4k
                      exception);
1206
27.4k
                    if (profile != (StringInfo *) NULL)
1207
27.4k
                      {
1208
27.4k
                        if (profiles == (LinkedListInfo *) NULL)
1209
9.95k
                          profiles=NewLinkedList(0);
1210
27.4k
                        (void) AppendValueToLinkedList(profiles,profile);
1211
27.4k
                      }
1212
27.4k
                  }
1213
28.3k
                info=(unsigned char *) RelinquishMagickMemory(info);
1214
28.3k
              }
1215
28.7k
            break;
1216
28.7k
          }
1217
28.7k
          default:
1218
932
          {
1219
1.55k
            while (ReadBlobBlock(image,buffer) != 0) ;
1220
932
            break;
1221
28.7k
          }
1222
33.6k
        }
1223
33.6k
      }
1224
193k
    if (c != (unsigned char) ',')
1225
181k
      continue;
1226
12.1k
    image_count++;
1227
12.1k
    if (image_count != 1)
1228
5.59k
      {
1229
        /*
1230
          Allocate next image structure.
1231
        */
1232
5.59k
        AcquireNextImage(image_info,image,exception);
1233
5.59k
        if (GetNextImageInList(image) == (Image *) NULL)
1234
0
          {
1235
0
            status=MagickFalse;
1236
0
            break;
1237
0
          }
1238
5.59k
        image=SyncNextImageInList(image);
1239
5.59k
      }
1240
    /*
1241
      Read image attributes.
1242
    */
1243
12.1k
    meta_image->page.x=(ssize_t) ReadBlobLSBShort(image);
1244
12.1k
    meta_image->page.y=(ssize_t) ReadBlobLSBShort(image);
1245
12.1k
    meta_image->scene=image->scene;
1246
12.1k
    (void) CloneImageProperties(image,meta_image);
1247
12.1k
    DestroyImageProperties(meta_image);
1248
12.1k
    image->storage_class=PseudoClass;
1249
12.1k
    image->compression=LZWCompression;
1250
12.1k
    image->columns=ReadBlobLSBShort(image);
1251
12.1k
    image->rows=ReadBlobLSBShort(image);
1252
12.1k
    image->depth=8;
1253
12.1k
    flag=(unsigned char) ReadBlobByte(image);
1254
12.1k
    image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace : NoInterlace;
1255
12.1k
    local_colors=BitSet((int) flag,0x80) == 0 ? global_colors : one <<
1256
300
      ((size_t) (flag & 0x07)+1);
1257
12.1k
    image->colors=local_colors;
1258
12.1k
    if (opacity == (ssize_t) image->colors)
1259
85
      image->colors++;
1260
12.0k
    else if (opacity > (ssize_t) image->colors)
1261
57
      opacity=(-1);
1262
12.1k
    image->ticks_per_second=100;
1263
12.1k
    image->alpha_trait=opacity >= 0 ? BlendPixelTrait : UndefinedPixelTrait;
1264
12.1k
    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.8k
      {
1273
        /*
1274
          Use global colormap.
1275
        */
1276
11.8k
        p=global_colormap;
1277
368k
        for (i=0; i < (ssize_t) image->colors; i++)
1278
356k
        {
1279
356k
          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1280
356k
          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1281
356k
          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1282
356k
          if (i == opacity)
1283
198
            {
1284
198
              image->colormap[i].alpha=(double) TransparentAlpha;
1285
198
              image->transparent_color=image->colormap[opacity];
1286
198
            }
1287
356k
        }
1288
11.8k
        if (image->colors > 0)
1289
11.8k
          image->background_color=image->colormap[MagickMin((ssize_t)
1290
11.8k
            background,(ssize_t) image->colors-1)];
1291
11.8k
      }
1292
221
    else
1293
221
      {
1294
221
        unsigned char
1295
221
          *colormap;
1296
1297
        /*
1298
          Read local colormap.
1299
        */
1300
221
        colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1301
221
          MagickMax(local_colors,256),3UL*sizeof(*colormap));
1302
221
        if (colormap == (unsigned char *) NULL)
1303
221
          ThrowGIFException(ResourceLimitError,"MemoryAllocationFailed");
1304
221
        (void) memset(colormap,0,3*MagickMax(local_colors,256)*
1305
221
          sizeof(*colormap));
1306
221
        count=ReadBlob(image,(3*local_colors)*sizeof(*colormap),colormap);
1307
221
        if (count != (ssize_t) (3*local_colors))
1308
40
          {
1309
40
            colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1310
40
            ThrowGIFException(CorruptImageError,"InsufficientImageDataInFile");
1311
0
          }
1312
181
        p=colormap;
1313
2.23k
        for (i=0; i < (ssize_t) image->colors; i++)
1314
2.05k
        {
1315
2.05k
          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
1316
2.05k
          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
1317
2.05k
          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
1318
2.05k
          if (i == opacity)
1319
57
            image->colormap[i].alpha=(double) TransparentAlpha;
1320
2.05k
        }
1321
181
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1322
181
      }
1323
12.0k
    if (image->gamma == 1.0)
1324
198
      {
1325
3.08k
        for (i=0; i < (ssize_t) image->colors; i++)
1326
2.98k
          if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
1327
101
            break;
1328
198
        (void) SetImageColorspace(image,i == (ssize_t) image->colors ?
1329
101
          GRAYColorspace : RGBColorspace,exception);
1330
198
      }
1331
12.0k
    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
12.0k
    status=SetImageExtent(image,image->columns,image->rows,exception);
1335
12.0k
    if (status == MagickFalse)
1336
161
      {
1337
161
        if (profiles != (LinkedListInfo *) NULL)
1338
9
          profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
1339
161
        global_colormap=(unsigned char *) RelinquishMagickMemory(
1340
161
          global_colormap);
1341
161
        meta_image=DestroyImage(meta_image);
1342
161
        return(DestroyImageList(image));
1343
161
      }
1344
    /*
1345
      Decode image.
1346
    */
1347
11.8k
    if (image_info->ping != MagickFalse)
1348
1.56k
      status=PingGIFImage(image,exception);
1349
10.2k
    else
1350
10.2k
      status=DecodeImage(image,opacity,exception);
1351
11.8k
    if ((image_info->ping == MagickFalse) && (status == MagickFalse))
1352
11.5k
      ThrowGIFException(CorruptImageError,"CorruptImage");
1353
11.5k
    if (profiles != (LinkedListInfo *) NULL)
1354
9.39k
      {
1355
9.39k
        StringInfo
1356
9.39k
          *profile;
1357
1358
        /*
1359
          Set image profiles.
1360
        */
1361
9.39k
        ResetLinkedListIterator(profiles);
1362
9.39k
        profile=(StringInfo *) GetNextValueInLinkedList(profiles);
1363
32.6k
        while (profile != (StringInfo *) NULL)
1364
23.2k
        {
1365
23.2k
          (void) SetImageProfilePrivate(image,profile,exception);
1366
23.2k
          profile=(StringInfo *) GetNextValueInLinkedList(profiles);
1367
23.2k
        }
1368
9.39k
        profiles=DestroyLinkedList(profiles,(void *(*)(void *)) NULL);
1369
9.39k
      }
1370
11.5k
    duration+=image->delay*image->iterations;
1371
11.5k
    if (image_info->number_scenes != 0)
1372
174
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1373
1
        break;
1374
11.5k
    opacity=(-1);
1375
11.5k
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1376
11.5k
      image->scene-1,image->scene);
1377
11.5k
    if (status == MagickFalse)
1378
0
      break;
1379
11.5k
  }
1380
6.44k
  image->duration=duration;
1381
6.44k
  if (profiles != (LinkedListInfo *) NULL)
1382
538
    profiles=DestroyLinkedList(profiles,DestroyGIFProfile);
1383
6.44k
  meta_image=DestroyImage(meta_image);
1384
6.44k
  global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1385
6.44k
  if ((image->columns == 0) || (image->rows == 0))
1386
5.90k
    ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1387
5.90k
  if (CloseBlob(image) == MagickFalse)
1388
0
    status=MagickFalse;
1389
5.90k
  if (status == MagickFalse)
1390
0
    return(DestroyImageList(image));
1391
5.90k
  return(GetFirstImageInList(image));
1392
5.90k
}
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.83k
{
1497
4.83k
  ImageInfo
1498
4.83k
    *write_info;
1499
1500
4.83k
  int
1501
4.83k
    c;
1502
1503
4.83k
  MagickBooleanType
1504
4.83k
    status;
1505
1506
4.83k
  MagickOffsetType
1507
4.83k
    scene;
1508
1509
4.83k
  RectangleInfo
1510
4.83k
    page;
1511
1512
4.83k
  size_t
1513
4.83k
    bits_per_pixel,
1514
4.83k
    delay,
1515
4.83k
    length,
1516
4.83k
    number_scenes,
1517
4.83k
    one;
1518
1519
4.83k
  ssize_t
1520
4.83k
    i,
1521
4.83k
    j,
1522
4.83k
    opacity;
1523
1524
4.83k
  unsigned char
1525
4.83k
    *colormap,
1526
4.83k
    *global_colormap,
1527
4.83k
    *q;
1528
1529
  /*
1530
    Open output image file.
1531
  */
1532
4.83k
  assert(image_info != (const ImageInfo *) NULL);
1533
4.83k
  assert(image_info->signature == MagickCoreSignature);
1534
4.83k
  assert(image != (Image *) NULL);
1535
4.83k
  assert(image->signature == MagickCoreSignature);
1536
4.83k
  assert(exception != (ExceptionInfo *) NULL);
1537
4.83k
  assert(exception->signature == MagickCoreSignature);
1538
4.83k
  if (IsEventLogging() != MagickFalse)
1539
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1540
4.83k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1541
4.83k
  if (status == MagickFalse)
1542
0
    return(status);
1543
  /*
1544
    Allocate colormap.
1545
  */
1546
4.83k
  global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
1547
4.83k
    sizeof(*global_colormap));
1548
4.83k
  colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
1549
4.83k
  if ((global_colormap == (unsigned char *) NULL) ||
1550
4.83k
      (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.71M
  for (i=0; i < 768; i++)
1560
3.71M
    colormap[i]=(unsigned char) 0;
1561
  /*
1562
    Write GIF header.
1563
  */
1564
4.83k
  write_info=CloneImageInfo(image_info);
1565
4.83k
  if (LocaleCompare(write_info->magick,"GIF87") != 0)
1566
4.83k
    (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.83k
  page.width=image->columns;
1576
4.83k
  if (image->page.width > page.width)
1577
4.19k
    page.width=image->page.width;
1578
4.83k
  page.height=image->rows;
1579
4.83k
  if (image->page.height > page.height)
1580
3.80k
    page.height=image->page.height;
1581
4.83k
  page.x=image->page.x;
1582
4.83k
  page.y=image->page.y;
1583
4.83k
  (void) WriteBlobLSBShort(image,(unsigned short) page.width);
1584
4.83k
  (void) WriteBlobLSBShort(image,(unsigned short) page.height);
1585
  /*
1586
    Write images to file.
1587
  */
1588
4.83k
  scene=0;
1589
4.83k
  one=1;
1590
4.83k
  number_scenes=GetImageListLength(image);
1591
4.83k
  do
1592
4.83k
  {
1593
4.83k
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1594
0
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
1595
4.83k
    opacity=(-1);
1596
4.83k
    if (IsImageOpaque(image,exception) != MagickFalse)
1597
4.79k
      {
1598
4.79k
        if ((image->storage_class == DirectClass) || (image->colors > 256))
1599
0
          (void) SetImageType(image,PaletteType,exception);
1600
4.79k
      }
1601
38
    else
1602
38
      {
1603
38
        double
1604
38
          alpha,
1605
38
          beta;
1606
1607
        /*
1608
          Identify transparent colormap index.
1609
        */
1610
38
        if ((image->storage_class == DirectClass) || (image->colors > 256))
1611
0
          (void) SetImageType(image,PaletteBilevelAlphaType,exception);
1612
4.08k
        for (i=0; i < (ssize_t) image->colors; i++)
1613
4.04k
          if (image->colormap[i].alpha != (double) OpaqueAlpha)
1614
38
            {
1615
38
              if (opacity < 0)
1616
38
                {
1617
38
                  opacity=i;
1618
38
                  continue;
1619
38
                }
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
38
        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
38
        if (opacity >= 0)
1646
38
          {
1647
38
            image->colormap[opacity].red=image->transparent_color.red;
1648
38
            image->colormap[opacity].green=image->transparent_color.green;
1649
38
            image->colormap[opacity].blue=image->transparent_color.blue;
1650
38
          }
1651
38
      }
1652
4.83k
    if ((image->storage_class == DirectClass) || (image->colors > 256))
1653
4.83k
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1654
13.9k
    for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1655
13.6k
      if ((one << bits_per_pixel) >= image->colors)
1656
4.49k
        break;
1657
4.83k
    q=colormap;
1658
172k
    for (i=0; i < (ssize_t) image->colors; i++)
1659
167k
    {
1660
167k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1661
167k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1662
167k
      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1663
167k
    }
1664
5.20k
    for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
1665
374
    {
1666
374
      *q++=(unsigned char) 0x0;
1667
374
      *q++=(unsigned char) 0x0;
1668
374
      *q++=(unsigned char) 0x0;
1669
374
    }
1670
4.83k
    if ((GetPreviousImageInList(image) == (Image *) NULL) ||
1671
0
        (write_info->adjoin == MagickFalse))
1672
4.83k
      {
1673
        /*
1674
          Write global colormap.
1675
        */
1676
4.83k
        c=0x80;
1677
4.83k
        c|=(8-1) << 4;  /* color resolution */
1678
4.83k
        c|=(int) (bits_per_pixel-1);   /* size of global colormap */
1679
4.83k
        (void) WriteBlobByte(image,(unsigned char) c);
1680
8.01k
        for (j=0; j < (ssize_t) image->colors; j++)
1681
8.01k
          if (IsPixelInfoEquivalent(&image->background_color,image->colormap+j))
1682
4.82k
            break;
1683
4.83k
        (void) WriteBlobByte(image,(unsigned char)
1684
4.83k
          (j == (ssize_t) image->colors ? 0 : j));  /* background color */
1685
4.83k
        (void) WriteBlobByte(image,(unsigned char) 0x00);  /* reserved */
1686
4.83k
        length=(size_t) (3*(one << bits_per_pixel));
1687
4.83k
        (void) WriteBlob(image,length,colormap);
1688
3.71M
        for (j=0; j < 768; j++)
1689
3.71M
          global_colormap[j]=colormap[j];
1690
4.83k
      }
1691
4.83k
    if (LocaleCompare(write_info->magick,"GIF87") != 0)
1692
4.83k
      {
1693
4.83k
        const char
1694
4.83k
          *value;
1695
1696
4.83k
        if ((GetPreviousImageInList(image) == (Image *) NULL) &&
1697
4.83k
            (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.83k
        (void) WriteBlobByte(image,(unsigned char) 0x21);
1719
4.83k
        (void) WriteBlobByte(image,(unsigned char) 0xf9);
1720
4.83k
        (void) WriteBlobByte(image,(unsigned char) 0x04);
1721
4.83k
        c=(int) (image->dispose << 2);
1722
4.83k
        if (opacity >= 0)
1723
38
          c|=0x01;
1724
4.83k
        (void) WriteBlobByte(image,(unsigned char) c);
1725
4.83k
        delay=(size_t) (100*image->delay/MagickMax((size_t)
1726
4.83k
          image->ticks_per_second,1));
1727
4.83k
        (void) WriteBlobLSBShort(image,(unsigned short) delay);
1728
4.83k
        (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
1729
4.83k
          0));
1730
4.83k
        (void) WriteBlobByte(image,(unsigned char) 0x00);
1731
4.83k
        if (fabs(image->gamma-1.0/2.2) > MagickEpsilon)
1732
3
          {
1733
3
            char
1734
3
              attributes[MagickPathExtent];
1735
1736
3
            ssize_t
1737
3
              count;
1738
1739
            /*
1740
              Write ImageMagick extension.
1741
            */
1742
3
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1743
3
               "  Writing GIF Extension %s","ImageMagick");
1744
3
            (void) WriteBlobByte(image,(unsigned char) 0x21);
1745
3
            (void) WriteBlobByte(image,(unsigned char) 0xff);
1746
3
            (void) WriteBlobByte(image,(unsigned char) 0x0b);
1747
3
            (void) WriteBlob(image,11,(unsigned char *) "ImageMagick");
1748
3
            count=FormatLocaleString(attributes,MagickPathExtent,"gamma=%g",
1749
3
              image->gamma);
1750
3
            (void) WriteBlobByte(image,(unsigned char) count);
1751
3
            (void) WriteBlob(image,(size_t) count,(unsigned char *) attributes);
1752
3
            (void) WriteBlobByte(image,(unsigned char) 0x00);
1753
3
          }
1754
4.83k
        value=GetImageProperty(image,"comment",exception);
1755
4.83k
        if (value != (const char *) NULL)
1756
92
          {
1757
92
            const char
1758
92
              *p;
1759
1760
92
            size_t
1761
92
              count;
1762
1763
            /*
1764
              Write comment extension.
1765
            */
1766
92
            (void) WriteBlobByte(image,(unsigned char) 0x21);
1767
92
            (void) WriteBlobByte(image,(unsigned char) 0xfe);
1768
237
            for (p=value; *p != '\0'; )
1769
145
            {
1770
145
              count=MagickMin(strlen(p),255);
1771
145
              (void) WriteBlobByte(image,(unsigned char) count);
1772
30.2k
              for (i=0; i < (ssize_t) count; i++)
1773
30.1k
                (void) WriteBlobByte(image,(unsigned char) *p++);
1774
145
            }
1775
92
            (void) WriteBlobByte(image,(unsigned char) 0x00);
1776
92
          }
1777
4.83k
        ResetImageProfileIterator(image);
1778
4.83k
        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.83k
            break;
1789
6.94k
          profile=GetImageProfile(image,name);
1790
6.94k
          if (profile != (StringInfo *) NULL)
1791
6.94k
          {
1792
6.94k
            if ((LocaleCompare(name,"ICC") == 0) ||
1793
5.26k
                (LocaleCompare(name,"ICM") == 0) ||
1794
5.26k
                (LocaleCompare(name,"IPTC") == 0) ||
1795
5.23k
                (LocaleCompare(name,"8BIM") == 0) ||
1796
2.64k
                (LocaleNCompare(name,"gif:",4) == 0))
1797
4.85k
            {
1798
4.85k
               ssize_t
1799
4.85k
                 offset;
1800
1801
4.85k
               unsigned char
1802
4.85k
                 *datum;
1803
1804
4.85k
               datum=GetStringInfoDatum(profile);
1805
4.85k
               length=GetStringInfoLength(profile);
1806
4.85k
               (void) WriteBlobByte(image,(unsigned char) 0x21);
1807
4.85k
               (void) WriteBlobByte(image,(unsigned char) 0xff);
1808
4.85k
               (void) WriteBlobByte(image,(unsigned char) 0x0b);
1809
4.85k
               if ((LocaleCompare(name,"ICC") == 0) ||
1810
3.18k
                   (LocaleCompare(name,"ICM") == 0))
1811
1.67k
                 {
1812
                   /*
1813
                     Write ICC extension.
1814
                   */
1815
1.67k
                   (void) WriteBlob(image,11,(unsigned char *) "ICCRGBG1012");
1816
1.67k
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1817
1.67k
                     "  Writing GIF Extension %s","ICCRGBG1012");
1818
1.67k
                 }
1819
3.18k
               else
1820
3.18k
                 if ((LocaleCompare(name,"IPTC") == 0))
1821
36
                   {
1822
                     /*
1823
                       Write IPTC extension.
1824
                     */
1825
36
                     (void) WriteBlob(image,11,(unsigned char *) "MGKIPTC0000");
1826
36
                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1827
36
                       "  Writing GIF Extension %s","MGKIPTC0000");
1828
36
                   }
1829
3.14k
                 else
1830
3.14k
                   if ((LocaleCompare(name,"8BIM") == 0))
1831
2.58k
                     {
1832
                       /*
1833
                         Write 8BIM extension.
1834
                       */
1835
2.58k
                        (void) WriteBlob(image,11,(unsigned char *)
1836
2.58k
                          "MGK8BIM0000");
1837
2.58k
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1838
2.58k
                          "  Writing GIF Extension %s","MGK8BIM0000");
1839
2.58k
                     }
1840
559
                   else
1841
559
                     {
1842
559
                       char
1843
559
                         extension[MagickPathExtent];
1844
1845
                       /*
1846
                         Write generic extension.
1847
                       */
1848
559
                       (void) memset(extension,0,sizeof(extension));
1849
559
                       (void) CopyMagickString(extension,name+4,
1850
559
                         sizeof(extension));
1851
559
                       (void) WriteBlob(image,11,(unsigned char *) extension);
1852
559
                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1853
559
                         "  Writing GIF Extension %s",name);
1854
559
                     }
1855
4.85k
               offset=0;
1856
12.1k
               while ((ssize_t) length > offset)
1857
7.31k
               {
1858
7.31k
                 size_t
1859
7.31k
                   block_length;
1860
1861
7.31k
                 if (((ssize_t) length-offset) < 255)
1862
4.83k
                   block_length=(size_t) ((ssize_t) length-offset);
1863
2.48k
                 else
1864
2.48k
                   block_length=255;
1865
7.31k
                 (void) WriteBlobByte(image,(unsigned char) block_length);
1866
7.31k
                 (void) WriteBlob(image,(size_t) block_length,datum+offset);
1867
7.31k
                 offset+=(ssize_t) block_length;
1868
7.31k
               }
1869
4.85k
               (void) WriteBlobByte(image,(unsigned char) 0x00);
1870
4.85k
            }
1871
6.94k
          }
1872
6.94k
        }
1873
4.83k
      }
1874
4.83k
    (void) WriteBlobByte(image,',');  /* image separator */
1875
    /*
1876
      Write the image header.
1877
    */
1878
4.83k
    page.x=image->page.x;
1879
4.83k
    page.y=image->page.y;
1880
4.83k
    if ((image->page.width != 0) && (image->page.height != 0))
1881
4.83k
      page=image->page;
1882
4.83k
    (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
1883
4.83k
    (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
1884
4.83k
    (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
1885
4.83k
    (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
1886
4.83k
    c=0x00;
1887
4.83k
    if (write_info->interlace != NoInterlace)
1888
0
      c|=0x40;  /* pixel data is interlaced */
1889
507k
    for (j=0; j < (ssize_t) (3*image->colors); j++)
1890
502k
      if (colormap[j] != global_colormap[j])
1891
0
        break;
1892
4.83k
    if (j == (ssize_t) (3*image->colors))
1893
4.83k
      (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.83k
    c=(int) MagickMax(bits_per_pixel,2);
1906
4.83k
    (void) WriteBlobByte(image,(unsigned char) c);
1907
4.83k
    status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1,
1908
4.83k
      exception);
1909
4.83k
    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.83k
    (void) WriteBlobByte(image,(unsigned char) 0x00);
1918
4.83k
    if (GetNextImageInList(image) == (Image *) NULL)
1919
4.83k
      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.83k
  (void) WriteBlobByte(image,';'); /* terminator */
1927
4.83k
  global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1928
4.83k
  colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1929
4.83k
  write_info=DestroyImageInfo(write_info);
1930
4.83k
  if (CloseBlob(image) == MagickFalse)
1931
0
    status=MagickFalse;
1932
4.83k
  return(status);
1933
4.83k
}