4067 lines
65 KiB
C
4067 lines
65 KiB
C
/**
|
|
|
|
** $Header: /roq/libim/imgif.c 1 11/02/99 4:38p Zaphod $
|
|
|
|
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
|
|
|
|
** a division of General Atomics, San Diego, California, USA
|
|
|
|
**
|
|
|
|
** Users and possessors of this source code are hereby granted a
|
|
|
|
** nonexclusive, royalty-free copyright and design patent license to
|
|
|
|
** use this code in individual software. License is not granted for
|
|
|
|
** commercial resale, in whole or in part, without prior written
|
|
|
|
** permission from SDSC. This source is provided "AS IS" without express
|
|
|
|
** or implied warranty of any kind.
|
|
|
|
**
|
|
|
|
** For further information contact:
|
|
|
|
** E-Mail: info@sds.sdsc.edu
|
|
|
|
**
|
|
|
|
** Surface Mail: Information Center
|
|
|
|
** San Diego Supercomputer Center
|
|
|
|
** P.O. Box 85608
|
|
|
|
** San Diego, CA 92138-5608
|
|
|
|
** (619) 534-5000
|
|
|
|
**/
|
|
|
|
|
|
|
|
#define HEADER " $Header: /roq/libim/imgif.c 1 11/02/99 4:38p Zaphod $"
|
|
|
|
|
|
|
|
/**
|
|
|
|
** FILE
|
|
|
|
** imgif.c - Compuserve Graphics Interchange Format
|
|
|
|
**
|
|
|
|
** PROJECT
|
|
|
|
** libim - SDSC image manipulation library
|
|
|
|
**
|
|
|
|
** DESCRIPTION
|
|
|
|
** imgif.c contains routines to read and write Compuserve GIF image
|
|
|
|
** format for the image manipulation library.
|
|
|
|
**
|
|
|
|
** PUBLIC CONTENTS
|
|
|
|
** d =defined constant
|
|
|
|
** f =function
|
|
|
|
** m =defined macro
|
|
|
|
** t =typedef/struct/union
|
|
|
|
** v =variable
|
|
|
|
** ? =other
|
|
|
|
**
|
|
|
|
** none
|
|
|
|
**
|
|
|
|
** PRIVATE CONTENTS
|
|
|
|
** imGifHeaderInfo t GIF header information
|
|
|
|
** imGifHeaderFields v imGifHeaderInfo description for Bin pkg
|
|
|
|
** imGifHeader v Gif header holder
|
|
|
|
** imGifImDescInfo t Gif image descriptor information
|
|
|
|
** imGifImDescFields v imGifImDescInfo description for Bin pkg
|
|
|
|
** imGifImDesc v Gif image descriptor holder
|
|
|
|
**
|
|
|
|
** IMGIFMAGIC d file magic number
|
|
|
|
** IMGIFBITPIXEL d mask to read #bits/pixel in the image
|
|
|
|
** IMGIFGLOBALCM d mask to read if a global colormap is present
|
|
|
|
** IMGIFLOCALCM d mask to read if a local colormap is present
|
|
|
|
** IMGIFINTERLACED d mask to read the pixel display sequence used
|
|
|
|
** IMGIFTERMINATOR d termination character of a Gif image file
|
|
|
|
** IMGIFEXTENSION d Gif extension block introducer character
|
|
|
|
** IMGIFSEPARATOR d image separator character
|
|
|
|
** IMGIFENDBLOCK d terminates extension blocks
|
|
|
|
** IMGIFNCOLORRES d # bits of color resolution
|
|
|
|
** IMGIFNBITSPIXEL d # bits per pixel
|
|
|
|
** IMGIFBACKGROUND d index of background color
|
|
|
|
** IMGIFCODESIZE d initial code size used for lzw algorithm
|
|
|
|
** IMGIFNOCOLORMAP d no color lookup table present
|
|
|
|
**
|
|
|
|
** imGifVfbRead1 f Read a mono Gif image
|
|
|
|
** imGifCltRead f Read a color lookup table
|
|
|
|
** imGifCltWrite f Write a color lookup table
|
|
|
|
** imGifVfbWrite8 f Write a 8-index Vfb
|
|
|
|
** imGifVfbWrite1 f Write a mono Vfb
|
|
|
|
** imGifRead f read a Compuserve GIF image
|
|
|
|
** imGifWrite f write a Compuserve GIF image
|
|
|
|
**
|
|
|
|
** HISTORY
|
|
|
|
** $Log: /roq/libim/imgif.c $
|
|
*
|
|
* 1 11/02/99 4:38p Zaphod
|
|
|
|
** Revision 1.22 1995/06/29 00:28:04 bduggan
|
|
|
|
** updated copyright year
|
|
|
|
**
|
|
|
|
** Revision 1.21 1995/06/15 20:19:28 bduggan
|
|
|
|
** removed use of 'new'
|
|
|
|
** Added some casts
|
|
|
|
**
|
|
|
|
** Revision 1.20 1995/05/30 16:57:24 bduggan
|
|
|
|
** Changed comment.
|
|
|
|
**
|
|
|
|
** Revision 1.19 1995/05/17 23:44:54 bduggan
|
|
|
|
** Added transparency support
|
|
|
|
**
|
|
|
|
** Revision 1.18 1995/04/03 21:24:38 bduggan
|
|
|
|
** took out #ifdef NEWMAGIC
|
|
|
|
**
|
|
|
|
** Revision 1.17 1995/01/10 23:23:37 bduggan
|
|
|
|
** Made read/write functions static
|
|
|
|
**
|
|
|
|
** Revision 1.17 1995/01/10 23:23:37 bduggan
|
|
|
|
** Made read/write functions static
|
|
|
|
**
|
|
|
|
** Revision 1.16 94/10/03 11:30:06 nadeau
|
|
|
|
** Updated to ANSI C and C++ compatibility.
|
|
|
|
** Removed all use of register keyword.
|
|
|
|
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
|
|
|
|
** Changed all float arguments to double.
|
|
|
|
** Added forward declarations.
|
|
|
|
** Added misc. casts to passify SGI and DEC compilers.
|
|
|
|
** Changed all macros and defined constants to have names
|
|
|
|
** starting with IM.
|
|
|
|
** Rearranged magic number structures for format handlers.
|
|
|
|
** Made format handler routines static (i.e., local to file).
|
|
|
|
** Updated comments, adding format descriptions and references.
|
|
|
|
** Updated indenting on some code.
|
|
|
|
** Updated copyright message.
|
|
|
|
**
|
|
|
|
** Revision 1.15 92/12/09 18:33:05 nadeau
|
|
|
|
** Corrected misinterpretation of CLT write flags that wrote
|
|
|
|
** grayscale INDEX8 images incorrectly. Also corrected and
|
|
|
|
** updated various info messages.
|
|
|
|
**
|
|
|
|
** Revision 1.14 92/12/03 01:48:12 nadeau
|
|
|
|
** Corrected info messages.
|
|
|
|
**
|
|
|
|
** Revision 1.13 92/11/23 18:42:14 nadeau
|
|
|
|
** Removed use of IMINFOMSG.
|
|
|
|
**
|
|
|
|
** Revision 1.12 92/11/04 11:49:03 groening
|
|
|
|
** put ImFIleFormat info and magic number info
|
|
|
|
** from imfmt.c into this file.
|
|
|
|
**
|
|
|
|
** Revision 1.11 92/10/12 15:57:13 vle
|
|
|
|
** Fixed typo: Limpel -> Lempel
|
|
|
|
**
|
|
|
|
** Revision 1.10 92/09/29 17:58:50 vle
|
|
|
|
** Added ImInfo messages.
|
|
|
|
**
|
|
|
|
** Revision 1.9 92/09/17 14:42:03 vle
|
|
|
|
** Updated to 89a specification. Fixed bug in 2-bit image read.
|
|
|
|
** Updated copyright notice.
|
|
|
|
**
|
|
|
|
** Revision 1.8 92/04/03 17:43:14 nadeau
|
|
|
|
** Added extern declarations of functions so that the SGI
|
|
|
|
** compiler and linker don't get confused.
|
|
|
|
**
|
|
|
|
** Revision 1.7 91/10/03 09:03:01 nadeau
|
|
|
|
** Fixed #includes. Turned off DEBUG.
|
|
|
|
**
|
|
|
|
** Revision 1.6 91/03/13 17:09:44 soraya
|
|
|
|
** fixing bugs
|
|
|
|
**
|
|
|
|
** Revision 1.5 91/03/11 09:16:40 soraya
|
|
|
|
** Optimization, finish of write, and removal of debug
|
|
|
|
** print statements.
|
|
|
|
**
|
|
|
|
** Revision 1.4 91/02/12 11:45:52 nadeau
|
|
|
|
** Removed the tag table checking and VFB conversion now
|
|
|
|
** handled by ImFileRead and ImFileWrite. Made the error
|
|
|
|
** checking more robust.
|
|
|
|
**
|
|
|
|
** Revision 1.3 91/01/31 08:34:20 soraya
|
|
|
|
** *** empty log message ***
|
|
|
|
**
|
|
|
|
** Revision 1.2 90/12/26 18:50:20 soraya
|
|
|
|
** *** empty log message ***
|
|
|
|
**
|
|
|
|
** Revision 1.1 90/12/26 13:24:43 soraya
|
|
|
|
** Initial revision
|
|
|
|
**
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "iminternal.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
** FORMAT
|
|
|
|
** gif - Compuserve Graphics Interchange Format
|
|
|
|
**
|
|
|
|
** AKA
|
|
|
|
** giff
|
|
|
|
**
|
|
|
|
** FORMAT REFERENCES
|
|
|
|
** Graphics Interchange Format, version 89a, CompuServe, 1990.
|
|
|
|
**
|
|
|
|
** Bit-Mapped Graphics, Steve Rimmer, McGraw-Hill, 1990.
|
|
|
|
**
|
|
|
|
** Graphics File Formats, David C. Kay, John R. Levine, McGraw-Hill,
|
|
|
|
** 1992.
|
|
|
|
**
|
|
|
|
** Supercharged Bitmapped Graphics, Steve Rimmer, McGraw-Hill, 1992.
|
|
|
|
**
|
|
|
|
** CODE CREDITS
|
|
|
|
** Custom development, Soraya Gonzales, Intevep S.A., Venzuela, 1990.
|
|
|
|
** Extensions, Vinh Le, San Diego Supercomputer Center, 1992.
|
|
|
|
** Extensions, Dave Nadeau, San Diego Supercomputer Center, 1993.
|
|
|
|
**
|
|
|
|
** DESCRIPTION
|
|
|
|
** CompuServe's GIF (Graphics Interchange Format) is used on on-line
|
|
|
|
** image libraries throughout the world for the storage of medium and
|
|
|
|
** low resolution images of 8-bit depths or less.
|
|
|
|
**
|
|
|
|
** Header Block
|
|
|
|
** GIF data streams begin with a header block of the form:
|
|
|
|
**
|
|
|
|
** Field Size
|
|
|
|
** ----- ----
|
|
|
|
** Signature 3 bytes
|
|
|
|
** Version 3 bytes
|
|
|
|
**
|
|
|
|
** The "Signature" field is always "GIF". The "Version" field is
|
|
|
|
** one of "87a" or "89a", corresponding to the two outstanding versions
|
|
|
|
** of the GIF format specification.
|
|
|
|
**
|
|
|
|
** This GIF translator reads 87a and 89a spec GIF files, but
|
|
|
|
** per recommendations in the GIF spec, always writes the
|
|
|
|
** lowest-common-denominator GIF files at 87a spec levels.
|
|
|
|
**
|
|
|
|
** Logical Screen Block
|
|
|
|
** Immediately following the GIF header is a logical screen block of
|
|
|
|
** the form:
|
|
|
|
**
|
|
|
|
** Field Size
|
|
|
|
** ----- ----
|
|
|
|
** Logical Screen Width 2 bytes, unsigned integer
|
|
|
|
** Logical Screen Height 2 bytes, unsigned integer
|
|
|
|
** Flags 1 byte
|
|
|
|
** Background Color Index 1 byte
|
|
|
|
** Pixel Aspect Ratio 1 byte
|
|
|
|
**
|
|
|
|
** The screen width and height refer to the size of the logical screen
|
|
|
|
** onto which the GIF image is to be displayed on the display device.
|
|
|
|
**
|
|
|
|
** This GIF translator ignores the screen width and height.
|
|
|
|
**
|
|
|
|
** The "Flags" field is a bitmask with the following bit meanings:
|
|
|
|
**
|
|
|
|
** Field Bits
|
|
|
|
** ----- ----
|
|
|
|
** Global Color Table 7
|
|
|
|
** Color Resolution 6,5,4
|
|
|
|
** Sort 3
|
|
|
|
** Size of Global Color Tb 2,1,0
|
|
|
|
**
|
|
|
|
** The "Global Color Table" flag indicates if the file has a global
|
|
|
|
** color table. If so, it'll immediately follow the Logical Screen
|
|
|
|
** Block in the file. Bit 7 = 0 = no global color table. Bit 7 = 1 =
|
|
|
|
** there is a global color table.
|
|
|
|
**
|
|
|
|
** This GIF translator can read global color tables, but the
|
|
|
|
** writer does not generate them. The writer uses local color
|
|
|
|
** tables instead.
|
|
|
|
**
|
|
|
|
** The "Color Resolution" flag gives the number of bits per primary color,
|
|
|
|
** minus 1. A value of 7 means 8-bits per primary and is typical.
|
|
|
|
**
|
|
|
|
** This GIF translator can read color table resolutions up to
|
|
|
|
** 8-bits per channel and converts them internally to ImClt's
|
|
|
|
** with 8-bits per channel. GIF files written by this
|
|
|
|
** translator are always 8-bits per channel.
|
|
|
|
**
|
|
|
|
** The "Sort" flag indicates if the global color table (if there is one)
|
|
|
|
** is sorted from most to least important color. Bit 3 = 0 = unsorted.
|
|
|
|
** Bit 3 = 1 = sorted.
|
|
|
|
**
|
|
|
|
** This GIF translator ignores color table sorting on reading.
|
|
|
|
** On writing, the color table is always unsorted.
|
|
|
|
**
|
|
|
|
** The "Global Color Table Size" field is used to calculate the length of
|
|
|
|
** the global color table. Take 2 and raise it to a power equal to this
|
|
|
|
** field plus 1. So, a value of 7 for the field gives 2^(7+1) entries,
|
|
|
|
** or 2^8 = 256 entries. Even when there is no global color table, this
|
|
|
|
** field should be set to the size of a typical color table to help
|
|
|
|
** future display routines.
|
|
|
|
**
|
|
|
|
** This GIF translator uses this field on reading to determine
|
|
|
|
** the global color table size, and sets this field on writing
|
|
|
|
** to an appropriate value.
|
|
|
|
**
|
|
|
|
** The "Background Color Index" field is an index into the global
|
|
|
|
** color table (if the table is present) and selects the color to use
|
|
|
|
** for background pixels not covered by image data from the GIF file.
|
|
|
|
** If there is no global color table, this field should be 0.
|
|
|
|
**
|
|
|
|
** This GIF translator doesn't use the background color on
|
|
|
|
** reading, and sets it to 0 on writing.
|
|
|
|
**
|
|
|
|
** The "Pixel Aspect Ratio" field gives the aspect ratio of pixels in
|
|
|
|
** the image and is meant to account for non-square pixels on crude
|
|
|
|
** graphics systems. A value of 0 means no aspect ratio information is
|
|
|
|
** provided in the field.
|
|
|
|
**
|
|
|
|
** This GIF translator ignores the pixel aspect ratio on reading,
|
|
|
|
** and sets it to 0 on writing.
|
|
|
|
**
|
|
|
|
** Global Color Table Block
|
|
|
|
** The global color table is a default color table for images in the file
|
|
|
|
** that don't have a local color table associated with them. This block
|
|
|
|
** is only present if the global color table flag is set in the Logical
|
|
|
|
** Screen block above.
|
|
|
|
**
|
|
|
|
** If present, this block will contain a number of bytes equal to:
|
|
|
|
**
|
|
|
|
** 3 * 2^(table size + 1)
|
|
|
|
**
|
|
|
|
** where the "table size" is given in the Logical Screen Block above.
|
|
|
|
**
|
|
|
|
** Color table values are in the order RGB, RGB, RGB, one byte per channel,
|
|
|
|
** from color table entry 0 to the maximum. The maximum number of entries
|
|
|
|
** allowed by the spec is 256.
|
|
|
|
**
|
|
|
|
** This GIF translator handles global color tables on reading
|
|
|
|
** image files, but never generates them on writing. All
|
|
|
|
** written images are provided with local color tables.
|
|
|
|
**
|
|
|
|
** Image Descriptor
|
|
|
|
** The image descriptor describes a raster image in the GIF file. There
|
|
|
|
** will be one image descriptor for each such image, with no upper limit
|
|
|
|
** on the number of images contained within a single GIF file.
|
|
|
|
**
|
|
|
|
** Image descriptions begin with an image descriptor block of the form:
|
|
|
|
**
|
|
|
|
** Field Size
|
|
|
|
** ----- ----
|
|
|
|
** Separator 1 byte
|
|
|
|
** Left Position 2 bytes, unsigned integer
|
|
|
|
** Top Position 2 bytes, unsigned integer
|
|
|
|
** Width 2 bytes, unsigned integer
|
|
|
|
** Height 2 bytes, unsigned integer
|
|
|
|
** Flags 1 byte
|
|
|
|
**
|
|
|
|
** The image separator marks the beginning of the descriptor and helps
|
|
|
|
** to separate images from each other in a multi-image file. The
|
|
|
|
** separator always contains the hex value "0x2C".
|
|
|
|
**
|
|
|
|
** The image left and top position values are relative to the logical
|
|
|
|
** screen, as defined in the logical screen block. (0,0) is at the
|
|
|
|
** top left of the logical screen.
|
|
|
|
**
|
|
|
|
** This GIF translator does not pay attention to logical screens.
|
|
|
|
** So, image left-top positions within such are ignored. On
|
|
|
|
** writing images, the left and top position values are always
|
|
|
|
** set to 0.
|
|
|
|
**
|
|
|
|
** The width and height fields give the image size in pixels.
|
|
|
|
**
|
|
|
|
** The "Flags" field is a bitmask with the following bit meanings:
|
|
|
|
**
|
|
|
|
** Field Bits
|
|
|
|
** ----- ----
|
|
|
|
** Local Color Table 7
|
|
|
|
** Interlace 6
|
|
|
|
** Sort 5
|
|
|
|
** Reserved 4,3
|
|
|
|
** Size of Local CLT 2,1,0
|
|
|
|
**
|
|
|
|
** The "Local Color Table" flag indicates if there is a local CLT
|
|
|
|
** immediately following the image descriptor. Bit 7 = 1 = there is
|
|
|
|
** a local CLT. Bit 7 = 0 = there isn't.
|
|
|
|
**
|
|
|
|
** This GIF translator handles local color tables with read
|
|
|
|
** images. Written images always have a local CLT if the
|
|
|
|
** VFB to be written had one. Grayscale VFB's without CLTs
|
|
|
|
** are written without local CLTs.
|
|
|
|
**
|
|
|
|
** The "Interlace" flag indicates if the image is interlaced using a
|
|
|
|
** 4-pass interlace pattern. Interlacing is discussed later on in this
|
|
|
|
** comment block. Bit 6 = 1 = the image is interlaced. Bit 6 = 0 =
|
|
|
|
** it isn't interlaced.
|
|
|
|
**
|
|
|
|
** This GIF translator handles interlaced incoming images,
|
|
|
|
** but only writes non-interlaced images.
|
|
|
|
**
|
|
|
|
** The "Sort" flag indicates if the local color table (if there is one)
|
|
|
|
** is sorted from most to least important color. Bit 5 = 0 = unsorted.
|
|
|
|
** Bit 5 = 1 = sorted.
|
|
|
|
**
|
|
|
|
** This GIF translator ignores color table sorting on reading.
|
|
|
|
** On writing, the color table is always unsorted.
|
|
|
|
**
|
|
|
|
** The "Size of Local Color Table" field is used to calculate the length of
|
|
|
|
** the local color table. Take 2 and raise it to a power equal to this
|
|
|
|
** field plus 1. So, a value of 7 for the field gives 2^(7+1) entries,
|
|
|
|
** or 2^8 = 256 entries. If there is no local CLT, this field should be
|
|
|
|
** set to 0.
|
|
|
|
**
|
|
|
|
** This GIF translator uses this field on reading to determine
|
|
|
|
** the local color table size, and sets this field on writing
|
|
|
|
** to an appropriate value.
|
|
|
|
**
|
|
|
|
** Local Color Table Block
|
|
|
|
** If an image has a local color table (see the "Flags" field of the
|
|
|
|
** image descriptor block), then a description of that table immediate
|
|
|
|
** follows the image descriptor for the image. This local CLT overrides
|
|
|
|
** any global CLT for this image only.
|
|
|
|
**
|
|
|
|
** If present, this block will contain a number of bytes equal to:
|
|
|
|
**
|
|
|
|
** 3 * 2^(table size + 1)
|
|
|
|
**
|
|
|
|
** where the "table size" is given in the Image Descriptor Block above.
|
|
|
|
**
|
|
|
|
** Color table values are in the order RGB, RGB, RGB, one byte per channel,
|
|
|
|
** from color table entry 0 to the maximum. The maximum number of entries
|
|
|
|
** allowed by the spec is 256.
|
|
|
|
**
|
|
|
|
** This GIF translator reads local CLTs as needed. On writing
|
|
|
|
** images, local CLTs are generated for VFBs with CLTs.
|
|
|
|
** Grayscale VFBs without CLTs are written without a local CLT.
|
|
|
|
**
|
|
|
|
** Image Data Block
|
|
|
|
** The image data for an image follows immediately after the local CLT
|
|
|
|
** (if any) following the image descriptor for the image. Image data is
|
|
|
|
** always compressed using a Limpel-Ziv & Welch (LZW) compression scheme
|
|
|
|
** described below.
|
|
|
|
**
|
|
|
|
** GIF Trailer
|
|
|
|
** The GIF data stream is terminated with a GIF trailer block of the
|
|
|
|
** form:
|
|
|
|
**
|
|
|
|
** Field Size
|
|
|
|
** ----- ----
|
|
|
|
** GIF Trailer 1 byte
|
|
|
|
**
|
|
|
|
** The "GIF Trailer" byte always has the hex value "0x3B".
|
|
|
|
**
|
|
|
|
** Extensions
|
|
|
|
** Various extensions are defined by the GIF spec. These extensions
|
|
|
|
** allow the embedding of various display and application-specific
|
|
|
|
** controls. All extensions begin with the following three fields:
|
|
|
|
**
|
|
|
|
** Field Size
|
|
|
|
** ----- ----
|
|
|
|
** Extension Introducer 1 byte
|
|
|
|
** Extension Label 1 byte
|
|
|
|
** Extension Block Size 1 byte
|
|
|
|
**
|
|
|
|
** The "Extension Introducer" is a flag indicating the start of an
|
|
|
|
** extension block and always has the hex value "0x21".
|
|
|
|
**
|
|
|
|
** The "Extension Label" indicates the type of extension. The 1989 spec
|
|
|
|
** defines the following extension labels:
|
|
|
|
**
|
|
|
|
** Extension Label Meaning
|
|
|
|
** --------------- -------
|
|
|
|
** 0xF9 Graphic Control Extension
|
|
|
|
** 0xFE Comment Extension
|
|
|
|
** 0x01 Plain Text Extension
|
|
|
|
** 0xFF Application Extension
|
|
|
|
**
|
|
|
|
** The "Extension Block Size" field gives the size, in bytes, of the
|
|
|
|
** extension block.
|
|
|
|
**
|
|
|
|
** This GIF translator ignores all extensions on reading GIF
|
|
|
|
** files, and generates no extensions when writing them.
|
|
|
|
**
|
|
|
|
** Image Data Interlacing
|
|
|
|
** The "Interlace" flag in the "Flags" field of an Image Descriptor
|
|
|
|
** Block indicates whether the following image data is interlaced or
|
|
|
|
** not. The basic idea is to order the scanlines in the image data
|
|
|
|
** so that widely separated scanlines come first, and then we fill in
|
|
|
|
** the ones we missed. This scheme was designed to allow quick previewing
|
|
|
|
** of an incomming GIF file by seeing some of the scanlines, all over
|
|
|
|
** the image, first. Then, if you didn't want to continue reading the
|
|
|
|
** GIF file you could cancel the read and save time by not bother with
|
|
|
|
** reading the rest in. Although this idea was meant for slower technology,
|
|
|
|
** it has proved useful once more, since transmission of data from one
|
|
|
|
** corner of the internet to the other is not instanataneous, and programs
|
|
|
|
** such as netScape display the image as it is received.
|
|
|
|
**
|
|
|
|
** So, we generate interlaced gif's.
|
|
|
|
**
|
|
|
|
** When interlacing is enabled, the image data is grouped into 4 passes:
|
|
|
|
**
|
|
|
|
** Pass Contains
|
|
|
|
** ---- --------
|
|
|
|
** 1 Every 8th row, starting with row 0
|
|
|
|
** 2 Every 8th row, starting with row 4
|
|
|
|
** 3 Every 4th row, starting with row 2
|
|
|
|
** 4 Every 2nd row, starting with row 1
|
|
|
|
**
|
|
|
|
** When interlacing is turned off, the image data instead contains
|
|
|
|
** image rows in sequential order from row 0 (top) to the last row.
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION DECLARATIONS
|
|
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static int imGifVfbRead1(int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb,
|
|
|
|
unsigned char interlaced,unsigned char codesize );
|
|
|
|
static int imGifVfbRead8(int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb,
|
|
|
|
unsigned char interlaced, unsigned char codesize );
|
|
|
|
static int imGifNBitsPixel (int ncolors,int *);
|
|
|
|
static int imGifRead( int ioType, int fd, FILE *fp,TagTable *flagsTable, TagTable *tagTable);
|
|
|
|
static int imGifWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable );
|
|
|
|
static int imGifWriteTransparency( int ioType, int fd, FILE* fp, int transValue);
|
|
|
|
#else
|
|
|
|
static int imGifVfbRead1( );
|
|
|
|
static int imGifVfbRead8( );
|
|
|
|
static int imGifNBitsPixel( );
|
|
|
|
|
|
|
|
static int imGifRead( );
|
|
|
|
static int imGifWrite( );
|
|
|
|
static int imGifWriteTransparency( );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FORMAT INFORMATION
|
|
|
|
* imGifNames - format's name and aliases
|
|
|
|
* imGifReadMap - read attributes
|
|
|
|
* imGifWriteMap - write attributes
|
|
|
|
* imGifMagicNumber - magic number
|
|
|
|
* imGifMagic - list of magic numbers
|
|
|
|
* ImFileGifFormat - master format description
|
|
|
|
*/
|
|
|
|
static char *imGifNames[ ] = { "gif", "giff", NULL };
|
|
|
|
static ImFileFormatReadMap imGifReadMap[ ] =
|
|
|
|
{
|
|
|
|
/* in out */
|
|
|
|
/* type,ch,dep, attr. VFB type attr. */
|
|
|
|
{ IN,1,1, LZW, IMVFBMONO, 0 },
|
|
|
|
{ IN,1,2, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,3, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,4, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,5, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,6, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,7, LZW, IMVFBINDEX8, 0 },
|
|
|
|
{ IN,1,8, LZW, IMVFBINDEX8, 0 },
|
|
|
|
|
|
|
|
{ IN,1,1, LZW|C, IMVFBMONO, C },
|
|
|
|
{ IN,1,2, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,3, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,4, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,5, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,6, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,7, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ IN,1,8, LZW|C, IMVFBINDEX8, C },
|
|
|
|
{ -1, 0, -1, 0 },
|
|
|
|
};
|
|
|
|
static ImFileFormatWriteMap imGifWriteMap[ ] =
|
|
|
|
{
|
|
|
|
/* in out */
|
|
|
|
/* VFB type, attr., type,ch,dep, attr., func */
|
|
|
|
{ IMVFBMONO, C|A, IN,1,1, LZW|C|A,imGifWrite },
|
|
|
|
{ IMVFBMONO, C, IN,1,1, LZW|C, imGifWrite },
|
|
|
|
{ IMVFBINDEX8, C|A, IN,1,8, LZW|C|A,imGifWrite },
|
|
|
|
{ IMVFBINDEX8, C, IN,1,8, LZW|C, imGifWrite },
|
|
|
|
{ -1, 0, -1, 0, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned char imGifMagicNumber87[ ] = { 'G', 'I', 'F', '8', '7', 'a' };
|
|
|
|
static unsigned char imGifMagicNumber89[ ] = { 'G', 'I', 'F', '8', '9', 'a' };
|
|
|
|
static ImFileMagic imFileGifMagic[ ] =
|
|
|
|
{
|
|
|
|
{ 0, 6, imGifMagicNumber87 },
|
|
|
|
{ 0, 6, imGifMagicNumber89 },
|
|
|
|
{ 0, 0, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
ImFileFormat ImFileGifFormat =
|
|
|
|
{
|
|
|
|
imGifNames, /* Names */
|
|
|
|
"Graphics Image File", /* Description */
|
|
|
|
"Compuserve", /* Creator */
|
|
|
|
"1- thru 8-bit color index Lempel-Ziv & Welch-compressed single- or\n\
|
|
multi-image files.", /* Read support */
|
|
"1 and 8-bit color index Lempel-Ziv & Welch-compressed single- or\n\
|
|
multi-image files.", /* Write support*/
|
|
|
|
imFileGifMagic, /* Magic #'s */
|
|
|
|
IMMULTI, IMPIPE, /* Read? */
|
|
|
|
IMMULTI, IMPIPE, /* Write? */
|
|
|
|
imGifRead, imGifReadMap, imGifWriteMap, /* Maps */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TYPEDEF & STRUCTURE
|
|
|
|
* imGifHeaderInfo - Gif header information
|
|
|
|
* imGifHeaderFields - Gif Info description for Bin pkg
|
|
|
|
* imGifHeader - Gif header holder
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The imGifHeaderInfo includes the GIF Header block and Logical Screen
|
|
|
|
* block fields.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct imGifHeaderInfo
|
|
|
|
{
|
|
|
|
unsigned char gif_magic[6]; /* GIF signature + version */
|
|
|
|
sdsc_uint16 gif_width; /* Screen width */
|
|
|
|
sdsc_uint16 gif_height; /* Screen height */
|
|
|
|
unsigned char gif_flags; /* Assorted flags */
|
|
|
|
unsigned char gif_background; /* Color index of screen background*/
|
|
|
|
unsigned char gif_aspect; /* Pixel aspect ratio */
|
|
|
|
} imGifHeaderInfo;
|
|
|
|
|
|
|
|
static imGifHeaderInfo imGifHeader; /* GIF file header */
|
|
|
|
|
|
|
|
static BinField imGifHeaderFields[ ] =
|
|
|
|
{
|
|
|
|
{ UCHAR, 1, 6 }, /* gif_magic */
|
|
|
|
{ UINT16, 2, 1 }, /* gif_width */
|
|
|
|
{ UINT16, 2, 1 }, /* gif_height */
|
|
|
|
{ UCHAR, 1, 1 }, /* gif_flags */
|
|
|
|
{ UCHAR, 1, 1 }, /* gif_background */
|
|
|
|
{ UCHAR, 1, 1 }, /* gif_aspect */
|
|
|
|
{ 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TYPEDEF & STRUCTURE
|
|
|
|
* imGifImDescInfo - Gif image descriptor information
|
|
|
|
* imGifImDescFields - imGifImDescInfo description for Bin pkg
|
|
|
|
* imGifImDesc - Gif image descriptor holder
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The image descriptor defines the actual placement and extents of the
|
|
|
|
* following image within the space defined by screen width and height.
|
|
|
|
* Also defined are flags to indicate the presence of a local color
|
|
|
|
* lookup map, the pixel display sequence and the #bits per pixel
|
|
|
|
* defined for this image.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct imGifImDescInfo
|
|
|
|
{
|
|
|
|
sdsc_uint16 im_left; /* Start of image from left side*/
|
|
|
|
sdsc_uint16 im_top; /* Start of image from top */
|
|
|
|
sdsc_uint16 im_width; /* Width of the image in pixels */
|
|
|
|
sdsc_uint16 im_height; /* Height of the image in pixels*/
|
|
|
|
unsigned char im_flags; /* Assorted flags */
|
|
|
|
|
|
|
|
}imGifImDescInfo;
|
|
|
|
|
|
|
|
static imGifImDescInfo imGifImDesc; /* GIF image descriptor */
|
|
|
|
|
|
|
|
static BinField imGifImDescFields[] =
|
|
|
|
{
|
|
|
|
{ UINT16, 2, 1 }, /* im_left */
|
|
|
|
{ UINT16, 2, 1 }, /* im_top */
|
|
|
|
{ UINT16, 2, 1 }, /* im_width */
|
|
|
|
{ UINT16, 2, 1 }, /* im_height */
|
|
|
|
{ UCHAR, 1, 1 }, /* im_flags */
|
|
|
|
{ 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TYPEDEF
|
|
|
|
* imGifControlBlock - Gif Control Block structure
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* This is the structure that is contained in an graphics control
|
|
|
|
* block. We just use it to set the transparency field.
|
|
|
|
*/
|
|
|
|
typedef struct imGifControlBlock
|
|
|
|
{
|
|
|
|
unsigned char blocksize; /* always 4 */
|
|
|
|
unsigned char flags; /* what's in the block */
|
|
|
|
sdsc_uint16 delay; /* how long to wait for a keypress */
|
|
|
|
unsigned char transparent_color; /* The color that is transparent */
|
|
|
|
unsigned char terminator; /* always 0 */
|
|
|
|
} imGifControlBlock;
|
|
|
|
|
|
|
|
static BinField imGifControlBlockFields[] =
|
|
|
|
{
|
|
|
|
{ UCHAR, 1, 1}, /* blocksize */
|
|
|
|
{ UCHAR, 1, 1}, /* flags */
|
|
|
|
{ UINT16, 2, 1}, /* delay */
|
|
|
|
{ UCHAR, 1, 1}, /* transparent_color */
|
|
|
|
{ UCHAR, 1, 1}, /* terminator */
|
|
|
|
{ 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CONSTANTS
|
|
|
|
* IMGIFMAGIC87a - file magic number, version 87a
|
|
|
|
* IMGIFMAGIC89a - file magic number, version 89a
|
|
|
|
* IMGIFBITPIXEL - mask to read #bits/pixel in the image
|
|
|
|
* IMGIFGLOBALCM - mask to read if a global colormap is present
|
|
|
|
* IMGIFLOCALCM - mask to read if a local colormap is present
|
|
|
|
* IMGIFINTERLACED - mask to read the pixel display sequence used
|
|
|
|
* IMGIFTERMINATOR - termination character of a Gif image file
|
|
|
|
* IMGIFEXTENSION - Gif extension block introducer character
|
|
|
|
* IMGIFSEPARATOR - image separator character
|
|
|
|
* IMGIFENDBLOCK - terminates extension blocks
|
|
|
|
* IMGIFNCOLORRES - # bits of color resolution
|
|
|
|
* IMGIFNBITSPIXEL - # bits per pixel
|
|
|
|
* IMGIFBACKGROUND - index of background color
|
|
|
|
* IMGIFCODESIZE - initial code size used for lzw algorithm
|
|
|
|
* IMGIFNOCOLORMAP - no color lookup table present
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define IMGIFMAGIC87a "GIF87a"
|
|
|
|
#define IMGIFMAGIC89a "GIF89a"
|
|
|
|
#define IMGIFBITPIXEL 0x07
|
|
|
|
#define IMGIFGLOBALCM 0x80
|
|
|
|
#define IMGIFLOCALCM 0x80
|
|
|
|
#define IMGIFINTERLACED 0x40
|
|
|
|
#define IMGIFTERMINATOR ';'
|
|
|
|
#define IMGIFEXTENSION '!'
|
|
|
|
#define IMGIFSEPARATOR ','
|
|
|
|
#define IMGIFENDBLOCK 0
|
|
|
|
#define IMGIFNCOLORRES 8
|
|
|
|
#define IMGIFNBITSPIXEL 8
|
|
|
|
#define IMGIFBACKGROUND 0
|
|
|
|
#define IMGIFCODESIZE IMGIFNBITSPIXEL
|
|
|
|
#define IMGIFNOCOLORMAP 0
|
|
|
|
#define IMGIFGRAPHICCONTROL 0xF9
|
|
|
|
#define IMGIFCOMMENT 0xFE
|
|
|
|
#define IMGIFPLAINTEXT 0x01
|
|
|
|
#define IMGIFAPPLICATION 0xFF
|
|
|
|
#define IMGIFTRANSPARENCY 0x01 /* For graphic control blocks */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifCltRead - read a color lookup table
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Used for reading either global or local color tables, this routine
|
|
|
|
* reads in a a table of nClt colors and stores it into a new ImClt
|
|
|
|
* which is then returned.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifCltRead( int ioType, int fd, FILE *fp, int nClt, ImClt **clt )
|
|
|
|
#else
|
|
|
|
imGifCltRead( ioType, fd, fp, nClt, clt )
|
|
|
|
int ioType; /* Type of I/O to do */
|
|
|
|
int fd; /* Descriptor to read from */
|
|
|
|
FILE *fp; /* Pointer to read from */
|
|
|
|
int nClt; /* # of colors to read */
|
|
|
|
ImClt **clt; /* Where to put them */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ImCltPtr cptr; /* Color pointer */
|
|
|
|
unsigned char *cltBuffer; /* Color lookup table buffer */
|
|
|
|
unsigned char *colorp; /* Color buffer pointer */
|
|
|
|
int i; /* Counter */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new ImClt and a temporary buffer to store the
|
|
|
|
* the raw incomming data.
|
|
|
|
*/
|
|
|
|
if ( (*clt = ImCltAlloc(nClt)) == IMCLTNULL)
|
|
|
|
{
|
|
|
|
ImErrorFatal ( ImQError(), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
ImMalloc( cltBuffer, unsigned char *, sizeof( UCHAR ) * nClt * 3 );
|
|
|
|
|
|
|
|
|
|
|
|
/* Read in Red, Green, and Blues. */
|
|
|
|
if ( ImBinRead( ioType, fd, fp, cltBuffer, UCHAR, 1, nClt * 3 ) == -1 )
|
|
|
|
{
|
|
|
|
free( (char *)cltBuffer );
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* And copy them to the ImClt. */
|
|
|
|
cptr = ImCltQFirst( *clt );
|
|
|
|
colorp = cltBuffer;
|
|
|
|
for ( i = 0; i < nClt; i++ )
|
|
|
|
{
|
|
|
|
ImCltSRed( cptr, *(colorp++) );
|
|
|
|
ImCltSGreen( cptr, *(colorp++) );
|
|
|
|
ImCltSBlue( cptr, *(colorp++) );
|
|
|
|
ImCltSInc( *clt, cptr );
|
|
|
|
}
|
|
|
|
free( (char *) cltBuffer );
|
|
|
|
return ( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifExtRead - Read the gif extension blocks
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The only extension we pay attention to is image transparency.
|
|
|
|
* If we see this, we add it to the data table.
|
|
|
|
*
|
|
|
|
* Note that we intentionally don't use seek() calls to skip the
|
|
|
|
* extension data. This allows us to read from pipes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifExtRead( int ioType, int fd, FILE *fp, TagTable* tagTable )
|
|
|
|
#else
|
|
|
|
imGifExtRead( ioType, fd, fp, tagTable )
|
|
|
|
int ioType; /* Type of I/O to do */
|
|
|
|
int fd; /* Descriptor to read from */
|
|
|
|
FILE *fp; /* Pointer to read from */
|
|
|
|
TagTable *tagTable; /* tag table */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
unsigned char c, buf[256]; /* Temp buffer */
|
|
|
|
int transparency=0; /* Is this a transparency block? */
|
|
|
|
imGifControlBlock block; /* structure with transparency */
|
|
|
|
char* tmp; /* temporary string for tagtable */
|
|
|
|
char message[100]; /* buffer for message */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read in extension label
|
|
|
|
*/
|
|
|
|
if ( ImBinRead( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure extension blocks are valid ones
|
|
|
|
*/
|
|
|
|
switch( c )
|
|
|
|
{
|
|
|
|
case IMGIFGRAPHICCONTROL:
|
|
|
|
transparency = 1;
|
|
|
|
break;
|
|
|
|
case IMGIFCOMMENT:
|
|
|
|
case IMGIFPLAINTEXT:
|
|
|
|
case IMGIFAPPLICATION:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ImErrNo = IMESYNTAX;
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (transparency==1)
|
|
|
|
{
|
|
|
|
if ( ImBinReadStruct( ioType, fd, fp, &block,
|
|
|
|
imGifControlBlockFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
/* Put block.transparent_color in tagTable */
|
|
|
|
if (block.flags & IMGIFTRANSPARENCY)
|
|
|
|
{
|
|
|
|
ImMalloc(tmp, char * , 15 );
|
|
|
|
sprintf(tmp,"index=%d",(int)block.transparent_color);
|
|
|
|
TagTableAppend( tagTable,
|
|
|
|
TagEntryAlloc( "transparency value", POINTER, &tmp));
|
|
|
|
}
|
|
|
|
sprintf(message,"Pixels with index %d.",(int)block.transparent_color);
|
|
|
|
ImInfo ("Transparency",message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Skip over extension data
|
|
|
|
*/
|
|
|
|
for ( ; ; )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Read in block size or block terminator
|
|
|
|
*/
|
|
|
|
if ( ImBinRead( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If block terminator, quit loop
|
|
|
|
*/
|
|
|
|
if ( c == IMGIFENDBLOCK )
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip over block
|
|
|
|
*/
|
|
|
|
if ( ImBinRead( ioType, fd, fp, buf, UCHAR, 1, c ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifRead - read a gif image file
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* The file header is read and the magic number checked.
|
|
|
|
* Separate routines are then called to handle different
|
|
|
|
* sizes (1 and anything from 2 to 8)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifRead( int ioType, int fd, FILE *fp,TagTable *flagsTable, TagTable *tagTable)
|
|
|
|
#else
|
|
|
|
imGifRead( ioType, fd, fp, flagsTable, tagTable )
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Input file descriptor */
|
|
|
|
FILE *fp; /* Input file pointer */
|
|
|
|
TagTable *flagsTable; /* Flags */
|
|
|
|
TagTable *tagTable; /* Tag table to add to */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
|
|
|
|
ImVfb *vfb; /* Read in image */
|
|
|
|
int nGClt,nLClt; /* Number of Global and Local */
|
|
|
|
/* CLT entries */
|
|
|
|
ImClt *gClt, *lClt; /* Read in colormaps */
|
|
|
|
unsigned char c; /* aux var */
|
|
|
|
int end; /* end to reading images */
|
|
|
|
int status; /* Return status */
|
|
|
|
int imageCount = 1;/* Number of images processed */
|
|
|
|
char message[100]; /* ImInfo message */
|
|
|
|
int nbits; /* # of bits per pixel */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the Binary I/O package's byte order
|
|
|
|
*/
|
|
|
|
BinByteOrder( BINLBF );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read GIF header
|
|
|
|
*/
|
|
|
|
if ( ImBinReadStruct( ioType, fd, fp, &imGifHeader,
|
|
|
|
imGifHeaderFields )== -1)
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for valid Signature and version (treated as magic
|
|
|
|
* numbers). Always 6 bytes long.
|
|
|
|
*/
|
|
|
|
if( strncmp( (char*)imGifHeader.gif_magic, IMGIFMAGIC87a, 6 ) == 0 )
|
|
|
|
{
|
|
|
|
ImInfo( "Version", "GIF87a" );
|
|
|
|
}
|
|
|
|
else if ( strncmp( (char*)imGifHeader.gif_magic, IMGIFMAGIC89a, 6 ) == 0 )
|
|
|
|
{
|
|
|
|
ImInfo( "Version", "GIF89a" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImErrNo = IMEMAGIC;
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
ImInfo( "Byte Order", "Least Significant Byte First" );
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the Global Color Map if it exists
|
|
|
|
*/
|
|
|
|
gClt = IMCLTNULL;
|
|
|
|
lClt = IMCLTNULL;
|
|
|
|
if ( (imGifHeader.gif_flags & IMGIFGLOBALCM) == IMGIFGLOBALCM )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Compute the size of the GCLT and read it in.
|
|
|
|
*/
|
|
|
|
nGClt = 2 << ( imGifHeader.gif_flags & IMGIFBITPIXEL );
|
|
|
|
if ( imGifCltRead( ioType, fd, fp, nGClt, &gClt ) == -1 )
|
|
|
|
return ( -1 ); /* Error already handled */
|
|
|
|
sprintf( message, "%d Entries", nGClt );
|
|
|
|
ImInfo( "Global Color Table", message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImInfo( "Global Color Table", "none" );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Starts to read the images following
|
|
|
|
*/
|
|
|
|
end = 0;
|
|
|
|
while(!end)
|
|
|
|
{
|
|
|
|
if ( ImBinRead(ioType,fd,fp,&c,UCHAR,1,1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
switch(c)
|
|
|
|
{
|
|
|
|
case IMGIFSEPARATOR: /* Image separator character */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the gif image descriptor
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( ImBinReadStruct( ioType, fd, fp, &imGifImDesc,
|
|
|
|
imGifImDescFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Output -verbose messages
|
|
|
|
*/
|
|
|
|
sprintf( message, "%d of ?", imageCount++ );
|
|
|
|
ImInfo( "Image", message );
|
|
|
|
|
|
|
|
sprintf( message, "%d x %d", imGifImDesc.im_width,
|
|
|
|
imGifImDesc.im_height );
|
|
|
|
ImInfo( "Resolution", message );
|
|
|
|
|
|
|
|
if ( (imGifImDesc.im_flags & IMGIFLOCALCM) == IMGIFLOCALCM)
|
|
|
|
{
|
|
|
|
nbits = (imGifImDesc.im_flags & IMGIFBITPIXEL) + 1;
|
|
|
|
sprintf( message, "%d-bit Color Indexed", nbits );
|
|
|
|
ImInfo( "Type", message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No local color table. */
|
|
|
|
nbits = (imGifHeader.gif_flags&IMGIFBITPIXEL) + 1;
|
|
|
|
if ( gClt == NULL && nbits == 1 )
|
|
|
|
{
|
|
|
|
ImInfo( "Type", "1-bit Monochrome" );
|
|
|
|
}
|
|
|
|
else if ( gClt == NULL )
|
|
|
|
{
|
|
|
|
sprintf( message, "%d-bit Grayscale", nbits );
|
|
|
|
ImInfo( "Type", message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf( message, "%d-bit Color Indexed",nbits);
|
|
|
|
ImInfo( "Type", message );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the local color map if it exists
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( (imGifImDesc.im_flags & IMGIFLOCALCM) == IMGIFLOCALCM)
|
|
|
|
{
|
|
|
|
nLClt = 2 << ( imGifImDesc.im_flags & IMGIFBITPIXEL );
|
|
|
|
if ( imGifCltRead(ioType,fd,fp,nLClt,&lClt) == -1 )
|
|
|
|
return ( -1 );
|
|
|
|
sprintf( message, "%d Entries", nLClt );
|
|
|
|
ImInfo( "Local Color Table", message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImInfo( "Local Color Table", "none" );
|
|
|
|
}
|
|
|
|
|
|
|
|
ImInfo( "Compression Type", "Lempel-Ziv and Welch (LZW)");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the initial code size
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(ImBinRead(ioType,fd,fp,&c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the raster data into the vfb
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check the #bits/pixel
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( nbits == 1 )
|
|
|
|
status = imGifVfbRead1(ioType, fd, fp, flagsTable,
|
|
|
|
tagTable, &vfb,
|
|
|
|
(imGifImDesc.im_flags & IMGIFINTERLACED),c);
|
|
|
|
else
|
|
|
|
status = imGifVfbRead8( ioType, fd, fp, flagsTable,
|
|
|
|
tagTable, &vfb,
|
|
|
|
(imGifImDesc.im_flags & IMGIFINTERLACED),c);
|
|
|
|
if ( status == -1 )
|
|
|
|
return ( -1 ); /* Error already handled*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the color lookup table
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if a local color map is present then it is assigned
|
|
|
|
* to the vfb. if not, then the global color table
|
|
|
|
* is used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (((imGifImDesc.im_flags & IMGIFLOCALCM) == IMGIFLOCALCM )
|
|
|
|
&& ( lClt != IMCLTNULL) )
|
|
|
|
{
|
|
|
|
ImVfbSClt( vfb, lClt );
|
|
|
|
TagTableAppend( tagTable,
|
|
|
|
TagEntryAlloc( "image clt", POINTER, &lClt));
|
|
|
|
}
|
|
|
|
else if (gClt != IMCLTNULL)
|
|
|
|
{
|
|
|
|
ImVfbSClt( vfb, gClt );
|
|
|
|
TagTableAppend( tagTable,
|
|
|
|
TagEntryAlloc( "image clt", POINTER, &gClt));
|
|
|
|
}
|
|
|
|
TagTableAppend( tagTable,
|
|
|
|
TagEntryAlloc( "image vfb", POINTER, &vfb));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMGIFEXTENSION: /* Gif extension block introducer */
|
|
|
|
if ( imGifExtRead(ioType,fd,fp, tagTable) == -1 )
|
|
|
|
return ( -1 ); /* Error already handled*/
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMGIFTERMINATOR: /* GIf terminator */
|
|
|
|
end = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifVfbRead8 - read 2-8 bit Gif image
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* A new VFB is allocated. The image is read in, pixel by pixel,
|
|
|
|
* using the LZW algorithm, into the VFB. The order of the
|
|
|
|
* scanlines is given by the value of interlaced. If it is
|
|
|
|
* equal to IMGIFINTERLACED means that the scanlines are
|
|
|
|
* organized in an interlaced way. If not, they are written
|
|
|
|
* sequentially.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifVfbRead8(int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb,
|
|
|
|
unsigned char interlaced, unsigned char codesize )
|
|
|
|
#else
|
|
|
|
imGifVfbRead8(ioType, fd, fp, flagsTable, tagTable, pVfb, interlaced, codesize )
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Input file descriptor */
|
|
|
|
FILE *fp; /* Input file pointer */
|
|
|
|
TagTable *flagsTable; /* Flags */
|
|
|
|
TagTable *tagTable; /* Tag table to add to */
|
|
|
|
ImVfb **pVfb; /* VFB to fill and return */
|
|
|
|
unsigned char interlaced; /* tells if the image is inter */
|
|
|
|
unsigned char codesize; /* Inital code size used by LWZ */
|
|
|
|
/* laced */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
unsigned char index; /* color index */
|
|
|
|
ImVfb *vfb; /* New vfb */
|
|
|
|
ImVfbPtr pptr; /* Pixel pointer */
|
|
|
|
int column; /* Column pixel into the image */
|
|
|
|
int row; /* Row pixel into the image */
|
|
|
|
int pass; /* used for interlaced image */
|
|
|
|
int value; /* pixel value returned by LWZ */
|
|
|
|
int size; /* size of image in pixels */
|
|
|
|
int cont; /* counter */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a VFB of the required size.
|
|
|
|
*/
|
|
|
|
if ( (*pVfb = ImVfbAlloc( imGifImDesc.im_width, imGifImDesc.im_height,
|
|
|
|
IMVFBINDEX8 )) == IMVFBNULL )
|
|
|
|
{
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
vfb = *pVfb;
|
|
|
|
|
|
|
|
/* initializing lzw structures */
|
|
|
|
if ( imLzwReadByte(ioType, fd, fp, TRUE, codesize ) < 0 )
|
|
|
|
return( 0 );
|
|
|
|
|
|
|
|
size = imGifImDesc.im_width * imGifImDesc.im_height;
|
|
|
|
pptr = ImVfbQFirst( vfb );
|
|
|
|
cont = 0;
|
|
|
|
if (interlaced != IMGIFINTERLACED)
|
|
|
|
{
|
|
|
|
while ((cont < size) &&
|
|
|
|
((value = imLzwReadByte(ioType, fd, fp, FALSE, codesize)) >= 0) )
|
|
|
|
{
|
|
|
|
index = value;
|
|
|
|
ImVfbSIndex8( vfb, pptr, index);
|
|
|
|
ImVfbSInc( vfb, pptr );
|
|
|
|
cont++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
column = row = pass = 0;
|
|
|
|
while ((cont < size) &&
|
|
|
|
((value = imLzwReadByte(ioType, fd, fp, FALSE, codesize)) >= 0 ))
|
|
|
|
{
|
|
|
|
pptr = ImVfbQPtr( vfb, column,row );
|
|
|
|
index = value;
|
|
|
|
ImVfbSIndex8( vfb, pptr, index);
|
|
|
|
cont++;
|
|
|
|
if (++column == imGifImDesc.im_width)
|
|
|
|
{
|
|
|
|
column = 0;
|
|
|
|
switch (pass) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
row+= 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row+= 4;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row+= 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (row >= imGifImDesc.im_height )
|
|
|
|
switch(++pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
row = 4;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row = 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifVfbRead1 - read 1-bit Gif image
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* A new VFB is allocated. The image is read in, one scanline at
|
|
|
|
* a time, and converted into the VFB.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifVfbRead1(int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb,
|
|
|
|
unsigned char interlaced,unsigned char codesize )
|
|
|
|
#else
|
|
|
|
imGifVfbRead1(ioType, fd, fp, flagsTable, tagTable, pVfb, interlaced,codesize )
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Input file descriptor */
|
|
|
|
FILE *fp; /* Input file pointer */
|
|
|
|
TagTable *flagsTable; /* Flags */
|
|
|
|
TagTable *tagTable; /* Tag table to add to */
|
|
|
|
ImVfb **pVfb; /* VFB to fill and return */
|
|
|
|
unsigned char interlaced; /* tells if the image is inter */
|
|
|
|
unsigned char codesize; /* Initial code size used by LWZ*/
|
|
|
|
/* laced */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ImVfb *vfb; /* New vfb */
|
|
|
|
ImVfbPtr pptr; /* Pixel pointer */
|
|
|
|
int column; /* Column pixel into the image */
|
|
|
|
int row; /* Row pixel into the image */
|
|
|
|
int pass; /* used for interlaced image */
|
|
|
|
int value; /* pixel value returned by LWZ */
|
|
|
|
int size; /* size of image in pixels */
|
|
|
|
int cont;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a VFB of the required size.
|
|
|
|
*/
|
|
|
|
if ( (*pVfb = ImVfbAlloc( imGifImDesc.im_width, imGifImDesc.im_height,
|
|
|
|
IMVFBMONO )) == IMVFBNULL )
|
|
|
|
{
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
vfb = *pVfb;
|
|
|
|
|
|
|
|
/* initializing lzw structures */
|
|
|
|
if ( imLzwReadByte(ioType, fd, fp, TRUE, (int) codesize ) < 0 )
|
|
|
|
return( 0 );
|
|
|
|
|
|
|
|
size = imGifImDesc.im_width * imGifImDesc.im_height;
|
|
|
|
pptr = ImVfbQFirst( vfb );
|
|
|
|
cont = 0;
|
|
|
|
if (interlaced != IMGIFINTERLACED)
|
|
|
|
{
|
|
|
|
while ((cont < size) &&
|
|
|
|
((value = imLzwReadByte(ioType, fd, fp, FALSE, codesize)) >= 0) )
|
|
|
|
{
|
|
|
|
ImVfbSMono( vfb, pptr, (value) ? 1 : 0);
|
|
|
|
ImVfbSInc( vfb, pptr );
|
|
|
|
cont++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
column = row = pass = 0;
|
|
|
|
while ((cont < size) &&
|
|
|
|
((value = imLzwReadByte(ioType, fd, fp, FALSE, codesize)) >= 0))
|
|
|
|
{
|
|
|
|
pptr = ImVfbQPtr( vfb, column,row );
|
|
|
|
ImVfbSMono ( vfb, pptr, (value) ? 1 : 0);
|
|
|
|
cont++;
|
|
|
|
if (++column == imGifImDesc.im_width)
|
|
|
|
{
|
|
|
|
column = 0;
|
|
|
|
switch (pass) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
row+= 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row+= 4;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row+= 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (row >= imGifImDesc.im_height )
|
|
|
|
switch(++pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
row = 4;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row = 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifCltWrite - Write a color lookup table
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Write the color lockup table clt into the file
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifCltWrite(int ioType, int fd, FILE *fp, int nClt,int newClt, ImClt *clt)
|
|
|
|
#else
|
|
|
|
imGifCltWrite(ioType, fd, fp, nClt,newClt, clt)
|
|
|
|
int ioType;
|
|
|
|
int fd;
|
|
|
|
FILE *fp;
|
|
|
|
int nClt;
|
|
|
|
int newClt;
|
|
|
|
ImClt *clt;
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ImCltPtr cptr; /* Color pointer */
|
|
|
|
unsigned char *cltBuffer; /* Color lookup table buffer */
|
|
|
|
unsigned char *colorp; /* Color buffer pointer */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ImMalloc( cltBuffer, unsigned char *, sizeof( unsigned char ) * newClt * 3 );
|
|
|
|
|
|
|
|
colorp = cltBuffer;
|
|
|
|
cptr = ImCltQFirst( clt );
|
|
|
|
|
|
|
|
for (i=0; i< nClt; i++)
|
|
|
|
{
|
|
|
|
*(colorp++) = ImCltQRed ( cptr );
|
|
|
|
*(colorp++) = ImCltQGreen( cptr );
|
|
|
|
*(colorp++) = ImCltQBlue ( cptr );
|
|
|
|
ImCltSInc( clt, cptr );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, cltBuffer, UCHAR, 1, newClt * 3 ) == -1)
|
|
|
|
{
|
|
|
|
free( (unsigned char *)cltBuffer );
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifVfbWrite8 - Write an 8-bit vfb into a gif file
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifVfbWrite8( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb *vfb,
|
|
|
|
unsigned char interlaced )
|
|
|
|
#else
|
|
|
|
imGifVfbWrite8( ioType, fd, fp, flagsTable, tagTable, vfb, interlaced )
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Input file descriptor */
|
|
|
|
FILE *fp; /* Input file pointer */
|
|
|
|
TagTable *flagsTable; /* Flags */
|
|
|
|
TagTable *tagTable; /* Tag table to add to */
|
|
|
|
ImVfb *vfb; /* VFB to write */
|
|
|
|
unsigned char interlaced; /* tells if the image is inter */
|
|
|
|
/* laced */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
unsigned char *rasterimage; /* image pixel values */
|
|
|
|
int i;
|
|
|
|
int size; /* size of the image */
|
|
|
|
int pass;
|
|
|
|
int row,column;
|
|
|
|
ImVfbPtr ptr;
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write an Image separator
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = IMGIFSEPARATOR;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the Image Descriptor and write it out
|
|
|
|
*/
|
|
|
|
|
|
|
|
imGifImDesc.im_left = imGifImDesc.im_top = 0;
|
|
|
|
imGifImDesc.im_width = ImVfbQWidth ( vfb );
|
|
|
|
imGifImDesc.im_height = ImVfbQHeight ( vfb );
|
|
|
|
imGifImDesc.im_flags = interlaced;
|
|
|
|
|
|
|
|
if ( ImBinWriteStruct( ioType, fd, fp, &imGifImDesc,
|
|
|
|
imGifImDescFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write out the initial code size before
|
|
|
|
* start to compress the raster data
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = IMGIFCODESIZE;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a buffer to store the image pixel values
|
|
|
|
* to be compressed
|
|
|
|
*/
|
|
|
|
|
|
|
|
size = imGifImDesc.im_width * imGifImDesc.im_height;
|
|
|
|
ImMalloc( rasterimage, unsigned char *, size );
|
|
|
|
if ( rasterimage == NULL )
|
|
|
|
{
|
|
|
|
ImErrNo = IMEMALLOC;
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill the buffer with the pixel values
|
|
|
|
*/
|
|
|
|
|
|
|
|
ptr = ImVfbQFirst(vfb);
|
|
|
|
if (interlaced != IMGIFINTERLACED)
|
|
|
|
for (i=0; i< size; i++)
|
|
|
|
{
|
|
|
|
rasterimage[i] = ImVfbQIndex8(vfb,ptr);
|
|
|
|
ImVfbSInc(vfb,ptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
column = row = pass = 0;
|
|
|
|
for (i=0; i< size; i++)
|
|
|
|
{
|
|
|
|
ptr = ImVfbQPtr( vfb, column,row );
|
|
|
|
rasterimage[i] = ImVfbQIndex8(vfb,ptr);
|
|
|
|
if (++column == imGifImDesc.im_width)
|
|
|
|
{
|
|
|
|
column = 0;
|
|
|
|
switch (pass) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
row+= 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row+= 4;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row+= 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (row >= imGifImDesc.im_height )
|
|
|
|
switch(++pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
row = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
row = 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compress the raster data
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
imLzwCompGif( ioType, fd, fp, IMGIFCODESIZE + 1, rasterimage, size);
|
|
|
|
|
|
|
|
free ((unsigned char *) rasterimage);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write out a Zero-length packet
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the Gif terminator
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = IMGIFTERMINATOR;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifVfbWrite1 - Write an 1-bit vfb into a gif file
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifVfbWrite1( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb *vfb,
|
|
|
|
unsigned char interlaced )
|
|
|
|
#else
|
|
|
|
imGifVfbWrite1( ioType, fd, fp, flagsTable, tagTable, vfb, interlaced )
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Input file descriptor */
|
|
|
|
FILE *fp; /* Input file pointer */
|
|
|
|
TagTable *flagsTable; /* Flags */
|
|
|
|
TagTable *tagTable; /* Tag table to add to */
|
|
|
|
ImVfb *vfb; /* VFB to write */
|
|
|
|
unsigned char interlaced; /* tells if the image is inter */
|
|
|
|
/* laced */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
unsigned char *rasterimage; /* image pixel values */
|
|
|
|
int i; /* counter */
|
|
|
|
int size; /* size of the image */
|
|
|
|
int pass; /* pass number */
|
|
|
|
int row,column; /* pixel row and pixel column */
|
|
|
|
ImVfbPtr ptr; /* pixel pointer */
|
|
|
|
unsigned char c; /* auxiliar var */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write an Image separator
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = IMGIFSEPARATOR;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the Image Descriptor and write it out
|
|
|
|
*/
|
|
|
|
|
|
|
|
imGifImDesc.im_left = imGifImDesc.im_top = 0;
|
|
|
|
imGifImDesc.im_width = ImVfbQWidth ( vfb );
|
|
|
|
imGifImDesc.im_height = ImVfbQHeight ( vfb );
|
|
|
|
imGifImDesc.im_flags = interlaced;
|
|
|
|
|
|
|
|
if ( ImBinWriteStruct( ioType, fd, fp, &imGifImDesc,
|
|
|
|
imGifImDescFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write out the initial code size before
|
|
|
|
* start to compress the raster data. When
|
|
|
|
* the number of bits per pixel is 1 the
|
|
|
|
* initial code size used for LWZ algorithm is
|
|
|
|
* equal to 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = 2;
|
|
|
|
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a buffer to store the image pixel values
|
|
|
|
* to be compressed
|
|
|
|
*/
|
|
|
|
|
|
|
|
size = imGifImDesc.im_width * imGifImDesc.im_height;
|
|
|
|
ImMalloc( rasterimage, unsigned char *, size );
|
|
|
|
if ( rasterimage == NULL )
|
|
|
|
{
|
|
|
|
ImErrNo = IMEMALLOC;
|
|
|
|
ImErrorFatal( ImQError( ), -1, ImErrNo );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill the buffer with the pixel values
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
ptr = ImVfbQFirst(vfb);
|
|
|
|
if (interlaced != IMGIFINTERLACED)
|
|
|
|
for (i=0; i< size; i++)
|
|
|
|
{
|
|
|
|
rasterimage[i] = (ImVfbQMono(vfb,ptr)? 1 : 0);
|
|
|
|
ImVfbSInc(vfb,ptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
column = row = pass = 0;
|
|
|
|
for (i=0; i< size; i++)
|
|
|
|
{
|
|
|
|
ptr = ImVfbQPtr( vfb, column,row );
|
|
|
|
rasterimage[i] = (ImVfbQMono(vfb,ptr)? 1 : 0);
|
|
|
|
if (++column == imGifImDesc.im_width)
|
|
|
|
{
|
|
|
|
column = 0;
|
|
|
|
switch (pass) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
row+= 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
row+= 4;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row+= 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (row >= imGifImDesc.im_height )
|
|
|
|
switch(++pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
row = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
row = 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
row = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Compress the raster data
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 3 = initial code size + 1
|
|
|
|
* the initial code size is always 2 for
|
|
|
|
* one-bit images
|
|
|
|
*/
|
|
|
|
|
|
|
|
imLzwCompGif( ioType, fd, fp, 3, rasterimage, size);
|
|
|
|
|
|
|
|
free ((unsigned char *) rasterimage);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write out a Zero-length packet
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the Gif terminator
|
|
|
|
*/
|
|
|
|
|
|
|
|
c = IMGIFTERMINATOR;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &c, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifWrite - write a vfb image into gif image format
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns # of tags written */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
|
|
|
|
#else
|
|
|
|
imGifWrite( pMap, ioType, fd, fp, flagsTable, tagTable )
|
|
|
|
ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */
|
|
|
|
int ioType; /* I/O flags */
|
|
|
|
int fd; /* Output file descriptor */
|
|
|
|
FILE *fp; /* Output file pointer */
|
|
|
|
TagTable *flagsTable; /* Format Flags */
|
|
|
|
TagTable *tagTable; /* Tag list to add to */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ImVfb *vfb; /* Read in image */
|
|
|
|
int nClt; /* Number of CLT entries */
|
|
|
|
ImClt *clt; /* Read in colormap */
|
|
|
|
int newClt; /* Number of CLT entries rounded to a power of two */
|
|
|
|
int nbitspixel; /* number of bits per pixel */
|
|
|
|
char message[100]; /* ImInfo message */
|
|
|
|
int transparency; /* transparency value */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ImInfo( "Version", "GIF89a" );
|
|
|
|
ImInfo( "Byte Order", "Least Significant Byte First" );
|
|
|
|
|
|
|
|
TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up the header and write it out
|
|
|
|
*/
|
|
|
|
strncpy((char*)imGifHeader.gif_magic,IMGIFMAGIC89a,6);
|
|
|
|
imGifHeader.gif_width = ImVfbQWidth ( vfb );
|
|
|
|
imGifHeader.gif_height = ImVfbQHeight( vfb );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decide how to write out the GIF file.
|
|
|
|
*/
|
|
|
|
if (pMap->map_outAttributes & IMCLTYES)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* A CLT should be written out. Higher level code will
|
|
|
|
* have insured that it has a CLT. Figure out how many
|
|
|
|
* bits per pixel based upon the CLT size.
|
|
|
|
*/
|
|
|
|
clt = ImVfbQClt( vfb );
|
|
|
|
nClt= ImCltQNColors( clt );
|
|
|
|
nbitspixel = imGifNBitsPixel(nClt,&newClt);
|
|
|
|
imGifHeader.gif_flags = IMGIFGLOBALCM;
|
|
|
|
imGifHeader.gif_flags|= (IMGIFNCOLORRES - 1) << 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* No CLT to write out. Could be grayscale or monochrome.
|
|
|
|
*/
|
|
|
|
if ( ImVfbQFields( vfb ) & IMVFBINDEX8 )
|
|
|
|
nbitspixel = 8;
|
|
|
|
else
|
|
|
|
nbitspixel = 1;
|
|
|
|
imGifHeader.gif_flags = IMGIFNOCOLORMAP;
|
|
|
|
}
|
|
|
|
imGifHeader.gif_flags |= (nbitspixel-1);
|
|
|
|
imGifHeader.gif_background = IMGIFBACKGROUND;
|
|
|
|
imGifHeader.gif_aspect =
|
|
|
|
( ImVfbQWidth( vfb ) / ImVfbQHeight( vfb ) + 15 ) / 64;
|
|
|
|
|
|
|
|
BinByteOrder( BINLBF );
|
|
|
|
|
|
|
|
if ( ImBinWriteStruct( ioType, fd, fp, &imGifHeader,
|
|
|
|
imGifHeaderFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the CLT if exists
|
|
|
|
*/
|
|
|
|
if (pMap->map_outAttributes & IMCLTYES)
|
|
|
|
{
|
|
|
|
if ( imGifCltWrite(ioType, fd, fp, nClt, newClt, clt) == -1 )
|
|
|
|
return ( -1 );
|
|
|
|
sprintf( message, "%d Entries", nClt );
|
|
|
|
ImInfo( "Global Color Table", message );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ImInfo( "Global Color Table", "none" );
|
|
|
|
|
|
|
|
ImInfo( "Image", "1 of 1" );
|
|
|
|
|
|
|
|
sprintf( message, "%d x %d", imGifHeader.gif_width,
|
|
|
|
imGifHeader.gif_height );
|
|
|
|
ImInfo( "Resolution", message );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is a request for transparency or if
|
|
|
|
* there's transparency in the tagTable, add it to
|
|
|
|
* the image.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((transparency=ImGetTransparency(tagTable, flagsTable, vfb))!=-1)
|
|
|
|
{
|
|
|
|
if (imGifWriteTransparency( ioType, fd, fp, transparency)==-1)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* query the vfb and call the appropiate routine */
|
|
|
|
if ((ImVfbQFields( vfb ) & IMVFBMONO ))
|
|
|
|
{
|
|
|
|
ImInfo( "Type", "1-bit Monochrome" );
|
|
|
|
ImInfo( "Local Color Table", "none" );
|
|
|
|
ImInfo( "Compression Type", "Lempel-Ziv and Welch (LZW)" );
|
|
|
|
|
|
|
|
return(imGifVfbWrite1(ioType,fd,fp,flagsTable,tagTable,
|
|
|
|
vfb,IMGIFINTERLACED));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( pMap->map_outAttributes & IMCLTYES )
|
|
|
|
sprintf( message, "%d-bit Color Indexed", nbitspixel );
|
|
|
|
else
|
|
|
|
sprintf( message, "%d-bit Grayscale", nbitspixel );
|
|
|
|
ImInfo( "Type", message );
|
|
|
|
ImInfo( "Local Color Table", "none" );
|
|
|
|
ImInfo( "Compression Type", "Lempel-Ziv and Welch (LZW)" );
|
|
|
|
|
|
|
|
return(imGifVfbWrite8(ioType,fd,fp,flagsTable,tagTable,
|
|
|
|
vfb,IMGIFINTERLACED));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifNBitsPixel - compute # of bits to represent a color
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Rounds the number of colors to the closest power
|
|
|
|
* of two and return the necesary number of bits to
|
|
|
|
* represent this number of colors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int /* Returns # of bits */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifNBitsPixel (int ncolors,int *newNumber)
|
|
|
|
#else
|
|
|
|
imGifNBitsPixel (ncolors,newNumber)
|
|
|
|
int ncolors; /* number of colors */
|
|
|
|
int *newNumber; /* new number of colors */
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
int nbits;
|
|
|
|
|
|
|
|
*newNumber = 2;
|
|
|
|
nbits = 1;
|
|
|
|
if ( ncolors > 256)
|
|
|
|
{
|
|
|
|
nbits = 8;
|
|
|
|
*newNumber = 256;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (*newNumber < ncolors)
|
|
|
|
{
|
|
|
|
(*newNumber) <<= 1;
|
|
|
|
nbits++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(nbits);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION
|
|
|
|
* imGifWriteTransparency
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
* Write out the color which is transparent in the image
|
|
|
|
* as specified by the flags table. (As a default, write out
|
|
|
|
* the most popular color in the image.)
|
|
|
|
*
|
|
|
|
* If the tagEntry parameter specifies an index value, use that.
|
|
|
|
*
|
|
|
|
* If the tagEntry parameter specifes an rgb value, use the most
|
|
|
|
* common index value with that rgb value.
|
|
|
|
*
|
|
|
|
* If the tagEntry parameter speciefies "most common", use the
|
|
|
|
* most common index value in the image.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int /* returns status */
|
|
|
|
#ifdef __STDC__
|
|
|
|
imGifWriteTransparency( int ioType, int fd, FILE* fp, int transparency)
|
|
|
|
#else
|
|
|
|
imGifWriteTransparency( ioType, fd, fp, transparency)
|
|
|
|
int ioType;
|
|
|
|
int fd;
|
|
|
|
FILE* fp;
|
|
|
|
int transparency;
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
imGifControlBlock controlBlock; /* data */
|
|
|
|
unsigned char blockId; /* id for block */
|
|
|
|
char message[1000]; /*message buffer */
|
|
|
|
|
|
|
|
/* Specify that this is an extension */
|
|
|
|
blockId = IMGIFEXTENSION;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &blockId, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Specify what type of extension this is */
|
|
|
|
blockId = IMGIFGRAPHICCONTROL;
|
|
|
|
if ( ImBinWrite( ioType, fd, fp, &blockId, UCHAR, 1, 1 ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(message,"Pixels with index %d.",transparency);
|
|
|
|
ImInfo("Transparency",message);
|
|
|
|
|
|
|
|
controlBlock.blocksize = 0x04;
|
|
|
|
controlBlock.flags = 0x01;
|
|
|
|
controlBlock.delay = 0x00;
|
|
|
|
controlBlock.transparent_color = (unsigned char)transparency;
|
|
|
|
controlBlock.terminator = 0x00;
|
|
|
|
|
|
|
|
if ( ImBinWriteStruct( ioType, fd, fp, &controlBlock,
|
|
|
|
imGifControlBlockFields ) == -1 )
|
|
|
|
{
|
|
|
|
ImReturnBinError( );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|