[comp.graphics] GIF extensions

jindak@surfside.sgi.com (Chris Schoeneman) (07/29/90)

In article <OTTO.90Jul27095755@tukki.jyu.fi> otto@tukki.jyu.fi (Otto J.
Makela) proposes a new thread of discussion:  upgrading the GIF
standard.  In the last couple of weeks, there have been several postings
about this topic.  I wanted to add my $0.02.  Otto's suggestions are
indented below.  Sorry about the size.

    The current (and only) GIF standard is GIF87a.  It was designed
with extensibility and the hardware of the time in mind.  As a result
the standard is:  1) easy to enhance, and 2) inadequate for today's
hardware and user.  And now a brief lesson on the GIF standard.
    Enhancements are added as '!' extension blocks.  Each block has an
8 bit function code;  if a reader doesn't know a particular function,
it should skip over the block.  ALL GIF readers should accept '!' blocks
and skip over them if necessary.
    Tom Lane has pointed out that some GIF readers don't skip over
unrecognized '!' blocks, but crash instead.  Therefore, these readers
do not conform to the GIF standard.  Future versions of these readers
should at least accept '!' blocks if not make use of them, otherwise
these readers will become obsolete due to wider use of '!' blocks.
    GIF87a allows multiple images per file and one logical screen.  The
screen and each image may have its own color map (of up to 256 colors).
Images fit onto the logical screen and may use the screens color map.

> better compression - some asymmetric 2D compressions squeeze the picture
> real nice and are reasonably fast when decompressing; compression takes
> more time, of course

    The GIF standard uses LZW compression which achieves good compression
over a wide range of images.  It's also fast and easy to implement.  I
don't know anything about 'asymmetric 2D' compression schemes and would
like to hear more.  But adding it to GIF87a would probably double the
size of an encoder or decoder.  And replacing LZW would make all current
images unusable (unless translated).  So IMHO GIF should say with LZW.

> pixel shape information - on the PC with a VGA you can get about five
> different pixel ratios, and on just any machine with different graphics
> modes you end up with different shaped pixels in different modes; the
> current standard does not support any pixel information

    This is true.  Aspect ratio information is, of course, very
important.  I posted a proposal for a '!' extension to solve this
problem two weeks ago.  The important bit was:

>   7 6 5 4 3 2 1 0   Byte #
>  +---------------+
>  |0 0 1 0 0 0 0 1|    1        '!' - GIF extension block introducer
>  +---------------+
>  |0 1 0 1 0 0 1 0|    2        'R' - For 'aspect Ratio'
>  +---------------+
>  |0 0 0 0 0 0 1 0|    3         2  - Two bytes in block
>  +---------------+
>  |  pixel width  |    4            - First part of ratio (numerator)
>  +---------------+
>  | pixel height  |    5            - Second part of ratio (denominator)
>  +---------------+
>  |0 0 0 0 0 0 0 0|    6         0  - extension block end code
>  +---------------+
>Let byte four equal 'x' and byte five equal 'y'  Then x:y is the _pixel_
>aspect ratio.  'x' and 'y' should be relatively prime (ie they should
>have no common divisor except one), but they don't have to be.

This proposal received a favorable response.  Allen Braunsdorf noted
that this extension should apply to the logical screen, not individual
images (for simplicity).  This makes a lot of sense, so:
  All aspect ratio extension blocks after the first one or after any
  image descriptors are ignored.

> more colors per image - now that VGAs are common, we've hit the end of the
> standard; also for example the Amiga is able to show 4096 colors (albeit
> restrictedly)

    Another important point.  While most VGA's today only allow 256 at
once, this will change.  However, CompuServe, in an effort to save a
few bits, only allows 3 bits to describe the number of bits per pixel,
for a maximum of eight;  this means 256 colors tops.  GIF87a does use
24 bits to define these colors, though.  The 3 bit fields can't be
widened within the GIF87a standard, though they could be overridden.
    24 bit images won't be compressed much at all if all 24 bits are
stored together since scanned images have a lot of noise.  In 8 bits
noise isn't so bad, patterns usually form.  With 24 bits, noise is
terrible;  figure on virtually no compression for a scanned image.
    The solution, of course, is to separate the channels.  That is,
store all the reds, then the greens, then the blues.  Now we have
three 8 bit images.  This naturally presents a solution to the 8 bit
color problem.  Since GIF87a allows multiple images per file, we can
store a 24 bit image as three 8 bit images and some information on
how to combine the images.

   7 6 5 4 3 2 1 0   Byte #
  +---------------+
  |0 0 1 0 0 0 0 1|    1        '!' - GIF extension block introducer
  +---------------+
  |0 1 0 1 0 0 1 1|    2        'S' - For 'Stencil'
  +---------------+
  |0 0 0 0 0 0 1 0|    3         3  - Three bytes in block
  +---------------+
  |  red stencil  |    4            - 24 bits of bit mask. Bitwise
  +---------------+
  | green stencil |    5            - AND the logical screen's color
  +---------------+
  |  blue stencil |    5            - with the mask before drawing.
  +---------------+
  |0 0 0 0 0 0 0 0|    7         0  - extension block end code
  +---------------+

There should be no more than one of these before an image descriptor
block (image data).  In any case, all but the first are ignored, and
this block only affects the next image.  Every pixel in the area of
the logical screen under the next image should be bitwise AND'ed with
the 24 bit stencil mask.  Then image data should be bitwise OR'ed with
the screen's data.
    Now we can store a 24 bit image as three 8 bit images.  The first
image (the red channel) would be preceeded by the '!' stencil
extension:  0,83,3,0,0,0,0.  The screen pixels under the image are
cleared to all zeros since we bitwise AND with 0.  The colors of the
image are (r,g,b): (0,0,0),(1,0,0),(2,0,0),(3,0,0), ... ,(254,0,0),
(255,0,0), i.e. all possible 8 bit red intensities.  Each pixel is OR'ed
with the screen pixel (which has a zero).  When the decoder has
finished drawing this image, all the red components of the image have
been drawn.
    The next image (green) is preceded by: 0,83,3,255,0,0,0.  The colors
are all the greens.  The red channel of the screen pixels are unchanged,
the green and blue channels are cleared.  After drawing the image, we
have the red and green channels visible.
    The final image (blue) is preceeded by: 0,83,3,255,255,0,0.  The
image is drawn as above, resulting in the final 24 bit color image.

NOTE:  This extension isn't restricted to this scenario.
  * From 1-8 bits can be added at once.
  * Images with any number of bit planes (up to 24) can be drawn
  * Bit planes can be drawn in any order

    We could make an image with 4 red planes, 5 green planes, and 3
blue planes.  This could be stored as:
  * 16 color red image, 32 color green image, 8 color blue image
  * 16 color red image, 256 color green-cyan-blue image.
  * 12 2 color images.
The stencils and colors need only be set correctly.

    IMHO this extension gives a maximum of flexibility with a minimum
of extra information and additions to GIF.

> define better color coding - for some reason, GIFs made on a Macintosh
> tend to come out a lot darker on a PC (this could be a problem with the
> Mac software, but I suspect that it's something more esoteric like the
> color characteristics of a Mac display/display card vs. a PC VGA)

    This is probably due to the gamma's of the monitors.  Every montior
has non-linearities in intensity.  If this isn't corrected for, images
come out dark and contrasty.  Each GIF screen should have information
about the gamma values it's calibrated to.

   7 6 5 4 3 2 1 0   Byte #
  +---------------+
  |0 0 1 0 0 0 0 1|    1        '!' - GIF extension block introducer
  +---------------+
  |0 1 0 0 0 1 1 1|    2        'G' - For 'Gamma calibration'
  +---------------+
  |0 0 0 0 0 0 1 0|    3         3  - Three bytes in block
  +---------------+
  |   red gamma   |    4            - Gamma values for each color.
  +---------------+
  |  green gamma  |    5            - Images are calibrated for display
  +---------------+
  |   blue gamma  |    5            - on a montior with these gammas.
  +---------------+
  |0 0 0 0 0 0 0 0|    7         0  - extension block end code
  +---------------+

The gamma values are in fixed point, unsigned format:
  +---------------+  Two integral bits, 6 fractional bits.
  |7 6|5         0|  The actual floating point gamma is found
  +---------------+  by dividing by 64.0
The range is 0.0 - 3.984375, with a resolution of 0.015625.
Since most montiors are in the range 1 - 4, this should be okay.
Images can then be adjusted for different gamma values for display
on any monitor.  The decoder must, or course, know the monitor's
gamma values.  If only one is known, use it for all three colors.

    Only the first '!' gamma block should be used, all others are
ignored.  Furthermore, the '!' gamma block should come before any
image descriptor blocks.  If the field is absent, the decoder should
assume 1.0 for all three colors.  This is probably wrong, and the
decoder may want to indicate this.
    Future images should be calibrated to a gamma of 1.0 for all
colors.  The extension should be included so the decoder knows for
sure that the gammas are all 1.0.  If absent the decoder may assume
unity, but it may also assume that this assumption is wrong.

I've taken up enough bandwidth (overall I'd say I added my $2 :-).
Anybody have any comments?  About the proposals, I mean, not the
length.

-Chris Schoeneman
	       Chris Schoeneman | I was neat, clean, shaved and sober,
    jindak@surfside.esd.sgi.com | and I didn't care who knew it.
	 Silicon Graphics, Inc. |		-Raymond Chandler
	      Mountain View, CA |		 (The Big Sleep)