Dec 092017
A GIF viewer that includes full Turbo Pascal 4.0+ source code.
File DEGIF.ZIP from The Programmer’s Corner in
Category Printer + Display Graphics
A GIF viewer that includes full Turbo Pascal 4.0+ source code.
File Name File Size Zip Size Zip Type
DEGIF.DOC 17408 6120 deflated
DEGIF.TPU 4064 1969 deflated
DEGIFER.EXE 15120 9998 deflated
DEGIFER.PAS 4736 1794 deflated

Download File DEGIF.ZIP Here

Contents of the DEGIF.DOC file



DEGIF is a Turbo Pascal Unit to decode graphic images stored in
CompuServe's Graphic Interchange Format (GIF). With this unit you can write
your own GIF decoder or add GIF to any application. "GIF" and "Graphic
Interchange Format" are trademarks of H & R Block, Inc. The GIF standard
itself is in the public domain.

This unit is fully documented but we will not release the source code
at this time. This is a shareware product with a registration fee of $25
payable to Cyborg Software Systems, Inc. 3119 Cossell Drive, Indianapolis,
IN 46224. This unit, the documentation and the source and executable code
for DEGIFER are all Copyright 1988 by Cyborg Software Systems, Inc.

You may use this material for personal non-commercial use. If you like
it we ask you to register it. If you distribute it for free you must
distribute it in its original ARC form with all files intact. If you
distribute it for a fee or if you wish to use DEGIF in any commercial
application or custom programming written for fee or under contract, you
must register it. Violation of the above terms infringes our copyright.
Registered users will receive the next update free of charge. Further
updates will cost registered users $5.

Parts of this code are very loosely based on EXPANDER.INC by Bob Berry
which was a Turbo Pascal 3.0 translation of EXPANDER.C written in C by Steve
Wilhite. Sincere thanks and credit to them.


The best way we know to document the DEGIF unit is to give an example
program called DEGIFER. DEGIFER is a very, very primitive GIF display
program for CGA graphics. It makes no attempts to match colors. It just
plots points in (COLOR mod 4). On 2 color images its great. Most 16 color
images are viewible. Beyond that you're on your own.

You should print out a copy of DEGIFER.PAS and follow it along its main
routine as we go.

2.1 Initialization

The first thing you must do is pass a procedure pointer to your
routines called GetByte and PutByte. GetByte must be a far-call function to
retrieve one byte from the GIF file. PutByte must be a far-call procedure
to put one pixel on the screen. We will discuss these routines in section
3.0 below. AddrGetByte and AddrPutByte are a global pointers declared in
the DEGIF unit but you must initialize them.

The next few lines of DEGIFER's main routine engage the CRT unit and
prints the copyright notice. A file name is retrieved from the command line
or the user is prompted for one. The file is opened. This is the file that
GetByte gets its bytes from.

The variables SkipIt, EOFin, Done, BufIndx and Count are initialized.

Copyright (c) 1988 Cyborg Software Systems, Inc. page 1.


They are specific to this demo and your application may not need them.

The DEGIF unit defines the following....

Type MapType=(Global,Local);

GIF files may or may not have a global color map and or a local color
map for multiple image files. DEGIF needs its variable CurMap:MapType to be
initialized before you begin.

2.2 Procedure GetGIFSig

All valid GIF files begin with a 6 byte signature. The DEGIF unit
provides a procedure GetGIFSig to retrieve it. After calling GetGIFSig the
global string GIFSig should contain the string. As of this writing (March
1988) the only valid string is 'GIF87a'.

2.3 Procedure GetScrDes

Following the GIF signature in a GIF file is the screen description.
The DEGIF unit provides a procedure GetScrDes to retrieve it and initialize
several global variables.

ScreenWidth and ScreenHeight are type Word and contain the screen width
and height in pixels. All images in this file will fit in this virtual
screen space. Its up to you to scale, clip or scroll the image if it
doesn't fit your physical screen. There is no information anywhere in
current GIF files to help determine the proper aspect ratio. You have to
just guess that in all likelihood screens of 320 x 200, 640 x 200, 320 x 400
or 640 x 400 are really all supposed to be of the same aspect ratio. What
you do with stuff like 640 x 350 or 640 x 480 on a screen that won't hold it
is up to you.

MapExists[Global] is a boolean that tells you if there is a global
color map for this file.

BitsOfColorPerPrimary is a Word but the only valid values are [1..8].
I was just too lazy to declare it as a byte or sub-range type . It
is the topic of much debate among GIF developers as to how useful it is. It
isn't necessary and my experience is it is unreliable. For EGA created
images its value should be 2 because each primary color (red, green and
blue) is designated by 2 bits. EGA's can therefore have 2^(2+2+2)=64
possible colors. The GIF file might contain only 16 so
BitsOfColorPerPrimary doesn't tell you how many you can display at once or
how many colors are in this image.

BitsPerPixel[Global] is a word that does tell you. You really don't
need this value but we give it to you anyway. We provide also provide
NumberOfColors[Global] which again is a word but it is in the range
[1..256]. It is computed by...

NumberOfColors[Global]:= (1 shl BitsPerPixel[Global]);

Copyright (c) 1988 Cyborg Software Systems, Inc. page 2.


This means GIF color maps always contain 2, 4, 8, 16, 32, 64, 128 or
256 entries. The image may not actually contain that many colors. It may
use fewer. I have no problem with 16 color images that contain only 10 or
12 colors. It really raises my dandruff when I download 256 color images
with 31 colors!!! Editorial over.

Some GIF files are composed of multiple small images that may overlap
or may not fill the screen. The standard says you should first fill in a
background before plotting the images. Some decoders don't bother. They
leave the background black. DEGIF gives you BackgrColorIndex which tells
you what color to paint the background.

Next DEGIFER calls DisplayScrDes. This is its own routine which not
only tells the user the information from the screen descriptor, it also
attempts to correct aspect ratio by squeezing the image horizontally,
smashing it vertically or clipping it if that doesn't work. You are
responsible for coming up with such topological gymnastics and should feel
free to do it however you want.

2.4 Procedure GetColorMap

The GIF standard provides for an optional global color map. Most GIF
files contain one. GetScrDes sets the boolean MapExists[Global] to true if
there is a global map. The map is put in the following arrays....

RedValue,GreenValue,BlueValue: array [0..255] of byte;

Only values in the range [0..NumberOfColors[Global]-1] are defined.
They are intensity values from [0..255] for the red, blue and green
components of the color.

After calling GetColorMap you must decide on a mapping method. This is
the proverbial thing that "separates the men from the boys" when it comes to
implementing GIF. DEGIFER does a total cop-out and ignores the map
completely. It has the following statements...

if MapExists[Global] then GetColorMap;

...but you'll probably want to implement it as...

if MapExists[Global]
then begin GetColorMap; DoMapping end
else UseDefaultMap;

The job of your DoMapping is to fill the array Color which is defined
by the DEGIF unit as...

Color: array [Global..Local,0..255] of byte;

DoMapping should look like this...

procedure DoMapping;

Copyright (c) 1988 Cyborg Software Systems, Inc. page 3.


var I:integer;
for I:=0 to NumberOfColors[CurMap]-1 do
Color[CurMap,I]:= { Some function of }
{ RedValue[I], }
{ BlueValue[I] & }
{ GreenValue[I] }

Here is a sample DoMapping that computes a least squares mapping for a
16 color mode on a PCjr or Tandy 1000...

procedure DoMapping;
MyRed:array [0..15] of byte=
(000,000,000,000, 170,170,170,170, 085,085,085,085, 255,255,255,255);
MyGreen:array [0..15] of byte=
(000,000,170,170, 000,000,170,170, 085,085,255,255, 085,085,255,255);
MyBlue:array [0..15] of byte=
(000,170,000,170, 000,170,000,170, 085,255,085,255, 085,255,085,255);
var I,J,K:byte; D1,D2:real;
for I:=0 to NumberOfColors[CurMap]-1 do
D1:=9999.99; K:=0;
for J:=0 to 15 do
D2:= SQRT( (RedValue[I]-MyRed[J]) * (RedValue[I]-MyRed[J])+
(GreenValue[I]-MyGreen[J]) * (GreenValue[I]-MyGreen[J])+
(BlueValue[I]-MyBlue[J]) * (BlueValue[I]-MyBlue[J]) );

if D2 < D1 then begin K:=J; D1:=D2 end

2.5 Reading blocks

Its time now to get down to actual plotting! DEGIFER uses the GRAPH3
procedure GraphColorMode to get into CGA's 320 x 200 x 4 color mode.

The next thing to appear in a GIF file is a block. There are currently
only two types. Image blocks are preceded by a comma. Extension blocks are
preceded by an exclamation point. Any characters other than a ',' or '!'
may be ignored. Keep reading until there is nothing left to read.
Currently no extension blocks are defined. The DEGIF unit has a procedure
that lets you skip extension blocks. It is cleverly called SkipExtendBlock.

2.6 Procedure GetImageDescription

After finding an image block which begins with a comma you should call
DEGIF's GetImageDescription procedure. It sets up the following global
variables declared in DEGIF. Unless noted, all are type word.

Copyright (c) 1988 Cyborg Software Systems, Inc. page 4.


ImageLeft and ImageTop define the coordinates of this image relative to
the screen description. A value of 0,0 is the upper left corner of the

ImageWidth and ImageHeight give the dimensions of this image. The
image may overlap previous images. It may or may not fill the screen. It
should never exceed the screen description.

MapExists[Local] is a boolean that tells you if a local color map
exists for this image. If no local map exists then you should use the
global map. Subsequent images never use old local maps. They always use
their own local maps or they revert to the global map. The following code
implements this properly.

if MapExists[Local]
then begin CurMap:=Local; GetColorMap; DoMapping end
else CurMap:=Global;

Note that GetColorMap and DoMapping depend on CurMap.

The boolean variable Interlaced tells you how to plot the scan lines.
See section 3.2 for a discussion of interlaced images.

BitsPerPixel[Local] and NumberOfColors[Local] tell you the same things
about the local map that their global brothers tell you about the global

The AdjustImage routine is specific to DEGIFER and you may or may not
need it.

2.7 Function ExpandGIF

The data blocks which follow are the image data index values compressed
in a variable length 12 bit-maximum modified LZW compression scheme.


That's what I said when I first became a GIF developer. They just
handed me a bunch of code written in "C" by Steve Wilhite. They said just
use this code and everything will be ok. There was one problem. I don't
know "C"! Enter Bob Berry who sees C and Pascal. My first GIF decoder used
his Turbo Pascal 3.0 translation from Wilhite's "C". I plugged. It
chugged. Out came GIF! Presto!

Since then I've rewritten ExpandGIF several times on my own and I
understand "image data index values compressed in a variable length 12 bit
maximum modified LZW compression scheme."

But you don't need to.

ExpandGIF calls your GetByte routine to get compressed data one byte at
a time. It does all the magic by calling your PutByte routine to put the
dots on the screen.

Copyright (c) 1988 Cyborg Software Systems, Inc. page 5.


When the entire image is done ExpandGIF returns an integer. Anything
other than a 0 is an error.


Routines like DoMapping and DisplayScreenDescription and AdjustImage
are so totally your responsibility that we really can't say much more about
them because you may want to do them differently. The GetByte and PutByte
need more explanation.



3.1 Function GetByte

You must provide a function GetByte:Byte which returns sequential bytes
from somewhere. It will most likely be a file but DEGIF could get its
information from a modem to view GIF on-line. You'd need more information
to do this than is provided here. (When I figure it out myself I'll have a
new DEGIF uploaded.)

This function must be a far function and is compiled with the {$F+}
directive. The simplest GetByte is..

function GetByte:byte;
var b:byte;

3.2 Procedure PutByte(Pix:integer)

PutByte isn't that simple. It passes you an integer in the range
[0..255] that is the index to the Color array. PutByte should plot the
color given by Color[CurMap,Pix] at location x,y. The catch is what are x
and y?

On non-interlaced images you just start at X:=ImageLeft and
Y:=ImageTop. You plot points along Y and increment X until you've plotted
ImageWidth of them. That is until X=ImageLeft+ImageWidth. Then you reset X
to ImageLeft, increment Y and plot the next line.

Interlaced images start with Y=ImageTop but they make 4 interlaced
passes. Pass 1 begins at ImageTop+0 and plots every 8th line. Pass 2
starts at ImageTop+4 and also plots every 8th line. Pass 3 starts at
ImageTop+2 and plots every 4th line. Pass 4 starts at ImageTop+1 and plots
every other line. These 4 passes fill the screen.

In DEGIFER's PutByte routine I invented a Pass 5 which starts at

Copyright (c) 1988 Cyborg Software Systems, Inc. page 6.


ImageTop+0 and plots every line. My procedure AdjustImage contains...

if Interlaced then Pass:=1 else Pass:=5;

This fully implements interlaced images.

The PutByte routine must be compiled with the {$F+} far directive on.


Here is the interface section of the DEGIF unit.

unit degif;

type MapType=(Global,Local);

var GIFSig:String[6]; {GIF ID string usually = 'GIF87a'}
CurMap:MapType; {Current Map in use}
BitsPerPixel, {in this image}
NumberOfColors {in this image}
:array [Global..Local] of word;
BackgrColorIndex, {Background Color index}
BitsOfColorPerPrimary, {For example on EGA=2}
ImageLeft, {Left edge of image relative to virtual screen}
ImageTop, {Top edge of image relative to virtual screen}
ImageWidth, {in pixels}
ImageHeight, {in pixels}
ScreenHeight, {in pixels}
ScreenWidth:word; {in pixels}
MapExists:array [Global..Local] of boolean;
AddrGetByte, {Pointer to user supplied GetByte}
AddrPutByte:pointer; {Pointer to user supplied PutByte}
RedValue,GreenValue,BlueValue: array [0..255] of byte;
Color: array [Global..Local,0..255] of byte;

function ExpandGif: integer;

procedure GetColorMap;

procedure GetGIFSig;

procedure GetImageDescription;

procedure GetScrDes;

procedure SkipExtendBlock;


This unit is written entirely in Turbo Pascal 4.0 and contains no
assembler or Inline code. My #1 goal was to get this available as soon as

Copyright (c) 1988 Cyborg Software Systems, Inc. page 7.


possible. My #2 goal will be to make it fast. After that I'll add on-line
viewing support and any new extensions to the GIF87a standard.

To make it worth my trouble I need your support. Please show your
appreciation and register this product.

Copyright (c) 1988 Cyborg Software Systems, Inc. page 8.

 December 9, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>