Newsgroup: comp.lang.c++
Subject: Re: Decoding GIF file in C? [Source code here]
From: kirannd1989@...
Date: Wed, 8 Jan 2014 19:23:59 -0800 (PST)
Hi..
i tried compiling this code but there are few undefined Macro/functions like MK_FP().
I am trying it on WIN32, VS2012.. i have made changes accordingly.
Is this solution dependent on any library.
Thanks in advance
On Monday, August 1, 1994 1:02:48 PM UTC+5:30, Cyborg wrote:
> In article <msm6.775622996@...> msm6@... (Muhammad Salman Mughal) writes:
> >
> >Hi there,
> >
> > I am desperately looking for a C code that could decode a GIF file
> > in DOS. Anybody out there who knows how to do it? I will really
> > appreciate any help.
> >
>
>
> The following code is based on a LZW decoder originally coded by Steven A.
> Bennett. All I did is write the code for parsing the GIF format, passing
> the approptiate data to the LZW decoder and writing the code for displaying
> the data on the screen. Both 87a and 89a formats are accepted.
>
> Video BIOS must support VESA functions - the code selects a video mode
> whith a resolution just high enough to display the given GIF file. Max
> resolution is 1280x1024, pictures larger than this will be partially
> displayed. Interlaced GIFs are supported. Program was only tested on my
> video card (Cirrus 5428 VESA Local Bus). It was not intended for public
> release but since I've already written it and the guy i desperate...
>
> Compiles with Borland C++ v3.1
>
> ----------------------- chop here --------------------------
>
> /* Various error codes used by decoder
> * and my own routines... It's okay
> * for you to define whatever you want,
> * as long as it's negative... It will be
> * returned intact up the various subroutine
> * levels...
> */
> #define READ_ERROR -1
> #define WRITE_ERROR -2
> #define OPEN_ERROR -3
> #define CREATE_ERROR -4
> #define OUT_OF_MEMORY -5
> #define BAD_CODE_SIZE -6
>
> #define ISIZE 2048 // image line size
> #define BSIZE 256 // buffer size
> #define PSIZE 768 // pallette size
> #define NULL 0L
> #define MAX_CODES 4095
>
> #include <dos.h>
> #include <conio.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> /* Static variables */
> short curr_size; /* The current code size */
> short clear; /* Value for a clear code */
> short ending; /* Value for a ending code */
> short newcodes; /* First available code */
> short top_slot; /* Highest code for current size */
> short slot; /* Last read code */
>
> /* The following static variables are used
> * for seperating out codes
> */
> short navail_bytes = 0; /* # bytes left in block */
> short nbits_left = 0; /* # bits left in current byte */
> unsigned char b1; /* Current byte */
> unsigned char byte_buff[257]; /* Current block */
> unsigned char *pbytes; /* Pointer to next byte in block */
>
> /* The reason we have these separated like this instead of using
> * a structure like the original Wilhite code did, is because this
> * stuff generally produces significantly faster code when compiled...
> * This code is full of similar speedups... (For a good book on writing
> * C for speed or for space optimisation, see Efficient C by Tom Plum,
> * published by Plum-Hall Associates...)
> */
> unsigned char stack[MAX_CODES + 1]; /* Stack for storing pixels */
> unsigned char suffix[MAX_CODES + 1]; /* Suffix table */
> unsigned short prefix[MAX_CODES + 1]; /* Prefix linked list */
>
> long code_mask[13] = {
> 0x0000,
> 0x0001, 0x0003, 0x0007, 0x000F,
> 0x001F, 0x003F, 0x007F, 0x00FF,
> 0x01FF, 0x03FF, 0x07FF, 0x0FFF
> };
>
> // incremented each time an out of range code is read by the decoder
> int bad_code_count;
>
> unsigned char far *buffer=NULL; // file buffer
> unsigned char far *grgb=NULL; // global rgb table
> unsigned char far *lrgb=NULL; // local rgb table
> unsigned char far *pixels=NULL; // line of pixels to be displayed
> unsigned char far *vid=NULL; // ptr to start of graphics window
> unsigned char background=0; // background color index
> unsigned long offset=0; // offset into graphics window
> unsigned long piclen; // total screen size in pixels
> unsigned int realx; // real picture width
> unsigned int realy; // real picture height
> unsigned int xsize=0; // graphic width
> unsigned int ysize=0; // graphic height
> unsigned int win=0; // window number
> unsigned int granularity=0; // granularity of video window
> unsigned int group=0; // picture group (interlaced or not)
> FILE *fp; // file pointer
>
> /* int get_byte()
> * - This function is expected to return the next byte from
> * the GIF file or a negative number defined in ERRS.H
> */
> int get_byte(){
> unsigned char c;
>
> if(fscanf(fp, "%c", &c)==1)
> return((int)c);
> else
> return(READ_ERROR);
> }
>
> /* int out_line(unsigned char pixels[], int linelen)
> * - This function takes a full line of pixels (one byte per pixel) and
> * displays them (or does whatever your program wants with them...). It
> * should return zero, or negative if an error or some other event occurs
> * which would require aborting the decode process... Note that the length
> * passed will almost always be equal to the line length passed to the
> * decoder function, with the sole exception occurring when an ending code
> * occurs in an odd place in the GIF file... In any case, linelen will be
> * equal to the number of pixels passed...
> */
> int out_line(unsigned char *pixels, int linelen){
> unsigned long segment;
>
> segment=offset&(unsigned long)(granularity-1);
>
> // put pixels on screen
> memmove(vid+segment, pixels, linelen);
> memset(vid+segment+linelen, background, xsize-linelen);
> switch (group) {
> case 0:
> offset+=xsize;
> break;
> case 1:
> offset+=xsize*8;
> if(offset>=piclen){
> group++;
> offset=xsize*4;
> }
> break;
> case 2:
> offset+=xsize*8;
> if(offset>=piclen){
> group++;
> offset=xsize*2;
> }
> break;
> case 3:
> offset+=xsize*4;
> if(offset>=piclen){
> group++;
> offset=xsize;
> }
> break;
> case 4:
> offset+=xsize*2;
> break;
> default:
> break;
> }
>
> // if we've run over a window granularity border, move window position
> if((offset>>12)!=win){
> win=offset>>12;
> asm pusha
> asm mov ax, 0x4f05
> asm mov bx, 0x0000
> asm mov dx, win
> asm int 0x10
> asm popa
> }
> return(1);
> }
>
>
> /* This function initializes the decoder for reading a new image.
> */
> static short init_exp(short size)
> {
> curr_size = size + 1;
> top_slot = 1 << curr_size;
> clear = 1 << size;
> ending = clear + 1;
> slot = newcodes = ending + 1;
> navail_bytes = nbits_left = 0;
> return(0);
> }
>
> /* get_next_code()
> * - gets the next code from the GIF file. Returns the code, or else
> * a negative number in case of file errors...
> */
> static short get_next_code()
> {
> short i, x;
> unsigned long ret;
>
> if (nbits_left == 0)
> {
> if (navail_bytes <= 0)
> {
>
> /* Out of bytes in current block, so read next block
> */
> pbytes = byte_buff;
> if ((navail_bytes = get_byte()) < 0)
> return(navail_bytes);
> else if (navail_bytes)
> {
> for (i = 0; i < navail_bytes; ++i)
> {
> if ((x = get_byte()) < 0)
> return(x);
> byte_buff[i] = x;
> }
> }
> }
> b1 = *pbytes++;
> nbits_left = 8;
> --navail_bytes;
> }
>
> ret = b1 >> (8 - nbits_left);
> while (curr_size > nbits_left)
> {
> if (navail_bytes <= 0)
> {
>
> /* Out of bytes in current block, so read next block
> */
> pbytes = byte_buff;
> if ((navail_bytes = get_byte()) < 0)
> return(navail_bytes);
> else if (navail_bytes)
> {
> for (i = 0; i < navail_bytes; ++i)
> {
> if ((x = get_byte()) < 0)
> return(x);
> byte_buff[i] = x;
> }
> }
> }
> b1 = *pbytes++;
> ret |= b1 << nbits_left;
> nbits_left += 8;
> --navail_bytes;
> }
> nbits_left -= curr_size;
> ret &= code_mask[curr_size];
> return((short)(ret));
> }
>
> /* DECODE.C - An LZW decoder for GIF
> *
> * Copyright (C) 1987, by Steven A. Bennett
> *
> * Permission is given by the author to freely redistribute and include
> * this code in any program as long as this credit is given where due.
> *
> * In accordance with the above, I want to credit Steve Wilhite who wrote
> * the code which this is heavily inspired by...
> *
> * GIF and 'Graphics Interchange Format' are trademarks (tm) of
> * Compuserve, Incorporated, an H&R Block Company.
> *
> * Release Notes: This file contains a decoder routine for GIF images
> * which is similar, structurally, to the original routine by Steve Wilhite.
> * It is, however, somewhat noticably faster in most cases.
> *
> * short decode(linewidth)
> * short linewidth; * Pixels per line of image *
> *
> * - This function decodes an LZW image, according to the method used
> * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded
> * will generate a call to out_line(), which is a user specific function
> * to display a line of pixels. The function gets it's codes from
> * get_next_code() which is responsible for reading blocks of data and
> * seperating them into the proper size codes. Finally, get_byte() is
> * the global routine to read the next byte from the GIF file.
> *
> * It is generally a good idea to have linewidth correspond to the actual
> * width of a line (as specified in the Image header) to make your own
> * code a bit simpler, but it isn't absolutely necessary.
> *
> * Returns: 0 if successful, else negative. (See ERRS.H)
> *
> */
>
> short decode(short linewidth)
> {
> register unsigned char *sp, *bufptr;
> unsigned char *buf;
> register short code, fc, oc, bufcnt;
> short c, size, ret;
>
> /* Initialize for decoding a new image...
> */
> if ((size = get_byte()) < 0)
> return(size);
> if (size < 2 || 9 < size)
> return(BAD_CODE_SIZE);
> init_exp(size);
>
> /* Initialize in case they forgot to put in a clear code.
> * (This shouldn't happen, but we'll try and decode it anyway...)
> */
> oc = fc = 0;
>
> /* Allocate space for the decode buffer
> */
> if ((buf = (unsigned char *)malloc(linewidth + 1)) == NULL)
> return(OUT_OF_MEMORY);
>
> /* Set up the stack pointer and decode buffer pointer
> */
> sp = stack;
> bufptr = buf;
> bufcnt = linewidth;
>
> /* This is the main loop. For each code we get we pass through the
> * linked list of prefix codes, pushing the corresponding "character" for
> * each code onto the stack. When the list reaches a single "character"
> * we push that on the stack too, and then start unstacking each
> * character for output in the correct order. Special handling is
> * included for the clear code, and the whole thing ends when we get
> * an ending code.
> */
> while ((c = get_next_code()) != ending)
> {
>
> /* If we had a file error, return without completing the decode
> */
> if (c < 0)
> {
> free(buf);
> return(0);
> }
>
> /* If the code is a clear code, reinitialize all necessary items.
> */
> if (c == clear)
> {
> curr_size = size + 1;
> slot = newcodes;
> top_slot = 1 << curr_size;
>
> /* Continue reading codes until we get a non-clear code
> * (Another unlikely, but possible case...)
> */
> while ((c = get_next_code()) == clear)
> ;
>
> /* If we get an ending code immediately after a clear code
> * (Yet another unlikely case), then break out of the loop.
> */
> if (c == ending)
> break;
>
> /* Finally, if the code is beyond the range of already set codes,
> * (This one had better NOT happen... I have no idea what will
> * result from this, but I doubt it will look good...) then set it
> * to color zero.
> */
> if (c >= slot)
> c = 0;
>
> oc = fc = c;
>
> /* And let us not forget to put the char into the buffer... And
> * if, on the off chance, we were exactly one pixel from the end
> * of the line, we have to send the buffer to the out_line()
> * routine...
> */
> *bufptr++ = c;
> if (--bufcnt == 0)
> {
> if ((ret = out_line(buf, linewidth)) < 0)
> {
> free(buf);
> return(ret);
> }
> bufptr = buf;
> bufcnt = linewidth;
> }
> }
> else
> {
>
> /* In this case, it's not a clear code or an ending code, so
> * it must be a code code... So we can now decode the code into
> * a stack of character codes. (Clear as mud, right?)
> */
> code = c;
>
> /* Here we go again with one of those off chances... If, on the
> * off chance, the code we got is beyond the range of those already
> * set up (Another thing which had better NOT happen...) we trick
> * the decoder into thinking it actually got the last code read.
> * (Hmmn... I'm not sure why this works... But it does...)
> */
> if (code >= slot)
> {
> if (code > slot)
> ++bad_code_count;
> code = oc;
> *sp++ = fc;
> }
>
> /* Here we scan back along the linked list of prefixes, pushing
> * helpless characters (ie. suffixes) onto the stack as we do so.
> */
> while (code >= newcodes)
> {
> *sp++ = suffix[code];
> code = prefix[code];
> }
>
> /* Push the last character on the stack, and set up the new
> * prefix and suffix, and if the required slot number is greater
> * than that allowed by the current bit size, increase the bit
> * size. (NOTE - If we are all full, we *don't* save the new
> * suffix and prefix... I'm not certain if this is correct...
> * it might be more proper to overwrite the last code...
> */
> *sp++ = code;
> if (slot < top_slot)
> {
> suffix[slot] = fc = code;
> prefix[slot++] = oc;
> oc = c;
> }
> if (slot >= top_slot)
> if (curr_size < 12)
> {
> top_slot <<= 1;
> ++curr_size;
> }
>
> /* Now that we've pushed the decoded string (in reverse order)
> * onto the stack, lets pop it off and put it into our decode
> * buffer... And when the decode buffer is full, write another
> * line...
> */
> while (sp > stack)
> {
> *bufptr++ = *(--sp);
> if (--bufcnt == 0)
> {
> if ((ret = out_line(buf, linewidth)) < 0)
> {
> free(buf);
> return(ret);
> }
> bufptr = buf;
> bufcnt = linewidth;
> }
> }
> }
> }
> ret = 0;
> if (bufcnt != linewidth)
> ret = out_line(buf, (linewidth - bufcnt));
> free(buf);
> return(ret);
> }
>
>
> // this function is called just before program exits
> void cleanup(void){
> // free any allocated resources
> if(fp!=NULL)
> fclose(fp);
> if(buffer!=NULL)
> free(buffer);
> if(grgb!=NULL)
> free(grgb);
> if(lrgb!=NULL)
> free(lrgb);
> if(pixels!=NULL)
> free(pixels);
> }
>
> void main(int argc, char **argv){
> unsigned int gctsize=0, lctsize=0, mode;
> int i;
>
> // set bad codes encountered to zero
> bad_code_count=0;
>
> // set function to be called on exit
> if(atexit(cleanup))
> exit(0);
>
> // exit if no file given
> if (argc<2){
> printf("Usage: %s gif_file\n", argv[0]);
> exit(0);
> }
>
> // try to open file
> if((fp=fopen(argv[1], "rb"))==NULL){
> printf("Failed to open file.\n");
> exit(0);
> }
>
> // allocate buffers
> buffer=(unsigned char *)malloc(BSIZE);
> pixels=(unsigned char *)malloc(ISIZE);
> grgb =(unsigned char *)malloc(PSIZE);
> lrgb =(unsigned char *)malloc(PSIZE);
> if((grgb==NULL) || (lrgb==NULL) || (pixels==NULL) || (buffer==NULL)){
> printf("Not enough memory.\n");
> exit(0);
> }
>
> fread(buffer, 1, 6, fp);
> // test file for valid GIF signature
> if(memcmp(buffer, "GIF", 3)!=0){
> printf("Not a GIF file.\n");
> exit(0);
> }
> // test file for version number
> if((memcmp(buffer+3, "87a", 3)!=0) && (memcmp(buffer+3, "89a", 3)!=0)){
> printf("Unsuported GIF version. Hit a key to decode anyway.\n");
> getch();
> }
>
> // read logical screen descriptor
> fread(buffer, 1, 7, fp);
>
> // test for global color table presence
> if(*(buffer+4)&0x80){
> // compute global color table size
> gctsize=1<<((*(buffer+4)&0x07) + 1);
> // read global color table into buffer
> fread(grgb, 1, gctsize*3, fp);
> // adjust colors to crappy 6-bit PC-DAC values
> for(i=0; i<gctsize*3; i++)
> *(grgb+i)>>=2;
> }
> // get background color index
> background=*(buffer+5);
>
>
> // scan file for data blocks
> while((i=get_byte())>0) {
> // in end of GIF marker encountered then exit
> if(i==0x3b)
> exit(0);
> // test for extentions
> if(i==0x21){
> if( (i=get_byte()) < 0 )
> exit(0);
> // if graphic color extention present or
> // coment extention present or
> // plain text extention present or
> // application extention present then skip it
> if( (i==0x01) || (i==0xf9) || (i==0xfe) || (i==0xff)){
> while((i=get_byte())!=0){
> if(fread(buffer, 1, i, fp)!=i)
> exit(0);
> }
> }
> }
>
> // test for presence of image descriptor
> if(i==0x2c){
> // get image descriptor
> fread(buffer, 1, 9, fp);
> // interlaced flag is set or cleared accordingly
> if(*(buffer+8)&0x40)
> group=1;
> realx=xsize=*(buffer+4) | (*(buffer+5)<<8);
> realy=ysize=*(buffer+6) | (*(buffer+7)<<8);
> // test for presence of local color table
> if(*(buffer+8)&0x80){
> // compute local color table size
> lctsize=1<<((*(buffer+8)&0x07) + 1);
> // read local color table into buffer
> fread(lrgb, 1, lctsize*3, fp);
> // adjust colors to crappy 6-bit PC-DAC values
> for(i=0; i<gctsize*3; i++)
> *(lrgb+i)>>=2;
> }
>
> // choose a video mode that will just fit the image
> if((xsize<=640) && (ysize<=480)){
> mode=0x101; // VESA 640 x 480 x 256
> xsize=640;
> ysize=480;
> } else if ((xsize<=800) && (ysize<=600)){
> mode=0x103; // VESA 800 x 600 x 256
> xsize=800;
> ysize=600;
> } else if ((xsize<=1024) && (ysize<=768)){
> mode=0x105; // VESA 1024 x 768 x 256
> xsize=1024;
> ysize=768;
> } else {
> mode=0x107; // VESA 1280 x 1024 x 256
> xsize=1280;
> ysize=1024;
> }
>
> piclen=(unsigned long)xsize*(unsigned long)ysize;
> // get video mode info through VESA call
> asm pusha
> asm mov ax, 0x4f01
> asm mov cx, mode
> asm les di, buffer
> asm int 0x10
> asm mov i, ax
> asm popa
>
> if(i!=0x004f){
> printf("VESA video functions not available.\n");
> exit(0);
> }
> // if mode not supported, or not color, or not graphics then exit
> if((*buffer&0x19)!=0x19){
> printf("Required graphics mode is not available.\n");
> exit(0);
> }
>
> // if window does not exist or is not writable exit
> if((*(buffer+2)&0x05)!=0x05) {
> printf("Cannot access video RAM.\n");
> exit(0);
> }
>
> // calculate window granularity
> granularity=(*(buffer+4) | (*(buffer+5)<<8))<<10;
> // calculate pointer to video RAM start
> vid=(unsigned char *)MK_FP((*(buffer+8) | (*(buffer+9)<<8)), 0);
>
> // set VESA video mode
> asm pusha
> asm mov ax, 0x4f02
> asm mov bx, mode
> asm int 0x10
> asm popa
>
> // set color table if present
> if(lctsize){
> // scope of local color table is local so once used it's gone
> lctsize=0;
> asm pusha
> asm mov ax, 0x1012
> asm mov bx, 0x0000
> asm mov cx, 0x0100
> asm les dx, lrgb
> asm int 0x10
> asm popa
> } else if(gctsize){
> // if no local color table then set global color table if present
> asm pusha
> asm mov ax, 0x1012
> asm mov bx, 0x0000
> asm mov cx, 0x0100
> asm les dx, grgb
> asm int 0x10
> asm pop es
> asm popa
> }
>
> // decode and display graphic
> decode(realx);
> // wait for key press
> getch();
>
> // set default text mode
> asm mov ax, 0x0003
> asm int 0x10
> }
> }
>
> // exit to dos
> exit(0);
> }
>
> -------------- chop here -------------------
>
> --
> +-----------------------------+-----------------------------------------------+
> | Alex Ivopol | If you love something set it free. If it |
> | cyborg@... | doesn't come back, hunt it down and kill it. |
> +-----------------------------+-----------------------------------------------+
via Usenet Forums - Usenet Search,Free Usenet - comp.lang.c++ http://ift.tt/1dP9txL
View all the progranning help forums at:
http://ift.tt/1dP9txN