📄 gif.c
字号:
if ((gif->last_code & code_mask) == 0) { if (gif->last_code == (1 << MAX_LWZ_BITS)) gif->last_code--; else { code_size++; code_mask = (1 << code_size) - 1; } } break; case 0: /* Reset codes size and mask */ gif->last_code = clear_code + 1; code_size = gif->input_code_size + 1; code_mask = (1 << code_size) - 1; break; case 2: /* End code... consume remaining data chunks..? */#ifdef ENABLE_ANIMATION gif->state = 2; gif->new_frame->filled = 1; return bsize - bufsize + 1;#else goto error;#endif default: MSG("dillo_gif_decode: error!\n"); goto error; } } } /* We reach here if * a) We have reached the end of the data block; * b) we ran out of data before reaching the end of the data block */ if (bufsize <= 0) break; /* We are out of data; */ /* Start of new data block */ bufsize--; if (!(packet_size = *buf++)) { /* This is the "block terminator" -- the last data block */ gif->state = 999; /* BUG: should Go back to getting GIF blocks. */ break; } } gif->packet_size = packet_size; gif->window = window; gif->bits_in_window = bits_in_window; gif->code_size = code_size; return bsize - bufsize; error: gif->state = 999; return bsize - bufsize;}/* * ? */static gint Gif_check_sig(DilloGif *gif, const guchar *ibuf, gint ibsize){ /* at beginning of file - read magic number */ if (ibsize < 6) return 0; if (strncmp(ibuf, "GIF", 3) != 0) { gif->state = 999; return 6; } if (strncmp(ibuf + 3, "87a", 3) != 0 && strncmp(ibuf + 3, "89a", 3) != 0) { gif->state = 999; return 6; } gif->state = 1; return 6;}/* Read the color map * * Implements, from the spec: * Global Color Table * Local Color Table */static inline size_t Gif_do_color_table(DilloGif *gif, void *Buf, const guchar *buf, size_t bsize, size_t CT_Size){ size_t Size = 3 * (1 << (1 + CT_Size)); if (Size > bsize) return 0; gif->ColorMap_ofs = (gulong) buf - (gulong) Buf; gif->NumColors = (1 << (1 + CT_Size)); return Size;}/* * This implements, from the spec: * <Logical Screen> ::= Logical Screen Descriptor [Global Color Table] */static size_t Gif_get_descriptor(DilloGif *gif, void *Buf, const guchar *buf, gint bsize){ /* screen descriptor */ size_t Size = 7, /* Size of descriptor */ mysize; /* Size of color table */ guchar Flags; if (bsize < 7) return 0; Flags = buf[4]; if (Flags & LOCALCOLORMAP) { mysize = Gif_do_color_table( gif, Buf, buf + 7, (size_t)bsize - 7, Flags & (size_t)0x7); if (!mysize) return 0; Size += mysize; /* Size of the color table that follows */ gif->Background = buf[5]; } gif->ColorResolution = (((buf[4] & 0x70) >> 3) + 1);#ifdef ENABLE_ANIMATION gif->Width = LM_to_uint(buf[0], buf[1]); gif->Height = LM_to_uint(buf[2], buf[3]); gif->AspectRatio = buf[6]; a_Dicache_set_parms(gif->url, gif->version, gif->Image, gif->Width, gif->Height, DILLO_IMG_TYPE_INDEXED);#endif return Size;}/* * This implements, from the spec: * <Table-Based Image> ::= Image Descriptor [Local Color Table] Image Data * * ('Buf' points to just after the Image separator) * we should probably just check that the local stuff is consistent * with the stuff at the header. For now, we punt... */static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, const guchar *buf, size_t bsize){ guchar Flags; size_t Size = 9 + 1; /* image descriptor size + first byte of image data */ if (bsize < 10) return 0; gif->Left = LM_to_uint(buf[0], buf[1]); gif->Top = LM_to_uint(buf[2], buf[3]); gif->Width = LM_to_uint(buf[4], buf[5]); gif->Height = LM_to_uint(buf[6], buf[7]);#ifdef ENABLE_ANIMATION gif->linebuf = g_realloc (gif->linebuf, gif->Width);#else gif->linebuf = g_malloc(gif->Width);#endif Flags = buf[8]; gif->Flags |= Flags & INTERLACE; gif->pass = 0; bsize -= 9; buf += 9; if (Flags & LOCALCOLORMAP) { size_t LSize = Gif_do_color_table( gif, Buf, buf, bsize, Flags & (size_t)0x7); if (!LSize) return 0; Size += LSize; buf += LSize; bsize -= LSize; } /* Finally, get the first byte of the LZW image data */ if (bsize < 1) return 0; gif->input_code_size = *buf++; if (gif->input_code_size > 8) { gif->state = 999; return Size; } gif->y = 0; Gif_lwz_init(gif); gif->spill_line_index = 0; gif->state = 3; /*Process the lzw data next */ if (gif->Image && gif->ColorMap_ofs#ifdef ENABLE_ANIMATION && gif->Image->dw->nr_frames == 0#endif ) { a_Dicache_set_cmap(gif->url, gif->version, gif->Image, (guchar *) Buf + gif->ColorMap_ofs, gif->NumColors, 256, gif->transparent); } return Size;}/* --- Top level data block processors ------------------------------------ */#define Img_Desc (0x2c)#define Trailer (0x3B)#define Ext_Id (0x21)#define CH_Null (0x00)/* * This identifies which kind of GIF blocks are next, and processes them. * It returns if there isn't enough data to process the next blocks, or if * the next block is the lzw data (which is streamed differently) * * This implements, from the spec, <Data>* Trailer * <Data> ::= <Graphic Block> | <Special-Purpose Block> * <Special-Purpose Block> ::= Application Extension | Comment Extension * <Graphic Block> ::= [Graphic Control Extension] <Graphic-Rendering Block> * <Graphic-Rendering Block> ::= <Table-Based Image> | Plain Text Extension * * <Data>* --> GIF_Block * <Data> --> while (...) * <Special-Purpose Block> --> Gif_do_extension * Graphic Control Extension --> Gif_do_extension * Plain Text Extension --> Gif_do_extension * <Table-Based Image> --> Gif_do_img_desc * * Return Value * 0 if not enough data is present, otherwise the number of bytes * "consumed" */static size_t GIF_Block(DilloGif * gif, void *Buf, const guchar *buf, size_t bsize){ size_t Size = 0, mysize; guchar C; if (bsize < 1) return 0; while (gif->state == 2) { if (bsize < 1) return Size; bsize--; switch (*buf++) { case Ext_Id: /* ! */ /* get the extension type */ if (bsize < 2) return Size; /* Have the extension block intepreted. */ C = *buf++; bsize--; mysize = Gif_do_extension(gif, C, buf, bsize); if (!mysize) /* Not all of the extension is there.. quit until more data * arrives */ return Size; bsize -= mysize; buf += mysize; /* Increment the amount consumed by the extension introducer * and id, and extension block size */ Size += mysize + 2;#ifdef ENABLE_ANIMATION /* fmsoft code followed */ gif->Image->dw->transparent = gif->transparent;#endif /* Do more GIF Blocks */ continue; case Img_Desc: /* Image descriptor: , */ mysize = Gif_do_img_desc(gif, Buf, buf, bsize); if (!mysize) return Size; /* Increment the amount consumed by the Image Separator and the * Resultant blocks */ Size += 1 + mysize; return Size; case Trailer: gif->state = 4; /* BUG: should close the rest of the file */ return Size + 1; break; /* GIF terminator */ case CH_Null: return Size + 1; default: /* Unknown */ /* gripe and complain */ _MSG ("gif.c::GIF_Block: Error, %s, 0x%x found\n", gif->url->url_string->str, *buf); gif->state = 999; return Size + 1; } } return Size;}#ifdef ENABLE_ANIMATIONstatic gint create_frame (DilloGif* gif){ AnimationFrame* frame; DwImage* gif_dw = gif->Image->dw; frame = g_malloc (sizeof(AnimationFrame)); if (!frame) return -1; else { frame->next = NULL; frame->disposal = gif->disposal; frame->off_x = gif->Left; frame->off_y = gif->Top; frame->width = gif->Width; frame->height = gif->Height; frame->delay_time = (gif->delayTime > 0)?gif->delayTime:10; frame->bits = g_malloc (frame->width * frame->height); frame->filled = 0; DEBUG_MSG (5, "New frame information:\n" " disposal: %d; \n" " left, top: %d, %d; \n" " width, height: %d, %d; \n" " delay_time: %d.\n", gif->disposal, gif->Left, gif->Top, gif->Width, gif->Height, gif->delayTime); } frame->prev = gif->new_frame; /* add this frame to the frame list */ if (NULL == gif_dw->frames) { gif_dw->frames = frame; } else { gif->new_frame->next = frame; } gif->new_frame = frame; gif_dw->nr_frames++; return gif_dw->nr_frames;}#endif/* * Process some bytes from the input gif stream. It's a state machine. * * From the GIF spec: * <GIF Data Stream> ::= Header <Logical Screen> <Data>* Trailer * * <GIF Data Stream> --> Gif_process_bytes * Header --> State 0 * <Logical Screen> --> State 1 * <Data>* --> State 2 * Trailer --> State > 3 * * State == 3 is special... this is inside of <Data> but all of the stuff in * there has been gotten and set up. So we stream it outside. */static size_t Gif_process_bytes(DilloGif *gif, const guchar *ibuf, gint bufsize, void *Buf){ gint tmp_bufsize = bufsize; size_t mysize; switch (gif->state) { case 0: mysize = Gif_check_sig(gif, ibuf, tmp_bufsize); if (!mysize) break; tmp_bufsize -= mysize; ibuf += mysize; if (gif->state != 1) break; case 1: mysize = Gif_get_descriptor(gif, Buf, ibuf, tmp_bufsize); if (!mysize) break; tmp_bufsize -= mysize; ibuf += mysize; gif->state = 2;#ifdef ENABLE_ANIMATION /* fmsoft code followed */ gif->Image->dw->bkcolor = gif->Background;#endif case 2: /* Ok, this loop construction looks weird. It implements the <Data>* of * the GIF grammar. All sorts of stuff is allocated to set up for the * decode part (state ==2) and then there is the actual decode part (3) */ mysize = GIF_Block(gif, Buf, ibuf, (size_t)tmp_bufsize); if (!mysize) break; tmp_bufsize -= mysize; ibuf += mysize; if (gif->state != 3) break;#ifdef ENABLE_ANIMATION /* fmsoft code followed */ create_frame (gif);#endif case 3: /* get an image byte */ /* The users sees all of this stuff */ mysize = Gif_decode(gif, ibuf, (size_t)tmp_bufsize); if (mysize == 0) { break; } ibuf += mysize; tmp_bufsize -= mysize;#ifdef ENABLE_ANIMATION /* fmsoft code followed */ if (gif->state == 2) break;#endif default: /* error - just consume all input */ tmp_bufsize = 0; break; } DEBUG_MSG(5, "Gif_process_bytes: final state %d, %ld bytes consumed\n", gif->state, (glong)(bufsize - tmp_bufsize)); return bufsize - tmp_bufsize;}#endif /* ENABLE_GIF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -