1 // Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
2 // All rights reserved.
3 //
4 // This file is part of the ImageIO Library, and as been adapted for CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h $
7 // $Id: gif_impl.h bdecbc9 2020-10-16T10:47:54+02:00 Raphael Grimm
8 // SPDX-License-Identifier: LGPL-3.0-or-later
9 //
10 //
11 // Author(s) : ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
12
13 #ifdef CGAL_HEADER_ONLY
14 #define CGAL_INLINE_FUNCTION inline
15 #else
16 #define CGAL_INLINE_FUNCTION
17 #endif
18
19 #include <string.h>
20
21 #ifdef WIN32
22 #include <io.h>
23 #endif
24
25 #ifdef CGAL_HEADER_ONLY
26
27 #define CGAL_GLOBAL_STATE_VAR(TYPE, NAME, VALUE) \
28 inline TYPE & get_static_##NAME() \
29 { \
30 static TYPE NAME = VALUE; \
31 return NAME; \
32 }
33
34 #else // CGAL_HEADER_ONLY
35
36 #define CGAL_GLOBAL_STATE_VAR(TYPE, NAME, VALUE) \
37 TYPE NAME; \
38 inline TYPE& get_static_##NAME() \
39 { \
40 return NAME; \
41 }
42
43 #endif // CGAL_HEADER_ONLY
44
45
46 /** Magic header for GIF files */
47 #define GIF_MAGIC "GIF8"
48
49
50
51 typedef unsigned char byte;
52 #define TRUE 1
53 #define FALSE 0
54
55 #define NEXTBYTE (*ptr++)
56 #define EXTENSION 0x21
57 #define IMAGESEP 0x2c
58 #define TRAILER 0x3b
59 #define INTERLACEMASK 0x40
60 #define COLORMAPMASK 0x80
61
62
63 #define CGAL_GIF_IMPL_DEBUG 0
64
65 //FILE *fp;
66 //int gif89 = 0;
67 static const char *id87 = "GIF87a";
68 static const char *id89 = "GIF89a";
69
70 static int EGApalette[16][3] = {
71 {0,0,0}, {0,0,128}, {0,128,0}, {0,128,128},
72 {128,0,0}, {128,0,128}, {128,128,0}, {200,200,200},
73 {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
74 {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
75
76
77 static int ReadCode();
78 static void DoInterlace(byte);
79 static int GifError(const char *);
80
CGAL_GLOBAL_STATE_VAR(byte *,Raster,nullptr)81 CGAL_GLOBAL_STATE_VAR(byte *, Raster, nullptr) /* The raster data stream, unblocked */
82 CGAL_GLOBAL_STATE_VAR(byte *, RawGIF, nullptr)
83 CGAL_GLOBAL_STATE_VAR(byte *, r, nullptr)
84 CGAL_GLOBAL_STATE_VAR(byte *, g, nullptr)
85 CGAL_GLOBAL_STATE_VAR(byte *, b, nullptr) /* The colormap */
86 CGAL_GLOBAL_STATE_VAR(int, BitOffset, 0) /* Bit Offset of next code */
87 CGAL_GLOBAL_STATE_VAR(int, XC, 0)
88 CGAL_GLOBAL_STATE_VAR(int, YC, 0) /* Output X and Y coords of current pixel */
89 CGAL_GLOBAL_STATE_VAR(int, CodeSize, 0) /* Code size, read from GIF header */
90 CGAL_GLOBAL_STATE_VAR(int, ReadMask, 0) /* Code AND mask for current code size */
91 CGAL_GLOBAL_STATE_VAR(int, Pass, 0) /* Used by output routine if interlaced pic */
92 CGAL_GLOBAL_STATE_VAR(int, Width, 0)
93 CGAL_GLOBAL_STATE_VAR(int, Height, 0) /* image dimensions */
94 CGAL_GLOBAL_STATE_VAR(unsigned char *, org, nullptr)
95 CGAL_GLOBAL_STATE_VAR(unsigned char *, buf, nullptr)
96
97 CGAL_INLINE_FUNCTION
98 int testGifHeader(char *magic,const char *) {
99 if (!strcmp(magic, GIF_MAGIC))
100 return 0;
101 else
102 return -1;
103 }
104 CGAL_INLINE_FUNCTION
createGifFormat()105 PTRIMAGE_FORMAT createGifFormat() {
106 PTRIMAGE_FORMAT f=(PTRIMAGE_FORMAT) ImageIO_alloc(sizeof(IMAGE_FORMAT));
107
108 f->testImageFormat=&testGifHeader;
109 f->readImageHeader=&readGifImage;
110 f->writeImage=0;
111 strcpy(f->fileExtension,".gif");
112 strcpy(f->realName,"Gif");
113 return f;
114 }
115
116 CGAL_INLINE_FUNCTION
use(int)117 void use(int) {} // warning killer
118
119 /*****************************/
120 CGAL_INLINE_FUNCTION
readGifImage(const char * name,_image * im)121 int readGifImage(const char *name,_image *im) {
122 FILE *fp;
123 int gif89 = 0;
124
125 byte ch, ch1;
126 byte *ptr, *ptr1;
127 int i, block;
128 int npixels, maxpixels, aspect;
129 float normaspect;
130 int OutCount = 0, /* Decompressor output 'stack count' */
131 RWidth, RHeight, /* screen dimensions */
132 /*LeftOfs, TopOfs, image offset */
133 BitsPerPixel, /* Bits per pixel, read from GIF header */
134 ColorMapSize, /* number of colors */
135 Background, /* background color */
136 InitCodeSize, /* Starting code size, used during Clear */
137 Code, /* Value returned by ReadCode */
138 MaxCode, /* limiting value for current code size */
139 ClearCode, /* GIF clear code */
140 EOFCode, /* GIF end-of-information code */
141 CurCode, OldCode=0, InCode, /* Decompressor variables */
142 FirstFree, /* First free code, generated per GIF spec */
143 FreeCode, /* Decompressor,next free slot in hash table */
144 FinChar=0, /* Decompressor variable */
145 BitMask, /* AND mask for data size */
146 Misc; /* miscellaneous bits (interlace, local cmap)*/
147 int Interlace, HasColormap;
148 /* not used
149 */
150 /* char header[10]; */
151
152 /* The hash table used by the decompressor */
153 int Prefix[4096];
154 int Suffix[4096];
155 /* An output array used by the decompressor */
156 int OutCode[4097];
157
158 /* initialize variables */
159 get_static_BitOffset() =
160 get_static_XC() =
161 get_static_YC() =
162 get_static_Pass() =
163 OutCount =
164 npixels =
165 maxpixels = 0;
166 get_static_RawGIF() = get_static_Raster() = nullptr;
167 gif89 = 0;
168
169 #ifdef WIN32
170 fp = fopen(name,"rb");
171 #else
172 fp = fopen(name,"r");
173 #endif
174 fp = fopen(name,"rb");
175 if (!fp) {
176 return(GifError("could not open a GIF file"));
177 }
178 /* find the size of the file */
179 fseek(fp, 0L, 2);
180 long filesize = ftell(fp);
181 fseek(fp, 0L, 0);
182
183 /* the +256's are so we can read truncated GIF files without fear of
184 segmentation violation */
185 if (!(ptr = get_static_RawGIF() = (byte *) ImageIO_alloc(filesize+256)))
186 return( GifError("not enough memory to read gif file") );
187
188 if (!(get_static_Raster() = (byte *) ImageIO_alloc(filesize+256)))
189 return( GifError("not enough memory to read gif file") );
190
191 if (fread(ptr, filesize, 1, fp) != 1)
192 return( GifError("GIF data read failed") );
193 if (strncmp((char *) ptr, id87, 6)==0) gif89 = 0;
194 else if (strncmp((char *) ptr, id89, 6)==0) gif89 = 1;
195 else return( GifError("not a GIF file"));
196
197 ptr += 6;
198 /* Get variables from the GIF screen descriptor */
199
200 ch = NEXTBYTE;
201 RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
202 ch = NEXTBYTE;
203 RHeight = ch + 0x100 * NEXTBYTE;
204 use(RWidth);
205 use(RHeight);
206
207 ch = NEXTBYTE;
208 HasColormap = ((ch & COLORMAPMASK) ? TRUE : FALSE);
209
210 BitsPerPixel = (ch & 7) + 1;
211 ColorMapSize = 1 << BitsPerPixel;
212 BitMask = ColorMapSize - 1;
213
214 Background = NEXTBYTE; /* background color... not used. */
215 use(Background);
216
217
218 aspect = NEXTBYTE;
219 if (aspect) {
220 if (!gif89) return(GifError("corrupt GIF file (screen descriptor)"));
221 else normaspect = (float) (aspect + 15) / 64.0f; /* gif89 aspect ratio */
222 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect);
223 }
224
225
226 /* Read in global colormap. */
227 if (HasColormap)
228 {
229 get_static_r() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
230 get_static_g() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
231 get_static_b() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
232
233 for (i = 0; i < ColorMapSize; i++) {
234 get_static_r()[i] = NEXTBYTE;
235 get_static_g()[i] = NEXTBYTE;
236 get_static_b()[i] = NEXTBYTE;
237 }
238 }
239 else {
240 /* no colormap in GIF file */
241 /* put std EGA palette (repeated 16 times) into colormap, for lack of
242 anything better to do */
243 ColorMapSize = 256;
244 get_static_r() = (byte *) ImageIO_alloc(256 * sizeof(byte));
245 get_static_g() = (byte *) ImageIO_alloc(256 * sizeof(byte));
246 get_static_b() = (byte *) ImageIO_alloc(256 * sizeof(byte));
247
248 for (i = 0; i < 256; i++) {
249 get_static_r()[i] = byte(EGApalette[i&15][0]);
250 get_static_g()[i] = byte(EGApalette[i&15][1]);
251 get_static_b()[i] = byte(EGApalette[i&15][2]);
252 }
253 }
254
255 /* possible things at this point are:
256 * an application extension block
257 * a comment extension block
258 * an (optional) graphic control extension block
259 * followed by either an image
260 * or a plaintext extension
261 */
262 while (1) {
263 block = NEXTBYTE;
264
265 if (block == EXTENSION) { /* parse extension blocks */
266 int i, fn, blocksize, aspnum, aspden;
267
268 /* read extension block */
269 fn = NEXTBYTE;
270
271 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF extension type 0x%02x\n", fn);
272
273 if (fn == 'R') { /* GIF87 aspect extension */
274 blocksize = NEXTBYTE;
275 if (blocksize == 2) {
276 aspnum = NEXTBYTE;
277 aspden = NEXTBYTE;
278 if (aspden>0 && aspnum>0)
279 normaspect = (float) aspnum / (float) aspden;
280 else { normaspect = 1.0; aspnum = aspden = 1; }
281
282 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n\n",
283 aspnum, aspden,normaspect);
284 }
285 else {
286 for (i=0; i<blocksize; i++) (void)NEXTBYTE;
287 }
288 }
289
290 else if (fn == 0xFE) { /* Comment Extension. just eat it */
291 int ch, j, sbsize;
292
293 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"Comment extension: ");
294 /* read (and ignore) data sub-blocks */
295 do {
296 j = 0; sbsize = NEXTBYTE;
297 while (j<sbsize) {
298 ch = NEXTBYTE; j++;
299 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"%c", ch);
300 }
301 } while (sbsize);
302 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"\n\n");
303 }
304
305 else if (fn == 0x01) { /* PlainText Extension */
306 int j,sbsize,ch;
307 int tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg;
308
309 /* SetISTR(ISTR_WARNING,
310 "PlainText extension found in GIF file. Ignored.");*/
311
312 sbsize = NEXTBYTE;
313 tgLeft = NEXTBYTE; tgLeft += (NEXTBYTE)<<8;
314 tgTop = NEXTBYTE; tgTop += (NEXTBYTE)<<8;
315 tgWidth = NEXTBYTE; tgWidth += (NEXTBYTE)<<8;
316 tgHeight = NEXTBYTE; tgHeight += (NEXTBYTE)<<8;
317 cWidth = NEXTBYTE;
318 cHeight = NEXTBYTE;
319 fg = NEXTBYTE;
320 bg = NEXTBYTE;
321 i=12;
322 for ( ; i<sbsize; i++) (void)NEXTBYTE; /* read rest of first subblock */
323
324 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,
325 "PlainText: tgrid=%d,%d %dx%d cell=%dx%d col=%d,%d\n",
326 tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight,
327 fg, bg);
328
329 /* read (and ignore) data sub-blocks */
330 do {
331 j = 0;
332 sbsize = NEXTBYTE;
333 while (j<sbsize) {
334 ch = NEXTBYTE; j++;
335 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"%c", ch);
336 }
337 } while (sbsize);
338 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"\n\n");
339 }
340
341
342 else if (fn == 0xF9) { /* Graphic Control Extension */
343 int j, sbsize;
344
345 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"Graphic Control extension\n\n");
346
347 /* SetISTR(ISTR_WARNING,
348 "Graphic Control Extension in GIF file. Ignored.");*/
349
350 /* read (and ignore) data sub-blocks */
351 do {
352 j = 0; sbsize = NEXTBYTE;
353 while (j<sbsize) { (void)NEXTBYTE; j++; }
354 } while (sbsize);
355 }
356
357
358 else { /* unknown extension */
359 int j, sbsize;
360
361 if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"unknown GIF extension 0x%02x\n\n", fn);
362
363 /* SetISTR(ISTR_WARNING,
364 "Unknown extension 0x%02x in GIF file. Ignored.",fn);*/
365
366 /* read (and ignore) data sub-blocks */
367 do {
368 j = 0; sbsize = NEXTBYTE;
369 while (j<sbsize) { (void)NEXTBYTE; j++; }
370 } while (sbsize);
371 }
372 }
373
374 else if (block == IMAGESEP) break; /* read an image */
375
376 else if (block == TRAILER) {
377 return( GifError("no image data found in GIF file") );
378 }
379
380 else return (GifError("Unknown block type found in file."));
381 }
382
383
384 /* read in values from the image descriptor */
385 ch = NEXTBYTE;
386 /* LeftOfs = ch + 0x100 * NEXTBYTE;*/
387 ch = NEXTBYTE;
388 /* TopOfs = ch + 0x100 * NEXTBYTE; */
389 ch = NEXTBYTE;
390 ch = NEXTBYTE;
391 ch = NEXTBYTE;
392 get_static_Width() = ch + 0x100 * NEXTBYTE;
393 ch = NEXTBYTE;
394 get_static_Height() = ch + 0x100 * NEXTBYTE;
395
396 Misc = NEXTBYTE;
397 Interlace = ((Misc & INTERLACEMASK) ? TRUE : FALSE);
398
399 if (Misc & 0x80) {
400 for (i=0; i< 1 << ((Misc&7)+1); i++) {
401 get_static_r()[i] = NEXTBYTE;
402 get_static_g()[i] = NEXTBYTE;
403 get_static_b()[i] = NEXTBYTE;
404 }
405 }
406
407
408 if (!HasColormap && !(Misc&0x80)) {
409 /* no global or local colormap */
410 /* SetISTR(ISTR_WARNING,
411 "No colormap in this GIF file. Assuming EGA colors.");*/
412 }
413
414
415
416 /* Start reading the raster data. First we get the intial code size
417 * and compute decompressor constant values, based on this code size.
418 */
419
420 /* SetISTR(ISTR_FORMAT, "GIF%s, %d bits per pixel, %sinterlaced. (%d bytes)",
421 (gif89) ? "89" : "87", BitsPerPixel,
422 Interlace ? "" : "non-", filesize);*/
423
424 get_static_CodeSize() = NEXTBYTE;
425
426 ClearCode = (1 << get_static_CodeSize());
427 EOFCode = ClearCode + 1;
428 FreeCode = FirstFree = ClearCode + 2;
429
430 /* The GIF spec has it that the code size is the code size used to
431 * compute the above values is the code size given in the file, but the
432 * code size used in compression/decompression is the code size given in
433 * the file plus one. (thus the ++).
434 */
435 get_static_CodeSize()++;
436 InitCodeSize = get_static_CodeSize();
437 MaxCode = (1 << get_static_CodeSize());
438 get_static_ReadMask() = MaxCode - 1;
439
440 /* UNBLOCK:
441 * Read the raster data. Here we just transpose it from the GIF array
442 * to the Raster array, turning it from a series of blocks into one long
443 * data stream, which makes life much easier for ReadCode().
444 */
445
446 ptr1 = get_static_Raster();
447 do {
448 ch = ch1 = NEXTBYTE;
449 while (ch--) {
450 *ptr1 = NEXTBYTE;
451 ptr1++; }
452 if ((ptr - get_static_RawGIF()) > filesize) {
453 /* SetISTR(ISTR_WARNING,
454 "This GIF file seems to be truncated. Winging it.");*/
455 break;
456 }
457 } while(ch1);
458 ImageIO_free(get_static_RawGIF()); get_static_RawGIF() = nullptr;
459
460
461 if (CGAL_GIF_IMPL_DEBUG) {
462 fprintf(stderr,"xv: LoadGIF() - picture is %dx%d, %d bits, %sinterlaced\n",
463 get_static_Width(), get_static_Height(), BitsPerPixel, Interlace ? "" : "non-");
464 }
465
466
467 /* Allocate the 'pic' */
468 maxpixels = get_static_Width()*get_static_Height();
469 im->xdim = get_static_Width();
470 im->ydim = get_static_Height();
471 im->zdim = 1;
472 im->vdim = 3;
473 im->wdim = 1;
474 im->wordKind = WK_FIXED;
475 im->sign = SGN_UNSIGNED;
476 im->data = ImageIO_alloc(get_static_Width() * get_static_Height() * 3);
477 get_static_org() = get_static_buf() = (unsigned char *) im->data;
478
479 if (!get_static_org())
480 return( GifError("not enough memory for image buffer") );
481
482
483 /* Decompress the file, continuing until you see the GIF EOF code.
484 * One obvious enhancement is to add checking for corrupt files here.
485 */
486 Code = ReadCode();
487 while (Code != EOFCode) {
488 /* Clear code sets everything back to its initial value, then reads the
489 * immediately subsequent code as uncompressed data.
490 */
491
492 if (Code == ClearCode) {
493 get_static_CodeSize() = InitCodeSize;
494 MaxCode = (1 << get_static_CodeSize());
495 get_static_ReadMask() = MaxCode - 1;
496 FreeCode = FirstFree;
497 Code = ReadCode();
498 CurCode = OldCode = Code;
499 FinChar = CurCode & BitMask;
500 if (!Interlace) {
501 *get_static_buf()++ = get_static_r()[FinChar];
502 *get_static_buf()++ = get_static_g()[FinChar];
503 *get_static_buf()++ = get_static_b()[FinChar];
504 }
505 else DoInterlace((byte)FinChar);
506 npixels++;
507 }
508
509 else {
510 /* If not a clear code, must be data: save same as CurCode and InCode */
511
512 /* if we're at maxcode and didn't get a clear, stop loading */
513 if (FreeCode>=4096) {
514 printf("freecode blew up\n");
515 break;
516 }
517
518 CurCode = InCode = Code;
519
520 /* If greater or equal to FreeCode, not in the hash table yet;
521 * repeat the last character decoded
522 */
523
524 if (CurCode >= FreeCode) {
525 CurCode = OldCode;
526 if (OutCount > 4096) {
527 printf("outcount1 blew up\n"); break; }
528 OutCode[OutCount++] = FinChar;
529 }
530
531 /* Unless this code is raw data, pursue the chain pointed to by CurCode
532 * through the hash table to its end; each code in the chain puts its
533 * associated output code on the output queue.
534 */
535
536 while (CurCode > BitMask) {
537 if (OutCount > 4096) {
538 fprintf(stderr,"outcount2 blew up\n"); break;} /* corrupt file */
539 OutCode[OutCount++] = Suffix[CurCode];
540 CurCode = Prefix[CurCode];
541 }
542
543 if (OutCount > 4096) {
544 printf("outcount blew up\n"); break; }
545
546 /* The last code in the chain is treated as raw data. */
547
548 FinChar = CurCode & BitMask;
549 OutCode[OutCount++] = FinChar;
550
551 /* Now we put the data out to the Output routine.
552 * It's been stacked LIFO, so deal with it that way...
553 */
554
555 /* safety thing: prevent exceeding range of 'pic' */
556 if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
557
558 npixels += OutCount;
559 if (!Interlace) for (i=OutCount-1; i>=0; i--) {
560 *get_static_buf()++ = get_static_r()[OutCode[i]];
561 *get_static_buf()++ = get_static_g()[OutCode[i]];
562 *get_static_buf()++ = get_static_b()[OutCode[i]];
563 }
564 else for (i=OutCount-1; i>=0; i--) DoInterlace((byte)OutCode[i]);
565 OutCount = 0;
566
567 /* Build the hash table on-the-fly. No table is stored in the file. */
568
569 Prefix[FreeCode] = OldCode;
570 Suffix[FreeCode] = FinChar;
571 OldCode = InCode;
572
573 /* Point to the next slot in the table. If we exceed the current
574 * MaxCode value, increment the code size unless it's already 12. If it
575 * is, do nothing: the next code decompressed better be CLEAR
576 */
577
578 FreeCode++;
579 if (FreeCode >= MaxCode) {
580 if (get_static_CodeSize() < 12) {
581 get_static_CodeSize()++;
582 MaxCode *= 2;
583 get_static_ReadMask() = (1 << get_static_CodeSize()) - 1;
584 }
585 }
586 }
587 Code = ReadCode();
588 if (npixels >= maxpixels) break;
589 }
590 ImageIO_free(get_static_Raster()); get_static_Raster() = nullptr;
591
592 if (npixels != maxpixels) {
593 /* SetISTR(ISTR_WARNING,"This GIF file seems to be truncated. Winging it.");*/
594 if (!Interlace)
595 memset(get_static_buf(), 0, 3*(maxpixels-npixels)); /* clear to EOBuffer */
596 }
597 /* SetDirRButt(F_FORMAT, F_GIF);
598 SetDirRButt(F_COLORS, F_FULLCOLOR);*/
599 return 1;
600 }
601
602
603 /* Fetch the next code from the raster data stream. The codes can be
604 * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
605 * maintain our location in the Raster array as a BIT Offset. We compute
606 * the byte Offset into the raster array by dividing this by 8, pick up
607 * three bytes, compute the bit Offset into our 24-bit chunk, shift to
608 * bring the desired code to the bottom, then mask it off and return it.
609 */
610
611 CGAL_INLINE_FUNCTION
ReadCode()612 static int ReadCode()
613 {
614 int RawCode, ByteOffset;
615
616 ByteOffset = get_static_BitOffset() / 8;
617 RawCode = get_static_Raster()[ByteOffset] + (get_static_Raster()[ByteOffset + 1] << 8);
618 if (get_static_CodeSize() >= 8)
619 RawCode += ( ((int) get_static_Raster()[ByteOffset + 2]) << 16);
620 RawCode >>= (get_static_BitOffset() % 8);
621 get_static_BitOffset() += get_static_CodeSize();
622
623 return(RawCode & get_static_ReadMask());
624 }
625
626
627 /***************************/
628 CGAL_INLINE_FUNCTION
DoInterlace(byte Index)629 static void DoInterlace(byte Index) {
630 static byte *ptr = nullptr;
631 static int oldYC = -1;
632
633 if (oldYC != get_static_YC()) {
634 ptr = get_static_org() + 3 * get_static_YC() * get_static_Width();
635 oldYC = get_static_YC();
636 }
637
638 if (get_static_YC() < get_static_Height()) {
639 *ptr++ = get_static_r()[Index];
640 *ptr++ = get_static_g()[Index];
641 *ptr++ = get_static_b()[Index];
642 }
643
644 /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
645 if (++get_static_XC() == get_static_Width()) {
646
647 /* deal with the interlace as described in the GIF
648 * spec. Put the decoded scan line out to the screen if we haven't gone
649 * past the bottom of it
650 */
651
652 get_static_XC() = 0;
653
654 switch (get_static_Pass()) {
655 case 0:
656 get_static_YC() += 8;
657 if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 4; }
658 break;
659
660 case 1:
661 get_static_YC() += 8;
662 if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 2; }
663 break;
664
665 case 2:
666 get_static_YC() += 4;
667 if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 1; }
668 break;
669
670 case 3:
671 get_static_YC() += 2; break;
672
673 default:
674 break;
675 }
676 }
677 }
678
679
680
681 /*****************************/
682 CGAL_INLINE_FUNCTION
GifError(const char * st)683 static int GifError(const char *st) {
684 fprintf(stderr,"readGifImage: error: %s\n",st);
685
686 if (get_static_RawGIF() != nullptr) ImageIO_free(get_static_RawGIF());
687 if (get_static_Raster() != nullptr) ImageIO_free(get_static_Raster());
688
689 return -1;
690 }
691
692 #undef CGAL_GLOBAL_STATE_VAR
693
694