1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
38 //-------------------------------
40 //-------------------------------
48 #include "OSGConfig.h"
53 #include "OSGGIFImageFileType.h"
58 # define OSG_GIF_ARG(ARG) ARG
60 # define OSG_GIF_ARG(ARG)
63 # define OSG_GIF_ARG(ARG) ARG
69 /*! \class OSG::GIFImageFileType
71 Image File Type to read/write and store/restore Image objects as
74 All the type specific code is included in the class. Does
75 not depend on external libs.
77 You have to --enable-gif in the configure line to enable
83 //--- GIF-INCLUDE START ----------------------------------------------------
85 #define GIF_MAXCOLORS 256
97 gif_keep_disposal
= 1,
98 gif_color_restore
= 2,
105 int transparent
; /* transparency index */
106 int delayTime
; /* Time in 1/100 of a second */
107 int inputFlag
; /* wait for input after display */
108 GIFDisposalType disposal
;
111 typedef struct GIFData
122 unsigned char cmapData
[GIF_MAXCOLORS
][3];
129 int cellWidth
, cellHeight
;
140 struct GIFData
*next
;
150 unsigned char cmapData
[GIF_MAXCOLORS
][3];
159 static GIFStream
*GIFRead (std::istream
&is
);
160 int GIFTest (char *);
161 int GIFWrite (char *, GIFStream
*, int);
162 static int GIFWriteFP(FILE *, GIFStream
*, int);
163 static int GIFFree (const GIFStream
*);
165 #endif // OSG_WITH_GIF
167 //--- GIF INCLUDE END ----------------------------------------------------
169 static const OSG::Char8
*gifSuffixArray
[] =
176 GIFImageFileType
GIFImageFileType::_the("image/gif",
178 sizeof(gifSuffixArray
));
182 //-------------------------------------------------------------------------
183 /*! Tries to fill the image object with the data read from
184 the given fileName. Returns true on success.
187 bool GIFImageFileType::read( Image
*OSG_GIF_ARG(pImage
),
188 std::istream
&OSG_GIF_ARG(is
),
189 const std::string
&OSG_GIF_ARG(mimetype
))
191 bool retCode
= false;
194 Image::PixelFormat pixelFormat
= Image::OSG_INVALID_PF
;
195 const GIFStream
*gifStream
= GIFRead(is
);
196 const GIFData
*gifData
= 0;
198 int i
, j
, destI
, lineSize
, lineEnd
;
199 unsigned red
, green
, blue
;
200 int transparentIndex
;
201 int streamWidth
= 0, streamHeight
= 0;
202 int curWidth
= 0, curHeight
= 0, channel
= 0;
203 int xOff
= 0, yOff
= 0;
204 const unsigned char *srcData
= 0;
205 unsigned char *destData
= 0;
207 unsigned frameCount
= 0, currentFrame
= 0;
208 const unsigned char *colorMap
= 0;
210 // int imageSize = 0;
218 for(gifData
= gifStream
->data
; gifData
; gifData
= gifData
->next
)
220 if(gifData
->type
== gif_image
)
225 FDEBUG(("GIF Frames: %d\n", frameCount
));
229 streamWidth
= gifStream
->width
;
230 streamHeight
= gifStream
->height
;
232 for(gifData
= gifStream
->data
; gifData
; gifData
= gifData
->next
)
234 switch(gifData
->type
)
239 FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
240 (currentFrame
+ 1), frameCount
));
244 transparentIndex
= gifData
->info
.transparent
;
245 frameDelay
= float(gifData
->info
.delayTime
) / 100.0f
;
246 curWidth
= gifData
->width
;
247 curHeight
= gifData
->height
;
251 // check if the movie is color or greyscale
253 if(gifData
->data
.image
.cmapSize
> 0)
255 colorMapSize
= gifData
->data
.image
.cmapSize
;
257 reinterpret_cast<const unsigned char *>(
258 gifData
->data
.image
.cmapData
);
260 // cout << "INFO: Use gifData colorMap" << endl;
262 else if(gifStream
->cmapSize
> 0)
264 colorMapSize
= gifStream
->cmapSize
;
266 reinterpret_cast<const unsigned char *>(
267 gifStream
->cmapData
);
269 // cout << "INFO: Use gifStream colorMap" << endl;
273 FWARNING(("Bad color map in "
274 "GIFImageFileType::read()\n"));
278 for(i
= 0; i
< colorMapSize
; i
++)
280 if(i
!= transparentIndex
)
282 red
= colorMap
[i
* 3 + 0];
283 green
= colorMap
[i
* 3 + 1];
284 blue
= colorMap
[i
* 3 + 2];
286 if(red
!= green
|| red
!= blue
)
294 // calculate the movie channel
296 (isColor
? 3 : 1) + (transparentIndex
>= 0 ? 1 : 0);
300 // is not the first frame
301 if((channel
== pImage
->getBpp()) &&
302 (streamWidth
== pImage
->getWidth()) &&
303 (streamHeight
== pImage
->getHeight()))
305 destData
= pImage
->editData(0, currentFrame
);
309 destData
= pImage
->editData(0, currentFrame
);
311 // This is probably wrong, but it's a start
312 switch(gifData
->info
.disposal
)
314 case gif_no_disposal
:
317 case gif_keep_disposal
:
321 pImage
->getWidth () *
322 pImage
->getHeight() *
326 case gif_color_restore
:
328 unsigned char r
,g
,b
,a
;
329 Int32 bgindex
= gifStream
->background
;
330 unsigned char *d
= destData
;
332 r
= colorMap
[bgindex
* 3 + 0];
333 g
= colorMap
[bgindex
* 3 + 1];
334 b
= colorMap
[bgindex
* 3 + 2];
335 a
= (bgindex
== transparentIndex
) ?
339 pImage
->getWidth () *
341 pixel
> 0; --pixel
, d
+= channel
)
352 case gif_image_restore
:
356 (currentFrame
>= 2) ?
357 (currentFrame
- 2) : 0),
358 pImage
->getWidth () *
359 pImage
->getHeight() *
363 FWARNING(("Unknown GIF disposal "
365 gifData
->info
.disposal
));
375 pixelFormat
= Image::OSG_L_PF
;
378 pixelFormat
= Image::OSG_LA_PF
;
381 pixelFormat
= Image::OSG_RGB_PF
;
384 pixelFormat
= Image::OSG_RGBA_PF
;
387 pImage
->set(pixelFormat
,
391 frameCount
, frameDelay
);
393 destData
= pImage
->editData();
396 // copy the image data
397 lineSize
= pImage
->getWidth() * channel
;
398 lineEnd
= curWidth
* channel
+ xOff
* channel
;
399 srcData
= gifData
->data
.image
.data
;
401 destData
+ ((pImage
->getHeight() - yOff
- 1)*lineSize
);
405 case 1: // Greyscale without Alpha
407 for(i
= curWidth
* curHeight
; i
--;)
409 destData
[destI
++] = colorMap
[*srcData
++ *3];
413 destData
-= lineSize
;
418 case 2: // Greyscale with Alpha
420 for(i
= curWidth
* curHeight
; i
--;)
422 colorIndex
= *srcData
++;
423 if(colorIndex
== transparentIndex
)
425 destData
[destI
++] = 0;
426 destData
[destI
++] = 0;
430 destData
[destI
++] = colorMap
[colorIndex
*3];
431 destData
[destI
++] = 255;
437 destData
-= lineSize
;
442 case 3: // RGB without Alpha
444 for(i
= curWidth
* curHeight
; i
--;)
446 colorIndex
= *srcData
++;
447 for(j
= 0; j
< 3; j
++)
450 colorMap
[colorIndex
* 3 + j
];
456 destData
-= lineSize
;
461 case 4: // RGB with Alpha
464 for(i
= curWidth
* curHeight
; i
--;)
466 colorIndex
= *srcData
++;
467 if(colorIndex
== transparentIndex
)
470 for(j
= 0; j
< 3; j
++)
471 destData
[destI
++] = 0; // RGB
472 destData
[destI
++] = 0; // ALPHA
479 for(j
= 0; j
< 3; j
++)
482 colorMap
[colorIndex
* 3 + j
];// RGB
485 destData
[destI
++] = 255; // ALPHA
491 destData
-= lineSize
;
520 //-------------------------------------------------------------------------
521 /*! Tries to write the image object to the given fileName.
522 Returns true on success.
525 bool GIFImageFileType::write(const Image
* ,
530 SWARNING
<< getMimeType() << " write is not implemented " << endLog
;
533 SWARNING
<< getMimeType()
534 << " write is not compiled into the current binary "
541 //-------------------------------------------------------------------------
543 Tries to determine the mime type of the data provided by an input stream
544 by searching for magic bytes. Returns the mime type or an empty string
545 when the function could not determine the mime type.
548 std::string
GIFImageFileType::determineMimetypeFromStream(std::istream
&is
)
552 is
.read(filecode
, 4);
553 is
.seekg(-4, std::ios::cur
);
555 return strncmp(filecode
, "GIF8", 4) == 0 ?
556 std::string(getMimeType()) : std::string();
559 bool GIFImageFileType::validateHeader(const Char8
*fileName
, bool &implemented
)
566 FILE *file
= fopen(fileName
, "rb");
575 fread(static_cast<void *>(&magic
[0]), 4, 1, file
);
587 //-------------------------------------------------------------------------
588 /*! Constructor used for the singleton object
591 GIFImageFileType::GIFImageFileType(const Char8
*mimeType
,
592 const Char8
*suffixArray
[],
593 UInt16 suffixByteCount
) :
594 Inherited(mimeType
,suffixArray
, suffixByteCount
)
598 //-------------------------------------------------------------------------
602 GIFImageFileType::~GIFImageFileType(void)
608 //--- GIF-READ START ----------------------------------------------------
610 ** Copyright 1994, Home Pages, Inc.
612 ** Please read the file COPYRIGHT for specific information.
615 ** 257 Castro St. Suite 219
616 ** Mountain View, CA 94041
618 ** Phone: 1 415 903 5353
619 ** Fax: 1 415 903 5345
621 ** EMail: support@homepages.com
624 /* +-------------------------------------------------------------------+ */
625 /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */
626 /* | Permission to use, copy, modify, and distribute this software | */
627 /* | and its documentation for any purpose and without fee is hereby | */
628 /* | granted, provided that the above copyright notice appear in all | */
629 /* | copies and that both that copyright notice and this permission | */
630 /* | notice appear in supporting documentation. This software is | */
631 /* | provided "as is" without express or implied warranty. | */
632 /* +-------------------------------------------------------------------+ */
636 #define MAX_LWZ_BITS 12
638 #define INTERLACE 0x40
639 #define LOCALCOLORMAP 0x80
641 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
642 #define ReadOK(is, buffer, len) (is.read(reinterpret_cast<char*>(buffer), \
643 len).gcount() == len)
644 #define MKINT(a, b) (((b) << 8) | (a))
645 #define NEW(x) (static_cast<x *>(malloc(sizeof(x))))
646 /***************************************************************************
648 * ERROR() -- should not return
649 * INFO_MSG() -- info message, can be ignored
651 ***************************************************************************/
654 #define INFO_MSG(fmt) pm_message fmt
655 #define ERROR(str) pm_error(str)
658 #define INFO_MSG(fmt)
659 #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
661 #define INFO_MSG(fmt) { FINFO(("Info loading gif: '%s'!\n", fmt)); }
662 #define GIF_ERROR(str) { FWARNING(("Error loading gif: '%s'!\n", str)); \
663 longjmp(setjmp_buffer, 1); }
667 /***************************************************************************/
669 static int readColorMap(std::istream
&, int, unsigned char [GIF_MAXCOLORS
][3]);
670 static int GetDataBlock(std::istream
&, unsigned char *);
671 static void readImage (std::istream
&, int, int, int, unsigned char *);
673 static jmp_buf setjmp_buffer
;
675 static int verbose
= GIF_FALSE
;
676 //static int showComment = GIF_FALSE;
679 static GIFStream
*GIFRead(std::istream
&is
)
681 unsigned char buf
[256];
683 GIFStream
*gifStream
= 0;
685 GIF89info info
= {0, 0, 0, gif_no_disposal
};
686 int resetInfo
= GIF_TRUE
;
689 if(setjmp(setjmp_buffer
))
692 if(!ReadOK(is
, buf
, 6))
694 GIF_ERROR("error reading magic number");
697 if(strncmp(reinterpret_cast<char *>(buf
), "GIF", 3) != 0)
698 GIF_ERROR("not a GIF file");
700 if((strncmp((reinterpret_cast<char *>(buf
)) + 3, "87a", 3) != 0) &&
701 (strncmp((reinterpret_cast<char *>(buf
)) + 3, "89a", 3) != 0))
703 GIF_ERROR("bad version number, not '87a' or '89a'");
706 if(!ReadOK(is
, buf
, 7))
708 GIF_ERROR("failed to read screen descriptor");
711 gifStream
= NEW(GIFStream
);
713 gifStream
->width
= MKINT(buf
[0], buf
[1]);
714 gifStream
->height
= MKINT(buf
[2], buf
[3]);
716 gifStream
->cmapSize
= 2 << (buf
[4] & 0x07);
717 gifStream
->colorMapSize
= gifStream
->cmapSize
;
718 gifStream
->colorResolution
= (int(buf
[4] & 0x70) >> 3) + 1;
719 gifStream
->background
= buf
[5];
720 gifStream
->aspectRatio
= buf
[6];
722 gifStream
->data
= NULL
;
724 end
= &gifStream
->data
;
727 ** Global colormap is present.
729 if(BitSet(buf
[4], LOCALCOLORMAP
))
731 if(readColorMap(is
, gifStream
->cmapSize
, gifStream
->cmapData
))
733 GIF_ERROR("unable to get global colormap");
738 gifStream
->cmapSize
= 0;
739 gifStream
->background
= -1;
742 if(gifStream
->aspectRatio
!= 0 && gifStream
->aspectRatio
!= 49)
744 INFO_MSG(("warning - non-square pixels"));
747 while(ReadOK(is
, &c
, 1) && c
!= ';')
751 info
.disposal
= static_cast<GIFDisposalType
>(0);
754 info
.transparent
= -1;
755 resetInfo
= GIF_FALSE
;
762 if(!ReadOK(is
, &c
, 1))
764 GIF_ERROR("EOF / read error on extention function code");
768 { /* graphic control */
769 (void) GetDataBlock(is
, buf
);
771 static_cast<GIFDisposalType
>((buf
[0] >> 2) & 0x7);
772 info
.inputFlag
= (buf
[0] >> 1) & 0x1;
773 info
.delayTime
= MKINT(buf
[1], buf
[2]);
774 if(BitSet(buf
[0], 0x1))
775 info
.transparent
= buf
[3];
777 while(GetDataBlock(is
, buf
) != 0)
780 else if(c
== 0xfe || c
== 0x01)
787 ** Comment or Plain Text
793 (void) GetDataBlock(is
, buf
);
795 cur
->type
= gif_text
;
797 cur
->x
= MKINT(buf
[0], buf
[1]);
798 cur
->y
= MKINT(buf
[2], buf
[3]);
799 cur
->width
= MKINT(buf
[4], buf
[5]);
800 cur
->height
= MKINT(buf
[6], buf
[7]);
802 cur
->data
.text
.cellWidth
= buf
[8];
803 cur
->data
.text
.cellHeight
= buf
[9];
804 cur
->data
.text
.fg
= buf
[10];
805 cur
->data
.text
.bg
= buf
[11];
807 resetInfo
= GIF_TRUE
;
811 cur
->type
= gif_comment
;
814 text
= static_cast<char *>(malloc(size
));
816 while((n
= GetDataBlock(is
, buf
)) != 0)
820 text
= static_cast<char *>(realloc(text
, size
+= 256));
823 memcpy(text
+ len
, buf
, n
);
829 cur
->data
.text
.len
= len
;
830 cur
->data
.text
.text
= text
;
834 cur
->data
.comment
.len
= len
;
835 cur
->data
.comment
.text
= text
;
841 ** Unrecogonized extension, consume it.
843 while(GetDataBlock(is
, buf
) > 0)
849 if(!ReadOK(is
, buf
, 9))
851 GIF_ERROR("couldn't read left/top/width/height");
856 cur
->type
= gif_image
;
858 cur
->x
= MKINT(buf
[0], buf
[1]);
859 cur
->y
= MKINT(buf
[2], buf
[3]);
860 cur
->width
= MKINT(buf
[4], buf
[5]);
861 cur
->height
= MKINT(buf
[6], buf
[7]);
862 cur
->data
.image
.cmapSize
= 1 << ((buf
[8] & 0x07) + 1);
863 if(BitSet(buf
[8], LOCALCOLORMAP
))
865 if(readColorMap(is
, cur
->data
.image
.cmapSize
,
866 cur
->data
.image
.cmapData
))
868 GIF_ERROR("unable to get local colormap");
873 cur
->data
.image
.cmapSize
= 0;
876 cur
->data
.image
.data
= static_cast<unsigned char *>(
877 malloc(cur
->width
* cur
->height
));
878 cur
->data
.image
.interlaced
= BitSet(buf
[8], INTERLACE
);
879 readImage(is
, BitSet(buf
[8], INTERLACE
), cur
->width
, cur
->height
,
880 cur
->data
.image
.data
);
882 resetInfo
= GIF_TRUE
;
886 FINFO(("Info loading gif: bogus character 0x%02x, ignoring",
899 GIF_ERROR("EOF / data stream");
906 static int GIFFreeData(const GIFData
*gifData
)
912 switch(gifData
->type
)
915 if(gifData
->data
.image
.data
)
917 free(gifData
->data
.image
.data
);
921 if(gifData
->data
.comment
.text
)
923 free(gifData
->data
.comment
.text
);
927 if(gifData
->data
.text
.text
)
929 free(gifData
->data
.text
.text
);
943 static int GIFFree(const GIFStream
*gifStream
)
946 GIFData
*gifData
, *gifNext
;
950 gifData
= gifStream
->data
;
953 gifNext
= gifData
->next
;
954 GIFFreeData(gifData
);
964 static int readColorMap(std::istream
&is
, int size
, unsigned char data
[GIF_MAXCOLORS
][3])
967 unsigned char rgb
[3 * GIF_MAXCOLORS
];
968 unsigned char *cp
= rgb
;
970 if(!ReadOK(is
, rgb
, size
* 3))
973 for(i
= 0; i
< size
; i
++)
986 static int ZeroDataBlock
= GIF_FALSE
;
990 static int GetDataBlock(std::istream
&is
, unsigned char *buf
)
994 if(!ReadOK(is
, &count
, 1))
996 INFO_MSG(("error in getting DataBlock size"));
1000 ZeroDataBlock
= count
== 0;
1002 if((count
!= 0) && (!ReadOK(is
, buf
, count
)))
1004 INFO_MSG(("error in reading DataBlock"));
1016 ** Pulled out of nextCode
1018 static int curbit
, lastbit
, get_done
, last_byte
;
1019 static int return_clear
;
1024 static int stack
[(1 << (MAX_LWZ_BITS
)) * 2], *sp
;
1025 static int code_size
, set_code_size
;
1026 static int max_code
, max_code_size
;
1027 static int clear_code
, end_code
;
1031 static void initLWZ(int input_code_size
)
1033 // static int inited = GIF_FALSE;
1035 set_code_size
= input_code_size
;
1036 code_size
= set_code_size
+ 1;
1037 clear_code
= 1 << set_code_size
;
1038 end_code
= clear_code
+ 1;
1039 max_code_size
= 2 * clear_code
;
1040 max_code
= clear_code
+ 2;
1042 curbit
= lastbit
= 0;
1044 get_done
= GIF_FALSE
;
1046 return_clear
= GIF_TRUE
;
1052 static int nextCode(std::istream
&is
, int code_size_in
)
1054 static unsigned char buf
[280];
1055 static int maskTbl
[16] =
1078 return_clear
= GIF_FALSE
;
1082 end
= curbit
+ code_size_in
;
1090 if(curbit
>= lastbit
)
1092 GIF_ERROR("ran off the end of my bits");
1098 buf
[0] = buf
[last_byte
- 2];
1099 buf
[1] = buf
[last_byte
- 1];
1101 if((count
= GetDataBlock(is
, &buf
[2])) == 0)
1102 get_done
= GIF_TRUE
;
1104 last_byte
= 2 + count
;
1105 curbit
= (curbit
- lastbit
) + 16;
1106 lastbit
= (2 + count
) * 8;
1108 end
= curbit
+ code_size_in
;
1117 ret
= buf
[i
] | (buf
[i
+ 1] << 8);
1120 ret
= buf
[i
] | (buf
[i
+ 1] << 8) | (buf
[i
+ 2] << 16);
1123 ret
= (ret
>> (curbit
% 8)) & maskTbl
[code_size_in
];
1125 curbit
+= code_size_in
;
1130 #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
1133 static int nextLWZ(std::istream
&is
)
1135 static int table
[2][(1 << MAX_LWZ_BITS
)];
1136 static int firstcode
, oldcode
;
1140 while((code
= nextCode(is
, code_size
)) >= 0)
1142 if(code
== clear_code
)
1144 for(i
= 0; i
< clear_code
; ++i
)
1150 for(; i
< (1 << MAX_LWZ_BITS
); ++i
)
1151 table
[0][i
] = table
[1][i
] = 0;
1152 code_size
= set_code_size
+ 1;
1153 max_code_size
= 2 * clear_code
;
1154 max_code
= clear_code
+ 2;
1158 firstcode
= oldcode
= nextCode(is
, code_size
);
1159 } while(firstcode
== clear_code
);
1164 if(code
== end_code
)
1167 unsigned char buf
[260];
1172 while((count
= GetDataBlock(is
, buf
)) > 0)
1177 INFO_MSG(("missing EOD in data stream"));
1185 if(code
>= max_code
)
1191 while(code
>= clear_code
)
1193 *sp
++ = table
[1][code
];
1194 if(code
== table
[0][code
])
1196 GIF_ERROR("circular table entry BIG ERROR");
1199 code
= table
[0][code
];
1202 *sp
++ = firstcode
= table
[1][code
];
1204 if((code
= max_code
) < (1 << MAX_LWZ_BITS
))
1206 table
[0][code
] = oldcode
;
1207 table
[1][code
] = firstcode
;
1209 if((max_code
>= max_code_size
) &&
1210 (max_code_size
< (1 << MAX_LWZ_BITS
)))
1227 static void readImage(std::istream
&is
, int interlace
, int width
, int height
,
1228 unsigned char *data
)
1230 unsigned char *dp
, c
;
1232 int v
, xpos
= 0, ypos
= 0;
1236 ** Initialize the Compression routines
1238 if(!ReadOK(is
, &c
, 1))
1240 GIF_ERROR("EOF / read error on image data");
1247 FINFO(("Info loading gif: reading %d by %d%s GIF image",
1248 width
, height
, interlace
? " interlaced" : ""));
1254 int pass
= 0, step
= 8;
1256 for(i
= 0; i
< height
; i
++)
1258 dp
= &data
[width
* ypos
];
1259 for(xpos
= 0; xpos
< width
; xpos
++)
1261 if((v
= readLWZ(is
)) < 0)
1267 if((ypos
+= step
) >= height
)
1274 } while(ypos
> height
);
1281 for(ypos
= 0; ypos
< height
; ypos
++)
1283 for(xpos
= 0; xpos
< width
; xpos
++)
1285 if((v
= readLWZ(is
)) < 0)
1294 if(readLWZ(is
) >= 0)
1296 INFO_MSG(("too much input data, ignoring extra..."));
1302 //--- GIF-READ END ------------------------------------------------------
1303 //--- GIF-WRITE START ---------------------------------------------------
1305 ** Copyright 1994, Home Pages, Inc.
1307 ** Please read the file COPYRIGHT for specific information.
1310 ** 257 Castro St. Suite 219
1311 ** Mountain View, CA 94041
1313 ** Phone: 1 415 903 5353
1314 ** Fax: 1 415 903 5345
1316 ** EMail: support@homepages.com
1319 /* +-------------------------------------------------------------------+ */
1320 /* | Copyright 1993, David Koblas (koblas@netcom.com) | */
1322 /* | Permission to use, copy, modify, and to distribute this software | */
1323 /* | and its documentation for any purpose is hereby granted without | */
1324 /* | fee, provided that the above copyright notice appear in all | */
1325 /* | copies and that both that copyright notice and this permission | */
1326 /* | notice appear in supporting documentation. There is no | */
1327 /* | representations about the suitability of this software for | */
1328 /* | any purpose. this software is provided "as is" without express | */
1329 /* | or implied warranty. | */
1331 /* +-------------------------------------------------------------------+ */
1332 /* ppmtogif.c - read a portable pixmap and produce a GIF file
1334 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
1335 ** Lempel-Zim compression based on "compress".
1337 ** Copyright (C) 1989 by Jef Poskanzer.
1339 ** Permission to use, copy, modify, and distribute this software and its
1340 ** documentation for any purpose and without fee is hereby granted, provided
1341 ** that the above copyright notice appear in all copies and that both that
1342 ** copyright notice and this permission notice appear in supporting
1343 ** documentation. This software is provided "as is" without express or
1344 ** implied warranty.
1346 ** The Graphics Interchange Format(c) is the Copyright property of
1347 ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
1348 ** CompuServe Incorporated.
1353 #define PUTBYTE(v, fp) putc(v, fp)
1354 #define PUTWORD(v, fp) \
1357 putc(((v) & 0xff), fp); \
1358 putc((((v) >> 8) & 0xff), fp); \
1361 * a code_int must be able to hold 2**BITS values of type int, and also -1
1363 typedef int code_int
;
1365 typedef long int count_int
;
1367 static void putImage(FILE *, int, int, int, int, unsigned char *);
1368 static void putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS
][3]);
1369 static void putDataBlocks(FILE *fp
, int, unsigned char *);
1370 static void putGif89Info(FILE *, GIF89info
*);
1372 static void output(code_int code
);
1373 static void cl_block(void);
1374 static void cl_hash(count_int hsize
);
1375 static void char_init(void);
1376 static void char_out(int c
);
1377 static void flush_char(void);
1388 static int cvalCMP(struct cval
*a
, struct cval
*b
)
1390 return b
->cnt
- a
->cnt
;
1394 static int optimizeCMAP(GIFStream
*stream
)
1396 GIFData
*cur
= 0, *img
= 0;
1399 for(cur
= stream
->data
; cur
!= NULL
; cur
= cur
->next
)
1401 if(cur
->type
== gif_image
)
1409 ** No images, no optimizations...
1410 ** or too many images...
1412 if(count
== 0 || count
> 1)
1416 ** One image, nice and simple...
1417 ** Insure there is a global colormap, and optimize the
1422 unsigned char *dp
= img
->data
.image
.data
;
1423 unsigned char *ep
= dp
+ img
->width
* img
->height
;
1424 struct cval vals
[256];
1428 unsigned char tmap
[256][3], rmap
[256];
1430 if((size
= img
->data
.image
.cmapSize
) == 0)
1431 size
= stream
->cmapSize
;
1433 for(i
= 0; i
< size
; i
++)
1439 for(dp
= img
->data
.image
.data
, i
= 0; dp
< ep
; i
++, dp
++)
1443 ** Quite, I'm doing a bubble sort... ACK!
1445 qsort(vals
, size
, sizeof(vals
[0]),
1446 reinterpret_cast<int(*) (const void *, const void *)>(cvalCMP
));
1448 for(i
= 0; i
< size
; i
++)
1449 if(vals
[i
].idx
!= i
)
1453 ** Already sorted, no change!
1457 for(i
= 0; i
< size
; i
++)
1458 rmap
[vals
[i
].idx
] = i
;
1461 ** Now reorder the colormap, and the image
1463 for(dp
= img
->data
.image
.data
, i
= 0; dp
< ep
; i
++, dp
++)
1465 if(img
->info
.transparent
!= -1)
1467 img
->info
.transparent
= rmap
[img
->info
.transparent
];
1471 ** Toast the local colormap
1473 if(img
->data
.image
.cmapSize
!= 0)
1475 for(i
= 0; i
< size
; i
++)
1477 stream
->cmapData
[i
][0] = img
->data
.image
.cmapData
[i
][0];
1478 stream
->cmapData
[i
][1] = img
->data
.image
.cmapData
[i
][1];
1479 stream
->cmapData
[i
][2] = img
->data
.image
.cmapData
[i
][2];
1482 img
->data
.image
.cmapSize
= 0;
1483 stream
->cmapSize
= size
;
1487 ** Now finally reorer the colormap
1489 for(i
= 0; i
< size
; i
++)
1491 tmap
[i
][0] = stream
->cmapData
[i
][0];
1492 tmap
[i
][1] = stream
->cmapData
[i
][1];
1493 tmap
[i
][2] = stream
->cmapData
[i
][2];
1496 for(i
= 0; i
< size
; i
++)
1498 stream
->cmapData
[rmap
[i
]][0] = tmap
[i
][0];
1499 stream
->cmapData
[rmap
[i
]][1] = tmap
[i
][1];
1500 stream
->cmapData
[rmap
[i
]][2] = tmap
[i
][2];
1508 ** Return the ceiling log of n
1510 static int binaryLog(int val
)
1517 for(i
= 1; i
<= 8; i
++)
1524 #pragma set woff 1209
1528 static int GIFWriteFP(FILE *fp
, GIFStream
*stream
, int optimize
)
1531 int flag
= GIF_FALSE
;
1533 int globalBitsPP
= 0;
1542 ** First find if this is a 87A or an 89A GIF image
1543 ** also, figure out the color resolution of the image.
1545 resolution
= binaryLog(stream
->cmapSize
) - 1;
1546 for(cur
= stream
->data
; !flag
&& cur
!= NULL
; cur
= cur
->next
)
1548 if(cur
->type
== gif_text
|| cur
->type
== gif_comment
)
1552 else if(cur
->type
== gif_image
)
1554 int v
= binaryLog(cur
->data
.image
.cmapSize
);
1560 ** Uses one of the 89 extensions.
1562 if(cur
->info
.transparent
!= -1 ||
1563 cur
->info
.delayTime
!= 0 ||
1564 cur
->info
.inputFlag
!= 0 ||
1565 cur
->info
.disposal
!= 0)
1574 optimize
= optimizeCMAP(stream
);
1576 fwrite(flag
? "GIF89a" : "GIF87a", 1, 6, fp
);
1578 PUTWORD(stream
->width
, fp
);
1579 PUTWORD(stream
->height
, fp
);
1582 ** assume 256 entry color resution, and non sorted colormap
1584 c
= ((resolution
& 0x07) << 5) | 0x00;
1585 if(stream
->cmapSize
!= 0)
1587 globalBitsPP
= binaryLog(stream
->cmapSize
);
1589 c
|= globalBitsPP
- 1;
1593 ** Is the global colormap optimized?
1599 PUTBYTE(stream
->background
, fp
);
1600 PUTBYTE(stream
->aspectRatio
, fp
);
1602 putColorMap(fp
, stream
->cmapSize
, stream
->cmapData
);
1604 for(cur
= stream
->data
; cur
!= NULL
; cur
= cur
->next
)
1606 if(cur
->type
== gif_image
)
1610 putGif89Info(fp
, &cur
->info
);
1613 PUTWORD(cur
->x
, fp
);
1614 PUTWORD(cur
->y
, fp
);
1615 PUTWORD(cur
->width
, fp
);
1616 PUTWORD(cur
->height
, fp
);
1618 c
= cur
->data
.image
.interlaced
? 0x40 : 0x00;
1619 if(cur
->data
.image
.cmapSize
!= 0)
1621 bpp
= binaryLog(cur
->data
.image
.cmapSize
);
1632 putColorMap(fp
, cur
->data
.image
.cmapSize
, cur
->data
.image
.cmapData
);
1634 putImage(fp
, cur
->data
.image
.interlaced
, bpp
, cur
->width
,
1635 cur
->height
, cur
->data
.image
.data
);
1637 else if(cur
->type
== gif_comment
)
1643 cur
->data
.comment
.len
,
1644 reinterpret_cast<unsigned char *>(cur
->data
.comment
.text
));
1646 else if(cur
->type
== gif_text
)
1648 putGif89Info(fp
, &cur
->info
);
1653 PUTWORD(cur
->x
, fp
);
1654 PUTWORD(cur
->y
, fp
);
1655 PUTWORD(cur
->width
, fp
);
1656 PUTWORD(cur
->height
, fp
);
1658 PUTBYTE(cur
->data
.text
.cellWidth
, fp
);
1659 PUTBYTE(cur
->data
.text
.cellHeight
, fp
);
1660 PUTBYTE(cur
->data
.text
.fg
, fp
);
1661 PUTBYTE(cur
->data
.text
.bg
, fp
);
1666 reinterpret_cast<unsigned char *>(cur
->data
.text
.text
));
1671 ** Write termination
1679 #pragma reset woff 1209
1683 int GIFWrite(char *file
, GIFStream
*stream
, int optimize
)
1687 FILE *fp
= fopen(file
, "wb");
1691 int s
= GIFWriteFP(fp
, stream
, optimize
);
1701 static void putColorMap(FILE *fp
, int size
, unsigned char data
[GIF_MAXCOLORS
][3])
1705 for(i
= 0; i
< size
; i
++)
1707 PUTBYTE(data
[i
][0], fp
);
1708 PUTBYTE(data
[i
][1], fp
);
1709 PUTBYTE(data
[i
][2], fp
);
1714 static void putDataBlocks(FILE *fp
, int size
, unsigned char *data
)
1720 n
= size
> 255 ? 255 : size
;
1723 fwrite(data
, 1, n
, fp
);
1728 PUTBYTE(0, fp
); /* End Block */
1732 #pragma set woff 1209
1736 static void putGif89Info(FILE *fp
, GIF89info
*info
)
1740 if(info
->transparent
== -1 &&
1741 info
->delayTime
== 0 &&
1742 info
->inputFlag
== 0 &&
1743 info
->disposal
== 0)
1749 c
= (info
->inputFlag
? 0x02 : 0x00) | ((info
->disposal
& 0x07) << 2) | ((info
->transparent
!= -1) ? 0x01 : 0x00);
1751 PUTWORD(info
->delayTime
, fp
);
1752 PUTBYTE(info
->transparent
, fp
);
1761 #pragma reset woff 1209
1764 /***************************************************************************
1766 * GIFCOMPR.C - GIF Image compression routines
1768 * Lempel-Ziv compression based on 'compress'. GIF modifications by
1769 * David Rowley (mgardi@watdcsu.waterloo.edu)
1771 ***************************************************************************/
1778 #define HSIZE 5003 /* 80% occupancy */
1781 typedef char char_type
;
1783 typedef unsigned char char_type
;
1788 * GIF Image compression - modified 'compress'
1790 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
1792 * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
1793 * Jim McKie (decvax!mcvax!jim)
1794 * Steve Davies (decvax!vax135!petsd!peora!srd)
1795 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
1796 * James A. Woods (decvax!ihnp4!ames!jaw)
1797 * Joe Orost (decvax!vax135!petsd!joe)
1800 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
1801 static int n_bits
; /* number of bits/code */
1802 static int maxbits
; /* user settable max # bits/code */
1803 static code_int maxcode
; /* maximum code, given n_bits */
1804 static code_int maxmaxcode
; /* should NEVER generate this code */
1805 #define MAXCODE(n_bits) ((static_cast<code_int>(1) << (n_bits)) - 1)
1806 static count_int htab
[HSIZE
];
1807 static unsigned short codetab
[HSIZE
];
1808 #define HashTabOf(i) htab[i]
1809 #define CodeTabOf(i) codetab[i]
1811 static code_int hsize
; /* for dynamic table sizing */
1813 static unsigned long cur_accum
;
1814 static int cur_bits
;
1817 * To save much memory, we overlay the table used by compress() with those
1818 * used by decompress(). The tab_prefix table is the same size and type
1819 * as the codetab. The tab_suffix table needs 2**BITS characters. We
1820 * get this from the beginning of htab. The output stack uses the rest
1821 * of htab, and contains characters. There is plenty of room for any
1822 * possible stack (stack used to be 8000 characters).
1824 #define tab_prefixof(i) CodeTabOf(i)
1825 #define tab_suffixof(i) ((char_type *) (htab))[i]
1826 #define de_stack ((char_type *) &tab_suffixof((code_int) 1 << BITS))
1827 static code_int free_ent
; /* first unused entry */
1830 * block compression parameters -- after all codes are used up,
1831 * and compression rate changes, start over.
1833 static int clear_flg
;
1835 // static int offset = 0;
1837 * compress stdin to stdout
1839 * Algorithm: use open addressing double hashing (no chaining) on the
1840 * prefix code / next character combination. We do a variant of Knuth's
1841 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1842 * secondary probe. Here, the modular division first probe is gives way
1843 * to a faster exclusive-or manipulation. Also do block compression with
1844 * an adaptive reset, whereby the code table is cleared when the compression
1845 * ratio decreases, but after the table fills. The variable-length output
1846 * codes are re-sized at this point, and a special CLEAR code is generated
1847 * for the decompressor. Late addition: construct the table according to
1848 * file size for noticeable speed improvement on small files. Please direct
1849 * questions about this implementation to ames!jaw.
1851 static int g_init_bits
;
1852 static FILE *g_outfile
;
1854 static int ClearCode
;
1860 #pragma set woff 1209
1863 static void putImage(FILE *fp
, int interlaced
, int bpp
, int width
, int height
,
1864 unsigned char *data
)
1866 // unsigned char *end = data + width * height;
1867 int left
= interlaced
? width
: width
* height
;
1868 int cury
= 0, pass
= 0;
1869 unsigned char *dp
= data
;
1871 code_int v
, i
, ent
, disp
, hsize_reg
;
1882 g_init_bits
= bpp
+ 1;
1887 ** Set up the globals: g_init_bits - initial number of bits
1888 ** g_outfile - pointer to output file
1893 ** Set up the necessary values
1896 clear_flg
= GIF_FALSE
;
1898 maxmaxcode
= 1 << BITS
;
1899 maxcode
= MAXCODE(n_bits
= g_init_bits
);
1904 ClearCode
= (1 << (g_init_bits
- 1));
1905 EOFCode
= ClearCode
+ 1;
1906 free_ent
= ClearCode
+ 2;
1908 char_init(); /* clear the output accumulator */
1911 for(fcode
= long(hsize
); fcode
< 65536; fcode
*= 2)
1913 hshift
= 8 - hshift
; /* set hash code range bound */
1916 cl_hash(count_int(hsize
)); /* clear hash table */
1918 output(code_int(ClearCode
));
1925 ** Fetch the next pixel
1964 } while(pass
< 3 && cury
>= height
);
1967 dp
= data
+ cury
* width
;
1980 fcode
= long((long(c
) << maxbits
) + ent
);
1982 i
= ((code_int(c
) << hshift
) ^ ent
); /* xor hashing */
1993 ** secondary hash (after G. Knott)
1995 disp
= hsize_reg
- i
;
2012 output(code_int(ent
));
2014 if(free_ent
< maxmaxcode
)
2016 CodeTabOf(i
) = free_ent
++; /* code -> hashtable */
2017 HashTabOf(i
) = fcode
;
2026 ** Put out the final code.
2028 output(code_int(ent
));
2029 output(code_int(EOFCode
));
2038 #pragma reset woff 1209
2041 /*****************************************************************
2044 * Output the given code.
2046 * code: A n_bits-bit integer. If == -1, then EOF. This assumes
2047 * that n_bits =< (long)wordsize - 1.
2049 * Outputs code to the file.
2051 * Chars are 8 bits long.
2053 * Maintain a BITS character long buffer (so that 8 codes will
2054 * fit in it exactly). Use the VAX insv instruction to insert each
2055 * code in turn. When the buffer fills up empty it and start over.
2058 static unsigned long masks
[] = { 0x0000,
2059 0x0001, 0x0003, 0x0007, 0x000F,
2060 0x001F, 0x003F, 0x007F, 0x00FF,
2061 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
2062 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
2064 static void output(code_int code
)
2066 cur_accum
&= masks
[cur_bits
];
2070 cur_accum
|= (long(code
) << cur_bits
);
2077 while(cur_bits
>= 8)
2079 char_out(static_cast<unsigned int>(cur_accum
& 0xff));
2085 ** If the next entry is going to be too big for the code size,
2086 ** then increase it, if possible.
2088 if(free_ent
> maxcode
|| clear_flg
)
2092 maxcode
= MAXCODE(n_bits
= g_init_bits
);
2093 clear_flg
= GIF_FALSE
;
2098 if(n_bits
== maxbits
)
2099 maxcode
= maxmaxcode
;
2101 maxcode
= MAXCODE(n_bits
);
2108 ** At EOF, write the rest of the buffer.
2112 char_out(static_cast<unsigned int>(cur_accum
& 0xff));
2124 * Clear out the hash table
2126 static void cl_block(void)
2128 cl_hash(count_int(hsize
));
2129 free_ent
= ClearCode
+ 2;
2130 clear_flg
= GIF_TRUE
;
2132 output(code_int(ClearCode
));
2136 static void cl_hash(count_int hsizeIn
) /* reset code table */
2140 for(i
= 0; i
< hsizeIn
; i
++)
2144 /******************************************************************************
2146 * GIF Specific routines
2148 ******************************************************************************/
2150 ** Number of characters so far in this 'packet'
2155 ** Define the storage for the packet accumulator
2157 static char accum
[256];
2160 ** Set up the 'byte output' routine
2162 static void char_init(void)
2168 ** Add a character to the end of the current packet, and if it is 254
2169 ** characters, flush the packet to disk.
2171 static void char_out(int c
)
2173 accum
[a_count
++] = c
;
2179 ** Flush the packet to disk, and reset the accumulator
2181 static void flush_char(void)
2185 PUTBYTE(a_count
, g_outfile
);
2186 fwrite(accum
, 1, a_count
, g_outfile
);
2191 //--- GIF-WRITE END -----------------------------------------------------