Turbo C DOS 代码
/****************************************************************************
** 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 ();
}