📄 gif.c
字号:
* Return Value * 0 = There wasn't enough bytes read yet to read the whole datablock * otherwise the size of the data blocks */static inline size_t Gif_data_blocks(const guchar *Buf, size_t BSize){ size_t Size = 0; if (BSize < 1) return 0; while (Buf[0]) { if (BSize <= (size_t)(Buf[0] + 1)) return 0; Size += Buf[0] + 1; BSize -= Buf[0] + 1; Buf += Buf[0] + 1; } return Size + 1;}/* * This is a GIF extension. We ignore it with this routine. * Buffer points to just after the extension label. * * Return Value * 0 -- block not processed * otherwise the size of the extension label. */static inline size_t Gif_do_generic_ext(const guchar *Buf, size_t BSize){ size_t Size = Buf[0] + 1, DSize; /* The Block size (the first byte) is supposed to be a specific size * for each extension... we don't check. */ if (Buf[0] > BSize) return 0; DSize = Gif_data_blocks(Buf + Size, BSize - Size); if (!DSize) return 0; Size += DSize; return Size <= BSize ? Size : 0;}/* * ? */static inline size_t Gif_do_gc_ext(DilloGif *gif, const guchar *Buf, size_t BSize){ /* Graphic Control Extension */ size_t Size = Buf[0] + 2; guint Flags; if (Size > BSize) return 0; Buf++; Flags = Buf[0];#ifdef ENABLE_ANIMATION /* The packed fields */ gif->disposal = (Buf[0] >> 2) & 0x7; gif->inputFlag = (Buf[0] >> 1) & 0x1; /* Delay time */ gif->delayTime = LM_to_uint(Buf[1], Buf[2]);#endif /* Transparent color index, may not be valid (unless flag is set) */ if ((Flags & 0x1)) { gif->transparent = Buf[3]; } return Size;}#define App_Ext (0xff)#define Cmt_Ext (0xfe)#define GC_Ext (0xf9)#define Txt_Ext (0x01)/* * ? * Return value: * TRUE when the extension is over */static size_t Gif_do_extension(DilloGif *gif, guint Label, const guchar *buf, size_t BSize){ switch (Label) { case GC_Ext: /* Graphics extension */ return Gif_do_gc_ext(gif, buf, BSize); case Cmt_Ext: /* Comment extension */ return Gif_data_blocks(buf, BSize); case Txt_Ext: /* Plain text Extension */ /* This extension allows (rcm thinks) the image to be rendered as text. */ case App_Ext: /* Application Extension */ default: return Gif_do_generic_ext(buf, BSize); /*Ignore Extension */ }}/* --- General Image Decoder ----------------------------------------------- *//* Here begins the new push-oriented decoder. *//* * ? */static void Gif_lwz_init(DilloGif *gif){#ifdef ENABLE_ANIMATION if (gif->spill_lines != NULL) { gint i; for (i = 0; i < gif->num_spill_lines_max; i++) g_free (gif->spill_lines[i]); g_free (gif->spill_lines); }#endif gif->num_spill_lines_max = 1; gif->spill_lines = g_malloc (sizeof(guchar *) * gif->num_spill_lines_max); gif->spill_lines[0] = g_malloc (gif->Width); gif->bits_in_window = 0; /* First code in table = clear_code +1 * Last code in table = first code in table * clear_code = (1<< input code size) */ gif->last_code = (1 << gif->input_code_size) + 1; memset(gif->code_and_byte, 0, (1 + gif->last_code) * sizeof(gif->code_and_byte[0])); gif->code_size = gif->input_code_size + 1; gif->line_index = 0;#ifdef ENABLE_ANIMATION gif->packet_size = 0; gif->window = 0;#endif}/* * Send the image line to the dicache, also handling the interlacing. */static void Gif_emit_line(DilloGif *gif, const guchar *linebuf){#ifdef ENABLE_ANIMATION if (gif->new_frame) { memcpy (gif->new_frame->bits + gif->new_frame->width * gif->y, linebuf, gif->new_frame->width); } if (gif->Image->dw->nr_frames < 2) { a_Dicache_write(gif->Image, gif->url, gif->version, linebuf, 0, gif->y); }#else a_Dicache_write(gif->Image, gif->url, gif->version, linebuf, 0, gif->y);#endif if (gif->Flags & INTERLACE) { switch (gif->pass) { case 0: case 1: gif->y += 8; break; case 2: gif->y += 4; break; case 3: gif->y += 2; break; } if (gif->y >= gif->Height) { gif->pass++; switch (gif->pass) { case 1: gif->y = 4; break; case 2: gif->y = 2; break; case 3: gif->y = 1; break; default: /* arriving here is an error in the input image. */ gif->y = 0; break; } } } else { if (gif->y < gif->Height) gif->y++; }}/* * I apologize for the large size of this routine and the goto error * construct - I almost _never_ do that. I offer the excuse of * optimizing for speed. * * RCM -- busted these down into smaller subroutines... still very hard to * read. *//* * Decode the packetized lwz bytes */static void Gif_literal(DilloGif *gif, guint code){ gif->linebuf[gif->line_index++] = code; if (gif->line_index >= gif->Width) { Gif_emit_line(gif, gif->linebuf); gif->line_index = 0; } gif->length[gif->last_code + 1] = 2; gif->code_and_byte[gif->last_code + 1] = (code << 8); gif->code_and_byte[gif->last_code] |= code;}/* * ? *//* Profiling reveals over half the GIF time is spent here: */static void Gif_sequence(DilloGif *gif, guint code){ guint o_index, o_size, orig_code; guint sequence_length = gif->length[code]; guint line_index = gif->line_index; gint num_spill_lines; gint spill_line_index = gif->spill_line_index; guchar *last_byte_ptr, *obuf; gif->length[gif->last_code + 1] = sequence_length + 1; gif->code_and_byte[gif->last_code + 1] = (code << 8); /* We're going to traverse the sequence backwards. Thus, * we need to allocate spill lines if the sequence won't * fit entirely within the present scan line. */ if (line_index + sequence_length <= gif->Width) { num_spill_lines = 0; obuf = gif->linebuf; o_index = line_index + sequence_length; o_size = sequence_length - 1; } else { num_spill_lines = (line_index + sequence_length - 1) / gif->Width; o_index = (line_index + sequence_length - 1) % gif->Width + 1; if (num_spill_lines > gif->num_spill_lines_max) { /* Allocate more spill lines. */ spill_line_index = gif->num_spill_lines_max; gif->num_spill_lines_max = num_spill_lines << 1; gif->spill_lines = g_realloc(gif->spill_lines, gif->num_spill_lines_max * sizeof(guchar *)); for (; spill_line_index < gif->num_spill_lines_max; spill_line_index++) gif->spill_lines[spill_line_index] = g_malloc(gif->Width); } spill_line_index = num_spill_lines - 1; obuf = gif->spill_lines[spill_line_index]; o_size = o_index; } gif->line_index = o_index; /* for afterwards */ /* for fixing up later if last_code == code */ orig_code = code; last_byte_ptr = obuf + o_index - 1; /* spill lines are allocated, and we are clear to * write. This loop does not write the first byte of * the sequence, however (last byte traversed). */ while (sequence_length > 1) { sequence_length -= o_size; /* Write o_size bytes to * obuf[o_index - o_size..o_index). */ for (; o_size > 0 && o_index > 0; o_size--) { guint code_and_byte = gif->code_and_byte[code]; DEBUG_MSG(5, "%d ", gif->code_and_byte[code] & 255); obuf[--o_index] = code_and_byte & 255; code = code_and_byte >> 8; } /* Prepare for writing to next line. */ if (o_index == 0) { if (spill_line_index > 0) { spill_line_index--; obuf = gif->spill_lines[spill_line_index]; o_size = gif->Width; } else { obuf = gif->linebuf; o_size = sequence_length - 1; } o_index = gif->Width; } } /* Ok, now we write the first byte of the sequence. */ /* We are sure that the code is literal. */ DEBUG_MSG(5, "%d", code); obuf[--o_index] = code; gif->code_and_byte[gif->last_code] |= code; /* Fix up the output if the original code was last_code. */ if (orig_code == gif->last_code) { *last_byte_ptr = code; DEBUG_MSG(5, " fixed (%d)!", code); } DEBUG_MSG(5, "\n"); /* Output any full lines. */ if (gif->line_index >= gif->Width) { Gif_emit_line(gif, gif->linebuf); gif->line_index = 0; } if (num_spill_lines) { if (gif->line_index) Gif_emit_line(gif, gif->linebuf); for (spill_line_index = 0; spill_line_index < num_spill_lines - (gif->line_index ? 1 : 0); spill_line_index++) Gif_emit_line(gif, gif->spill_lines[spill_line_index]); } if (num_spill_lines) { /* Swap the last spill line with the gif line, using * linebuf as the swap temporary. */ guchar *linebuf = gif->spill_lines[num_spill_lines - 1]; gif->spill_lines[num_spill_lines - 1] = gif->linebuf; gif->linebuf = linebuf; } gif->spill_line_index = spill_line_index;}/* * ? * * Return Value: * 2 -- quit * 1 -- new last code needs to be done * 0 -- okay, but reset the code table * < 0 on error * -1 if the decompression code was not in the lookup table */static gint Gif_process_code(DilloGif *gif, guint code, guint clear_code){ /* A short table describing what to do with the code: * code < clear_code : This is uncompressed, raw data * code== clear_code : Reset the decompression table * code== clear_code+1: End of data stream * code > clear_code+1: Compressed code; look up in table */ if (code < clear_code) { /* a literal code. */ DEBUG_MSG(5, "literal\n"); Gif_literal(gif, code); return 1; } else if (code >= clear_code + 2) { /* a sequence code. */ if (code > gif->last_code) return -1; Gif_sequence(gif, code); return 1; } else if (code == clear_code) { /* clear code. Resets the whole table */ DEBUG_MSG(5, "clear\n"); return 0; } else { /* end code. */ DEBUG_MSG(5, "end\n"); return 2; }}/* * ? */static gint Gif_decode(DilloGif *gif, const guchar *buf, size_t bsize){ /* * Data block processing. The image stuff is a series of data blocks. * Each data block is 1 to 256 bytes long. The first byte is the length * of the data block. 0 == the last data block. */ size_t bufsize, packet_size; guint clear_code; guint window; gint bits_in_window; guint code; gint code_size; guint code_mask; bufsize = bsize; /* Want to get all inner loop state into local variables. */ packet_size = gif->packet_size; window = gif->window; bits_in_window = gif->bits_in_window; code_size = gif->code_size; code_mask = (1 << code_size) - 1; clear_code = 1 << gif->input_code_size; /* If packet size == 0, we are at the start of a data block. * The first byte of the data block indicates how big it is (0 == last * datablock) * packet size is set to this size; it indicates how much of the data block * we have left to process. */ while (bufsize > 0) { /* lwz_bytes is the number of remaining lwz bytes in the packet. */ gint lwz_bytes = MIN(packet_size, bufsize); bufsize -= lwz_bytes; packet_size -= lwz_bytes; for (; lwz_bytes > 0; lwz_bytes--) { /* printf ("%d ", *buf) would print the depacketized lwz stream. */ /* Push the byte onto the "end" of the window (MSB). The low order * bits always come first in the LZW stream. */ window = (window >> 8) | (*buf++ << 24); bits_in_window += 8; while (bits_in_window >= code_size) { /* Extract the code. The code is code_size (3 to 12) bits long, * at the start of the window */ code = (window >> (32 - bits_in_window)) & code_mask; DEBUG_MSG(5, "code = %d, clear_code = %d", code, clear_code); bits_in_window -= code_size; switch (Gif_process_code(gif, code, clear_code)) { case 1: /* Increment last code */ gif->last_code++; /*gif->code_and_byte[gif->last_code+1]=0; */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -