⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gif.c

📁 嵌入式下基于MiniGUI的Web Browser
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * File: gif.c * * Copyright (C) 1997 Raph Levien <raph@acm.org> * Copyright (C) 2000-2002 Jorge Arellano Cid <jcid@dillo.org> * * 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. *//* * The GIF decoder for dillo. It is responsible for decoding GIF data * and transferring it to the dicache. *//* Notes 13 Oct 1997 --RLL * * Today, just for the hell of it, I implemented a new decoder from * scratch. It's oriented around pushing bytes, while the old decoder * was based around reads which may suspend. There were basically * three motivations. * * 1. To increase the speed. * * 2. To fix some bugs I had seen, most likely due to suspension. * * 3. To make sure that the code had no buffer overruns or the like. * * 4. So that the code could be released under a freer license. * * Let's see how we did on speed. I used a large image for testing * (fvwm95-2.gif). * * The old decoder spent a total of about 1.04 seconds decoding the * image. Another .58 seconds went into Image_line, almost * entirely conversion from colormap to RGB. * * The new decoder spent a total of 0.46 seconds decoding the image. * However, the time for Image_line went up to 1.01 seconds. * Thus, even though the decoder seems to be about twice as fast, * the net gain is pretty minimal. Could this be because of cache * effects? * * Lessons learned: The first, which I keep learning over and over, is * not to try to optimize too much. It doesn't work. Just keep things * simple. * * Second, it seems that the colormap to RGB conversion is really a * significant part of the overall time. It's possible that going * directly to 16 bits would help, but that's optimization again :) *//* todo: * + Make sure to handle error cases gracefully (including aborting the * connection, if necessary). */#include <mgdconfig.h>#ifdef ENABLE_GIF#include <stdio.h>              /* for sprintf */#include <string.h>             /* for memcpy and memmove */#include <glib.h>#include "msg.h"#include "image.h"#include "web.h"#include "cache.h"#include "dicache.h"#include "prefs.h"#define DEBUG_LEVEL 6#include "debug.h"#define INTERLACE      0x40#define LOCALCOLORMAP  0x80#define LM_to_uint(a,b)   ((((guchar)b)<<8)|((guchar)a))#define        MAXCOLORMAPSIZE         256#define        MAX_LWZ_BITS            12typedef struct _DilloGif {   DilloImage *Image;   DilloUrl *url;   gint version;   gint state;   size_t Start_Ofs;   guint Flags;   guchar input_code_size;   guchar *linebuf;   gint pass;   guint y;   /* state for lwz_read_byte */   gint code_size;   /* The original GifScreen from giftopnm */   guint Top;   guint Left;   guint Width;   guint Height;   size_t ColorMap_ofs;   guint ColorResolution;   guint NumColors;   gint Background;   guint spill_line_index;#ifdef ENABLE_ANIMATION   guint AspectRatio;#endif   /* Gif89 extensions */   gint transparent;#ifdef ENABLE_ANIMATION   /* None are used: */   gint delayTime;   gint inputFlag;   gint disposal;   guint time_unit;#endif   /* state for the new push-oriented decoder */   gint packet_size;       /* The amount of the data block left to process */   guint window;   gint bits_in_window;   guint last_code;        /* Last "compressed" code in the look up table */   guint line_index;   guchar **spill_lines;   gint num_spill_lines_max;   gint length[(1 << MAX_LWZ_BITS) + 1];   gint code_and_byte[(1 << MAX_LWZ_BITS) + 1];#ifdef ENABLE_ANIMATION   AnimationFrame* new_frame;#endif} DilloGif;/* Some invariants: * * last_code <= code_mask * * code_and_byte is stored packed: (code << 8) | byte *//* * Forward declarations */static void Gif_write(DilloGif *gif, void *Buf, guint BufSize);static void Gif_close(DilloGif *gif, CacheClient_t *Client);static size_t Gif_process_bytes(DilloGif *gif, const guchar *buf,                                gint bufsize, void *Buf);static DilloGif *Gif_new(DilloImage *Image, DilloUrl *url, gint version);static void Gif_callback(int Op, CacheClient_t *Client);/* exported function */DwWidget *a_Gif_image(const char *Type, void *Ptr, CA_Callback_t *Call,                      void **Data);/* * MIME handler for "image/gif" type * (Sets Gif_callback as cache-client) */DwWidget *a_Gif_image(const char *Type, void *Ptr, CA_Callback_t *Call,                      void **Data){   DilloWeb *web = Ptr;   DICacheEntry *DicEntry;   if ( !web->Image )      web->Image = a_Image_new(0, 0, NULL, prefs.bg_color);      /* todo: get the backgound color from the parent widget -- Livio. */   /* Add an extra reference to the Image (for dicache usage) */   a_Image_ref(web->Image);   DicEntry = a_Dicache_get_entry(web->url);   if ( !DicEntry ) {      /* Let's create an entry for this image... */      DicEntry = a_Dicache_add_entry(web->url);      /* ... and let the decoder feed it! */      *Data = Gif_new(web->Image, DicEntry->url, DicEntry->version);      *Call = (CA_Callback_t) Gif_callback;   } else {      /* Let's feed our client from the dicache */      a_Dicache_ref(DicEntry->url, DicEntry->version);      *Data = web->Image;      *Call = (CA_Callback_t) a_Dicache_callback;   }   return DW_WIDGET (web->Image->dw);}/* * Create a new gif structure for decoding a gif into a RGB buffer */static DilloGif *Gif_new(DilloImage *Image, DilloUrl *url, gint version){   DilloGif *gif = g_malloc(sizeof(DilloGif));   gif->Image = Image;   gif->url = url;   gif->version = version;   gif->Flags = 0;   gif->state = 0;   gif->Start_Ofs = 0;   gif->linebuf = NULL;   gif->Background = -1;   gif->transparent = -1;   gif->num_spill_lines_max = 0;   gif->spill_lines = NULL;   gif->window = 0;   gif->packet_size = 0;   gif->ColorMap_ofs = 0;   #ifdef ENABLE_ANIMATION   gif->delayTime = -1;   gif->inputFlag = -1;   gif->disposal = -1;   gif->time_unit = 10;   gif->new_frame = NULL;#endif   return gif;}/* * This function is a cache client, it receives data from the cache * and dispatches it to the appropriate gif-processing functions */static void Gif_callback(int Op, CacheClient_t *Client){   if ( Op )      Gif_close(Client->CbData, Client);   else      Gif_write(Client->CbData, Client->Buf, Client->BufSize);}#ifdef ENABLE_ANIMATIONstatic void restore_bk_color (DwImage* dw, AnimationFrame* frame){    gint w, h, i, pitch = dw->width * 3;    guchar* dst_row = dw->buffer + pitch * frame->off_y + 3 * frame->off_x;    guchar* pixel;    if (dw->transparent < 0)        return;    DEBUG_MSG (5, "restore the bk color: %d, %d, %d, %d\n",                    frame->off_x, frame->off_y, frame->width, frame->height);    i = dw->transparent * 3;    for (h = 0; h < frame->height; h++) {        pixel = dst_row;        for (w = 0; w < frame->width; w++) {            pixel [0] = dw->cmap [i];            pixel [1] = dw->cmap [i + 1];            pixel [2] = dw->cmap [i + 2];            pixel += 3;        }        dst_row += pitch;    }}static void fill_frame (DwImage* dw, AnimationFrame* frame){    gint w, h, dst_pitch;    guchar *src_row, *dst_row, *dst_pixel;    if (frame == NULL || frame->filled == 0)        return;    DEBUG_MSG (5, "fill frame: %d, %d, %d, %d\n",                    frame->off_x, frame->off_y, frame->width, frame->height);    dst_pitch = dw->width * 3;    src_row = frame->bits;    dst_row = dw->buffer + dst_pitch * frame->off_y + frame->off_x * 3;    for (h = 0; h < frame->height; h++) {        dst_pixel = dst_row;        for (w = 0; w < frame->width; w++) {            if (src_row [w] != dw->transparent) {                gint i = src_row[w] * 3;                dst_pixel [0] = dw->cmap [i];                dst_pixel [1] = dw->cmap [i + 1];                dst_pixel [2] = dw->cmap [i + 2];            }            dst_pixel += 3;        }        src_row += frame->width;        dst_row += dst_pitch;    }}static void anim_treat_frame_disposal (DwImage* dw, AnimationFrame* frame){    int disposal = -1;    if (frame)        disposal = frame->disposal;    switch(disposal) {    case 2:        restore_bk_color (dw, frame);        break;    case 3:        fill_frame (dw, frame->prev);        break;    default:        /* no nothing */        break;    }}static gint Gif_play_frames (DwImage* dw){    DwWidget *widget;    gint delay_time = -1;    if (dw->current_frame)        delay_time = dw->current_frame->delay_time;    dw->elapsed_10ms++;    if (delay_time > 0 && dw->elapsed_10ms >= delay_time) {        if (dw->done_frame)            anim_treat_frame_disposal (dw, dw->done_frame);        if (!dw->current_frame->next)            dw->current_frame = dw->frames;        else            dw->current_frame = dw->current_frame->next;        fill_frame (dw, dw->current_frame);        dw->done_frame = dw->current_frame;        dw->elapsed_10ms = 0;        widget = DW_WIDGET(dw);        p_Dw_widget_queue_draw_area (widget,                     0,                     0 + p_Dw_style_box_offset_y(widget->style),                    dw->width, dw->height);    }    return 1;}#endif/* * Receive and process new chunks of GIF image data */static void Gif_write(DilloGif *gif, void *Buf, guint BufSize){   guchar *buf;   gint bufsize, bytes_consumed;   /* Sanity checks */   if (!Buf || !gif->Image || BufSize == 0)      return;   DEBUG_MSG(5, "Gif_write: %u bytes\n", BufSize);#ifdef ENABLE_ANIMATION   do {#endif             buf = ((guchar *) Buf) + gif->Start_Ofs;      bufsize = BufSize - gif->Start_Ofs;      /* Process the bytes in the input buffer. */      bytes_consumed = Gif_process_bytes(gif, buf, bufsize, Buf);      if (bytes_consumed < 1)#ifdef ENABLE_ANIMATION         break;#else        return;#endif      gif->Start_Ofs += bytes_consumed;#ifdef ENABLE_ANIMATION   } while (TRUE);   DEBUG_MSG(5, "Gif info: frame = %d\n", gif->Image->dw->nr_frames);   if (!gif->Image->dw->timer &&      gif->Image->dw->frames &&      gif->Image->dw->frames->next) {            DEBUG_MSG(5, "Add a timer to play the animation: %d\n",                       gif->Image->dw->nr_frames);      gif->Image->dw->current_frame = gif->Image->dw->frames;      gif->Image->dw->timer = g_timeout_add_full          (G_PRIORITY_DEFAULT+1, 5, (GSourceFunc)Gif_play_frames,            gif->Image->dw, NULL);   }#endif   DEBUG_MSG(5, "exit Gif_write, bufsize=%ld\n", (glong)bufsize);}/* * Finish the decoding process (and free the memory) */static void Gif_close(DilloGif *gif, CacheClient_t *Client){   gint i;   DEBUG_MSG(5, "destroy gif %p\n", gif);#ifdef ENABLE_ANIMATION   if (gif->Image->dw->nr_frames > 1) {      /* force to reload the Gif89a animation file */      a_Dicache_invalidate_entry(gif->url);   }#endif   a_Dicache_close(gif->url, gif->version, Client);   g_free(gif->linebuf);   if (gif->spill_lines != NULL) {      for (i = 0; i < gif->num_spill_lines_max; i++)         g_free(gif->spill_lines[i]);      g_free(gif->spill_lines);   }   g_free(gif);}/* --- GIF Extensions ----------------------------------------------------- *//* * This reads a sequence of GIF data blocks.. and ignores them! * Buf points to the first data block. *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -