This file: README.gifs

Not copyrighted by Koen D'Hondt, <ripley@xs4all.nl>

------------------------------------------------------------------------------

The first part of this file contains a lot of disclaimers and warnings.
They might seem (actually, they are) rather ridiculous, but let me tell you
that Unisys *really* means business when it comes to using the LZW algorithm
without a valid license. I sure as hell want to cover my behind (to put it
nicely). This file wouldn't be here if it wasn't for Unisys's utterly
mindboggling attitude towards the use of the LZW algorithm for decoding GIF
images. I can tell you I had some very frustrating weeks when I negotiated with
Unisys to obtain a LZW license.

------------------------------------------------------------------------------

First of all a very big disclaimer:

    THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND.  THE AUTHOR
    SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF COPYRIGHTS,
    TRADE SECRETS OR ANY PATENTS BY THIS FILE OR ANY PART THEREOF.  IN NO
    EVENT WILL THE AUTHOR BE LIABLE FOR ANY LOST REVENUE OR PROFITS OR
    OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL DAMAGES.

    IF YOU DECIDE TO USE THE INFORMATION CONTAINED IN THIS FILE TO CONSTRUCT
    AND USE THE LZW ALGORITHM YOU AGREE TO ACCEPT FULL RESPONSIBILITY WITH
    RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRECTS OR ANY PATENTS.
    IN NO EVENT WILL THE AUTHOR BE LIABLE FOR ANY LOST REVENUE OR PROFITS OR
    OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL DAMAGES, INCLUDING BUT NOT
    LIMITED TO ANY DAMAGES RESULTING FROM ANY ACTIONS IN A COURT OF LAW.

And now an equally big warning:

    YOU ARE HEREBY WARNED THAT USE OF THE LZW ALGORITHM WITHOUT HAVING
    OBTAINED A PROPER LICENSE FROM UNISYS CONSTITUTES A VIOLATION OF
    APPLICABLE PATENT LAW. AS SUCH YOU WILL BE HELD LEGALLY RESPONSIBLE FOR
    ANY INFRINGEMENT OF THE UNISYS LZW PATENT.

    UNISYS REQUIRES YOU TO HAVE A LZW LICENSE FOR *EVERY* TASK IN WHICH THE
    LZW ALGORITHM IS BEING USED (WHICH INCLUDES DECODING THE LZW COMPRESSED
    RASTER DATA AS FOUND IN GIF IMAGES). THE FACT THAT YOUR APPLICATION MAY
    OR MAY NOT BE DISTRIBUTED AS FREEWARE IS OF NO CONCERN TO UNISYS.

    IF YOU RESIDE IN A COUNTRY WHERE SOFTWARE PATENT LAWS DO NOT APPLY,
    PLEASE BE WARNED THAT EXPORTING SOFTWARE CONTAINING THE LZW ALGORITHM TO
    COUNTRIES WHERE SOFTWARE PATENT LAW *DOES* APPLY WITHOUT A VALID LICENSE
    ALSO CONSTITUTES A VIOLATION OF PATENT LAW IN THE COUNTRY OF DESTINATION.
    
All in all:

    If you want to use the LZW algorithm without a valid license from Unisys,
    you are on your own.

------------------------------------------------------------------------------

So far for all the legal stuff, now on to what this file is all about:
implementing a LZW decoder in applications using XmHTML.


As you might have read in the README file, XmHTML uses a workaround to decode
GIF images instead of using a built-in LZW decoder. This ensures that neither
you, users of your applications and I require a license from Unisys. This
workaround is rather efficient for normal gifs and small animations and
normally spoken you should not see a noticable slowdown. Large animations 
however generally cause a slightly noticable slowdown, and on very large
animations the slowdown can be very visible. Unless you already have a license
which grants you the use of an LZW decoder (or want to buy one), this is 
something you and I have to live with.

However, you *can* replace the workaround with a true LZW decoder. I do not
advise this at all, *unless* you (or the company you work for) already has
obtained a LZW license from Unisys. If you really want to get a license from
Unisys, be prepared to pay 1,000$ (april 1997) for the license and also be
prepared to accept the totally frustrating restrictions set forth in the
license (contact Unisys at lzw_info@unisys.com if you are certain you want
get a license).

Adding a true GIF LZW decoder to applications using XmHTML
----------------------------------------------------------

XmHTML widget's provide the XmNdecodeGIFProc resource which enables you to
replace the internal GIF workaround with a true GIF LZW decoder.

The interface definition for a GIF decoding procedure is as follows:

typedef int (*XmImageGifProc)(XmHTMLGIFStream*);

Where XmHTMLGIFStream is defined as follows:

typedef struct _XmHTMLGIFStream{
	/* read-only fields */
	int state;					/* decoder state */
	int codesize;				/* initial LZW codesize */
	Boolean is_progressive;		/* when used by a progressive loader */
	unsigned char *next_in;		/* next input byte */
	Cardinal avail_in;			/* number of bytes available at next_in.
								 * Will never exceed 256 bytes
								 */
	Cardinal total_in;			/* total nb of input bytes read so far */

	/* fields to be updated by caller */
	unsigned char *next_out;	/* next output byte should be put there.
								 * Allocated and updated by XmHTML.
								 */
	Cardinal avail_out;			/* remaining free space at next_out */
	Cardinal total_out;			/* total nb of bytes output so far */

	String msg;					/* last error message, NULL if no error */
	XtPointer external_state;	/* room for decoder-specific data */
}XmHTMLGIFStream;

The external decoder must return one of the following values:

GIF_STREAM_OK
	successfully decoded the next chunk of data;

GIF_STREAM_END
	end of gif data. XmHTML will also set this value in the state field
	of the above structure if it has detected the zero data block itself;

GIF_STREAM_ERR
	an error occured in the decoder. You can set an appropriate error message
	in the msg field in the above structure which XmHTML will display.

As you might have noticed, this structure strongly resembles the z_stream
structure found in zlib 1.0.4. It provides a clean interface with little room
for errors. The external decoder is only responsible for decoding the LZW
compressed raster data, nothing else. XmHTML will take care of the actual
image composition (palette allocation, interlaced gif handling, animated gif
reading, etc..).

The following section explains the different fields in the XmHTMLGIFStream
structure and their allowable (or expected) values.

int state;					/* decoder state */

	The state field can have any of the following values:

	GIF_STREAM_INIT
		set when the decoder is called for the first time on a gif file. This
		is the stage at which the decoder should initialize its internal
		structures. The only valid field at this stage is the state field
		itself. The decoder should return GIF_STREAM_OK when the
		initialization was successfully. Returning any other code will be
		considered an error.

	GIF_STREAM_FINAL
		set when either all data has been uncompressed or an error occured.
		The decoder should free the resources it has allocated. The return
		value is ignored.

	This field is set by XmHTML.

int codesize;				/* initial LZW codesize */

	This is the initial GIF codesize as read from the raw image data. This
	value must be used to properly set up the decompressor tables.

	This field is set by XmHTML.

Boolean is_progressive;		/* when used by a progressive loader */

	This field indicates if the current decoder is being used to decode
	an image that is being loaded progressively.

	This field is set by XmHTML.

unsigned char *next_in;		/* next input byte */

	This field contains a pointer to the start of the next block of compressed
	image data. This is the data that should be decompressed.

	This field is set by XmHTML.

Cardinal avail_in;			/* number of bytes available at next_in.

	This field contains the number of bytes that next_in contains. As the
	block size of compressed gif raster data is limited to 256 bytes (see
	below) this number will never exceed 256, it will generally be smaller.

	This field is set by XmHTML.

Cardinal total_in;			/* total nb of input bytes read so far */

	This field represents the total number of compressed data read so far.
	It is the sum of all successive avail_in counts.

	This field is set by XmHTML.

unsigned char *next_out;	/* next output byte should be put there.

	This field points to a buffer that will be receiving the decompressed
	raster data. It is allocated and maintained by XmHTML. Upon the first
	invokation of the external decoder, XmHTML will allocate the receiving
	buffer (which is given by the width and height of the final image). 
	Upon each successive invokation XmHTML will update this field to point
	to the next available output byte.

Cardinal avail_out;			/* remaining free space at next_out */

	This field contains the number of bytes that is still available at
	next_out. When the value of this field drops to zero all data has been
	decoded and the decoder should return GIF_STREAM_END.

	This field *must* be maintained by the caller.

Cardinal total_out;			/* total nb of bytes output so far */

	This field contains the number of bytes decoded so far. XmHTML uses this
	field to offer an additional level of error detection: when it reaches the
	size of the output buffer while avail_out is non-zero the image data is
	corrupt.
	This field *must* be maintained by the caller.

String msg;					/* last error message, NULL if no error */

	When the external decoder detects an error (corrupt image data) and it
	returns GIF_STREAM_ERR, XmHTML will display the text pointed to by msg.
	XmHTML assumes this is a ptr to a static memory area and will not free it.

XtPointer external_state;	/* room for decoder-specific data */

	This field can be used to store data specific to the external decoder. It
	is not used by XmHTML in any way.


The format of the LZW compressed raster data is as follows (see the GIF87a or
GIF89a spec for the full definition):

         7 6 5 4 3 2 1 0

        +---------------+

        |   code size   | 

        +---------------+     ---+

        |blok byte count|        |

        +---------------+        |

        :               :        +-- Repeated as many times as necessary

        |  data bytes   |        |

        :               :        |

        +---------------+     ---+

        . . .       . . .

        +---------------+

        |0 0 0 0 0 0 0 0|       zero byte count (terminates data stream)

        +---------------+

The block byte count defines how many bytes are contained within the following 
data bytes. As all fields are one byte long, the block byte count can never
exceed 256.

A great deal of public applications/libraries are capabable of decoding GIF
images. A number of them are:

	- gif2png, Alexander Lehmann
	- Mosaic, various authors
		file gifread.c
	- netpbm, various authors
	- pbmplus, various authors
		file giftoppm.c
	- gd, the Gif Manipulating Library
		http://siva.cshl.org/gd/gd.html
		http://sunsite.unc.edu/boutell/index.html
	- libjpeg, Thomas G. Lane and The Independent JPEG Group.
		file rdgif.c (quite heavily modified though)

	- ImageMagick, John Cristy
		http://www.wizards.dupont.com/cristy/ImageMagick.html
		ftp://ftp.wizards.dupont.com/pub/ImageMagick/
		ftp://ftp.x.org/contrib/applications/ImageMagick/
		Look at compress.c, routine GIFDecodeImage.

	- xgif, John Bradley
		file xgifload.c
	- xv, John Bradley
		file xvgif.c

	- giftool, Mark Podliplec
	- gifmerge, Mark Podliplec

There are literally hundreds of applications capable of reading gif images.
Just pick the one that suits your needs.

A totally free, uncopyrighted gifdecoder can be found in the contrib directory.
It is from a contributor who whishes to stay anonymous (can you blame him?).

That's all there is. Question? Suggestions? Mail me at ripley@xs4all.nl

Koen D'Hondt.
