.PL ENGIF TURBO PASCAL UNIT DOCUMENTATION 1.0 INTRODUCTION ENGIF is a Turbo Pascal Unit to encode graphic images stored in CompuServe's Graphic Interchange Format (GIF). With this unit you can write your own GIF encoder or add GIF to any application. With its companion unit DEGIF you can write GIF utilities to re-encode existing images. "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. If you are already registered for DEGIF, you need not register ENGIF. In future releases the two units will be distributed as a single package. This unit, the documentation and the source and executable code for RELACE 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 ENGIF 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 ENCODE.INC by Bob Berry which was a Turbo Pascal 3.0 translation of routines written in C by Steve Wilhite. Sincere thanks and credit to them. If all you are interested in is the RELACE utility then it is used by simply typing.... C:\>RELACE IN.GIF OUT.GIF .....where IN.GIF is a GIF file to be laced or un-laced and OUT.GIF is the output file. WARNING: DO NOT SPECIFY THE SAME FILE! OUT.GIF is overwritten and can be destroyed. This is just a simple demo. Its not a foolproof professional program. 2.0 GIF ENCODING The best way we know to document the ENGIF unit is to give an example program called RELACE. RELACE is a utility which will run on any IBM PC compatible regardless of graphic cards. It uses the DEGIF unit to decode an image to memory and then uses ENGIF to re-encode it. You are given the option to interlace non-interlaced images or un-lace interlaced images -- hence the name RELACE. If you do not already have a copy of the DEGIF unit and documentation, we suggest you obtain them from the same source as you obtained ENGIF. You should print out a copy of RELACE.PAS and follow it along its main routine as we go. Copyright (c) 1988 Cyborg Software Systems, Inc. page 1. ENGIF TURBO PASCAL UNIT DOCUMENTATION 2.1 Initialization The ENGIF unit requires that you establish a pointer to your procedure WrtByte. WrtByte must be a far-call procedure to write one byte to the output file. We will discuss this routine in section 3.0 below. AddrWrtByte is a global pointer declared in the ENGIF unit but you must initialize it. AddrGetByte and AddrPutByte are required by the DEGIF unit. The next few lines of RELACE'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. Names for the source and destination files are retrieved from the command line or you are prompted for them. The files are opened. Because ENGIF "uses" DEGIF, many of DEGIF's types, variables and routines are needed by ENGIF too. 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 and ENGIF need the variable CurMap:MapType to be initialized before you begin. 2.2 Procedure PutGIFSig 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'. Similarly ENGIF provides PutGIFSig to write the signature to the output file. If you are not using GetGIFSig, you should use the following.... Gifsig:='GIF87a'; PutGIFSig; 2.3 Procedure PutScrDes 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. PutScrDes in the ENGIF unit is used to write a screen description. Unlike PutGIFSig, PutScrDes does not simply write back the variables which GetScrDes read because you may wish to write different values with ENGIF while maintaining the DEGIF variables. The PutScrDes routine is passed the following parameters. procedure PutScrDes(SW,SH,BC,CR,PR:word;ME:boolean); ScreenWidth and ScreenHeight (or SW and SH) 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 or clip the image if it doesn't fit the global screen size you specify. Some GIF files are composed of multiple small images that may overlap Copyright (c) 1988 Cyborg Software Systems, Inc. page 2. ENGIF TURBO PASCAL UNIT DOCUMENTATION 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. You should use BC to pass the index of the background color you want. BitsOfColorPerPrimary (or CR meaning "Color Resolution") 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 what should be put there and how useful it is. It isn't necessary for most decoding and my experience is it is unreliable. As an example, for EGA created images its value should be 2 because each primary color (red, green and blue) is designated by 2 bits. BitsPerPixel[Global] (or PR meaning "Pixel Resolution") is a Word that does tells you the number of colors in the color map. It is also necessary for ENGIF's compression routine to establish a minimum code size. The only valid values are [1..8]. The number of colors in the global color map is computed by... NumberOfColors[Global]:= (1 shl BitsPerPixel[Global]); 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. MapExists[Global] (or ME) is a boolean that tells you if there is a global color map for this file. Next, RELACE builds a virtual screen on the heap and initializes it to the background color. It then calls DisplayScrDes. This is its own routine which simply tells the user the information from the screen descriptor. If you intend to modify any of the screen description, this is where you would do it. Finally we call PutScrDes. RELACE does simply pass on the values obtained by DEGIF but many other applications of ENGIF might make changes. 2.4 Procedure PutColorMap 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. If you passed ME=true to PutScrDes then you must have one too. The map is put in the following arrays.... RedValue,GreenValue,BlueValue: array [0..255] of byte; These global arrays are declared in DEGIF and if you change them you lose the old values. This probably will not be a problem. Only index 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. See the DEGIF documentation for more details on the color maps. Copyright (c) 1988 Cyborg Software Systems, Inc. page 3. ENGIF TURBO PASCAL UNIT DOCUMENTATION The PutColorMap routine in ENGIF writes the values from those arrays. It requires that CurMap and NumberOfColors[CurMap] have the proper values. 2.5 Writing blocks Its time now to get down to actual encoding! 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. GIF files are terminated by a semi-colon. Any characters other than a ';' or a ',' or '!' may be ignored. ENGIF currently has no facility for writing extension blocks so RELACE uses DEGIF's SkipExtendBlock routine. Currently no extension blocks are defined. 2.6 Procedure PutImageDescription After finding an image block which begins with a comma, RELACE does... WrtByte(ord(',')); ... and reads the image description using GetImageDescription. The image description is output with... procedure PutImageDescription(IL,IT,IW,IH,PR:word;ME,ITL:boolean); ImageLeft and ImageTop (or IL and IT) define the coordinates of this image relative to the screen description. A value of 0,0 is the upper left corner of the screen. ImageWidth and ImageHeight (or IW and IH) 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. BitsPerPixel[Local] (or PR for Pixel Resolution) and NumberOfColors[Local] tell you the same things about the local map that their global brothers tell you about the global map. MapExists[Local] (or ME) is a boolean that tells you if a local color map exists for this image. Our AdjustImage routine prompts you to determine whether or not the output file should be interlaced. It sets the variable LaceIt. Note that the variable Interlaced tells whether or not the input image is laced and LaceIt (passed as ITL) controls the output image. See section 3.2 for a discussion of interlaced images. If you have a local color map then you must call GetColorMap and PutColorMap with CurMap:=Local. 2.7 Procedures CompressGIF(Pix) and EndCompress The data blocks which follow are the image data index values compressed in a variable length 12 bit-maximum modified LZW compression scheme. Copyright (c) 1988 Cyborg Software Systems, Inc. page 4. ENGIF TURBO PASCAL UNIT DOCUMENTATION HUH? 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 DEGIF's 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. DEGIF's 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. When the entire image is done ExpandGIF returns an integer. Anything other than a 0 is an error. To compress the GIF image we simply call CompressGIF repeatedly passing the image bytes to it. When we are done we call EndCompress which clears the compression buffer and terminates the image block. See section 3.2 for RELACE's method of outputing interlaced images. 2.8 Terminator When you've output all the images, you should write a GIF terminator by... WrtByte(ord(';')); ...and close the output file. 3.0 ROUTINES YOU PROVIDE Routines like 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 WrtByte, GetByte and PutByte need more explanation. DO NOT FORGET TO INCLUDE THESE LINES! AddrWrtByte:=@WrtByte; AddrGetByte:=@GetByte; AddrPutByte:=@PutByte; 3.1 Procedure WrtByte(I:integer); You must provide a procedure WrtByte which outputs bytes to the output file. This function must be a far function and is compiled with the {$F+} directive. The simplest WrtByte is.. Copyright (c) 1988 Cyborg Software Systems, Inc. page 5. ENGIF TURBO PASCAL UNIT DOCUMENTATION {$F+} procedure WrtByte(I: integer); var B:byte; begin B:=lo(I); write(OutFile,B) end; {$F-} 3.2 Interlacing images If you want your images interlaced, you must pass bytes to CompressGIF in the proper order. You pass a byte that is the index to the color array. That color will eventually be plotted at location x,y. The catch is what are x and y? On non-interlaced images you just start at XCord:=ImageLeft and YCord:=ImageTop. You pass points along Y and increment X until you've plotted ImageWidth of them. That is until XCord=ImageLeft+ImageWidth. Then you reset X to ImageLeft, increment Y and plot the next line. Interlaced images start with YCord:=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 RELACE the PutByte routine and the "repeat until" structure in the main routine both deal with interlacing. For non-interlaced images I invented a Pass 5 which starts at ImageTop+0 and plots every line. I simply say ... if Interlaced then Pass:=1 else Pass:=5; This fully implements interlaced images. 4.0 INTERFACE Because ENGIF uses DEGIF you will have access to both ENGIF's variables and routines as well as ENGIF's. 4.1 DEGIF interface Here is the interface section of the DEGIF unit. unit degif; interface 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} Copyright (c) 1988 Cyborg Software Systems, Inc. page 6. ENGIF TURBO PASCAL UNIT DOCUMENTATION :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; Interlaced: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; 4.2 ENGIF interface Here is ENGIF's interface.... unit engif; interface uses degif; var AddrWrtByte:pointer; {Pointer to user supplied WrtByte} procedure CompressGIF(Pix: byte); procedure EndCompress; procedure PutColorMap; procedure PutGIFSig; procedure PutImageDescription(IL,IT,IW,IH,PR:word;ME,ITL:boolean); procedure PutScrDes(SW,SH,BC,CR,PR:word;ME:boolean); 5.0 FINAL WORDS 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. ENGIF TURBO PASCAL UNIT DOCUMENTATION possible. My #2 goal will be to make it fast. After that I'll add extension block 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.