1
0
Fork 0
forked from len0rd/rockbox

imageviewer: gif viewer based on giflib-5.0.2

This adds ability to view gif images in rockbox.
Works both on color and gray/monochrome targets (greylib).
Aspect correction is supported as well.

Limitations:
- animated gifs are restricted to 32 frames
- animated gifs loop always (loopcount is ignored)
- plain text extension is not supported
- animated gifs with interframe delay = 0 are treated as still
  images (web browsers usually treat delay 0 as 100ms to prevent
  exhaustive CPU load by such images)

Change-Id: I61501f801ddcd403410e38d83e6bddc9883e7ede
This commit is contained in:
Marcin Bukat 2012-11-02 13:03:58 +01:00
parent b35f82c91f
commit 0ceaff2b65
23 changed files with 3006 additions and 15 deletions

View file

@ -70,6 +70,7 @@ pictureflow,demos
pitch_detector,apps
plasma,demos
png,viewers
gif,viewers
pong,games
ppm,viewers
properties,viewers

View file

@ -4,3 +4,4 @@ png
#ifdef HAVE_LCD_COLOR
ppm
#endif
gif

View file

@ -230,8 +230,9 @@ static int load_image(char *filename, struct image_info *info,
return PLUGIN_OK;
}
static int get_image(struct image_info *info, int ds)
static int get_image(struct image_info *info, int frame, int ds)
{
(void)frame;
struct t_disp* p_disp = &disp[ds]; /* short cut */
info->width = bmp.width/ds;

View file

@ -0,0 +1,6 @@
../../../../lib/tlsf/src/tlsf.c
dgif_lib.c
gifalloc.c
gif_decoder.c
gif.c
gif_err.c

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,241 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (c) 2012 Marcin Bukat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "lcd.h"
#include <lib/pluginlib_bmp.h>
#include "../imageviewer.h"
#include "bmp.h"
#include "gif_decoder.h"
#include "gif_lib.h"
/* decoder context struct */
static struct gif_decoder decoder;
static char print[32]; /* use a common snprintf() buffer */
/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
/* max 32 frames */
static unsigned char *disp[GIF_MAX_FRAMES][9];
static unsigned char *disp_buf;
#if defined(HAVE_LCD_COLOR)
#define resize_bitmap smooth_resize_bitmap
#else
#define resize_bitmap grey_resize_bitmap
#endif
#if defined(USEGSLIB) && (CONFIG_PLATFORM & PLATFORM_HOSTED)
/* hack: fix error "undefined reference to `_grey_info'". */
GREY_INFO_STRUCT
#endif /* USEGSLIB */
static void draw_image_rect(struct image_info *info,
int x, int y, int width, int height)
{
unsigned char **pdisp = (unsigned char **)info->data;
#ifdef HAVE_LCD_COLOR
rb->lcd_bitmap_part((fb_data *)*pdisp, info->x + x, info->y + y,
STRIDE(SCREEN_MAIN, info->width, info->height),
x + MAX(0, (LCD_WIDTH-info->width)/2),
y + MAX(0, (LCD_HEIGHT-info->height)/2),
width, height);
#else
mylcd_ub_gray_bitmap_part(*pdisp,
info->x + x, info->y + y, info->width,
x + MAX(0, (LCD_WIDTH-info->width)/2),
y + MAX(0, (LCD_HEIGHT-info->height)/2),
width, height);
#endif
}
static int img_mem(int ds)
{
struct gif_decoder *p_decoder = &decoder;
return p_decoder->native_img_size/ds;
}
static int load_image(char *filename, struct image_info *info,
unsigned char *buf, ssize_t *buf_size)
{
int w, h;
long time = 0; /* measured ticks */
struct gif_decoder *p_decoder = &decoder;
unsigned char *memory, *memory_max;
size_t memory_size;
/* cleanup */
memset(&disp, 0, sizeof(disp));
/* align buffer */
memory = (unsigned char *)((intptr_t)(buf + 3) & ~3);
memory_max = (unsigned char *)((intptr_t)(memory + *buf_size) & ~3);
memory_size = memory_max - memory;
#ifdef DISK_SPINDOWN
if (iv->running_slideshow && iv->immediate_ata_off) {
/* running slideshow and time is long enough: power down disk */
rb->storage_sleep();
}
#endif
/* initialize decoder context struct, set buffer decoder is free
* to use.
*/
gif_decoder_init(p_decoder, memory, memory_size);
/* populate internal data from gif file control structs */
gif_open(filename, p_decoder);
if (!p_decoder->error)
{
if (!iv->running_slideshow)
{
rb->lcd_putsf(0, 2, "image %dx%d",
p_decoder->width,
p_decoder->height);
rb->lcd_putsf(0, 3, "decoding %d*%d",
p_decoder->width,
p_decoder->height);
rb->lcd_update();
}
/* the actual decoding */
time = *rb->current_tick;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
gif_decode(p_decoder, iv->cb_progress);
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
time = *rb->current_tick - time;
}
if (!iv->running_slideshow && !p_decoder->error)
{
rb->snprintf(print, sizeof(print), " %ld.%02ld sec ", time/HZ, time%HZ);
rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */
rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print);
rb->lcd_update();
}
if (p_decoder->error)
{
rb->splashf(HZ, "%s", GifErrorString(p_decoder->error));
return PLUGIN_ERROR;
}
info->x_size = p_decoder->width;
info->y_size = p_decoder->height;
info->frames_count = p_decoder->frames_count;
info->delay = p_decoder->delay;
//p_decoder->native_img_size = (p_decoder->native_img_size + 3) & ~3;
disp_buf = p_decoder->mem +
((p_decoder->native_img_size*p_decoder->frames_count + 3) & ~3);
*buf_size = memory_max - disp_buf;
return PLUGIN_OK;
}
static int get_image(struct image_info *info, int frame, int ds)
{
unsigned char **p_disp = &disp[frame][ds]; /* short cut */
struct gif_decoder *p_decoder = &decoder;
info->width = p_decoder->width / ds;
info->height = p_decoder->height / ds;
info->data = p_disp;
if (*p_disp != NULL)
{
/* we still have it */
return PLUGIN_OK;
}
/* assign image buffer */
if (ds > 1)
{
if (!iv->running_slideshow)
{
rb->lcd_putsf(0, 3, "resizing %d*%d", info->width, info->height);
rb->lcd_update();
}
struct bitmap bmp_src, bmp_dst;
/* size of the scalled image */
int size = img_mem(ds);
if (disp_buf + size >= p_decoder->mem + p_decoder->mem_size)
{
/* have to discard the current */
int i;
for (i=1; i<=8; i++)
disp[frame][i] = NULL; /* invalidate all bitmaps */
/* start again from the beginning of the buffer */
disp_buf = p_decoder->mem +
p_decoder->native_img_size*p_decoder->frames_count;
}
*p_disp = disp_buf;
disp_buf += size;
bmp_src.width = p_decoder->width;
bmp_src.height = p_decoder->height;
bmp_src.data = p_decoder->mem + p_decoder->native_img_size*frame;
bmp_dst.width = info->width;
bmp_dst.height = info->height;
bmp_dst.data = *p_disp;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
resize_bitmap(&bmp_src, &bmp_dst);
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
}
else
{
*p_disp = p_decoder->mem + p_decoder->native_img_size*frame;
}
return PLUGIN_OK;
}
const struct image_decoder image_decoder = {
true,
img_mem,
load_image,
get_image,
draw_image_rect,
};
IMGDEC_HEADER

View file

@ -0,0 +1,30 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
GIFSRCDIR := $(IMGVSRCDIR)/gif
GIFBUILDDIR := $(IMGVBUILDDIR)/gif
GIF_SRC := $(call preprocess, $(GIFSRCDIR)/SOURCES)
GIF_OBJ := $(call c2obj, $(GIF_SRC))
OTHER_SRC += $(GIF_SRC)
ROCKS += $(GIFBUILDDIR)/gif.ovl
$(GIFBUILDDIR)/gif.refmap: $(GIF_OBJ)
$(GIFBUILDDIR)/gif.link: $(PLUGIN_LDS) $(GIFBUILDDIR)/gif.refmap
$(GIFBUILDDIR)/gif.ovl: $(GIF_OBJ)
#-Os breaks decoder - dunno why
GIFFLAGS = $(IMGDECFLAGS) -O0
# Compile PNG plugin with extra flags (adapted from ZXBox)
$(GIFBUILDDIR)/%.o: $(GIFSRCDIR)/%.c $(GIFSRCDIR)/gif.make
$(SILENT)mkdir -p $(dir $@)
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(GIFFLAGS) -c $< -o $@

View file

@ -0,0 +1,491 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (c) 2012 Marcin Bukat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <lib/pluginlib_bmp.h>
#include "bmp.h"
#if LCD_DEPTH < 8
#include <lib/grey.h>
#endif
#include "gif_lib.h"
#include "gif_decoder.h"
#ifndef resize_bitmap
#if defined(HAVE_LCD_COLOR)
#define resize_bitmap smooth_resize_bitmap
#else
#define resize_bitmap grey_resize_bitmap
#endif
#endif
#if defined(HAVE_LCD_COLOR)
typedef struct uint8_rgb pixel_t;
#define NATIVE_SZ (GifFile->SWidth*GifFile->SHeight*FB_DATA_SZ)
#define PIXEL_TRANSPARENT 0x00
#else
typedef unsigned char pixel_t;
#define NATIVE_SZ (GifFile->SWidth*GifFile->SHeight)
#define PIXEL_TRANSPARENT 0xff
#endif
#define PIXELS_SZ (GifFile->SWidth*GifFile->SHeight*sizeof(pixel_t))
static GifFileType *GifFile;
static void gif2pixels(GifPixelType *Line, pixel_t *out,
int Row, int Col, int Width)
{
int x;
#ifndef HAVE_LCD_COLOR
struct uint8_rgb rgb;
#endif
GifColorType *ColorMapEntry;
/* Color map to use */
ColorMapObject *ColorMap = (GifFile->Image.ColorMap ?
GifFile->Image.ColorMap :
GifFile->SColorMap);
pixel_t *pixel = out + ((Row * GifFile->SWidth) + Col);
for (x = 0; x < Width; x++, pixel++)
{
ColorMapEntry = &ColorMap->Colors[Line[x]];
if (GifFile->Image.GCB &&
GifFile->Image.GCB->TransparentColor == Line[x])
continue;
#ifdef HAVE_LCD_COLOR
pixel->red = ColorMapEntry->Red;
pixel->green = ColorMapEntry->Green;
pixel->blue = ColorMapEntry->Blue;
#else
rgb.red = ColorMapEntry->Red;
rgb.green = ColorMapEntry->Green;
rgb.blue = ColorMapEntry->Blue;
*pixel = brightness(rgb);
#endif
}
}
static void pixels2native(struct scaler_context *ctx,
pixel_t *pixels_buffer,
int Row)
{
#ifdef HAVE_LCD_COLOR
const struct custom_format *cformat = &format_native;
#else
const struct custom_format *cformat = &format_grey;
#endif
void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
cformat->output_row_8;
output_row_8(Row, (void *)(pixels_buffer + (Row*ctx->bm->width)), ctx);
}
void gif_decoder_init(struct gif_decoder *d, void *mem, size_t size)
{
memset(d, 0, sizeof(struct gif_decoder));
d->mem = mem;
d->mem_size = size;
/* mem allocator init */
init_memory_pool(d->mem_size, d->mem);
}
void gif_open(char *filename, struct gif_decoder *d)
{
if ((GifFile = DGifOpenFileName(filename, &d->error)) == NULL)
return;
d->width = GifFile->SWidth;
d->height = GifFile->SHeight;
d->frames_count = 0;
}
static void set_canvas_background(GifPixelType *Line, pixel_t *out,
GifFileType *GifFile)
{
int i;
/* Reading Gif spec it seems one should always use background color
* in canvas but most real files omit this and sets background color to 0
* (which IS valid index). We can choose to either conform to standard
* (and wrongly display most of gifs with transparency) or stick to
* common practise and treat background color 0 as transparent.
* I preffer the second.
*/
if (GifFile->SColorMap && GifFile->SBackGroundColor != 0)
{
memset(Line, GifFile->SBackGroundColor, GifFile->SWidth);
for(i=0; i<GifFile->SHeight; i++)
gif2pixels(Line, out, i, 0, GifFile->SWidth);
}
else
{
memset(out, PIXEL_TRANSPARENT, PIXELS_SZ);
}
}
/* var names adhere to giflib coding style */
void gif_decode(struct gif_decoder *d,
void (*pf_progress)(int current, int total))
{
int i, j;
int Size;
int Row;
int Col;
int Width;
int Height;
int ExtCode;
GifPixelType *Line;
GifRecordType RecordType;
GifByteType *Extension;
unsigned char *out = NULL;
/* The way Interlaced image should
* be read - offsets and jumps
*/
const char InterlacedOffset[] = { 0, 4, 2, 1 };
const char InterlacedJumps[] = { 8, 8, 4, 2 };
/* used for color conversion */
struct bitmap bm;
struct scaler_context ctx = {
.bm = &bm,
.dither = 0
};
/* initialize struct */
memset(&bm, 0, sizeof(struct bitmap));
Size = GifFile->SWidth * sizeof(GifPixelType); /* Size in bytes one row.*/
Line = (GifPixelType *)malloc(Size);
if (Line == NULL)
{
/* error allocating temp space */
d->error = D_GIF_ERR_NOT_ENOUGH_MEM;
return;
}
/* We use two pixel buffers if dispose method asks
* for restoration of the previous state.
* We only swap the indexes leaving data in place.
*/
int buf_idx = 0;
pixel_t *pixels_buffer[2];
pixels_buffer[0] = (pixel_t *)malloc(PIXELS_SZ);
pixels_buffer[1] = NULL;
if (pixels_buffer[0] == NULL)
{
d->error = D_GIF_ERR_NOT_ENOUGH_MEM;
return;
}
/* Global background color */
set_canvas_background(Line, pixels_buffer[0], GifFile);
bm.width = GifFile->SWidth;
bm.height = GifFile->SHeight;
d->native_img_size = NATIVE_SZ;
if (pf_progress != NULL)
pf_progress(0, 100);
/* Scan the content of the GIF file and load the image(s) in: */
do
{
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
switch (RecordType)
{
case IMAGE_DESC_RECORD_TYPE:
if (DGifGetImageDesc(GifFile) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
/* Image Position relative to canvas */
Row = GifFile->Image.Top;
Col = GifFile->Image.Left;
Width = GifFile->Image.Width;
Height = GifFile->Image.Height;
/* Check Color map to use */
if (GifFile->Image.ColorMap == NULL &&
GifFile->SColorMap == NULL)
{
d->error = D_GIF_ERR_NO_COLOR_MAP;
return;
}
/* sanity check */
if (GifFile->Image.Left+GifFile->Image.Width>GifFile->SWidth ||
GifFile->Image.Top+GifFile->Image.Height>GifFile->SHeight)
{
d->error = D_GIF_ERR_DATA_TOO_BIG;
return;
}
if (GifFile->Image.GCB &&
GifFile->Image.GCB->DisposalMode == DISPOSE_PREVIOUS)
{
/* We need to take a snapshot before processing the image
* in order to restore canvas to previous state after
* rendering
*/
buf_idx ^= 1;
if (pixels_buffer[buf_idx] == NULL)
pixels_buffer[buf_idx] = (pixel_t *)malloc(PIXELS_SZ);
}
if (GifFile->Image.Interlace)
{
/* Need to perform 4 passes on the image */
for (i = 0; i < 4; i++)
{
for (j = Row + InterlacedOffset[i];
j < Row + Height;
j += InterlacedJumps[i])
{
if (DGifGetLine(GifFile, Line, Width) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
gif2pixels(Line, pixels_buffer[buf_idx],
Row + j, Col, Width);
}
pf_progress(25*(i+1), 100);
}
}
else
{
for (i = 0; i < Height; i++)
{
/* load single line into buffer */
if (DGifGetLine(GifFile, Line, Width) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
gif2pixels(Line, pixels_buffer[buf_idx],
Row + i, Col, Width);
pf_progress(100*(i+1)/Height, 100);
}
}
/* allocate space for new frame */
out = realloc(out, d->native_img_size*(d->frames_count + 1));
if (out == NULL)
{
d->error = D_GIF_ERR_NOT_ENOUGH_MEM;
return;
}
bm.data = out + d->native_img_size*d->frames_count;
/* animated gif */
if (GifFile->Image.GCB && GifFile->Image.GCB->DelayTime != 0)
{
for (i=0; i < ctx.bm->height; i++)
pixels2native(&ctx, (void *)pixels_buffer[buf_idx], i);
/* restore to the background color */
switch (GifFile->Image.GCB->DisposalMode)
{
case DISPOSE_BACKGROUND:
set_canvas_background(Line, pixels_buffer[buf_idx],
GifFile);
break;
case DISPOSE_PREVIOUS:
buf_idx ^= 1;
break;
default:
/* DISPOSAL_UNSPECIFIED
* DISPOSE_DO_NOT
*/
break;
}
d->frames_count++;
if (d->frames_count > GIF_MAX_FRAMES)
{
d->error = D_GIF_ERR_NOT_ENOUGH_MEM;
return;
}
}
break;
case EXTENSION_RECORD_TYPE:
if (DGifGetExtension(GifFile, &ExtCode, &Extension) ==
GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
if (ExtCode == GRAPHICS_EXT_FUNC_CODE)
{
if (GifFile->Image.GCB == NULL)
GifFile->Image.GCB = (GraphicsControlBlock *)
malloc(sizeof(GraphicsControlBlock));
if (DGifExtensionToGCB(Extension[0],
Extension + 1,
GifFile->Image.GCB) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
d->delay = GifFile->Image.GCB->DelayTime;
}
/* Skip anything else */
while (Extension != NULL)
{
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
}
break;
/* including TERMINATE_RECORD_TYPE */
default:
break;
}
} while (RecordType != TERMINATE_RECORD_TYPE);
/* free all internal allocated data */
if (DGifCloseFile(GifFile) == GIF_ERROR)
{
d->error = GifFile->Error;
return;
}
/* not animated gif */
if (d->frames_count == 0)
{
for (i=0; i < ctx.bm->height; i++)
pixels2native(&ctx, (void *)pixels_buffer[buf_idx], i);
d->frames_count++;
}
free(pixels_buffer[0]);
if (pixels_buffer[1])
free(pixels_buffer[1]);
free(Line);
/* WARNING !!!! */
/* GifFile object is trashed from now on, DONT use it */
/* Move bitmap in native format to the front of the buff */
memmove(d->mem, out, d->frames_count*d->native_img_size);
/* correct aspect ratio */
#if (LCD_PIXEL_ASPECT_HEIGHT != 1 || LCD_PIXEL_ASPECT_WIDTH != 1)
struct bitmap img_src, img_dst; /* scaler vars */
struct dim dim_src, dim_dst; /* recalc_dimensions vars */
size_t c_native_img_size; /* size of the image after correction */
dim_src.width = bm.width;
dim_src.height = bm.height;
dim_dst.width = bm.width;
dim_dst.height = bm.height;
/* defined in apps/recorder/resize.c */
if (!recalc_dimension(&dim_dst, &dim_src))
{
/* calculate 'corrected' image size */
#ifdef HAVE_LCD_COLOR
c_native_img_size = dim_dst.width * dim_dst.height * FB_DATA_SZ;
#else
c_native_img_size = dim_dst.width * dim_dst.height;
#endif
/* check memory constraints
* do the correction only if there is enough
* free memory
*/
if (d->native_img_size*d->frames_count + c_native_img_size <=
d->mem_size)
{
img_dst.width = dim_dst.width;
img_dst.height = dim_dst.height;
img_dst.data = (unsigned char *)d->mem +
d->native_img_size*d->frames_count;
for (i = 0; i < d->frames_count; i++)
{
img_src.width = dim_src.width;
img_src.height = dim_src.height;
img_src.data = (unsigned char *)d->mem + i*d->native_img_size;
/* scale the bitmap to correct physical
* pixel dimentions
*/
resize_bitmap(&img_src, &img_dst);
/* copy back corrected image */
memmove(d->mem + i*c_native_img_size,
img_dst.data,
c_native_img_size);
}
/* update decoder struct */
d->width = img_dst.width;
d->height = img_dst.height;
d->native_img_size = c_native_img_size;
}
}
#endif
}

View file

@ -0,0 +1,37 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (c) 2012 Marcin Bukat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#define GIF_MAX_FRAMES 32
struct gif_decoder {
unsigned char *mem;
size_t mem_size;
int width;
int height;
int frames_count;
int delay;
size_t native_img_size;
int error;
};
void gif_decoder_init(struct gif_decoder *decoder, void *mem, size_t size);
void gif_open(char *filename, struct gif_decoder *d);
void gif_decode(struct gif_decoder *d, void (*pf_progress)(int current, int total));

View file

@ -0,0 +1,99 @@
/*****************************************************************************
gif_err.c - handle error reporting for the GIF library.
****************************************************************************/
/* #include <stdio.h> */
#include "gif_lib.h"
#include "gif_lib_private.h"
/*****************************************************************************
Return a string description of the last GIF error
*****************************************************************************/
char *
GifErrorString(int ErrorCode)
{
char *Err;
switch (ErrorCode) {
#if 0
case E_GIF_ERR_OPEN_FAILED:
Err = "Failed to open given file";
break;
case E_GIF_ERR_WRITE_FAILED:
Err = "Failed to write to given file";
break;
case E_GIF_ERR_HAS_SCRN_DSCR:
Err = "Screen descriptor has already been set";
break;
case E_GIF_ERR_HAS_IMAG_DSCR:
Err = "Image descriptor is still active";
break;
case E_GIF_ERR_NO_COLOR_MAP:
Err = "Neither global nor local color map";
break;
case E_GIF_ERR_DATA_TOO_BIG:
Err = "Number of pixels bigger than width * height";
break;
case E_GIF_ERR_NOT_ENOUGH_MEM:
Err = "Failed to allocate required memory";
break;
case E_GIF_ERR_DISK_IS_FULL:
Err = "Write failed (disk full?)";
break;
case E_GIF_ERR_CLOSE_FAILED:
Err = "Failed to close given file";
break;
case E_GIF_ERR_NOT_WRITEABLE:
Err = "Given file was not opened for write";
break;
#endif
case D_GIF_ERR_OPEN_FAILED:
Err = "Failed to open given file";
break;
case D_GIF_ERR_READ_FAILED:
Err = "Failed to read from given file";
break;
case D_GIF_ERR_NOT_GIF_FILE:
Err = "Data is not in GIF format";
break;
case D_GIF_ERR_NO_SCRN_DSCR:
Err = "No screen descriptor detected";
break;
case D_GIF_ERR_NO_IMAG_DSCR:
Err = "No Image Descriptor detected";
break;
case D_GIF_ERR_NO_COLOR_MAP:
Err = "Neither global nor local color map";
break;
case D_GIF_ERR_WRONG_RECORD:
Err = "Wrong record type detected";
break;
case D_GIF_ERR_DATA_TOO_BIG:
Err = "Number of pixels bigger than width * height";
break;
case D_GIF_ERR_NOT_ENOUGH_MEM:
Err = "Failed to allocate required memory";
break;
case D_GIF_ERR_CLOSE_FAILED:
Err = "Failed to close given file";
break;
case D_GIF_ERR_NOT_READABLE:
Err = "Given file was not opened for read";
break;
case D_GIF_ERR_IMAGE_DEFECT:
Err = "Image is defective, decoding aborted";
break;
case D_GIF_ERR_EOF_TOO_SOON:
Err = "Image EOF detected before image complete";
break;
default:
Err = NULL;
break;
}
return Err;
}
/* end */

View file

@ -0,0 +1,39 @@
/******************************************************************************
gif_hash.h - magfic constants and declarations for GIF LZW
******************************************************************************/
#ifndef _GIF_HASH_H_
#define _GIF_HASH_H_
//#include <unistd.h>
#include <stdint.h>
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
/* The 32 bits of the long are divided into two parts for the key & code: */
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
/* The key is the upper 20 bits. The code is the lower 12. */
#define HT_GET_KEY(l) (l >> 12)
#define HT_GET_CODE(l) (l & 0x0FFF)
#define HT_PUT_KEY(l) (l << 12)
#define HT_PUT_CODE(l) (l & 0x0FFF)
typedef struct GifHashTableType {
uint32_t HTable[HT_SIZE];
} GifHashTableType;
GifHashTableType *_InitHashTable(void);
void _ClearHashTable(GifHashTableType *HashTable);
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code);
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key);
#endif /* _GIF_HASH_H_ */
/* end */

View file

@ -0,0 +1,308 @@
/******************************************************************************
gif_lib.h - service library for decoding and encoding GIF images
*****************************************************************************/
#ifndef _GIF_LIB_H_
#define _GIF_LIB_H_ 1
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GIFLIB_MAJOR 5
#define GIFLIB_MINOR 0
#define GIFLIB_RELEASE 2
#define GIF_ERROR 0
#define GIF_OK 1
#include <stdbool.h>
#include "rb_glue.h"
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
typedef unsigned char GifPixelType;
typedef unsigned char *GifRowType;
typedef unsigned char GifByteType;
typedef unsigned int GifPrefixType;
typedef int GifWord;
/******************************************************************************
GIF89 structures
******************************************************************************/
typedef struct GraphicsControlBlock {
int DisposalMode;
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
#define DISPOSE_DO_NOT 1 /* Leave image in place */
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
bool UserInputFlag; /* User confirmation required before disposal */
int DelayTime; /* pre-display delay in 0.01sec units */
int TransparentColor; /* Palette index for transparency, -1 if none */
#define NO_TRANSPARENT_COLOR -1
} GraphicsControlBlock;
typedef struct GifColorType {
GifByteType Red, Green, Blue;
} GifColorType;
typedef struct ColorMapObject {
int ColorCount;
int BitsPerPixel;
bool SortFlag;
GifColorType *Colors; /* on malloc(3) heap */
} ColorMapObject;
typedef struct GifImageDesc {
GifWord Left, Top, Width, Height; /* Current image dimensions. */
bool Interlace; /* Sequential/Interlaced lines. */
ColorMapObject *ColorMap; /* The local color map */
GraphicsControlBlock *GCB; /* Graphic control block */
} GifImageDesc;
typedef struct ExtensionBlock {
int ByteCount;
GifByteType *Bytes; /* on malloc(3) heap */
int Function; /* The block function code */
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block */
} ExtensionBlock;
typedef struct SavedImage {
GifImageDesc ImageDesc;
GifByteType *RasterBits; /* on malloc(3) heap */
int ExtensionBlockCount; /* Count of extensions before image */
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
} SavedImage;
typedef struct GifFileType {
GifWord SWidth, SHeight; /* Size of virtual canvas */
GifWord SColorResolution; /* How many colors can we generate? */
GifWord SBackGroundColor; /* Background color for virtual canvas */
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
int ImageCount; /* Number of current image (both APIs) */
GifImageDesc Image; /* Current image (low-level API) */
SavedImage *SavedImages; /* Image sequence (high-level API) */
int ExtensionBlockCount; /* Count extensions past last image */
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
int Error; /* Last error condition reported */
void *UserData; /* hook to attach user data (TVT) */
void *Private; /* Don't mess with this! */
} GifFileType;
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
typedef enum {
UNDEFINED_RECORD_TYPE,
SCREEN_DESC_RECORD_TYPE,
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
EXTENSION_RECORD_TYPE, /* Begin with '!' */
TERMINATE_RECORD_TYPE /* Begin with ';' */
} GifRecordType;
/* func type to read gif data from arbitrary sources (TVT) */
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
/* func type to write gif data to arbitrary targets.
* Returns count of bytes written. (MRB)
*/
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
/******************************************************************************
GIF encoding routines
******************************************************************************/
/* Main entry points */
GifFileType *EGifOpenFileName(const char *GifFileName,
const bool GifTestExistence, int *Error);
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
int EGifSpew(GifFileType * GifFile);
char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
int EGifCloseFile(GifFileType * GifFile);
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
#define E_GIF_ERR_WRITE_FAILED 2
#define E_GIF_ERR_HAS_SCRN_DSCR 3
#define E_GIF_ERR_HAS_IMAG_DSCR 4
#define E_GIF_ERR_NO_COLOR_MAP 5
#define E_GIF_ERR_DATA_TOO_BIG 6
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
#define E_GIF_ERR_DISK_IS_FULL 8
#define E_GIF_ERR_CLOSE_FAILED 9
#define E_GIF_ERR_NOT_WRITEABLE 10
/* These are legacy. You probably do not want to call them directly */
int EGifPutScreenDesc(GifFileType *GifFile,
const int GifWidth, const int GifHeight,
const int GifColorRes,
const int GifBackGround,
const ColorMapObject *GifColorMap);
int EGifPutImageDesc(GifFileType *GifFile,
const int GifLeft, const int GifTop,
const int GifWidth, const int GifHeight,
const bool GifInterlace,
const ColorMapObject *GifColorMap);
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
int GifLineLen);
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
int EGifPutExtensionBlock(GifFileType *GifFile,
const int GifExtLen, const void *GifExtension);
int EGifPutExtensionTrailer(GifFileType *GifFile);
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
const int GifExtLen,
const void *GifExtension);
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
const GifByteType *GifCodeBlock);
int EGifPutCodeNext(GifFileType *GifFile,
const GifByteType *GifCodeBlock);
/******************************************************************************
GIF decoding routines
******************************************************************************/
/* Main entry points */
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
int DGifSlurp(GifFileType * GifFile);
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
int DGifCloseFile(GifFileType * GifFile);
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
#define D_GIF_ERR_READ_FAILED 102
#define D_GIF_ERR_NOT_GIF_FILE 103
#define D_GIF_ERR_NO_SCRN_DSCR 104
#define D_GIF_ERR_NO_IMAG_DSCR 105
#define D_GIF_ERR_NO_COLOR_MAP 106
#define D_GIF_ERR_WRONG_RECORD 107
#define D_GIF_ERR_DATA_TOO_BIG 108
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
#define D_GIF_ERR_CLOSE_FAILED 110
#define D_GIF_ERR_NOT_READABLE 111
#define D_GIF_ERR_IMAGE_DEFECT 112
#define D_GIF_ERR_EOF_TOO_SOON 113
/* These are legacy. You probably do not want to call them directly */
int DGifGetScreenDesc(GifFileType *GifFile);
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
int DGifGetImageDesc(GifFileType *GifFile);
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
int DGifGetComment(GifFileType *GifFile, char *GifComment);
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
GifByteType **GifExtension);
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
GifByteType **GifCodeBlock);
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
/******************************************************************************
Color table quantization (deprecated)
******************************************************************************/
int GifQuantizeBuffer(unsigned int Width, unsigned int Height,
int *ColorMapSize, GifByteType * RedInput,
GifByteType * GreenInput, GifByteType * BlueInput,
GifByteType * OutputBuffer,
GifColorType * OutputColorMap);
/******************************************************************************
Error handling and reporting.
******************************************************************************/
extern char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
/*****************************************************************************
Everything below this point is new after version 1.2, supporting `slurp
mode' for doing I/O in two big belts with all the image-bashing in core.
******************************************************************************/
/******************************************************************************
Color map handling from gif_alloc.c
******************************************************************************/
extern ColorMapObject *GifMakeMapObject(int ColorCount,
const GifColorType *ColorMap);
extern void GifFreeMapObject(ColorMapObject *Object);
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
const ColorMapObject *ColorIn2,
GifPixelType ColorTransIn2[]);
extern int GifBitSize(int n);
/******************************************************************************
Support for the in-core structures allocation (slurp mode).
******************************************************************************/
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
ExtensionBlock **ExtensionBlocks,
int Function,
unsigned int Len, unsigned char ExtData[]);
extern void GifFreeExtensions(int *ExtensionBlock_Count,
ExtensionBlock **ExtensionBlocks);
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
const SavedImage *CopyFrom);
extern void GifFreeSavedImages(GifFileType *GifFile);
/******************************************************************************
5.x functions for GIF89 graphics control blocks
******************************************************************************/
int DGifExtensionToGCB(const size_t GifExtensionLength,
const GifByteType *GifExtension,
GraphicsControlBlock *GCB);
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
GifByteType *GifExtension);
int DGifSavedExtensionToGCB(GifFileType *GifFile,
int ImageIndex,
GraphicsControlBlock *GCB);
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
GifFileType *GifFile,
int ImageIndex);
/******************************************************************************
The library's internal utility font
******************************************************************************/
#define GIF_FONT_WIDTH 8
#define GIF_FONT_HEIGHT 8
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
extern void GifDrawText8x8(SavedImage *Image,
const int x, const int y,
const char *legend, const int color);
extern void GifDrawBox(SavedImage *Image,
const int x, const int y,
const int w, const int d, const int color);
extern void GifDrawRectangle(SavedImage *Image,
const int x, const int y,
const int w, const int d, const int color);
extern void GifDrawBoxedText8x8(SavedImage *Image,
const int x, const int y,
const char *legend,
const int border, const int bg, const int fg);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _GIF_LIB_H */
/* end */

View file

@ -0,0 +1,59 @@
/****************************************************************************
gif_lib_private.h - internal giflib routines and structures
****************************************************************************/
#ifndef _GIF_LIB_PRIVATE_H
#define _GIF_LIB_PRIVATE_H
#include "gif_lib.h"
#include "gif_hash.h"
#define EXTENSION_INTRODUCER 0x21
#define DESCRIPTOR_INTRODUCER 0x2c
#define TERMINATOR_INTRODUCER 0x3b
#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
#define LZ_BITS 12
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
#define FILE_STATE_WRITE 0x01
#define FILE_STATE_SCREEN 0x02
#define FILE_STATE_IMAGE 0x04
#define FILE_STATE_READ 0x08
#define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ)
#define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
typedef struct GifFilePrivateType {
GifWord FileState, FileHandle, /* Where all this data goes to! */
BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
ClearCode, /* The CLEAR LZ code. */
EOFCode, /* The EOF LZ code. */
RunningCode, /* The next code algorithm can generate. */
RunningBits, /* The number of bits required to represent RunningCode. */
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
LastCode, /* The code before the current code. */
CrntCode, /* Current algorithm code. */
StackPtr, /* For character stack (see below). */
CrntShiftState; /* Number of bits in CrntShiftDWord. */
unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
unsigned long PixelCount; /* Number of pixels in image. */
int File; /* File as stream. (converted to int in rb) */
InputFunc Read; /* function to read gif input (TVT) */
OutputFunc Write; /* function to write gif output (MRB) */
GifByteType Buf[256]; /* Compressed input is buffered here. */
GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
GifPrefixType Prefix[LZ_MAX_CODE + 1];
GifHashTableType *HashTable;
bool gif89;
} GifFilePrivateType;
#endif /* _GIF_LIB_PRIVATE_H */
/* end */

View file

@ -0,0 +1,405 @@
/*****************************************************************************
GIF construction tools
****************************************************************************/
#include <stdlib.h>
/* #include <stdio.h> */
#include <string.h>
#include "gif_lib.h"
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
/******************************************************************************
Miscellaneous utility functions
******************************************************************************/
/* return smallest bitfield size n will fit in */
int
GifBitSize(int n)
{
register int i;
for (i = 1; i <= 8; i++)
if ((1 << i) >= n)
break;
return (i);
}
/******************************************************************************
Color map object functions
******************************************************************************/
/*
* Allocate a color map of given size; initialize with contents of
* ColorMap if that pointer is non-NULL.
*/
ColorMapObject *
GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
{
ColorMapObject *Object;
/*** FIXME: Our ColorCount has to be a power of two. Is it necessary to
* make the user know that or should we automatically round up instead? */
if (ColorCount != (1 << GifBitSize(ColorCount))) {
return ((ColorMapObject *) NULL);
}
Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
if (Object == (ColorMapObject *) NULL) {
return ((ColorMapObject *) NULL);
}
Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
if (Object->Colors == (GifColorType *) NULL) {
free(Object);
return ((ColorMapObject *) NULL);
}
Object->ColorCount = ColorCount;
Object->BitsPerPixel = GifBitSize(ColorCount);
if (ColorMap != NULL) {
memcpy((char *)Object->Colors,
(char *)ColorMap, ColorCount * sizeof(GifColorType));
}
return (Object);
}
/*******************************************************************************
Free a color map object
*******************************************************************************/
void
GifFreeMapObject(ColorMapObject *Object)
{
if (Object != NULL) {
(void)free(Object->Colors);
(void)free(Object);
}
}
/* #ifdef DEBUG */
#if 0
void
DumpColorMap(ColorMapObject *Object,
FILE * fp)
{
if (Object != NULL) {
int i, j, Len = Object->ColorCount;
for (i = 0; i < Len; i += 4) {
for (j = 0; j < 4 && j < Len; j++) {
(void)fprintf(fp, "%3d: %02x %02x %02x ", i + j,
Object->Colors[i + j].Red,
Object->Colors[i + j].Green,
Object->Colors[i + j].Blue);
}
(void)fprintf(fp, "\n");
}
}
}
#endif /* DEBUG */
/*******************************************************************************
Compute the union of two given color maps and return it. If result can't
fit into 256 colors, NULL is returned, the allocated union otherwise.
ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
copied iff they didn't exist before. ColorTransIn2 maps the old
ColorIn2 into the ColorUnion color map table./
*******************************************************************************/
ColorMapObject *
GifUnionColorMap(const ColorMapObject *ColorIn1,
const ColorMapObject *ColorIn2,
GifPixelType ColorTransIn2[])
{
int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
ColorMapObject *ColorUnion;
/*
* We don't worry about duplicates within either color map; if
* the caller wants to resolve those, he can perform unions
* with an empty color map.
*/
/* Allocate table which will hold the result for sure. */
ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
ColorIn2->ColorCount) * 2, NULL);
if (ColorUnion == NULL)
return (NULL);
/*
* Copy ColorIn1 to ColorUnion.
*/
for (i = 0; i < ColorIn1->ColorCount; i++)
ColorUnion->Colors[i] = ColorIn1->Colors[i];
CrntSlot = ColorIn1->ColorCount;
/*
* Potentially obnoxious hack:
*
* Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
* of table 1. This is very useful if your display is limited to
* 16 colors.
*/
while (ColorIn1->Colors[CrntSlot - 1].Red == 0
&& ColorIn1->Colors[CrntSlot - 1].Green == 0
&& ColorIn1->Colors[CrntSlot - 1].Blue == 0)
CrntSlot--;
/* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
/* Let's see if this color already exists: */
for (j = 0; j < ColorIn1->ColorCount; j++)
if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
sizeof(GifColorType)) == 0)
break;
if (j < ColorIn1->ColorCount)
ColorTransIn2[i] = j; /* color exists in Color1 */
else {
/* Color is new - copy it to a new slot: */
ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
ColorTransIn2[i] = CrntSlot++;
}
}
if (CrntSlot > 256) {
GifFreeMapObject(ColorUnion);
return ((ColorMapObject *) NULL);
}
NewGifBitSize = GifBitSize(CrntSlot);
RoundUpTo = (1 << NewGifBitSize);
if (RoundUpTo != ColorUnion->ColorCount) {
register GifColorType *Map = ColorUnion->Colors;
/*
* Zero out slots up to next power of 2.
* We know these slots exist because of the way ColorUnion's
* start dimension was computed.
*/
for (j = CrntSlot; j < RoundUpTo; j++)
Map[j].Red = Map[j].Green = Map[j].Blue = 0;
/* perhaps we can shrink the map? */
if (RoundUpTo < ColorUnion->ColorCount)
ColorUnion->Colors = (GifColorType *)realloc(Map,
sizeof(GifColorType) * RoundUpTo);
}
ColorUnion->ColorCount = RoundUpTo;
ColorUnion->BitsPerPixel = NewGifBitSize;
return (ColorUnion);
}
/*******************************************************************************
Apply a given color translation to the raster bits of an image
*******************************************************************************/
void
GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
{
register int i;
register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
for (i = 0; i < RasterSize; i++)
Image->RasterBits[i] = Translation[Image->RasterBits[i]];
}
/******************************************************************************
Extension record functions
******************************************************************************/
int
GifAddExtensionBlock(int *ExtensionBlockCount,
ExtensionBlock **ExtensionBlocks,
int Function,
unsigned int Len,
unsigned char ExtData[])
{
ExtensionBlock *ep;
if (*ExtensionBlocks == NULL)
*ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
else
*ExtensionBlocks = (ExtensionBlock *)realloc(*ExtensionBlocks,
sizeof(ExtensionBlock) *
(*ExtensionBlockCount + 1));
if (*ExtensionBlocks == NULL)
return (GIF_ERROR);
ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
ep->Function = Function;
ep->ByteCount=Len;
ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
if (ep->Bytes == NULL)
return (GIF_ERROR);
if (ExtData != NULL) {
memcpy(ep->Bytes, ExtData, Len);
}
return (GIF_OK);
}
void
GifFreeExtensions(int *ExtensionBlockCount,
ExtensionBlock **ExtensionBlocks)
{
ExtensionBlock *ep;
if (*ExtensionBlocks == NULL)
return;
for (ep = *ExtensionBlocks;
ep < (*ExtensionBlocks + *ExtensionBlockCount);
ep++)
(void)free((char *)ep->Bytes);
(void)free((char *)*ExtensionBlocks);
*ExtensionBlocks = NULL;
*ExtensionBlockCount = 0;
}
/******************************************************************************
Image block allocation functions
******************************************************************************/
/* Private Function:
* Frees the last image in the GifFile->SavedImages array
*/
void
FreeLastSavedImage(GifFileType *GifFile)
{
SavedImage *sp;
if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
return;
/* Remove one SavedImage from the GifFile */
GifFile->ImageCount--;
sp = &GifFile->SavedImages[GifFile->ImageCount];
/* Deallocate its Colormap */
if (sp->ImageDesc.ColorMap != NULL) {
GifFreeMapObject(sp->ImageDesc.ColorMap);
sp->ImageDesc.ColorMap = NULL;
}
/* Deallocate the image data */
if (sp->RasterBits != NULL)
free((char *)sp->RasterBits);
/* Deallocate any extensions */
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
/*** FIXME: We could realloc the GifFile->SavedImages structure but is
* there a point to it? Saves some memory but we'd have to do it every
* time. If this is used in GifFreeSavedImages then it would be inefficient
* (The whole array is going to be deallocated.) If we just use it when
* we want to free the last Image it's convenient to do it here.
*/
}
/*
* Append an image block to the SavedImages array
*/
SavedImage *
GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
{
SavedImage *sp;
if (GifFile->SavedImages == NULL)
GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
else
GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
sizeof(SavedImage) * (GifFile->ImageCount + 1));
if (GifFile->SavedImages == NULL)
return ((SavedImage *)NULL);
else {
sp = &GifFile->SavedImages[GifFile->ImageCount++];
memset((char *)sp, '\0', sizeof(SavedImage));
if (CopyFrom != NULL) {
memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
/*
* Make our own allocated copies of the heap fields in the
* copied record. This guards against potential aliasing
* problems.
*/
/* first, the local color map */
if (sp->ImageDesc.ColorMap != NULL) {
sp->ImageDesc.ColorMap = GifMakeMapObject(
CopyFrom->ImageDesc.ColorMap->ColorCount,
CopyFrom->ImageDesc.ColorMap->Colors);
if (sp->ImageDesc.ColorMap == NULL) {
FreeLastSavedImage(GifFile);
return (SavedImage *)(NULL);
}
}
/* next, the raster */
sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
CopyFrom->ImageDesc.Height *
CopyFrom->ImageDesc.Width);
if (sp->RasterBits == NULL) {
FreeLastSavedImage(GifFile);
return (SavedImage *)(NULL);
}
memcpy(sp->RasterBits, CopyFrom->RasterBits,
sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
CopyFrom->ImageDesc.Width);
/* finally, the extension blocks */
if (sp->ExtensionBlocks != NULL) {
sp->ExtensionBlocks = (ExtensionBlock *)malloc(
sizeof(ExtensionBlock) *
CopyFrom->ExtensionBlockCount);
if (sp->ExtensionBlocks == NULL) {
FreeLastSavedImage(GifFile);
return (SavedImage *)(NULL);
}
memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
}
}
return (sp);
}
}
void
GifFreeSavedImages(GifFileType *GifFile)
{
SavedImage *sp;
if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
return;
}
for (sp = GifFile->SavedImages;
sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
if (sp->ImageDesc.ColorMap != NULL) {
GifFreeMapObject(sp->ImageDesc.ColorMap);
sp->ImageDesc.ColorMap = NULL;
}
if (sp->RasterBits != NULL)
free((char *)sp->RasterBits);
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
}
free((char *)GifFile->SavedImages);
GifFile->SavedImages = NULL;
}
/* end */

View file

@ -0,0 +1,44 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (c) 2012 Marcin Bukat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include <tlsf.h>
#undef memset
#define memset(a,b,c) rb->memset((a),(b),(c))
#undef memmove
#define memmove(a,b,c) rb->memmove((a),(b),(c))
#undef memcmp
#define memcmp(a,b,c) rb->memcmp((a),(b),(c))
#undef strncmp
#define strncmp(a,b,c) rb->strncmp((a),(b),(c))
#define fread(ptr, size, nmemb, stream) rb->read(stream, ptr, size*nmemb)
#define fclose(stream) rb->close(stream)
#define fdopen(a,b) ((a))
#define malloc(a) tlsf_malloc((a))
#define free(a) tlsf_free((a))
#define realloc(a, b) tlsf_realloc((a),(b))
#define calloc(a,b) tlsf_calloc((a),(b))
#ifndef SIZE_MAX
#define SIZE_MAX INT_MAX
#endif

View file

@ -28,8 +28,9 @@ static const char *decoder_names[MAX_IMAGE_TYPES] = {
"jpeg",
"png",
#ifdef HAVE_LCD_COLOR
"ppm"
"ppm",
#endif
"gif"
};
/* Check file type by magic number or file extension
@ -53,6 +54,7 @@ enum image_type get_image_type(const char *name, bool quiet)
#ifdef HAVE_LCD_COLOR
{ ".ppm", IMAGE_PPM },
#endif
{ ".gif", IMAGE_GIF },
};
static const struct {
char *magic; /* magic number */
@ -66,6 +68,8 @@ enum image_type get_image_type(const char *name, bool quiet)
{ "P3", 2, IMAGE_PPM },
{ "P6", 2, IMAGE_PPM },
#endif
{ "GIF87a", 6, IMAGE_GIF },
{ "GIF89a", 6, IMAGE_GIF },
};
enum image_type type = IMAGE_UNKNOWN;

View file

@ -32,6 +32,7 @@ enum image_type {
#ifdef HAVE_LCD_COLOR
IMAGE_PPM,
#endif
IMAGE_GIF,
MAX_IMAGE_TYPES
};

View file

@ -550,17 +550,38 @@ static void pan_view_down(struct image_info *info)
/* interactively scroll around the image */
static int scroll_bmp(struct image_info *info)
{
static long ss_timeout = 0;
int button;
#if defined(IMGVIEW_ZOOM_PRE) || defined(IMGVIEW_MENU_PRE)
int lastbutton = BUTTON_NONE;
#endif
if (!ss_timeout && iv_api.slideshow_enabled)
ss_timeout = *rb->current_tick + settings.ss_timeout * HZ;
while (true)
{
if (iv_api.slideshow_enabled)
button = rb->button_get_w_tmo(settings.ss_timeout * HZ);
{
if (info->frames_count > 1 && info->delay &&
settings.ss_timeout * HZ > info->delay)
{
/* animated content and delay between subsequent frames
* is shorter then slideshow delay
*/
button = rb->button_get_w_tmo(info->delay);
}
else
button = rb->button_get_w_tmo(settings.ss_timeout * HZ);
}
else
button = rb->button_get(true);
{
if (info->frames_count > 1 && info->delay)
button = rb->button_get_w_tmo(info->delay);
else
button = rb->button_get(true);
}
iv_api.running_slideshow = false;
@ -595,9 +616,28 @@ static int scroll_bmp(struct image_info *info)
case BUTTON_NONE:
if (iv_api.slideshow_enabled && entries > 1)
{
iv_api.running_slideshow = true;
return change_filename(DIR_NEXT);
if (info->frames_count > 1)
{
/* animations */
if (TIME_AFTER(*rb->current_tick, ss_timeout))
{
iv_api.running_slideshow = true;
ss_timeout = 0;
return change_filename(DIR_NEXT);
}
else
return NEXT_FRAME;
}
else
{
/* still picture */
iv_api.running_slideshow = true;
return change_filename(DIR_NEXT);
}
}
else
return NEXT_FRAME;
break;
#ifdef IMGVIEW_SLIDE_SHOW
@ -838,9 +878,11 @@ static int load_and_show(char* filename, struct image_info *info)
cx = info->x_size/ds/2; /* center the view */
cy = info->y_size/ds/2;
/* used to loop through subimages in animated gifs */
int frame = 0;
do /* loop the image prepare and decoding when zoomed */
{
status = imgdec->get_image(info, ds); /* decode or fetch from cache */
status = imgdec->get_image(info, frame, ds); /* decode or fetch from cache */
if (status == PLUGIN_ERROR)
{
file_pt[curfile] = NULL;
@ -849,7 +891,7 @@ static int load_and_show(char* filename, struct image_info *info)
set_view(info, cx, cy);
if(!iv_api.running_slideshow)
if(!iv_api.running_slideshow && (info->frames_count == 1))
{
rb->lcd_putsf(0, 3, "showing %dx%d", info->width, info->height);
rb->lcd_update();
@ -870,6 +912,7 @@ static int load_and_show(char* filename, struct image_info *info)
while (1)
{
status = scroll_bmp(info);
if (status == ZOOM_IN)
{
if (ds > ds_min || (imgdec->unscaled_avail && ds > 1))
@ -899,16 +942,19 @@ static int load_and_show(char* filename, struct image_info *info)
else
continue;
}
/* next frame in animated content */
if (status == NEXT_FRAME)
frame = (frame + 1)%info->frames_count;
break;
}
#ifdef USEGSLIB
grey_show(false); /* switch off overlay */
#endif
rb->lcd_clear_display();
}
while (status > PLUGIN_OTHER);
#ifdef USEGSLIB
grey_show(false); /* switch off overlay */
rb->lcd_update();
#endif
return status;

View file

@ -58,6 +58,7 @@ enum {
ZOOM_IN,
ZOOM_OUT,
NEXT_FRAME,
};
#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && defined(HAVE_DISK_STORAGE)
@ -82,6 +83,8 @@ struct image_info {
int x_size, y_size; /* set size of loaded image in load_image(). */
int width, height; /* set size of resized image in get_image(). */
int x, y; /* display position */
int frames_count; /* number of subframes */
int delay; /* delay expressed in ticks between frames */
void *data; /* use freely in decoder. not touched in ui. */
};
@ -115,6 +118,7 @@ struct image_decoder {
/* return needed size of buffer to store downscaled image by ds.
* this is used to calculate min downscale. */
int (*img_mem)(int ds);
/* load image from filename. use the passed buffer to store loaded, decoded
* or resized image later, so save it to local variables if needed.
* set width and height of info properly. also, set buf_size to remaining
@ -125,7 +129,8 @@ struct image_decoder {
/* downscale loaded image by ds. use the buffer passed to load_image to
* reszie image and/or store resized image.
* return PLUGIN_ERROR for error. ui will skip to next image. */
int (*get_image)(struct image_info *info, int ds);
int (*get_image)(struct image_info *info, int frame, int ds);
/* draw part of image */
void (*draw_image_rect)(struct image_info *info,
int x, int y, int width, int height);

View file

@ -190,8 +190,9 @@ static int load_image(char *filename, struct image_info *info,
return PLUGIN_OK;
}
static int get_image(struct image_info *info, int ds)
static int get_image(struct image_info *info, int frame, int ds)
{
(void)frame;
int w, h; /* used to center output */
int size; /* decompressed image size */
long time; /* measured ticks */

View file

@ -226,8 +226,9 @@ static int load_image(char *filename, struct image_info *info,
return PLUGIN_OK;
}
static int get_image(struct image_info *info, int ds)
static int get_image(struct image_info *info, int frame, int ds)
{
(void)frame;
unsigned char **p_disp = &disp[ds]; /* short cut */
LodePNG_Decoder *p_decoder = &decoder;

View file

@ -150,8 +150,9 @@ static int load_image(char *filename, struct image_info *info,
return PLUGIN_OK;
}
static int get_image(struct image_info *info, int ds)
static int get_image(struct image_info *info, int frame, int ds)
{
(void)frame;
unsigned char **p_disp = &disp[ds]; /* short cut */
struct ppm_info *p_ppm = &ppm;

View file

@ -23,6 +23,7 @@ png,viewers/imageviewer,2
#ifdef HAVE_LCD_COLOR
ppm,viewers/imageviewer,2
#endif
gif,viewers/imageviewer,2
ucl,viewers/rockbox_flash,3
rvf,viewers/video,4
mp3,viewers/vbrfix,5