Pillow
378 строк · 12.3 Кб
1/*
2* The Python Imaging Library.
3* $Id$
4*
5* encoder for uncompressed GIF data
6*
7* history:
8* 97-01-05 fl created (writes uncompressed data)
9* 97-08-27 fl fixed off-by-one error in buffer size test
10* 98-07-09 fl added interlace write support
11* 99-02-07 fl rewritten, now uses a run-length encoding strategy
12* 99-02-08 fl improved run-length encoding for long runs
13* 2020-12-12 rdg Reworked for LZW compression.
14*
15* Copyright (c) Secret Labs AB 1997-99.
16* Copyright (c) Fredrik Lundh 1997.
17*
18* See the README file for information on usage and redistribution.
19*/
20
21#include "Imaging.h"22
23#include "Gif.h"24
25enum { INIT, ENCODE, FINISH };26
27/* GIF LZW encoder by Raymond Gardner. */
28/* Released here under PIL license. */
29
30/* This LZW encoder conforms to the GIF LZW format specified in the original
31* Compuserve GIF 87a and GIF 89a specifications (see e.g.
32* https://www.w3.org/Graphics/GIF/spec-gif87.txt Appendix C and
33* https://www.w3.org/Graphics/GIF/spec-gif89a.txt Appendix F).
34*/
35
36/* Return values */
37#define GLZW_OK 038#define GLZW_NO_INPUT_AVAIL 139#define GLZW_NO_OUTPUT_AVAIL 240#define GLZW_INTERNAL_ERROR 341
42#define CODE_LIMIT 409643
44/* Values of entry_state */
45enum {46LZW_INITIAL,47LZW_TRY_IN1,48LZW_TRY_IN2,49LZW_TRY_OUT1,50LZW_TRY_OUT2,51LZW_FINISHED
52};53
54/* Values of control_state */
55enum { PUT_HEAD, PUT_INIT_CLEAR, PUT_CLEAR, PUT_LAST_HEAD, PUT_END };56
57static void58glzwe_reset(GIFENCODERSTATE *st) {59st->next_code = st->end_code + 1;60st->max_code = 2 * st->clear_code - 1;61st->code_width = st->bits + 1;62memset(st->codes, 0, sizeof(st->codes));63}
64
65static void66glzwe_init(GIFENCODERSTATE *st) {67st->clear_code = 1 << st->bits;68st->end_code = st->clear_code + 1;69glzwe_reset(st);70st->entry_state = LZW_INITIAL;71st->buf_bits_left = 8;72st->code_buffer = 0;73}
74
75static int76glzwe(77GIFENCODERSTATE *st,78const UINT8 *in_ptr,79UINT8 *out_ptr,80UINT32 *in_avail,81UINT32 *out_avail,82UINT32 end_of_data
83) {84switch (st->entry_state) {85case LZW_TRY_IN1:86get_first_byte:87if (!*in_avail) {88if (end_of_data) {89goto end_of_data;90}91st->entry_state = LZW_TRY_IN1;92return GLZW_NO_INPUT_AVAIL;93}94st->head = *in_ptr++;95(*in_avail)--;96
97case LZW_TRY_IN2:98encode_loop:99if (!*in_avail) {100if (end_of_data) {101st->code = st->head;102st->put_state = PUT_LAST_HEAD;103goto put_code;104}105st->entry_state = LZW_TRY_IN2;106return GLZW_NO_INPUT_AVAIL;107}108st->tail = *in_ptr++;109(*in_avail)--;110
111/* Knuth TAOCP vol 3 sec. 6.4 algorithm D. */112/* Hash found experimentally to be pretty good. */113/* This works ONLY with TABLE_SIZE a power of 2. */114st->probe = ((st->head ^ (st->tail << 6)) * 31) & (TABLE_SIZE - 1);115while (st->codes[st->probe]) {116if ((st->codes[st->probe] & 0xFFFFF) == ((st->head << 8) | st->tail)) {117st->head = st->codes[st->probe] >> 20;118goto encode_loop;119} else {120// Reprobe decrement must be non-zero and relatively prime to table121// size. So, any odd positive number for power-of-2 size.122if ((st->probe -= ((st->tail << 2) | 1)) < 0) {123st->probe += TABLE_SIZE;124}125}126}127/* Key not found, probe is at empty slot. */128st->code = st->head;129st->put_state = PUT_HEAD;130goto put_code;131insert_code_or_clear: /* jump here after put_code */132if (st->next_code < CODE_LIMIT) {133st->codes[st->probe] =134(st->next_code << 20) | (st->head << 8) | st->tail;135if (st->next_code > st->max_code) {136st->max_code = st->max_code * 2 + 1;137st->code_width++;138}139st->next_code++;140} else {141st->code = st->clear_code;142st->put_state = PUT_CLEAR;143goto put_code;144reset_after_clear: /* jump here after put_code */145glzwe_reset(st);146}147st->head = st->tail;148goto encode_loop;149
150case LZW_INITIAL:151glzwe_reset(st);152st->code = st->clear_code;153st->put_state = PUT_INIT_CLEAR;154put_code:155st->code_bits_left = st->code_width;156check_buf_bits:157if (!st->buf_bits_left) { /* out buffer full */158
159case LZW_TRY_OUT1:160if (!*out_avail) {161st->entry_state = LZW_TRY_OUT1;162return GLZW_NO_OUTPUT_AVAIL;163}164*out_ptr++ = st->code_buffer;165(*out_avail)--;166st->code_buffer = 0;167st->buf_bits_left = 8;168}169/* code bits to pack */170UINT32 n = st->buf_bits_left < st->code_bits_left ? st->buf_bits_left171: st->code_bits_left;172st->code_buffer |= (st->code & ((1 << n) - 1)) << (8 - st->buf_bits_left);173st->code >>= n;174st->buf_bits_left -= n;175st->code_bits_left -= n;176if (st->code_bits_left) {177goto check_buf_bits;178}179switch (st->put_state) {180case PUT_INIT_CLEAR:181goto get_first_byte;182case PUT_HEAD:183goto insert_code_or_clear;184case PUT_CLEAR:185goto reset_after_clear;186case PUT_LAST_HEAD:187goto end_of_data;188case PUT_END:189goto flush_code_buffer;190default:191return GLZW_INTERNAL_ERROR;192}193
194end_of_data:195st->code = st->end_code;196st->put_state = PUT_END;197goto put_code;198flush_code_buffer: /* jump here after put_code */199if (st->buf_bits_left < 8) {200case LZW_TRY_OUT2:201if (!*out_avail) {202st->entry_state = LZW_TRY_OUT2;203return GLZW_NO_OUTPUT_AVAIL;204}205*out_ptr++ = st->code_buffer;206(*out_avail)--;207}208st->entry_state = LZW_FINISHED;209return GLZW_OK;210
211case LZW_FINISHED:212return GLZW_OK;213
214default:215return GLZW_INTERNAL_ERROR;216}217}
218/* -END- GIF LZW encoder. */
219
220int
221ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {222UINT8 *ptr;223UINT8 *sub_block_ptr;224UINT8 *sub_block_limit;225UINT8 *buf_limit;226GIFENCODERSTATE *context = (GIFENCODERSTATE *)state->context;227int r;228
229UINT32 in_avail, in_used;230UINT32 out_avail, out_used;231
232if (state->state == INIT) {233state->state = ENCODE;234glzwe_init(context);235
236if (context->interlace) {237context->interlace = 1;238context->step = 8;239} else {240context->step = 1;241}242
243/* Need at least 2 bytes for data sub-block; 5 for empty image */244if (bytes < 5) {245state->errcode = IMAGING_CODEC_CONFIG;246return 0;247}248/* sanity check */249if (state->xsize <= 0 || state->ysize <= 0) {250/* Is this better than an error return? */251/* This will handle any legal "LZW Minimum Code Size" */252memset(buf, 0, 5);253in_avail = 0;254out_avail = 5;255r = glzwe(context, (const UINT8 *)"", buf + 1, &in_avail, &out_avail, 1);256if (r == GLZW_OK) {257r = 5 - out_avail;258if (r < 1 || r > 3) {259state->errcode = IMAGING_CODEC_BROKEN;260return 0;261}262buf[0] = r;263state->errcode = IMAGING_CODEC_END;264return r + 2;265} else {266/* Should not be possible unless something external to this267* routine messes with our state data */
268state->errcode = IMAGING_CODEC_BROKEN;269return 0;270}271}272/* Init state->x to make if() below true the first time through. */273state->x = state->xsize;274}275
276buf_limit = buf + bytes;277sub_block_limit = sub_block_ptr = ptr = buf;278
279/* On entry, buf is output buffer, bytes is space available in buf.280* Loop here getting input until buf is full or image is all encoded. */
281for (;;) {282/* Set up sub-block ptr and limit. sub_block_ptr stays at beginning283* of sub-block until it is full. ptr will advance when any data is
284* placed in buf.
285*/
286if (ptr >= sub_block_limit) {287if (buf_limit - ptr < 2) { /* Need at least 2 for data sub-block */288return ptr - buf;289}290sub_block_ptr = ptr;291sub_block_limit =292sub_block_ptr +293(256 < buf_limit - sub_block_ptr ? 256 : buf_limit - sub_block_ptr);294*ptr++ = 0;295}296
297/* Get next row of pixels. */298/* This if() originally tested state->x==0 for the first time through.299* This no longer works, as the loop will not advance state->x if
300* glzwe() does not consume any input; this would advance the row
301* spuriously. Now pre-init state->x above for first time, and avoid
302* entering if() when state->state is FINISH, or it will loop
303* infinitely.
304*/
305if (state->x >= state->xsize && state->state == ENCODE) {306if (!context->interlace && state->y >= state->ysize) {307state->state = FINISH;308continue;309}310
311/* get another line of data */312state->shuffle(313state->buffer,314(UINT8 *)im->image[state->y + state->yoff] +315state->xoff * im->pixelsize,316state->xsize317);318state->x = 0;319
320/* step forward, according to the interlace settings */321state->y += context->step;322while (context->interlace && state->y >= state->ysize) {323switch (context->interlace) {324case 1:325state->y = 4;326context->interlace = 2;327break;328case 2:329context->step = 4;330state->y = 2;331context->interlace = 3;332break;333case 3:334context->step = 2;335state->y = 1;336context->interlace = 0;337break;338default:339/* just make sure we don't loop forever */340context->interlace = 0;341}342}343}344
345in_avail = state->xsize - state->x; /* bytes left in line */346out_avail = sub_block_limit - ptr; /* bytes left in sub-block */347r = glzwe(348context,349&state->buffer[state->x],350ptr,351&in_avail,352&out_avail,353state->state == FINISH354);355out_used = sub_block_limit - ptr - out_avail;356*sub_block_ptr += out_used;357ptr += out_used;358in_used = state->xsize - state->x - in_avail;359state->x += in_used;360
361if (r == GLZW_OK) {362/* Should not be possible when end-of-data flag is false. */363state->errcode = IMAGING_CODEC_END;364return ptr - buf;365} else if (r == GLZW_NO_INPUT_AVAIL) {366/* Used all the input line; get another line */367continue;368} else if (r == GLZW_NO_OUTPUT_AVAIL) {369/* subblock is full */370continue;371} else {372/* Should not be possible unless something external to this373* routine messes with our state data */
374state->errcode = IMAGING_CODEC_BROKEN;375return 0;376}377}378}
379