diff options
Diffstat (limited to 'Source/DirectFB/interfaces/IDirectFBImageProvider/idirectfbimageprovider_gif.c')
-rwxr-xr-x | Source/DirectFB/interfaces/IDirectFBImageProvider/idirectfbimageprovider_gif.c | 924 |
1 files changed, 924 insertions, 0 deletions
diff --git a/Source/DirectFB/interfaces/IDirectFBImageProvider/idirectfbimageprovider_gif.c b/Source/DirectFB/interfaces/IDirectFBImageProvider/idirectfbimageprovider_gif.c new file mode 100755 index 0000000..f9e8229 --- /dev/null +++ b/Source/DirectFB/interfaces/IDirectFBImageProvider/idirectfbimageprovider_gif.c @@ -0,0 +1,924 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include <directfb.h> + +#include <display/idirectfbsurface.h> + +#include <media/idirectfbimageprovider.h> + +#include <core/coredefs.h> +#include <core/coretypes.h> + +#include <core/layers.h> +#include <core/surface.h> + +#include <misc/gfx_util.h> +#include <direct/interface.h> +#include <direct/mem.h> +#include <direct/memcpy.h> +#include <misc/util.h> + +static DFBResult +Probe( IDirectFBImageProvider_ProbeContext *ctx ); + +static DFBResult +Construct( IDirectFBImageProvider *thiz, + ... ); + +#include <direct/interface_implementation.h> + +DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, GIF ) + + +#ifndef NODEBUG +#define GIFERRORMSG(x...) { fprintf( stderr, "(GIFLOADER) "x ); \ + fprintf( stderr, "\n" ); } +#else +#define GIFERRORMSG(x...) +#endif + +#define MAXCOLORMAPSIZE 256 + +#define CM_RED 0 +#define CM_GREEN 1 +#define CM_BLUE 2 + +#define MAX_LWZ_BITS 12 + +#define INTERLACE 0x40 +#define LOCALCOLORMAP 0x80 + +#define BitSet(byte, bit) (((byte) & (bit)) == (bit)) + +#define LM_to_uint(a,b) (((b)<<8)|(a)) + +/* + * private data struct of IDirectFBImageProvider_GIF + */ +typedef struct { + int ref; /* reference counter */ + + IDirectFBDataBuffer *buffer; + + u32 *image; + int image_width; + int image_height; + bool image_transparency; + u32 image_colorkey; + + unsigned int Width; + unsigned int Height; + u8 ColorMap[3][MAXCOLORMAPSIZE]; + unsigned int BitPixel; + unsigned int ColorResolution; + u32 Background; + unsigned int AspectRatio; + + + int GrayScale; + int transparent; + int delayTime; + int inputFlag; + int disposal; + + + u8 buf[280]; + int curbit, lastbit, done, last_byte; + + + int fresh; + int code_size, set_code_size; + int max_code, max_code_size; + int firstcode, oldcode; + int clear_code, end_code; + int table[2][(1<< MAX_LWZ_BITS)]; + int stack[(1<<(MAX_LWZ_BITS))*2], *sp; + + DIRenderCallback render_callback; + void *render_callback_ctx; + + CoreDFB *core; +} IDirectFBImageProvider_GIF_data; + +static bool verbose = false; +static bool showComment = false; +static bool ZeroDataBlock = false; + +static u32* ReadGIF( IDirectFBImageProvider_GIF_data *data, int imageNumber, + int *width, int *height, bool *transparency, + u32 *key_rgb, bool alpha, bool headeronly); + +static bool ReadOK( IDirectFBDataBuffer *buffer, void *data, unsigned int len ); + + +static DirectResult +IDirectFBImageProvider_GIF_AddRef ( IDirectFBImageProvider *thiz ); + +static DirectResult +IDirectFBImageProvider_GIF_Release ( IDirectFBImageProvider *thiz ); + +static DFBResult +IDirectFBImageProvider_GIF_RenderTo( IDirectFBImageProvider *thiz, + IDirectFBSurface *destination, + const DFBRectangle *destination_rect ); + +static DFBResult +IDirectFBImageProvider_GIF_SetRenderCallback( IDirectFBImageProvider *thiz, + DIRenderCallback callback, + void *context ); + +static DFBResult +IDirectFBImageProvider_GIF_GetSurfaceDescription( IDirectFBImageProvider *thiz, + DFBSurfaceDescription *dsc ); + +static DFBResult +IDirectFBImageProvider_GIF_GetImageDescription( IDirectFBImageProvider *thiz, + DFBImageDescription *dsc ); + + +static DFBResult +Probe( IDirectFBImageProvider_ProbeContext *ctx ) +{ + if (strncmp ((char*) ctx->header, "GIF8", 4) == 0) + return DFB_OK; + + return DFB_UNSUPPORTED; +} + +static DFBResult +Construct( IDirectFBImageProvider *thiz, + ... ) +{ + IDirectFBDataBuffer *buffer; + CoreDFB *core; + va_list tag; + + DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBImageProvider_GIF) + + va_start( tag, thiz ); + buffer = va_arg( tag, IDirectFBDataBuffer * ); + core = va_arg( tag, CoreDFB * ); + va_end( tag ); + + data->ref = 1; + + data->GrayScale = -1; + data->transparent = -1; + data->delayTime = -1; + + data->core = core; + data->buffer = buffer; + buffer->AddRef( buffer ); + + data->image = ReadGIF( data, 1, &data->image_width, &data->image_height, + &data->image_transparency, &data->image_colorkey, + true, false ); + + buffer->Release( buffer ); + data->buffer = NULL; + + if (!data->image) { + DIRECT_DEALLOCATE_INTERFACE( thiz ); + return DFB_FAILURE; + } + + thiz->AddRef = IDirectFBImageProvider_GIF_AddRef; + thiz->Release = IDirectFBImageProvider_GIF_Release; + thiz->RenderTo = IDirectFBImageProvider_GIF_RenderTo; + thiz->SetRenderCallback = IDirectFBImageProvider_GIF_SetRenderCallback; + thiz->GetImageDescription = IDirectFBImageProvider_GIF_GetImageDescription; + thiz->GetSurfaceDescription = + IDirectFBImageProvider_GIF_GetSurfaceDescription; + + return DFB_OK; +} + +static void +IDirectFBImageProvider_GIF_Destruct( IDirectFBImageProvider *thiz ) +{ + IDirectFBImageProvider_GIF_data *data = + (IDirectFBImageProvider_GIF_data*)thiz->priv; + + if (data->image) + D_FREE( data->image ); + + DIRECT_DEALLOCATE_INTERFACE( thiz ); +} + +static DirectResult +IDirectFBImageProvider_GIF_AddRef( IDirectFBImageProvider *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_GIF) + + data->ref++; + + return DFB_OK; +} + +static DirectResult +IDirectFBImageProvider_GIF_Release( IDirectFBImageProvider *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_GIF) + + if (--data->ref == 0) { + IDirectFBImageProvider_GIF_Destruct( thiz ); + } + + return DFB_OK; +} + +static DFBResult +IDirectFBImageProvider_GIF_RenderTo( IDirectFBImageProvider *thiz, + IDirectFBSurface *destination, + const DFBRectangle *dest_rect ) +{ + DFBResult ret; + DFBRegion clip; + DFBRectangle rect; + DFBSurfacePixelFormat format; + IDirectFBSurface_data *dst_data; + CoreSurface *dst_surface; + + DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF) + + dst_data = (IDirectFBSurface_data*) destination->priv; + if (!dst_data) + return DFB_DEAD; + + dst_surface = dst_data->surface; + if (!dst_surface) + return DFB_DESTROYED; + + dfb_region_from_rectangle( &clip, &dst_data->area.current ); + + if (dest_rect) { + if (dest_rect->w < 1 || dest_rect->h < 1) + return DFB_INVARG; + rect = *dest_rect; + rect.x += dst_data->area.wanted.x; + rect.y += dst_data->area.wanted.y; + } + else { + rect = dst_data->area.wanted; + } + + ret = destination->GetPixelFormat( destination, &format ); + if (ret) + return ret; + + /* actual loading and rendering */ + if (dfb_rectangle_region_intersects( &rect, &clip )) { + CoreSurfaceBufferLock lock; + + ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock ); + if (ret) + return ret; + + dfb_scale_linear_32( data->image, data->image_width, data->image_height, + lock.addr, lock.pitch, &rect, dst_surface, &clip ); + + dfb_surface_unlock_buffer( dst_surface, &lock ); + + if (data->render_callback) { + DIRenderCallbackResult r; + + rect.x = 0; + rect.y = 0; + rect.w = data->image_width; + rect.h = data->image_height; + + r = data->render_callback( &rect, data->render_callback_ctx ); + + if (r != DIRCR_OK) + return DFB_INTERRUPTED; + } + } + + return DFB_OK; +} + +static DFBResult +IDirectFBImageProvider_GIF_SetRenderCallback( IDirectFBImageProvider *thiz, + DIRenderCallback callback, + void *context ) +{ + DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF) + + data->render_callback = callback; + data->render_callback_ctx = context; + + return DFB_OK; +} + +static DFBResult +IDirectFBImageProvider_GIF_GetSurfaceDescription( IDirectFBImageProvider *thiz, + DFBSurfaceDescription *dsc ) +{ + DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF) + + dsc->flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT; + dsc->width = data->image_width; + dsc->height = data->image_height; + dsc->pixelformat = dfb_primary_layer_pixelformat(); + + return DFB_OK; +} + +static DFBResult +IDirectFBImageProvider_GIF_GetImageDescription( IDirectFBImageProvider *thiz, + DFBImageDescription *dsc ) +{ + DIRECT_INTERFACE_GET_DATA (IDirectFBImageProvider_GIF) + + if (data->image_transparency) { + dsc->caps = DICAPS_COLORKEY; + + dsc->colorkey_r = (data->image_colorkey & 0xff0000) >> 16; + dsc->colorkey_g = (data->image_colorkey & 0x00ff00) >> 8; + dsc->colorkey_b = (data->image_colorkey & 0x0000ff); + } + else + dsc->caps = DICAPS_NONE; + + return DFB_OK; +} + + +/********************************** + GIF Loader Code + **********************************/ + +static int ReadColorMap( IDirectFBDataBuffer *buffer, int number, + u8 buf[3][MAXCOLORMAPSIZE] ) +{ + int i; + u8 rgb[3]; + + for (i = 0; i < number; ++i) { + if (! ReadOK( buffer, rgb, sizeof(rgb) )) { + GIFERRORMSG("bad colormap" ); + return true; + } + + buf[CM_RED][i] = rgb[0] ; + buf[CM_GREEN][i] = rgb[1] ; + buf[CM_BLUE][i] = rgb[2] ; + } + return false; +} + +static int GetDataBlock(IDirectFBDataBuffer *buffer, u8 *buf) +{ + unsigned char count; + + if (! ReadOK( buffer, &count, 1 )) { + GIFERRORMSG("error in getting DataBlock size" ); + return -1; + } + ZeroDataBlock = count == 0; + + if ((count != 0) && (! ReadOK( buffer, buf, count ))) { + GIFERRORMSG("error in reading DataBlock" ); + return -1; + } + + return count; +} + +static int GetCode(IDirectFBImageProvider_GIF_data *data, int code_size, int flag) +{ + int i, j, ret; + unsigned char count; + + if (flag) { + data->curbit = 0; + data->lastbit = 0; + data->done = false; + return 0; + } + + if ( (data->curbit+code_size) >= data->lastbit) { + if (data->done) { + if (data->curbit >= data->lastbit) { + GIFERRORMSG("ran off the end of my bits" ); + } + return -1; + } + data->buf[0] = data->buf[data->last_byte-2]; + data->buf[1] = data->buf[data->last_byte-1]; + + if ((count = GetDataBlock( data->buffer, &data->buf[2] )) == 0) { + data->done = true; + } + + data->last_byte = 2 + count; + data->curbit = (data->curbit - data->lastbit) + 16; + data->lastbit = (2+count) * 8; + } + + ret = 0; + for (i = data->curbit, j = 0; j < code_size; ++i, ++j) { + ret |= ((data->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; + } + data->curbit += code_size; + + return ret; +} + +static int DoExtension( IDirectFBImageProvider_GIF_data *data, int label ) +{ + unsigned char buf[256] = { 0 }; + char *str; + + switch (label) { + case 0x01: /* Plain Text Extension */ + str = "Plain Text Extension"; + break; + case 0xff: /* Application Extension */ + str = "Application Extension"; + break; + case 0xfe: /* Comment Extension */ + str = "Comment Extension"; + while (GetDataBlock( data->buffer, (u8*) buf ) != 0) { + if (showComment) + GIFERRORMSG("gif comment: %s", buf ); + } + return false; + case 0xf9: /* Graphic Control Extension */ + str = "Graphic Control Extension"; + (void) GetDataBlock( data->buffer, (u8*) buf ); + data->disposal = (buf[0] >> 2) & 0x7; + data->inputFlag = (buf[0] >> 1) & 0x1; + data->delayTime = LM_to_uint( buf[1], buf[2] ); + if ((buf[0] & 0x1) != 0) { + data->transparent = buf[3]; + } + while (GetDataBlock( data->buffer, (u8*) buf ) != 0) + ; + return false; + default: + str = (char*) buf; + snprintf(str, 256, "UNKNOWN (0x%02x)", label); + break; + } + + if (verbose) + GIFERRORMSG("got a '%s' extension", str ); + + while (GetDataBlock( data->buffer, (u8*) buf ) != 0) + ; + + return false; +} + +static int LWZReadByte( IDirectFBImageProvider_GIF_data *data, int flag, int input_code_size ) +{ + int code, incode; + int i; + + if (flag) { + data->set_code_size = input_code_size; + data->code_size = data->set_code_size+1; + data->clear_code = 1 << data->set_code_size ; + data->end_code = data->clear_code + 1; + data->max_code_size = 2*data->clear_code; + data->max_code = data->clear_code+2; + + GetCode(data, 0, true); + + data->fresh = true; + + for (i = 0; i < data->clear_code; ++i) { + data->table[0][i] = 0; + data->table[1][i] = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) { + data->table[0][i] = data->table[1][0] = 0; + } + data->sp = data->stack; + + return 0; + } + else if (data->fresh) { + data->fresh = false; + do { + data->firstcode = data->oldcode = GetCode( data, data->code_size, false ); + } while (data->firstcode == data->clear_code); + + return data->firstcode; + } + + if (data->sp > data->stack) { + return *--data->sp; + } + + while ((code = GetCode( data, data->code_size, false )) >= 0) { + if (code == data->clear_code) { + for (i = 0; i < data->clear_code; ++i) { + data->table[0][i] = 0; + data->table[1][i] = i; + } + for (; i < (1<<MAX_LWZ_BITS); ++i) { + data->table[0][i] = data->table[1][i] = 0; + } + data->code_size = data->set_code_size+1; + data->max_code_size = 2*data->clear_code; + data->max_code = data->clear_code+2; + data->sp = data->stack; + data->firstcode = data->oldcode = GetCode( data, data->code_size, false ); + + return data->firstcode; + } + else if (code == data->end_code) { + int count; + u8 buf[260]; + + if (ZeroDataBlock) { + return -2; + } + + while ((count = GetDataBlock( data->buffer, buf )) > 0) + ; + + if (count != 0) + GIFERRORMSG("missing EOD in data stream " + "(common occurence)"); + + return -2; + } + + incode = code; + + if (code >= data->max_code) { + *data->sp++ = data->firstcode; + code = data->oldcode; + } + + while (code >= data->clear_code) { + *data->sp++ = data->table[1][code]; + if (code == data->table[0][code]) { + GIFERRORMSG("circular table entry BIG ERROR"); + } + code = data->table[0][code]; + } + + *data->sp++ = data->firstcode = data->table[1][code]; + + if ((code = data->max_code) <(1<<MAX_LWZ_BITS)) { + data->table[0][code] = data->oldcode; + data->table[1][code] = data->firstcode; + ++data->max_code; + if ((data->max_code >= data->max_code_size) + && (data->max_code_size < (1<<MAX_LWZ_BITS))) + { + data->max_code_size *= 2; + ++data->code_size; + } + } + + data->oldcode = incode; + + if (data->sp > data->stack) { + return *--data->sp; + } + } + return code; +} + +static int SortColors (const void *a, const void *b) +{ + return (*((const u8 *) a) - *((const u8 *) b)); +} + +/* looks for a color that is not in the colormap and ideally not + even close to the colors used in the colormap */ +static u32 FindColorKey( int n_colors, u8 cmap[3][MAXCOLORMAPSIZE] ) +{ + u32 color = 0xFF000000; + u8 csort[MAXCOLORMAPSIZE]; + int i, j, index, d; + + if (n_colors < 1) + return color; + + D_ASSERT( n_colors <= MAXCOLORMAPSIZE ); + + for (i = 0; i < 3; i++) { + direct_memcpy( csort, cmap[i], n_colors ); + qsort( csort, n_colors, 1, SortColors ); + + for (j = 1, index = 0, d = 0; j < n_colors; j++) { + if (csort[j] - csort[j-1] > d) { + d = csort[j] - csort[j-1]; + index = j; + } + } + if ((csort[0] - 0x0) > d) { + d = csort[0] - 0x0; + index = n_colors; + } + if (0xFF - (csort[n_colors - 1]) > d) { + index = n_colors + 1; + } + + if (index < n_colors) + csort[0] = csort[index] - (d/2); + else if (index == n_colors) + csort[0] = 0x0; + else + csort[0] = 0xFF; + + color |= (csort[0] << (8 * (2 - i))); + } + + return color; +} + +static u32* ReadImage( IDirectFBImageProvider_GIF_data *data, int width, int height, + u8 cmap[3][MAXCOLORMAPSIZE], u32 key_rgb, + bool interlace, bool ignore ) +{ + u8 c; + int v; + int xpos = 0, ypos = 0, pass = 0; + u32 *image; + + /* + ** Initialize the decompression routines + */ + if (! ReadOK( data->buffer, &c, 1 )) + GIFERRORMSG("EOF / read error on image data" ); + + if (LWZReadByte( data, true, c ) < 0) + GIFERRORMSG("error reading image" ); + + /* + ** If this is an "uninteresting picture" ignore it. + */ + if (ignore) { + if (verbose) + GIFERRORMSG("skipping image..." ); + + while (LWZReadByte( data, false, c ) >= 0) + ; + return NULL; + } + + // FIXME: allocates four additional bytes because the scaling functions + // in src/misc/gfx_util.c have an off-by-one bug which causes + // segfaults on darwin/osx (not on linux) + if ((image = D_MALLOC(width * height * 4 + 4)) == NULL) { + GIFERRORMSG("couldn't alloc space for image" ); + } + + if (verbose) { + GIFERRORMSG("reading %d by %d%s GIF image", width, height, + interlace ? " interlaced" : "" ); + } + + while ((v = LWZReadByte( data, false, c )) >= 0 ) { + u32 *dst = image + (ypos * width + xpos); + + if (v == data->transparent) { + *dst++ = key_rgb; + } + else { + *dst++ = (0xFF000000 | + cmap[CM_RED][v] << 16 | + cmap[CM_GREEN][v] << 8 | + cmap[CM_BLUE][v]); + } + + ++xpos; + if (xpos == width) { + xpos = 0; + if (interlace) { + switch (pass) { + case 0: + case 1: + ypos += 8; + break; + case 2: + ypos += 4; + break; + case 3: + ypos += 2; + break; + } + + if (ypos >= height) { + ++pass; + switch (pass) { + case 1: + ypos = 4; + break; + case 2: + ypos = 2; + break; + case 3: + ypos = 1; + break; + default: + goto fini; + } + } + } + else { + ++ypos; + } + } + if (ypos >= height) { + break; + } + } + +fini: + + if (LWZReadByte( data, false, c ) >= 0) { + GIFERRORMSG("too much input data, ignoring extra..."); + } + return image; +} + + +static u32* ReadGIF( IDirectFBImageProvider_GIF_data *data, int imageNumber, + int *width, int *height, bool *transparency, + u32 *key_rgb, bool alpha, bool headeronly) +{ + u8 buf[16]; + u8 c; + u8 localColorMap[3][MAXCOLORMAPSIZE]; + u32 colorKey = 0; + bool useGlobalColormap; + int bitPixel; + int imageCount = 0; + char version[4]; + + if (! ReadOK( data->buffer, buf, 6 )) { + GIFERRORMSG("error reading magic number" ); + } + + if (strncmp( (char *)buf, "GIF", 3 ) != 0) { + GIFERRORMSG("not a GIF file" ); + } + + direct_snputs( version, (char *)buf + 3, 4 ); + + if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { + GIFERRORMSG("bad version number, not '87a' or '89a'" ); + } + + if (! ReadOK(data->buffer,buf,7)) { + GIFERRORMSG("failed to read screen descriptor" ); + } + + data->Width = LM_to_uint( buf[0], buf[1] ); + data->Height = LM_to_uint( buf[2], buf[3] ); + data->BitPixel = 2 << (buf[4] & 0x07); + data->ColorResolution = (((buf[4] & 0x70) >> 3) + 1); + data->Background = buf[5]; + data->AspectRatio = buf[6]; + + if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ + if (ReadColorMap( data->buffer, data->BitPixel, data->ColorMap )) { + GIFERRORMSG("error reading global colormap" ); + } + } + + if (data->AspectRatio != 0 && data->AspectRatio != 49) { + /* float r = ( (float) data->AspectRatio + 15.0 ) / 64.0; */ + GIFERRORMSG("warning - non-square pixels"); + } + + data->transparent = -1; + data->delayTime = -1; + data->inputFlag = -1; + data->disposal = 0; + + for (;;) { + if (! ReadOK( data->buffer, &c, 1)) { + GIFERRORMSG("EOF / read error on image data" ); + } + + if (c == ';') { /* GIF terminator */ + if (imageCount < imageNumber) { + GIFERRORMSG("only %d image%s found in file", + imageCount, imageCount>1?"s":"" ); + } + return NULL; + } + + if (c == '!') { /* Extension */ + if (! ReadOK( data->buffer, &c, 1)) { + GIFERRORMSG("OF / read error on extention function code"); + } + DoExtension( data, c ); + continue; + } + + if (c != ',') { /* Not a valid start character */ + GIFERRORMSG("bogus character 0x%02x, ignoring", (int) c ); + continue; + } + + ++imageCount; + + if (! ReadOK( data->buffer, buf, 9 )) { + GIFERRORMSG("couldn't read left/top/width/height"); + } + + *width = LM_to_uint( buf[4], buf[5] ); + *height = LM_to_uint( buf[6], buf[7] ); + *transparency = (data->transparent != -1); + + if (headeronly && !(*transparency && key_rgb)) + return NULL; + + useGlobalColormap = ! BitSet( buf[8], LOCALCOLORMAP ); + + if (useGlobalColormap) { + if (*transparency && (key_rgb || !headeronly)) + colorKey = FindColorKey( data->BitPixel, + data->ColorMap ); + } + else { + bitPixel = 2 << (buf[8] & 0x07); + if (ReadColorMap( data->buffer, bitPixel, localColorMap )) + GIFERRORMSG("error reading local colormap" ); + + if (*transparency && (key_rgb || !headeronly)) + colorKey = FindColorKey( bitPixel, localColorMap ); + } + + if (key_rgb) + *key_rgb = colorKey; + + if (headeronly) + return NULL; + + if (alpha) + colorKey &= 0x00FFFFFF; + + return ReadImage( data, *width, *height, + (useGlobalColormap ? + data->ColorMap : localColorMap), colorKey, + BitSet( buf[8], INTERLACE ), + imageCount != imageNumber); + } +} + +static bool +ReadOK( IDirectFBDataBuffer *buffer, void *data, unsigned int len ) +{ + DFBResult ret; + + ret = buffer->WaitForData( buffer, len ); + if (ret) { + DirectFBError( "(DirectFB/ImageProvider_GIF) WaitForData failed", ret ); + return false; + } + + ret = buffer->GetData( buffer, len, data, NULL ); + if (ret) { + DirectFBError( "(DirectFB/ImageProvider_GIF) GetData failed", ret ); + return false; + } + + return true; +} + |