Home | Gaming | Programming | Play Online | Submit Article | Submit BETA | Advertise | Contact | Keyword Query | Trade Games
Games++ Games & Game Programming

GAMES++
Games++ Home
Games++ Gaming
Games++ Programming
Beta Testing Games
Free Online Games
Hints & Cheats

BROWSER UTILITIES
E-mail This Page
Add to Favorites

SITE SEARCH

Web Games++

AFFILIATES
Cheat Codes
Trickster Wiki
Game Ratings
Trade Games
Gameboy Cheats
PlayStation Cheats
BlackBerry Games
Photoshop Tutorials
Illustrator Tutorials
ImageReady Tutorials
Tutorial Bus
Fresh Tutorials

ADVERTISEMENT

ADVERTISEMENT

Displaying GIF Graphic Files In C

C/C++ Programming

By Steven H. Don

/****************************************************************************
** This support Compuserve 256 colour GIF87a and GIF89a image up to        **
** 320x200 in size.                                                        **
****************************************************************************/

//This program requires a stack of at least 19.5K!!

#include "stdio.h"

typedef
  struct GIFHeader {
    char          Signature [7];
    unsigned int  ScreenWidth, ScreenHeight;
    unsigned char Depth, Background, Zero;
  };
  struct GIFDescriptor {
    char          Separator;
    unsigned int  ImageLeft, ImageTop, ImageWidth, ImageHeight;
    unsigned char Depth;
  };

  char far *Screen = (char far *)0xA0000000L;
  //For loading from the file
  FILE                 *GIFFile;
  unsigned int         BPointer;
  unsigned char        Buffer [257];
  //GIF data is stored in blocks of a certain size
  unsigned char        BlockSize;
  //For loading the code
  unsigned char        CodeSize;
  char                 BitsIn;
  unsigned char        Temp;
  //Coordinates
  unsigned int         X, Y, tlX, tlY, brX, brY;
  //The string table
  unsigned int         Prefix [4096];
  unsigned char        Suffix [4096];

//This sets the display to VGA 320x200 in 256 colours
void VGAScreen ()
{
  asm {
    mov ax, 0x13
    int 0x10
  }
}

//This resets the display to text mode
void TextScreen ()
{
  asm {
    mov ax, 0x3
    int 0x10
  }
}

//This sets a DAC register to a specific Red Green Blue-value
void SetDAC(unsigned char DAC, unsigned char R, unsigned char G, unsigned char B)
{
  outportb (0x3C8, DAC);
  outportb (0x3C9, R);
  outportb (0x3C9, G);
  outportb (0x3C9, B);
}

//This sets one pixel on the screen
void PutPixel (unsigned int x, unsigned int y, unsigned char c)
{
  Screen [(y << 8) + (y << 6) + x] = c;
}

//Function to read from the buffer
unsigned char LoadByte ()
{
  //Read next block}
  if (BPointer == BlockSize) {
    fread (Buffer, BlockSize + 1, 1, GIFFile);
    BPointer = 0;
  }

  //Return byte
  return Buffer [BPointer++];
}

//Procedure to read the next code from the file
unsigned int ReadCode ()
{
  int           Counter;
  unsigned int  Code;

  Code = 0;
  //Read the code, bit by bit
  for (Counter = 0; Counter < CodeSize; Counter++) {
    //Maybe, a new byte needs to be loaded with a further 8 bits
    if (++BitsIn == 9) {
      Temp = LoadByte ();
      BitsIn = 1;
    }

    //Add the current bit to the code
    if (Temp & 1) Code += 1 << Counter;
    Temp >>= 1;
  }
  return Code;
}

//Procedure to draw a pixel
void NextPixel (unsigned int c)
{
  //Actually draw the pixel on screen
  PutPixel (X, Y, c & 255);

  //Move to next row, if necessary
  if (++X == brX) {
    X = tlX;
    Y++;
  }
}

//Local function to output a string. Returns the first character.
unsigned char OutString (unsigned int CurCode)
{
  unsigned int  OutCount;
  unsigned char OutCode [1024];

  //If it's a single character, output that
  if (CurCode < 256) {
    NextPixel (CurCode);
  } else {
    OutCount = 0;

    //Store the string, which ends up in reverse order
    do {
      OutCode [OutCount++] = Suffix [CurCode];
      CurCode = Prefix [CurCode];
    } while (CurCode > 255);

    //Add the last character
    OutCode [OutCount++] = CurCode;

    //Output all the string, in the correct order
    do {
      NextPixel (OutCode [--OutCount]);
    } while (OutCount);
  }
  //Return 1st character
  return CurCode;
}

//This actually loads the GIF
void LoadGIF (char *Filename)
{
  //For loading from the GIF file
  struct GIFHeader     Header;
  struct GIFDescriptor Descriptor;

  //Colour information
  unsigned char        BitsPerPixel,
                       NumOfColours;
  unsigned int         DAC;
  unsigned char        Palette [256][3];

  //For indexing the string table
  unsigned int         FirstFree, FreeCode;

  //All the code information
  unsigned char        InitCodeSize;
  unsigned int         Code, OldCode, MaxCode;

  //Special codes
  unsigned int         ClearCode, EOICode;

  //Check whether the GIF file exists, and open it
  GIFFile = fopen (Filename, "rb");
  if (GIFFile == 0) {
    TextScreen ();
    printf ("Could not open file %s", Filename);
    return;
  }

  //Read header
  fread (&Header, 6, 1, GIFFile);
  Header.Signature [6] = 0;
  fread (&Header.ScreenWidth, sizeof (Header) - 7, 1, GIFFile);

  //Check signature and terminator
  if ((strcmp (Header.Signature, "GIF87a")
    && strcmp (Header.Signature, "GIF89a"))
    || Header.Zero) {
    TextScreen ();
    printf ("Not a valid GIF file\n");
    return;
  }

  //Get amount of colours in image
  BitsPerPixel = 1 + (Header.Depth & 7);
  NumOfColours = (1 << BitsPerPixel) - 1;

  //Load global colour map
  fread (Palette, 3, (NumOfColours + 1), GIFFile);
  for (DAC = 0; DAC <= NumOfColours; DAC++)
    SetDAC (DAC, Palette [DAC][0] >> 2,
                 Palette [DAC][1] >> 2,
                 Palette [DAC][2] >> 2);

  //Load the image descriptor
  fread (&Descriptor, sizeof (Descriptor), 1, GIFFile);

  if (Descriptor.Separator != ',') {
    TextScreen ();
    printf ("Incorrect image descriptor.\n");
    return;
  }

  //Get image corner coordinates
  tlX = Descriptor.ImageLeft;
  tlY = Descriptor.ImageTop;
  brX = tlX + Descriptor.ImageWidth;
  brY = tlY + Descriptor.ImageHeight;

  //Some restrictions apply
  if (Descriptor.Depth & 128) {
    TextScreen ();
    printf ("Local colour maps not supported\n");
    return;
  }
  if (Descriptor.Depth & 64) {
    TextScreen ();
    printf ("Interlaced images not supported\n");
    return;
  }

  //Get initial code size
  fread (&CodeSize, 1, 1, GIFFile);

  //GIF data is stored in blocks, so it's necessary to know the size
  fread (&BlockSize, 1, 1, GIFFile);

  //Start loader
  BPointer = BlockSize;

  //Special codes used in the GIF spec
  ClearCode        = 1 << CodeSize;     //Code to reset
  EOICode          = ClearCode + 1;     //End of file

  //Initialize the string table
  FirstFree        = ClearCode + 2;     //Strings start here
  FreeCode         = FirstFree;         //Strings can be added here

  //Initial size of the code and its maximum value
  InitCodeSize     = ++CodeSize;
  MaxCode          = 1 << CodeSize;

  BitsIn = 8;

  //Start at top left of image
  X = Descriptor.ImageLeft;
  Y = Descriptor.ImageTop;

  do {
    //Read next code
    Code = ReadCode ();

    //If it's an End-Of-Information code, stop processing
         if (Code == EOICode) break;
    //If it's a clear code...
    else if (Code == ClearCode) {
      //Clear the string table
      FreeCode = FirstFree;

      //Set the code size to initial values
      CodeSize = InitCodeSize;
      MaxCode  = 1 << CodeSize;

      //The next code may be read
      Code = ReadCode ();
      OldCode = Code;

      //Set pixel
      NextPixel (Code);
    //Other codes
    } else {
      /*If the code is already in the string table, it's string is displayed,
      and the old string followed by the new string's first character is
      added to the string table.*/
      if (Code < FreeCode)
        Suffix [FreeCode] = OutString (Code);
      else {
      /*If it is not already in the string table, the old string followed by
      the old string's first character is added to the string table and
      displayed.*/
        Suffix [FreeCode] = OutString (OldCode);
        NextPixel (Suffix [FreeCode]);
      }

      //Finish adding to string table
      Prefix [FreeCode++] = OldCode;

      //If the code size needs to be adjusted, do so
      if (FreeCode >= MaxCode && CodeSize < 12) {
        CodeSize++;
        MaxCode <<= 1;
      }

      //The current code is now old
      OldCode = Code;
    }
  } while (Code != EOICode);

  //Close the GIF file
  fclose (GIFFile);
}

void main (int argcount, char *argvalue[])
{
  char FileName [80];

  //Check if a filename was passed as a parameter, otherwise ask for one
  if (argcount > 1) {
    strcpy (FileName, argvalue [1]);
  } else {
    printf ("Enter filename:");
    gets (FileName);
  }

  //Switch to graphics screen
  VGAScreen ();
  //Load GIF file
  LoadGIF (FileName);
  //Wait for keypress
  getch ();
  //Switch back to text mode
  TextScreen ();
}

Copyright © 1998-2007, Games++ All rights reserved. | Privacy Policy