X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b59bf2db65896d128d72016c201dc1df9ff6c94e..cd3c2375e6fddd3d478a6776900c21aaeb2d0f08:/src/common/imaggif.cpp diff --git a/src/common/imaggif.cpp b/src/common/imaggif.cpp index ddcce30a7f..1aed9a28cb 100644 --- a/src/common/imaggif.cpp +++ b/src/common/imaggif.cpp @@ -1,8 +1,9 @@ ///////////////////////////////////////////////////////////////////////////// // Name: imaggif.cpp // Purpose: wxGIFHandler -// Author: Guillermo Rodriguez Garcia -// wxWindows adaptation by Vaclav Slavik +// Author: Vaclav Slavik & Guillermo Rodriguez Garcia +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vaclav Slavik & Guillermo Rodriguez Garcia // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -11,444 +12,114 @@ #endif // For compilers that support precompilation, includes "wx.h". -#include +#include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop +# pragma hdrstop #endif -#include - -#include -#include -#include - -#include - -/* - -FOLLOWING CODE IS BY G.R.G. : -(except wxInputStream stuff) - -*/ - -/************************************************************************ - READGIF.H - Leer un archivo GIF de 8 bits - ------------------------------------------------------------------------ - Tratamiento Digital de la Imagen - ------------------------------------------------------------------------ - Guillermo Rodriguez Garcia - - - Version: 2.0 -*************************************************************************/ - -typedef struct -{ - int w; /* width */ - int h; /* height */ - unsigned char *p; /* bitmap */ - unsigned char *pal; /* palette */ -} IMAGEN; - - -/************************************************************************ - READGIF.C - Lee un archivo GIF de 256 colores - ------------------------------------------------------------------------ - Tratamiento Digital de la Imagen - ------------------------------------------------------------------------ - Guillermo Rodriguez Garcia - - - Version: 2.0 -*************************************************************************/ - - -#include -#include -#include - - -/* error codes */ -#define E_OK 0 /* everything was OK */ -#define E_ARCHIVO -1 /* error opening file */ -#define E_FORMATO -2 /* error in gif header */ -#define E_MEMORIA -3 /* error allocating memory */ - - -/* This class binding is by VS, so all bugs in it are mine ;-) */ - -class gifDecoder -{ - private: - /* globals */ - int restbits; /* remaining valid bits */ - unsigned int restbyte; /* remaining bytes in this block */ - unsigned int lastbyte; /* last byte read */ - - unsigned char* file; /* input file in memory */ - unsigned int file_pos, file_size; /* position & size in it */ - - int fgetc(); - void fread(void *ptr, size_t size, size_t nmemb); - void fseekcur(int rel_pos); - - public: - gifDecoder(unsigned char* mem, int sz) {file = mem; file_pos = 0; file_size = sz;} - int getcode(int bits); - int dgif(IMAGEN *img, int interl, int bits); - int readgif(IMAGEN *img); -}; - - -int gifDecoder::fgetc() -{ - if (file_pos < file_size) return file[file_pos++]; - else return EOF; -} - -void gifDecoder::fread(void *ptr, size_t size, size_t nmemb) -{ - int todo = size * nmemb; - if (todo + file_pos > file_size) todo = file_size - file_pos; - memcpy(ptr, file + file_pos, todo); - file_pos += todo; -} - -void gifDecoder::fseekcur(int rel_pos) -{ - file_pos += rel_pos; -} - -/* getcode: - * Reads the next code from the file, with size 'bits' - * v2.0 - changed to support 'bits' values < 8 - */ -int gifDecoder::getcode(int bits) -{ - unsigned int mask; /* bit mask */ - unsigned int code; /* code (result) */ - - - /* get remaining bits from last byte read */ - mask = (1 << bits) - 1; - code = (lastbyte >> (8 - restbits)) & mask; +#ifndef WX_PRECOMP +# include "wx/defs.h" +#endif - /* keep reading new bytes until needed */ - while (bits > restbits) - { - /* if no bytes left in this block, read the next block */ - if (restbyte == 0) - restbyte = fgetc(); +#if wxUSE_IMAGE && wxUSE_GIF - /* read next byte and isolate the bits we need */ - lastbyte = fgetc(); - mask = (1 << (bits - restbits)) - 1; - code = code + ((lastbyte & mask) << restbits); - restbyte--; +#include "wx/imaggif.h" +#include "wx/gifdecod.h" +#include "wx/wfstream.h" +#include "wx/log.h" +#include "wx/intl.h" - /* adjust total number of bits extracted from the buffer */ - restbits = restbits + 8; - } +IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) - /* find number of bits reamining for next code */ - restbits = (restbits - bits); +//----------------------------------------------------------------------------- +// wxGIFHandler +//----------------------------------------------------------------------------- - return code; -} +#if wxUSE_STREAMS -/* dgif: - * GIF decoding function. The initial code size (aka root size) - * is 'bits'. Supports interlaced images (interl == 1). - */ -int gifDecoder::dgif(IMAGEN *img, int interl, int bits) +bool wxGIFHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) { - int ab_prefix[4096]; /* alphabet (prefixes) */ - int ab_tail[4096]; /* alphabet (tails) */ - int stack[4096]; /* decompression stack */ - - int ab_clr; /* clear code */ - int ab_fin; /* end of info code */ - int ab_bits; /* actual symbol width, in bits */ - int ab_free; /* first free position in alphabet */ - int ab_max; /* last possible character in alphabet */ - int pass; /* pass number in interlaced images */ - int pos; /* index into decompresion stack */ - int x, y; /* position in image buffer */ + wxGIFDecoder *decod; + int error; + bool ok = TRUE; - int code, readcode, lastcode, abcabca; +// image->Destroy(); + decod = new wxGIFDecoder(&stream, TRUE); + error = decod->ReadGIF(); - /* these won't change */ - ab_clr = (1 << bits); - ab_fin = (1 << bits) + 1; - - /* these will change through the decompression proccess */ - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - pass = 1; - pos = x = y = 0; - - /* reset static globals */ - restbits = 0; - restbyte = 0; - lastbyte = 0; - - do + if ((error != wxGIF_OK) && (error != wxGIF_TRUNCATED)) { - /* get next code */ - readcode = code = getcode(ab_bits); - - /* end of image? */ - if (code == ab_fin) break; - - /* reset alphabet? */ - if (code == ab_clr) - { - /* reset main variables */ - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - - /* skip to next code */ - continue; - } - - /* unknown code: special case (like in ABCABCA) */ - if (code >= ab_free) - { - code = lastcode; /* take last string */ - stack[pos++] = abcabca; /* add first character */ - } - - /* build the string for this code in the stack */ - while (code > ab_clr) - { - stack[pos++] = ab_tail[code]; - code = ab_prefix[code]; - } - stack[pos] = code; /* push last code into the stack */ - abcabca = code; /* save for special case */ - - /* make new entry in alphabet (only if NOT just cleared) */ - if (lastcode != -1) + if (verbose) { - ab_prefix[ab_free] = lastcode; - ab_tail[ab_free] = code; - ab_free++; - - if ((ab_free > ab_max) && (ab_bits < 12)) - { - ab_bits++; - ab_max = (1 << ab_bits) - 1; - } - } - - /* dump stack data to the buffer */ - while (pos >= 0) - { - (img->p)[x + (y * (img->w))] = (char)stack[pos--]; - - if (++x >= (img->w)) + switch (error) { - x = 0; - - if (interl) - { - /* support for interlaced images */ - switch (pass) - { - case 1: y += 8; break; - case 2: y += 8; break; - case 3: y += 4; break; - case 4: y += 2; break; - } - if (y >= (img->h)) - { - switch (++pass) - { - case 2: y = 4; break; - case 3: y = 2; break; - case 4: y = 1; break; - } - } - } - else - { - /* non-interlaced */ - y++; - } + case wxGIF_INVFORMAT: + wxLogError(_("GIF: error in GIF image format.")); + break; + case wxGIF_MEMERR: + wxLogError(_("GIF: not enough memory.")); + break; + default: + wxLogError(_("GIF: unknown error!!!")); + break; } } - - pos = 0; - lastcode = readcode; + delete decod; + return FALSE; } - while (code != ab_fin); - - return 0; -} - -/* readgif: - * Reads a GIF image from the file with filename 'nombre' in the - * IMAGEN structure pointed by 'img'. Can read GIFs with any bit - * size (color depth), but the output image is always expanded - * to 8 bits per pixel. Also, the image palette always contains - * 256 colors, although some of them may be unused. Returns E_OK - * (== 0) on success, or an error code if something fails. Error - * codes are E_ARCHIVO, E_FORMATO, E_MEMORIA (see above). - */ -int gifDecoder::readgif(IMAGEN *img) -{ - int size, ncolors, bits, interl, i; - unsigned char pal[768]; - unsigned char buf[16]; - - /* read header and logical screen descriptor block (LSDB) */ - fread(buf, 1, 13); - - /* check GIF signature */ - if (memcmp(buf, "GIF", 3) != 0) return E_FORMATO; - - /* load global color map if available */ - if ((buf[10] & 0x80) == 0x80) + if ((error == wxGIF_TRUNCATED) && verbose) { - ncolors = 2 << (buf[10] & 0x07); - fread(pal, 1, 3 * ncolors); + wxLogError(_("GIF: data stream seems to be truncated.")); + /* go on; image data is OK */ } - /* skip extensions */ - while (fgetc() == 0x21) /* separator */ + if (index != -1) { - fgetc(); /* function code */ - - while ((i = fgetc()) != 0) /* byte count */ - fseekcur(i); + // We're already on index = 0 by default. So no need + // to call GoFrame(0) then. On top of that GoFrame doesn't + // accept an index of 0. (Instead GoFirstFrame() should be used) + // Also if the gif image has only one frame, calling GoFrame(0) + // fails because GoFrame() only works with gif animations. + // (It fails if IsAnimation() returns FALSE) + // All valid reasons to NOT call GoFrame when index equals 0. + if (index != 0) + { + ok = decod->GoFrame(index); + } } - /* read image descriptor block (IDB) */ - fread(buf, 1, 9); - img->w = buf[4] + 256 * buf[5]; - - img->h = buf[6] + 256 * buf[7]; - size = img->w * img->h; - interl = ((buf[8] & 0x40)? 1 : 0); - - /* load local color map if available */ - if ((buf[8] & 0x80) == 0x80) + if (ok) { - ncolors = 2 << (buf[8] & 0x07); - fread(pal, 1, 3 * ncolors); + ok = decod->ConvertToImage(image); } - - /* get initial code size from first byte in raster data */ - bits = fgetc(); - - /* allocate memory for image and palette */ - if ((img->p = (unsigned char*) malloc(size)) == NULL) return E_MEMORIA; - if ((img->pal = (unsigned char*) malloc(768)) == NULL) return E_MEMORIA; - - /* shift palette to fit VGA 6-bit format */ - for (i = 0; i < 768; i++) - (img->pal)[i] = (unsigned char)pal[i] /* >> 2 not needed under wxWin */; - - /* decode GIF */ - dgif(img, interl, bits); - - /* finish successfully :-) */ - return E_OK; -} - -/* - -FOLLOWING CODE IS BY V.S. : - -*/ - -//----------------------------------------------------------------------------- -// wxGIFHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) - -bool wxGIFHandler::LoadFile( wxImage *image, wxInputStream& stream ) -{ - unsigned char *ptr, *src, *pal; - int file_size; - unsigned char* file_con; - IMAGEN igif; - int i; - gifDecoder *decod; - - image->Destroy(); - - file_size = stream.StreamSize(); - file_con = (unsigned char*) malloc(file_size); - stream.Read(file_con, file_size); - decod = new gifDecoder(file_con, file_size); - - if (decod -> readgif(&igif) != E_OK) { - wxLogDebug("Error reading GIF"); - free(file_con); - delete decod; - return FALSE; - } - free(file_con); - delete decod; - - image->Create(igif.w, igif.h); - if (!image->Ok()) { - free(igif.pal); - free(igif.p); - return FALSE; + else + { + wxLogError(_("GIF: Invalid gif index.")); } - image->SetMask(FALSE); - ptr = image->GetData(); - src = igif.p; - pal = igif.pal; - for (i = 0; i < igif.w * igif.h; i++, src++) { - *(ptr++) = pal[3 * (*src) + 0]; - *(ptr++) = pal[3 * (*src) + 1]; - *(ptr++) = pal[3 * (*src) + 2]; - } + delete decod; - free(igif.pal); - free(igif.p); - return TRUE; + return ok; } -bool wxGIFHandler::SaveFile( wxImage *image, wxOutputStream& stream ) +bool wxGIFHandler::SaveFile( wxImage * WXUNUSED(image), + wxOutputStream& WXUNUSED(stream), bool verbose ) { - wxLogDebug("wxGIFHandler is read-only!!"); + if (verbose) + wxLogDebug(wxT("GIF: the handler is read-only!!")); + return FALSE; } -//////////////////// Module: - -/* We haven't yet decided to go for the wxModule approach or - * explicit handler-adding: assuming the latter for now -- JACS - -class wxGIFModule : public wxModule +bool wxGIFHandler::DoCanRead( wxInputStream& stream ) { - DECLARE_DYNAMIC_CLASS(wxGIFModule) - - public: - virtual bool OnInit() - { - wxImage::AddHandler(new wxGIFHandler); - return TRUE; - } - virtual void OnExit() {} -}; - -IMPLEMENT_DYNAMIC_CLASS(wxGIFModule, wxModule) - -*/ + wxGIFDecoder decod(&stream); + return decod.CanRead(); +} +#endif // wxUSE_STREAMS +#endif // wxUSE_GIF