~ubuntu-branches/ubuntu/intrepid/graphicsmagick/intrepid

« back to all changes in this revision

Viewing changes to coders/gif.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2006-05-06 16:28:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060506162808-vt2ni3r5nytcszms
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
% Copyright (C) 2003 GraphicsMagick Group
 
3
% Copyright (C) 2002 ImageMagick Studio
 
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
 
5
%
 
6
% This program is covered by multiple licenses, which are described in
 
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
 
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
 
9
%
 
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
11
%                                                                             %
 
12
%                                                                             %
 
13
%                                                                             %
 
14
%                             GGGG  IIIII  FFFFF                              %
 
15
%                            G        I    F                                  %
 
16
%                            G  GG    I    FFF                                %
 
17
%                            G   G    I    F                                  %
 
18
%                             GGG   IIIII  F                                  %
 
19
%                                                                             %
 
20
%                                                                             %
 
21
%            Read/Write Compuserv Graphics Interchange Format.                %
 
22
%                                                                             %
 
23
%                                                                             %
 
24
%                              Software Design                                %
 
25
%                                John Cristy                                  %
 
26
%                                 July 1992                                   %
 
27
%                                                                             %
 
28
%                                                                             %
 
29
%                                                                             %
 
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
31
%
 
32
%
 
33
*/
 
34
 
 
35
/*
 
36
  Include declarations.
 
37
*/
 
38
#include "magick/studio.h"
 
39
#include "magick/attribute.h"
 
40
#include "magick/blob.h"
 
41
#include "magick/cache.h"
 
42
#include "magick/color.h"
 
43
#include "magick/magick.h"
 
44
#include "magick/monitor.h"
 
45
#include "magick/quantize.h"
 
46
#include "magick/utility.h"
 
47
 
 
48
/*
 
49
  Forward declarations.
 
50
*/
 
51
static size_t
 
52
  ReadBlobBlock(Image *,unsigned char *);
 
53
 
 
54
static unsigned int
 
55
  WriteGIFImage(const ImageInfo *,Image *);
 
56
 
 
57
/*
 
58
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
59
%                                                                             %
 
60
%                                                                             %
 
61
%                                                                             %
 
62
%   D e c o d e I m a g e                                                     %
 
63
%                                                                             %
 
64
%                                                                             %
 
65
%                                                                             %
 
66
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
67
%
 
68
%  Method DecodeImage uncompresses an image via GIF-coding.
 
69
%
 
70
%  The format of the DecodeImage method is:
 
71
%
 
72
%      MagickPassFail DecodeImage(Image *image,const long opacity)
 
73
%
 
74
%  A description of each parameter follows:
 
75
%
 
76
%    o status:  Method DecodeImage returns MagickPass if all the pixels are
 
77
%      uncompressed without error, otherwise MagickFail.
 
78
%
 
79
%    o image: The address of a structure of type Image.
 
80
%
 
81
%    o opacity:  The colormap index associated with the transparent
 
82
%      color.
 
83
%
 
84
%
 
85
*/
 
86
#define MaxStackSize  4096
 
87
#define NullCode  (-1)
 
88
static MagickPassFail DecodeImage(Image *image,const long opacity)
 
89
{
 
90
  int
 
91
    bits,
 
92
    code_size,
 
93
    offset,
 
94
    pass;
 
95
 
 
96
  long
 
97
    available,
 
98
    clear,
 
99
    code,
 
100
    code_mask,
 
101
    end_of_information,
 
102
    in_code,
 
103
    old_code,
 
104
    y;
 
105
 
 
106
  register IndexPacket
 
107
    *indexes;
 
108
 
 
109
  register long
 
110
    x;
 
111
 
 
112
  register PixelPacket
 
113
    *q;
 
114
 
 
115
  register unsigned char
 
116
    *c;
 
117
 
 
118
  register unsigned long
 
119
    datum;
 
120
 
 
121
  size_t
 
122
    count;
 
123
 
 
124
  short
 
125
    *prefix;
 
126
 
 
127
  unsigned char
 
128
    data_size,
 
129
    first,
 
130
    index,
 
131
    *packet,
 
132
    *pixel_stack,
 
133
    *suffix,
 
134
    *top_stack;
 
135
 
 
136
  MagickPassFail
 
137
    status=MagickPass;
 
138
 
 
139
  assert(image != (Image *) NULL);
 
140
 
 
141
  data_size=ReadBlobByte(image);
 
142
  if (data_size > 8U)
 
143
    ThrowBinaryException(CorruptImageError,CorruptImage,image->filename);
 
144
  /*
 
145
    Allocate decoder tables.
 
146
  */
 
147
  packet=MagickAllocateMemory(unsigned char *,256);
 
148
  prefix=MagickAllocateMemory(short *,MaxStackSize*sizeof(short));
 
149
  suffix=MagickAllocateMemory(unsigned char *,MaxStackSize);
 
150
  pixel_stack=MagickAllocateMemory(unsigned char *,MaxStackSize+1);
 
151
  if ((packet == (unsigned char *) NULL) ||
 
152
      (prefix == (short *) NULL) ||
 
153
      (suffix == (unsigned char *) NULL) ||
 
154
      (pixel_stack == (unsigned char *) NULL))
 
155
    {
 
156
      MagickFreeMemory(pixel_stack);
 
157
      MagickFreeMemory(suffix);
 
158
      MagickFreeMemory(prefix);
 
159
      MagickFreeMemory(packet);
 
160
      ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
 
161
                           image->filename);
 
162
    }
 
163
  /*
 
164
    Initialize GIF data stream decoder.
 
165
  */
 
166
  clear=1 << data_size;
 
167
  end_of_information=clear+1;
 
168
  available=clear+2;
 
169
  old_code=NullCode;
 
170
  code_size=data_size+1;
 
171
  code_mask=(1 << code_size)-1;
 
172
  for (code=0; code < clear; code++)
 
173
  {
 
174
    prefix[code]=0;
 
175
    suffix[code]=(unsigned char) code;
 
176
  }
 
177
  /*
 
178
    Decode GIF pixel stream.
 
179
  */
 
180
  datum=0;
 
181
  bits=0;
 
182
  c=0;
 
183
  count=0;
 
184
  first=0;
 
185
  offset=0;
 
186
  pass=0;
 
187
  top_stack=pixel_stack;
 
188
  for (y=0; y < (long) image->rows; y++)
 
189
  {
 
190
    q=SetImagePixels(image,0,offset,image->columns,1);
 
191
    if (q == (PixelPacket *) NULL)
 
192
      {
 
193
        status=MagickFail;
 
194
        break;
 
195
      }
 
196
    indexes=GetIndexes(image);
 
197
    for (x=0; x < (long) image->columns; )
 
198
    {
 
199
      if (top_stack == pixel_stack)
 
200
        {
 
201
          if (bits < code_size)
 
202
            {
 
203
              /*
 
204
                Load bytes until there is enough bits for a code.
 
205
              */
 
206
              if (count == 0)
 
207
                {
 
208
                  /*
 
209
                    Read a new data block.
 
210
                  */
 
211
                  count=ReadBlobBlock(image,packet);
 
212
                  if (count == 0)
 
213
                    break;
 
214
                  c=packet;
 
215
                }
 
216
              datum+=(unsigned long) (*c) << bits;
 
217
              bits+=8;
 
218
              c++;
 
219
              count--;
 
220
              continue;
 
221
            }
 
222
          /*
 
223
            Get the next code.
 
224
          */
 
225
          code=(long) (datum & code_mask);
 
226
          datum>>=code_size;
 
227
          bits-=code_size;
 
228
          /*
 
229
            Interpret the code
 
230
          */
 
231
          if (code > available)
 
232
            {
 
233
              status=MagickFail;
 
234
              break;
 
235
            }
 
236
          if (code == end_of_information)
 
237
            break;
 
238
          if (code == clear)
 
239
            {
 
240
              /*
 
241
                Reset decoder.
 
242
              */
 
243
              code_size=data_size+1;
 
244
              code_mask=(1 << code_size)-1;
 
245
              available=clear+2;
 
246
              old_code=NullCode;
 
247
              continue;
 
248
            }
 
249
          if (old_code == NullCode)
 
250
            {
 
251
              *top_stack++=suffix[code];
 
252
              old_code=code;
 
253
              first=(unsigned char) code;
 
254
              continue;
 
255
            }
 
256
          in_code=code;
 
257
          if (code >= available)
 
258
            {
 
259
              *top_stack++=first;
 
260
              code=old_code;
 
261
            }
 
262
          while (code >= clear)
 
263
          {
 
264
            if ((top_stack-pixel_stack) >= MaxStackSize)
 
265
              {
 
266
                status=MagickFail;
 
267
                break;
 
268
              }
 
269
            *top_stack++=suffix[code];
 
270
            code=prefix[code];
 
271
          }
 
272
          if (status == MagickFail)
 
273
            break;
 
274
          first=suffix[code];
 
275
          /*
 
276
            Add a new string to the string table,
 
277
          */
 
278
          if (available >= MaxStackSize)
 
279
            {
 
280
              status=MagickFail;
 
281
              break;
 
282
            }
 
283
          *top_stack++=first;
 
284
          prefix[available]=(short) old_code;
 
285
          suffix[available]=first;
 
286
          available++;
 
287
          if (((available & code_mask) == 0) && (available < MaxStackSize))
 
288
            {
 
289
              code_size++;
 
290
              code_mask+=available;
 
291
            }
 
292
          old_code=in_code;
 
293
        }
 
294
      /*
 
295
        Pop a pixel off the pixel stack.
 
296
      */
 
297
      top_stack--;
 
298
      index=(*top_stack);
 
299
      VerifyColormapIndex(image,index);
 
300
      indexes[x]=index;
 
301
      *q=image->colormap[index];
 
302
      q->opacity=(Quantum)
 
303
        (index == opacity ? TransparentOpacity : OpaqueOpacity);
 
304
      x++;
 
305
      q++;
 
306
    }
 
307
    if (image->interlace == NoInterlace)
 
308
      offset++;
 
309
    else
 
310
      switch (pass)
 
311
      {
 
312
        case 0:
 
313
        default:
 
314
        {
 
315
          offset+=8;
 
316
          if (offset >= (long) image->rows)
 
317
            {
 
318
              pass++;
 
319
              offset=4;
 
320
            }
 
321
          break;
 
322
        }
 
323
        case 1:
 
324
        {
 
325
          offset+=8;
 
326
          if (offset >= (long) image->rows)
 
327
            {
 
328
              pass++;
 
329
              offset=2;
 
330
            }
 
331
          break;
 
332
        }
 
333
        case 2:
 
334
        {
 
335
          offset+=4;
 
336
          if (offset >= (long) image->rows)
 
337
            {
 
338
              pass++;
 
339
              offset=1;
 
340
            }
 
341
          break;
 
342
        }
 
343
        case 3:
 
344
        {
 
345
          offset+=2;
 
346
          break;
 
347
        }
 
348
      }
 
349
    if (!SyncImagePixels(image))
 
350
      {
 
351
        status=MagickFail;
 
352
        break;
 
353
      }
 
354
    if (x < (long) image->columns)
 
355
      {
 
356
        status=MagickFail;
 
357
        break;
 
358
      }
 
359
    if (image->previous == (Image *) NULL)
 
360
      if (QuantumTick(y,image->rows))
 
361
        if (!MagickMonitor(LoadImageText,y,image->rows,&image->exception))
 
362
          {
 
363
            status=MagickFail;
 
364
            break;
 
365
          }
 
366
  }
 
367
  MagickFreeMemory(pixel_stack);
 
368
  MagickFreeMemory(suffix);
 
369
  MagickFreeMemory(prefix);
 
370
  MagickFreeMemory(packet);
 
371
  if ((status == MagickFail) || (y < (long) image->rows))
 
372
    ThrowBinaryException(CorruptImageError,CorruptImage,image->filename);
 
373
  return(MagickPass);
 
374
}
 
375
 
 
376
/*
 
377
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
378
%                                                                             %
 
379
%                                                                             %
 
380
%                                                                             %
 
381
%   E n c o d e I m a g e                                                     %
 
382
%                                                                             %
 
383
%                                                                             %
 
384
%                                                                             %
 
385
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
386
%
 
387
%  Method EncodeImage compresses an image via GIF-coding.
 
388
%
 
389
%  The format of the EncodeImage method is:
 
390
%
 
391
%      MagickPassFail EncodeImage(const ImageInfo *image_info,Image *image,
 
392
%        const unsigned int data_size)
 
393
%
 
394
%  A description of each parameter follows:
 
395
%
 
396
%    o status:  Method EncodeImage returns MagickPass if all the pixels are
 
397
%      compressed without error, otherwise MagickFail.
 
398
%
 
399
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
400
%
 
401
%    o image: The address of a structure of type Image.
 
402
%
 
403
%    o data_size:  The number of bits in the compressed packet.
 
404
%
 
405
%
 
406
*/
 
407
#define MaxCode(number_bits)  ((1 << (number_bits))-1)
 
408
#define MaxHashTable  5003
 
409
#define MaxGIFBits  12
 
410
#if defined(HasLZW)
 
411
#  define MaxGIFTable  (1 << MaxGIFBits)
 
412
#else
 
413
#  define MaxGIFTable  max_code
 
414
#endif
 
415
#define GIFOutputCode(code) \
 
416
{ \
 
417
  /*  \
 
418
    Emit a code. \
 
419
  */ \
 
420
  if (bits > 0) \
 
421
    datum|=((long) code << bits); \
 
422
  else \
 
423
    datum=(long) code; \
 
424
  bits+=number_bits; \
 
425
  while (bits >= 8) \
 
426
  { \
 
427
    /*  \
 
428
      Add a character to current packet. \
 
429
    */ \
 
430
    packet[byte_count++]=(unsigned char) (datum & 0xff); \
 
431
    if (byte_count >= 254) \
 
432
      { \
 
433
        (void) WriteBlobByte(image,byte_count); \
 
434
        (void) WriteBlob(image,byte_count,(char *) packet); \
 
435
        byte_count=0; \
 
436
      } \
 
437
    datum>>=8; \
 
438
    bits-=8; \
 
439
  } \
 
440
  if (free_code > max_code)  \
 
441
    { \
 
442
      number_bits++; \
 
443
      if (number_bits == MaxGIFBits) \
 
444
        max_code=MaxGIFTable; \
 
445
      else \
 
446
        max_code=MaxCode(number_bits); \
 
447
    } \
 
448
}
 
449
static MagickPassFail EncodeImage(const ImageInfo *image_info,Image *image,
 
450
  const unsigned int data_size)
 
451
{
 
452
 
 
453
  int
 
454
#if defined(HasLZW)
 
455
    displacement,
 
456
    next_pixel,
 
457
#endif
 
458
    bits,
 
459
    byte_count,
 
460
    k,
 
461
    number_bits,
 
462
    offset,
 
463
    pass;
 
464
 
 
465
  long
 
466
    datum,
 
467
    y;
 
468
 
 
469
  register const PixelPacket
 
470
    *p;
 
471
 
 
472
  register IndexPacket
 
473
    *indexes;
 
474
 
 
475
  register long
 
476
    i,
 
477
    x;
 
478
 
 
479
  short
 
480
    clear_code,
 
481
    end_of_information_code,
 
482
    free_code,
 
483
    *hash_code,
 
484
    *hash_prefix,
 
485
    index,
 
486
    max_code,
 
487
    waiting_code;
 
488
 
 
489
  unsigned char
 
490
    *packet,
 
491
    *hash_suffix;
 
492
 
 
493
  /*
 
494
    Allocate encoder tables.
 
495
  */
 
496
  assert(image != (Image *) NULL);
 
497
  packet=MagickAllocateMemory(unsigned char *,256);
 
498
  hash_code=MagickAllocateMemory(short *,MaxHashTable*sizeof(short));
 
499
  hash_prefix=MagickAllocateMemory(short *,MaxHashTable*sizeof(short));
 
500
  hash_suffix=MagickAllocateMemory(unsigned char *,MaxHashTable);
 
501
  if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
 
502
      (hash_prefix == (short *) NULL) ||
 
503
      (hash_suffix == (unsigned char *) NULL))
 
504
    {
 
505
      MagickFreeMemory(packet);
 
506
      MagickFreeMemory(hash_code);
 
507
      MagickFreeMemory(hash_prefix);
 
508
      MagickFreeMemory(hash_suffix);
 
509
      return(MagickFail);
 
510
    }
 
511
  /*
 
512
    Initialize GIF encoder.
 
513
  */
 
514
  number_bits=data_size;
 
515
  max_code=MaxCode(number_bits);
 
516
  clear_code=((short) 1 << (data_size-1));
 
517
  end_of_information_code=clear_code+1;
 
518
  free_code=clear_code+2;
 
519
  byte_count=0;
 
520
  datum=0;
 
521
  bits=0;
 
522
  for (i=0; i < MaxHashTable; i++)
 
523
    hash_code[i]=0;
 
524
  GIFOutputCode(clear_code);
 
525
  /*
 
526
    Encode pixels.
 
527
  */
 
528
  offset=0;
 
529
  pass=0;
 
530
  waiting_code=0;
 
531
  for (y=0; y < (long) image->rows; y++)
 
532
  {
 
533
    p=AcquireImagePixels(image,0,offset,image->columns,1,&image->exception);
 
534
    if (p == (const PixelPacket *) NULL)
 
535
      break;
 
536
    indexes=GetIndexes(image);
 
537
    if (y == 0)
 
538
      waiting_code=(*indexes);
 
539
    for (x=(y == 0) ? 1 : 0; x < (long) image->columns; x++)
 
540
    {
 
541
      /*
 
542
        Probe hash table.
 
543
      */
 
544
      index=indexes[x] & 0xff;
 
545
      p++;
 
546
      k=(int) ((int) index << (MaxGIFBits-8))+waiting_code;
 
547
      if (k >= MaxHashTable)
 
548
        k-=MaxHashTable;
 
549
#if defined(HasLZW)
 
550
      next_pixel=False;
 
551
      displacement=1;
 
552
      if ((image_info->compression != NoCompression) && (hash_code[k] > 0))
 
553
        {
 
554
          if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
 
555
            {
 
556
              waiting_code=hash_code[k];
 
557
              continue;
 
558
            }
 
559
          if (k != 0)
 
560
            displacement=MaxHashTable-k;
 
561
          for ( ; ; )
 
562
          {
 
563
            k-=displacement;
 
564
            if (k < 0)
 
565
              k+=MaxHashTable;
 
566
            if (hash_code[k] == 0)
 
567
              break;
 
568
            if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
 
569
              {
 
570
                waiting_code=hash_code[k];
 
571
                next_pixel=True;
 
572
                break;
 
573
              }
 
574
          }
 
575
          if (next_pixel == True)
 
576
            continue;
 
577
        }
 
578
#endif
 
579
      GIFOutputCode(waiting_code);
 
580
      if (free_code < MaxGIFTable)
 
581
        {
 
582
          hash_code[k]=free_code++;
 
583
          hash_prefix[k]=waiting_code;
 
584
          hash_suffix[k]=(unsigned char) index;
 
585
        }
 
586
      else
 
587
        {
 
588
          /*
 
589
            Fill the hash table with empty entries.
 
590
          */
 
591
          for (k=0; k < MaxHashTable; k++)
 
592
            hash_code[k]=0;
 
593
          /*
 
594
            Reset compressor and issue a clear code.
 
595
          */
 
596
          free_code=clear_code+2;
 
597
          GIFOutputCode(clear_code);
 
598
          number_bits=data_size;
 
599
          max_code=MaxCode(number_bits);
 
600
        }
 
601
      waiting_code=index;
 
602
    }
 
603
    if (image_info->interlace == NoInterlace)
 
604
      offset++;
 
605
    else
 
606
      switch (pass)
 
607
      {
 
608
        case 0:
 
609
        default:
 
610
        {
 
611
          offset+=8;
 
612
          if (offset >= (long) image->rows)
 
613
            {
 
614
              pass++;
 
615
              offset=4;
 
616
            }
 
617
          break;
 
618
        }
 
619
        case 1:
 
620
        {
 
621
          offset+=8;
 
622
          if (offset >= (long) image->rows)
 
623
            {
 
624
              pass++;
 
625
              offset=2;
 
626
            }
 
627
          break;
 
628
        }
 
629
        case 2:
 
630
        {
 
631
          offset+=4;
 
632
          if (offset >= (long) image->rows)
 
633
            {
 
634
              pass++;
 
635
              offset=1;
 
636
            }
 
637
          break;
 
638
        }
 
639
        case 3:
 
640
        {
 
641
          offset+=2;
 
642
          break;
 
643
        }
 
644
      }
 
645
    if (image->previous == (Image *) NULL)
 
646
      if (QuantumTick(y,image->rows))
 
647
        if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
 
648
          break;
 
649
  }
 
650
  /*
 
651
    Flush out the buffered code.
 
652
  */
 
653
  GIFOutputCode(waiting_code);
 
654
  GIFOutputCode(end_of_information_code);
 
655
  if (bits > 0)
 
656
    {
 
657
      /*
 
658
        Add a character to current packet.
 
659
      */
 
660
      packet[byte_count++]=(unsigned char) (datum & 0xff);
 
661
      if (byte_count >= 254)
 
662
        {
 
663
          (void) WriteBlobByte(image,byte_count);
 
664
          (void) WriteBlob(image,byte_count,(char *) packet);
 
665
          byte_count=0;
 
666
        }
 
667
    }
 
668
  /*
 
669
    Flush accumulated data.
 
670
  */
 
671
  if (byte_count > 0)
 
672
    {
 
673
      (void) WriteBlobByte(image,byte_count);
 
674
      (void) WriteBlob(image,byte_count,(char *) packet);
 
675
    }
 
676
  /*
 
677
    Free encoder memory.
 
678
  */
 
679
  MagickFreeMemory(hash_suffix);
 
680
  MagickFreeMemory(hash_prefix);
 
681
  MagickFreeMemory(hash_code);
 
682
  MagickFreeMemory(packet);
 
683
  return(MagickPass);
 
684
}
 
685
 
 
686
/*
 
687
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
688
%                                                                             %
 
689
%                                                                             %
 
690
%                                                                             %
 
691
%   I s G I F                                                                 %
 
692
%                                                                             %
 
693
%                                                                             %
 
694
%                                                                             %
 
695
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
696
%
 
697
%  Method IsGIF returns MagickTrue if the image format type, identified by
 
698
%  the magick string, is GIF.
 
699
%
 
700
%  The format of the IsGIF method is:
 
701
%
 
702
%      MagickBool IsGIF(const unsigned char *magick,const size_t length)
 
703
%
 
704
%  A description of each parameter follows:
 
705
%
 
706
%    o status:  Method IsGIF returns True if the image format type is GIF.
 
707
%
 
708
%    o magick: This string is generally the first few bytes of an image file
 
709
%      or blob.
 
710
%
 
711
%    o length: Specifies the length of the magick string.
 
712
%
 
713
%
 
714
*/
 
715
static MagickBool IsGIF(const unsigned char *magick,const size_t length)
 
716
{
 
717
  if (length < 4)
 
718
    return(MagickFalse);
 
719
  if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
 
720
    return(MagickTrue);
 
721
  return(MagickFalse);
 
722
}
 
723
 
 
724
/*
 
725
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
726
%                                                                             %
 
727
%                                                                             %
 
728
%                                                                             %
 
729
+  R e a d B l o b B l o c k                                                  %
 
730
%                                                                             %
 
731
%                                                                             %
 
732
%                                                                             %
 
733
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
734
%
 
735
%  Method ReadBlobBlock reads data from the image file and returns it.  The
 
736
%  amount of data is determined by first reading a count byte.  The number
 
737
%  or bytes read is returned.
 
738
%
 
739
%  The format of the ReadBlobBlock method is:
 
740
%
 
741
%      size_t ReadBlobBlock(Image *image,unsigned char *data)
 
742
%
 
743
%  A description of each parameter follows:
 
744
%
 
745
%    o count:  Method ReadBlobBlock returns the number of bytes read.
 
746
%
 
747
%    o image: The image.
 
748
%
 
749
%    o data:  Specifies an area to place the information requested from
 
750
%      the file.
 
751
%
 
752
%
 
753
*/
 
754
static size_t ReadBlobBlock(Image *image,unsigned char *data)
 
755
{
 
756
  size_t
 
757
    count;
 
758
 
 
759
  unsigned char
 
760
    block_count;
 
761
 
 
762
  assert(image != (Image *) NULL);
 
763
  assert(image->signature == MagickSignature);
 
764
  assert(data != (unsigned char *) NULL);
 
765
  count=ReadBlob(image,1,&block_count);
 
766
  if (count == 0)
 
767
    return(0);
 
768
  return(ReadBlob(image,(size_t) block_count,data));
 
769
}
 
770
 
 
771
/*
 
772
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
773
%                                                                             %
 
774
%                                                                             %
 
775
%                                                                             %
 
776
%   R e a d G I F I m a g e                                                   %
 
777
%                                                                             %
 
778
%                                                                             %
 
779
%                                                                             %
 
780
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
781
%
 
782
%  Method ReadGIFImage reads a Compuserve Graphics image file and returns it.
 
783
%  It allocates the memory necessary for the new Image structure and returns a
 
784
%  pointer to the new image.
 
785
%
 
786
%  The format of the ReadGIFImage method is:
 
787
%
 
788
%      Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
789
%
 
790
%  A description of each parameter follows:
 
791
%
 
792
%    o image:  Method ReadGIFImage returns a pointer to the image after
 
793
%      reading.  A null image is returned if there is a memory shortage or
 
794
%      an error occurs.
 
795
%
 
796
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
797
%
 
798
%    o exception: return any errors or warnings in this structure.
 
799
%
 
800
%
 
801
*/
 
802
#define BitSet(byte,bit)  (((byte) & (bit)) == (bit))
 
803
#define LSBFirstOrder(x,y)  (((y) << 8) | (x))
 
804
static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
805
{
 
806
  Image
 
807
    *image;
 
808
 
 
809
  int
 
810
    status;
 
811
 
 
812
  long
 
813
    opacity;
 
814
 
 
815
  RectangleInfo
 
816
    page;
 
817
 
 
818
  register long
 
819
    i;
 
820
 
 
821
  register unsigned char
 
822
    *p;
 
823
 
 
824
  size_t
 
825
    count;
 
826
 
 
827
  unsigned char
 
828
    background,
 
829
    c,
 
830
    flag,
 
831
    *global_colormap,
 
832
    header[MaxTextExtent],
 
833
    magick[12];
 
834
 
 
835
  unsigned long
 
836
    delay,
 
837
    dispose,
 
838
    global_colors,
 
839
    image_count,
 
840
    iterations;
 
841
 
 
842
  /*
 
843
    Open image file.
 
844
  */
 
845
  assert(image_info != (const ImageInfo *) NULL);
 
846
  assert(image_info->signature == MagickSignature);
 
847
  assert(exception != (ExceptionInfo *) NULL);
 
848
  assert(exception->signature == MagickSignature);
 
849
  image=AllocateImage(image_info);
 
850
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
 
851
  if (status == MagickFail)
 
852
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
 
853
  /*
 
854
    Determine if this is a GIF file.
 
855
  */
 
856
  count=ReadBlob(image,6,(char *) magick);
 
857
  if ((count == 0) || ((LocaleNCompare((char *) magick,"GIF87",5) != 0) &&
 
858
      (LocaleNCompare((char *) magick,"GIF89",5) != 0)))
 
859
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
 
860
  global_colors=0;
 
861
  global_colormap=(unsigned char *) NULL;
 
862
  page.width=ReadBlobLSBShort(image);
 
863
  page.height=ReadBlobLSBShort(image);
 
864
  flag=ReadBlobByte(image);
 
865
  background=ReadBlobByte(image);
 
866
  c=ReadBlobByte(image);  /* reserved */
 
867
  global_colors=1 << ((flag & 0x07)+1);
 
868
  global_colormap=MagickAllocateMemory(unsigned char *,3*Max(global_colors,256));
 
869
  if (global_colormap == (unsigned char *) NULL)
 
870
    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
 
871
  if (BitSet(flag,0x80))
 
872
    (void) ReadBlob(image,3*global_colors,(char *) global_colormap);
 
873
  delay=0;
 
874
  dispose=0;
 
875
  iterations=1;
 
876
  opacity=(-1);
 
877
  image_count=0;
 
878
  for ( ; ; )
 
879
  {
 
880
    count=ReadBlob(image,1,(char *) &c);
 
881
    if (count == 0)
 
882
      break;
 
883
    if (c == ';')
 
884
      break;  /* terminator */
 
885
    if (c == '!')
 
886
      {
 
887
        /*
 
888
          GIF Extension block.
 
889
        */
 
890
        count=ReadBlob(image,1,(char *) &c);
 
891
        if (count == 0) {
 
892
          MagickFreeMemory(global_colormap);
 
893
          ThrowReaderException(CorruptImageError,UnableToReadExtensionBlock,     
 
894
            image);
 
895
        }
 
896
        switch (c)
 
897
        {
 
898
          case 0xf9:
 
899
          {
 
900
            /*
 
901
              Read Graphics Control extension.
 
902
            */
 
903
            while (ReadBlobBlock(image,header) != 0);
 
904
            dispose=header[0] >> 2;
 
905
            delay=(header[2] << 8) | header[1];
 
906
            if ((header[0] & 0x01) == 1)
 
907
              opacity=header[3];
 
908
            break;
 
909
          }
 
910
          case 0xfe:
 
911
          {
 
912
            char
 
913
              *comments;
 
914
 
 
915
            /*
 
916
              Read Comment extension.
 
917
            */
 
918
            comments=AllocateString((char *) NULL);
 
919
            for ( ; ; )
 
920
            {
 
921
              count=ReadBlobBlock(image,header);
 
922
              if (count == 0)
 
923
                break;
 
924
              header[count]='\0';
 
925
              (void) ConcatenateString(&comments,(const char *) header);
 
926
            }
 
927
            (void) SetImageAttribute(image,"comment",comments);
 
928
            MagickFreeMemory(comments);
 
929
            break;
 
930
          }
 
931
          case 0xff:
 
932
          {
 
933
            int
 
934
              loop;
 
935
 
 
936
            /*
 
937
              Read Netscape Loop extension.
 
938
            */
 
939
            loop=False;
 
940
            if (ReadBlobBlock(image,header) != 0)
 
941
              loop=!LocaleNCompare((char *) header,"NETSCAPE2.0",11);
 
942
            while (ReadBlobBlock(image,header) != 0)
 
943
            if (loop)
 
944
              iterations=(header[2] << 8) | header[1];
 
945
            break;
 
946
          }
 
947
          default:
 
948
          {
 
949
            while (ReadBlobBlock(image,header) != 0);
 
950
            break;
 
951
          }
 
952
        }
 
953
      }
 
954
    if (c != ',')
 
955
      continue;
 
956
    if (image_count != 0)
 
957
      {
 
958
        /*
 
959
          Allocate next image structure.
 
960
        */
 
961
        AllocateNextImage(image_info,image);
 
962
        if (image->next == (Image *) NULL)
 
963
          {
 
964
            DestroyImageList(image);
 
965
            MagickFreeMemory(global_colormap);
 
966
            return((Image *) NULL);
 
967
          }
 
968
        image=SyncNextImageInList(image);
 
969
        if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
 
970
          break;
 
971
      }
 
972
    image_count++;
 
973
    /*
 
974
      Read image attributes.
 
975
    */
 
976
    image->storage_class=PseudoClass;
 
977
    image->compression=LZWCompression;
 
978
    page.x=ReadBlobLSBShort(image);
 
979
    page.y=ReadBlobLSBShort(image);
 
980
    image->columns=ReadBlobLSBShort(image);
 
981
    image->rows=ReadBlobLSBShort(image);
 
982
    image->depth=8;
 
983
    flag=ReadBlobByte(image);
 
984
    image->interlace=BitSet(flag,0x40) ? PlaneInterlace : NoInterlace;
 
985
    image->colors=!BitSet(flag,0x80) ? global_colors : 0x01U << ((flag & 0x07)+1);
 
986
    if (opacity >= (long) image->colors)
 
987
      image->colors=opacity+1;
 
988
    image->page.width=page.width;
 
989
    image->page.height=page.height;
 
990
    image->page.y=page.y;
 
991
    image->page.x=page.x;
 
992
    image->delay=delay;
 
993
    image->dispose=(DisposeType) dispose;
 
994
    image->iterations=iterations;
 
995
    image->matte=opacity >= 0;
 
996
    delay=0;
 
997
    dispose=0;
 
998
    iterations=1;
 
999
    if ((image->columns == 0) || (image->rows == 0)) {
 
1000
      MagickFreeMemory(global_colormap);    
 
1001
      ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
 
1002
    }
 
1003
    /*
 
1004
      Inititialize colormap.
 
1005
    */
 
1006
    if (!AllocateImageColormap(image,image->colors)) {
 
1007
      MagickFreeMemory(global_colormap);    
 
1008
      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
 
1009
    }
 
1010
    if (!BitSet(flag,0x80))
 
1011
      {
 
1012
        /*
 
1013
          Use global colormap.
 
1014
        */
 
1015
        p=global_colormap;
 
1016
        for (i=0; i < (long) image->colors; i++)
 
1017
        {
 
1018
          image->colormap[i].red=ScaleCharToQuantum(*p++);
 
1019
          image->colormap[i].green=ScaleCharToQuantum(*p++);
 
1020
          image->colormap[i].blue=ScaleCharToQuantum(*p++);
 
1021
        }
 
1022
        image->background_color=
 
1023
          image->colormap[Min(background,image->colors-1)];
 
1024
      }
 
1025
    else
 
1026
      {
 
1027
        unsigned char
 
1028
          *colormap;
 
1029
 
 
1030
        /*
 
1031
          Read local colormap.
 
1032
        */
 
1033
        colormap=MagickAllocateMemory(unsigned char *,3*image->colors);
 
1034
        if (colormap == (unsigned char *) NULL)
 
1035
          {
 
1036
            MagickFreeMemory(global_colormap);
 
1037
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
1038
                                 image);
 
1039
          }
 
1040
        (void) ReadBlob(image,3*image->colors,(char *) colormap);
 
1041
        p=colormap;
 
1042
        for (i=0; i < (long) image->colors; i++)
 
1043
        {
 
1044
          image->colormap[i].red=ScaleCharToQuantum(*p++);
 
1045
          image->colormap[i].green=ScaleCharToQuantum(*p++);
 
1046
          image->colormap[i].blue=ScaleCharToQuantum(*p++);
 
1047
        }
 
1048
        MagickFreeMemory(colormap);
 
1049
      }
 
1050
    if (image_info->ping && (image_info->subrange != 0))
 
1051
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
1052
        break;
 
1053
    /*
 
1054
      Decode image.
 
1055
    */
 
1056
    status=DecodeImage(image,opacity);
 
1057
    if (!image_info->ping && (status == False)) {
 
1058
      MagickFreeMemory(global_colormap);    
 
1059
      ThrowReaderException(CorruptImageError,CorruptImage,image);
 
1060
    }
 
1061
    if (image_info->subrange != 0)
 
1062
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
1063
        break;
 
1064
  }
 
1065
  MagickFreeMemory(global_colormap);
 
1066
  if ((image->columns == 0) || (image->rows == 0))
 
1067
    ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
 
1068
  while (image->previous != (Image *) NULL)
 
1069
    image=image->previous;
 
1070
  CloseBlob(image);
 
1071
  return(image);
 
1072
}
 
1073
 
 
1074
/*
 
1075
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1076
%                                                                             %
 
1077
%                                                                             %
 
1078
%                                                                             %
 
1079
%   R e g i s t e r G I F I m a g e                                           %
 
1080
%                                                                             %
 
1081
%                                                                             %
 
1082
%                                                                             %
 
1083
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1084
%
 
1085
%  Method RegisterGIFImage adds attributes for the GIF image format to
 
1086
%  the list of supported formats.  The attributes include the image format
 
1087
%  tag, a method to read and/or write the format, whether the format
 
1088
%  supports the saving of more than one frame to the same file or blob,
 
1089
%  whether the format supports native in-memory I/O, and a brief
 
1090
%  description of the format.
 
1091
%
 
1092
%  The format of the RegisterGIFImage method is:
 
1093
%
 
1094
%      RegisterGIFImage(void)
 
1095
%
 
1096
*/
 
1097
ModuleExport void RegisterGIFImage(void)
 
1098
{
 
1099
  MagickInfo
 
1100
    *entry;
 
1101
 
 
1102
  entry=SetMagickInfo("GIF");
 
1103
  entry->decoder=(DecoderHandler) ReadGIFImage;
 
1104
  entry->encoder=(EncoderHandler) WriteGIFImage;
 
1105
  entry->magick=(MagickHandler) IsGIF;
 
1106
  entry->description=AcquireString("CompuServe graphics interchange format");
 
1107
#if !defined(HasLZW)
 
1108
  entry->version=AcquireString("LZW disabled");
 
1109
#endif
 
1110
  entry->module=AcquireString("GIF");
 
1111
  (void) RegisterMagickInfo(entry);
 
1112
  entry=SetMagickInfo("GIF87");
 
1113
  entry->decoder=(DecoderHandler) ReadGIFImage;
 
1114
  entry->encoder=(EncoderHandler) WriteGIFImage;
 
1115
  entry->magick=(MagickHandler) IsGIF;
 
1116
  entry->adjoin=False;
 
1117
  entry->description=AcquireString("CompuServe graphics interchange format");
 
1118
  entry->version=AcquireString("version 87a");
 
1119
  entry->module=AcquireString("GIF");
 
1120
  (void) RegisterMagickInfo(entry);
 
1121
}
 
1122
 
 
1123
/*
 
1124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1125
%                                                                             %
 
1126
%                                                                             %
 
1127
%                                                                             %
 
1128
%   U n r e g i s t e r G I F I m a g e                                       %
 
1129
%                                                                             %
 
1130
%                                                                             %
 
1131
%                                                                             %
 
1132
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1133
%
 
1134
%  Method UnregisterGIFImage removes format registrations made by the
 
1135
%  GIF module from the list of supported formats.
 
1136
%
 
1137
%  The format of the UnregisterGIFImage method is:
 
1138
%
 
1139
%      UnregisterGIFImage(void)
 
1140
%
 
1141
*/
 
1142
ModuleExport void UnregisterGIFImage(void)
 
1143
{
 
1144
  (void) UnregisterMagickInfo("GIF");
 
1145
  (void) UnregisterMagickInfo("GIF87");
 
1146
}
 
1147
 
 
1148
/*
 
1149
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1150
%                                                                             %
 
1151
%                                                                             %
 
1152
%                                                                             %
 
1153
%   W r i t e G I F I m a g e                                                 %
 
1154
%                                                                             %
 
1155
%                                                                             %
 
1156
%                                                                             %
 
1157
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
1158
%
 
1159
%  Method WriteGIFImage writes an image to a file in the Compuserve Graphics
 
1160
%  image format.
 
1161
%
 
1162
%  The format of the WriteGIFImage method is:
 
1163
%
 
1164
%      MagickPassFail WriteGIFImage(const ImageInfo *image_info,Image *image)
 
1165
%
 
1166
%  A description of each parameter follows.
 
1167
%
 
1168
%    o status: Method WriteGIFImage return MagickPass if the image is written.
 
1169
%      MagickFail is returned is there is a memory shortage or if the image file
 
1170
%      fails to write.
 
1171
%
 
1172
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
1173
%
 
1174
%    o image:  A pointer to an Image structure.
 
1175
%
 
1176
%
 
1177
*/
 
1178
static MagickPassFail WriteGIFImage(const ImageInfo *image_info,Image *image)
 
1179
{
 
1180
  Image
 
1181
    *next_image;
 
1182
 
 
1183
  int
 
1184
    y;
 
1185
 
 
1186
  long
 
1187
    opacity;
 
1188
 
 
1189
  QuantizeInfo
 
1190
    quantize_info;
 
1191
 
 
1192
  RectangleInfo
 
1193
    page;
 
1194
 
 
1195
  register IndexPacket
 
1196
    *indexes;
 
1197
 
 
1198
  register const PixelPacket
 
1199
    *p;
 
1200
 
 
1201
  register long
 
1202
    x;
 
1203
 
 
1204
  register long
 
1205
    i;
 
1206
 
 
1207
  register unsigned char
 
1208
    *q;
 
1209
 
 
1210
  size_t
 
1211
    j;
 
1212
 
 
1213
  unsigned char
 
1214
    bits_per_pixel,
 
1215
    c,
 
1216
    *colormap,
 
1217
    *global_colormap;
 
1218
 
 
1219
  unsigned int
 
1220
    interlace,
 
1221
    status;
 
1222
 
 
1223
  unsigned long
 
1224
    scene;
 
1225
 
 
1226
  /*
 
1227
    Open output image file.
 
1228
  */
 
1229
  assert(image_info != (const ImageInfo *) NULL);
 
1230
  assert(image_info->signature == MagickSignature);
 
1231
  assert(image != (Image *) NULL);
 
1232
  assert(image->signature == MagickSignature);
 
1233
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
 
1234
  if (status == MagickFail)
 
1235
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
 
1236
  /*
 
1237
    Determine image bounding box.
 
1238
  */
 
1239
  page.width=image->columns;
 
1240
  page.height=image->rows;
 
1241
  page.x=0;
 
1242
  page.y=0;
 
1243
  for (next_image=image; next_image != (Image *) NULL; )
 
1244
  {
 
1245
    page.x=next_image->page.x;
 
1246
    page.y=next_image->page.y;
 
1247
    if ((next_image->columns+page.x) > page.width)
 
1248
      page.width=next_image->columns+page.x;
 
1249
    if ((next_image->rows+page.y) > page.height)
 
1250
      page.height=next_image->rows+page.y;
 
1251
    next_image=next_image->next;
 
1252
  }
 
1253
  /*
 
1254
    Allocate colormap.
 
1255
  */
 
1256
  global_colormap=MagickAllocateMemory(unsigned char *,768);
 
1257
  colormap=MagickAllocateMemory(unsigned char *,768);
 
1258
  if ((global_colormap == (unsigned char *) NULL) ||
 
1259
      (colormap == (unsigned char *) NULL))
 
1260
    ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
 
1261
  for (i=0; i < 768; i++)
 
1262
    colormap[i]=0;
 
1263
  /*
 
1264
    Write GIF header.
 
1265
  */
 
1266
  if ((GetImageAttribute(image,"comment") == (ImageAttribute *) NULL) &&
 
1267
      !image_info->adjoin && !image->matte)
 
1268
    (void) WriteBlob(image,6,"GIF87a");
 
1269
  else
 
1270
    if (LocaleCompare(image_info->magick,"GIF87") == 0)
 
1271
      (void) WriteBlob(image,6,"GIF87a");
 
1272
    else
 
1273
      (void) WriteBlob(image,6,"GIF89a");
 
1274
  page.x=image->page.x;
 
1275
  page.y=image->page.y;
 
1276
  if ((image->page.width != 0) && (image->page.height != 0))
 
1277
    page=image->page;
 
1278
  (void) WriteBlobLSBShort(image,page.width);
 
1279
  (void) WriteBlobLSBShort(image,page.height);
 
1280
  /*
 
1281
    Write images to file.
 
1282
  */
 
1283
  interlace=image_info->interlace;
 
1284
  if (image_info->adjoin && (image->next != (Image *) NULL))
 
1285
    interlace=NoInterlace;
 
1286
  opacity=(-1);
 
1287
  scene=0;
 
1288
  do
 
1289
  {
 
1290
    (void) TransformColorspace(image,RGBColorspace);
 
1291
    if ((image->storage_class == DirectClass) || (image->colors > 256))
 
1292
      {
 
1293
        /*
 
1294
          GIF requires that the image is colormapped.
 
1295
        */
 
1296
        GetQuantizeInfo(&quantize_info);
 
1297
        quantize_info.dither=image_info->dither;
 
1298
        quantize_info.number_colors=image->matte ? 255 : 256;
 
1299
        (void) QuantizeImage(&quantize_info,image);
 
1300
        if (image->matte)
 
1301
          {
 
1302
            /*
 
1303
              Set transparent pixel.
 
1304
            */
 
1305
            opacity=(long) image->colors++;
 
1306
            MagickReallocMemory(image->colormap,
 
1307
              image->colors*sizeof(PixelPacket));
 
1308
            if (image->colormap == (PixelPacket *) NULL)
 
1309
              {
 
1310
                MagickFreeMemory(global_colormap);
 
1311
                MagickFreeMemory(colormap);
 
1312
                ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image)
 
1313
              }
 
1314
            image->colormap[opacity]=image->background_color;
 
1315
            for (y=0; y < (long) image->rows; y++)
 
1316
            {
 
1317
              p=AcquireImagePixels(image,0,y,image->columns,1,
 
1318
                &image->exception);
 
1319
              if (p == (const PixelPacket *) NULL)
 
1320
                break;
 
1321
              indexes=GetIndexes(image);
 
1322
              for (x=0; x < (long) image->columns; x++)
 
1323
              {
 
1324
                if (p->opacity == TransparentOpacity)
 
1325
                  indexes[x]=(IndexPacket) opacity;
 
1326
                p++;
 
1327
              }
 
1328
              if (!SyncImagePixels(image))
 
1329
                break;
 
1330
            }
 
1331
          }
 
1332
      }
 
1333
    else
 
1334
      if (image->matte)
 
1335
        {
 
1336
          /*
 
1337
            Identify transparent pixel index.
 
1338
          */
 
1339
          for (y=0; y < (long) image->rows; y++)
 
1340
          {
 
1341
            p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
 
1342
            if (p == (const PixelPacket *) NULL)
 
1343
              break;
 
1344
            indexes=GetIndexes(image);
 
1345
            for (x=0; x < (long) image->columns; x++)
 
1346
            {
 
1347
              if (p->opacity == TransparentOpacity)
 
1348
                {
 
1349
                  opacity=(long) indexes[x];
 
1350
                  break;
 
1351
                }
 
1352
              p++;
 
1353
            }
 
1354
            if (x < (long) image->columns)
 
1355
              break;
 
1356
          }
 
1357
        }
 
1358
    if (image->colormap == (PixelPacket *) NULL)
 
1359
      break;
 
1360
    for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
 
1361
      if ((1UL << bits_per_pixel) >= image->colors)
 
1362
        break;
 
1363
    q=colormap;
 
1364
    for (i=0; i < (long) image->colors; i++)
 
1365
    {
 
1366
      *q++=ScaleQuantumToChar(image->colormap[i].red);
 
1367
      *q++=ScaleQuantumToChar(image->colormap[i].green);
 
1368
      *q++=ScaleQuantumToChar(image->colormap[i].blue);
 
1369
    }
 
1370
    for ( ; i < (1L << bits_per_pixel); i++)
 
1371
    {
 
1372
      *q++=(Quantum) 0x0;
 
1373
      *q++=(Quantum) 0x0;
 
1374
      *q++=(Quantum) 0x0;
 
1375
    }
 
1376
    if ((image->previous == (Image *) NULL) || !image_info->adjoin)
 
1377
      {
 
1378
        /*
 
1379
          Write global colormap.
 
1380
        */
 
1381
        c=0x80;
 
1382
        c|=(8-1) << 4;  /* color resolution */
 
1383
        c|=(bits_per_pixel-1);   /* size of global colormap */
 
1384
        (void) WriteBlobByte(image,c);
 
1385
        for (p=image->colormap, j=0; j < Max(image->colors-1,1); j++, p++)
 
1386
          if (ColorMatch(&image->background_color,p))
 
1387
            break;
 
1388
        (void) WriteBlobByte(image,(long) j);  /* background color */
 
1389
        (void) WriteBlobByte(image,0x0);  /* reserved */
 
1390
        (void) WriteBlob(image,3*(1 << bits_per_pixel),(char *) colormap);
 
1391
        for (j=0; j < 768; j++)
 
1392
          global_colormap[j]=colormap[j];
 
1393
      }
 
1394
    if (LocaleCompare(image_info->magick,"GIF87") != 0)
 
1395
      {
 
1396
        /*
 
1397
          Write Graphics Control extension.
 
1398
        */
 
1399
        (void) WriteBlobByte(image,0x21);
 
1400
        (void) WriteBlobByte(image,0xf9);
 
1401
        (void) WriteBlobByte(image,0x04);
 
1402
        c=(unsigned char) ((int) image->dispose << 2);
 
1403
        if (opacity >= 0)
 
1404
          c|=0x01;
 
1405
        (void) WriteBlobByte(image,c);
 
1406
        (void) WriteBlobLSBShort(image,image->delay);
 
1407
        (void) WriteBlobByte(image,opacity >= 0 ? opacity : 0);
 
1408
        (void) WriteBlobByte(image,0x00);
 
1409
        if (GetImageAttribute(image,"comment") != (ImageAttribute *) NULL)
 
1410
          {
 
1411
            const ImageAttribute
 
1412
              *attribute;
 
1413
 
 
1414
            register char
 
1415
              *p;
 
1416
 
 
1417
            size_t
 
1418
              count;
 
1419
 
 
1420
            /*
 
1421
              Write Comment extension.
 
1422
            */
 
1423
            (void) WriteBlobByte(image,0x21);
 
1424
            (void) WriteBlobByte(image,0xfe);
 
1425
            attribute=GetImageAttribute(image,"comment");
 
1426
            p=attribute->value;
 
1427
            while (strlen(p) != 0)
 
1428
            {
 
1429
              count=Min(strlen(p),255);
 
1430
              (void) WriteBlobByte(image,(long) count);
 
1431
              for (i=0; i < (long) count; i++)
 
1432
                (void) WriteBlobByte(image,*p++);
 
1433
            }
 
1434
            (void) WriteBlobByte(image,0x0);
 
1435
          }
 
1436
        if ((image->previous == (Image *) NULL) &&
 
1437
            (image->next != (Image *) NULL) && (image->iterations != 1))
 
1438
          {
 
1439
            /*
 
1440
              Write Netscape Loop extension.
 
1441
            */
 
1442
            (void) WriteBlobByte(image,0x21);
 
1443
            (void) WriteBlobByte(image,0xff);
 
1444
            (void) WriteBlobByte(image,0x0b);
 
1445
            (void) WriteBlob(image,11,"NETSCAPE2.0");
 
1446
            (void) WriteBlobByte(image,0x03);
 
1447
            (void) WriteBlobByte(image,0x01);
 
1448
            (void) WriteBlobLSBShort(image,image->iterations);
 
1449
            (void) WriteBlobByte(image,0x00);
 
1450
          }
 
1451
      }
 
1452
    (void) WriteBlobByte(image,',');  /* image separator */
 
1453
    /*
 
1454
      Write the image header.
 
1455
    */
 
1456
    page.x=image->page.x;
 
1457
    page.y=image->page.y;
 
1458
    if ((image->page.width != 0) && (image->page.height != 0))
 
1459
      page=image->page;
 
1460
    (void) WriteBlobLSBShort(image,page.x);
 
1461
    (void) WriteBlobLSBShort(image,page.y);
 
1462
    (void) WriteBlobLSBShort(image,image->columns);
 
1463
    (void) WriteBlobLSBShort(image,image->rows);
 
1464
    c=0x00;
 
1465
    if (interlace != NoInterlace)
 
1466
      c|=0x40;  /* pixel data is interlaced */
 
1467
    for (j=0; j < (3*image->colors); j++)
 
1468
      if (colormap[j] != global_colormap[j])
 
1469
        break;
 
1470
    if (j == (3*image->colors))
 
1471
      (void) WriteBlobByte(image,c);
 
1472
    else
 
1473
      {
 
1474
        c|=0x80;
 
1475
        c|=(bits_per_pixel-1);   /* size of local colormap */
 
1476
        (void) WriteBlobByte(image,c);
 
1477
        (void) WriteBlob(image,3*(1 << bits_per_pixel),(char *) colormap);
 
1478
      }
 
1479
    /*
 
1480
      Write the image data.
 
1481
    */
 
1482
    c=Max(bits_per_pixel,2);
 
1483
    (void) WriteBlobByte(image,c);
 
1484
    status=EncodeImage(image_info,image,Max(bits_per_pixel,2)+1);
 
1485
    if (status == MagickFail)
 
1486
      {
 
1487
        MagickFreeMemory(global_colormap);
 
1488
        MagickFreeMemory(colormap);
 
1489
        ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image)
 
1490
      }
 
1491
    (void) WriteBlobByte(image,0x0);
 
1492
    if (image->next == (Image *) NULL)
 
1493
      break;
 
1494
    image=SyncNextImageInList(image);
 
1495
    status=MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),
 
1496
      &image->exception);
 
1497
    if (status == MagickFail)
 
1498
      break;
 
1499
  } while (image_info->adjoin);
 
1500
  (void) WriteBlobByte(image,';'); /* terminator */
 
1501
  MagickFreeMemory(global_colormap);
 
1502
  MagickFreeMemory(colormap);
 
1503
  if (image_info->adjoin)
 
1504
    while (image->previous != (Image *) NULL)
 
1505
      image=image->previous;
 
1506
  CloseBlob(image);
 
1507
  return(MagickPass);
 
1508
}