Tuesday, January 14, 2014

Decoding GIF file in C? [Source code here]

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

No comments:

Post a Comment