mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-27 18:36:17 +03:00
231 lines
5.0 KiB
C
231 lines
5.0 KiB
C
|
/*
|
||
|
* The Python Imaging Library.
|
||
|
* $Id$
|
||
|
*
|
||
|
* a fast, suspendable TIFF LZW decoder
|
||
|
*
|
||
|
* description:
|
||
|
* This code is based on the GIF decoder. There are some
|
||
|
* subtle differences between GIF and TIFF LZW, though:
|
||
|
* - The fill order is different. In the TIFF file, you
|
||
|
* must shift new bits in to the right, not to the left.
|
||
|
* - There is no blocking in the input data stream.
|
||
|
* - The code size is increased one step earlier than
|
||
|
* for GIF
|
||
|
* - Image data are seen as a byte stream, not a pixel
|
||
|
* stream. This means that the code size will always
|
||
|
* start at 9 bits.
|
||
|
*
|
||
|
* history:
|
||
|
* 95-09-13 fl Created (derived from GifDecode.c)
|
||
|
* 96-03-28 fl Revised API, integrated with PIL
|
||
|
* 97-01-05 fl Added filter support, added extra consistency checks
|
||
|
*
|
||
|
* Copyright (c) Fredrik Lundh 1995-97.
|
||
|
* Copyright (c) Secret Labs AB 1997.
|
||
|
*
|
||
|
* See the README file for information on usage and redistribution.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "Imaging.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h> /* memcpy() */
|
||
|
|
||
|
#include "Lzw.h"
|
||
|
|
||
|
|
||
|
int
|
||
|
ImagingLzwDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||
|
{
|
||
|
UINT8* p;
|
||
|
int c, i;
|
||
|
int thiscode;
|
||
|
LZWSTATE* context = (LZWSTATE*) state->context;
|
||
|
|
||
|
unsigned char *ptr = buf;
|
||
|
|
||
|
if (!state->state) {
|
||
|
|
||
|
/* Clear code */
|
||
|
context->clear = 1 << 8;
|
||
|
|
||
|
/* End code */
|
||
|
context->end = context->clear + 1;
|
||
|
|
||
|
state->state = 1;
|
||
|
}
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
if (state->state == 1) {
|
||
|
|
||
|
/* First free entry in table */
|
||
|
context->next = context->clear + 2;
|
||
|
|
||
|
/* Initial code size */
|
||
|
context->codesize = 8 + 1;
|
||
|
context->codemask = (1 << context->codesize) - 1;
|
||
|
|
||
|
/* Buffer pointer. We fill the buffer from right, which
|
||
|
allows us to return all of it in one operation. */
|
||
|
context->bufferindex = LZWBUFFER;
|
||
|
|
||
|
state->state = 2;
|
||
|
}
|
||
|
|
||
|
if (context->bufferindex < LZWBUFFER) {
|
||
|
|
||
|
/* Return whole buffer in one chunk */
|
||
|
i = LZWBUFFER - context->bufferindex;
|
||
|
p = &context->buffer[context->bufferindex];
|
||
|
|
||
|
context->bufferindex = LZWBUFFER;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
/* Get current symbol */
|
||
|
while (context->bitcount < context->codesize) {
|
||
|
|
||
|
if (bytes < 1)
|
||
|
return ptr - buf;;
|
||
|
|
||
|
/* Read next byte */
|
||
|
c = *ptr++; bytes--;
|
||
|
|
||
|
/* New bits are shifted in from from the right. */
|
||
|
context->bitbuffer = (context->bitbuffer << 8) | c;
|
||
|
context->bitcount += 8;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Extract current symbol from bit buffer. */
|
||
|
c = (context->bitbuffer >> (context->bitcount -
|
||
|
context->codesize))
|
||
|
& context->codemask;
|
||
|
|
||
|
/* Adjust buffer */
|
||
|
context->bitcount -= context->codesize;
|
||
|
|
||
|
/* If c is less than clear, it's a data byte. Otherwise,
|
||
|
it's either clear/end or a code symbol which should be
|
||
|
expanded. */
|
||
|
|
||
|
if (c == context->clear) {
|
||
|
if (state->state != 2)
|
||
|
state->state = 1;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (c == context->end)
|
||
|
break;
|
||
|
|
||
|
i = 1;
|
||
|
p = &context->lastdata;
|
||
|
|
||
|
if (state->state == 2) {
|
||
|
|
||
|
/* First valid symbol after clear; use as is */
|
||
|
if (c > context->clear) {
|
||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
context->lastdata = context->lastcode = c;
|
||
|
state->state = 3;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
thiscode = c;
|
||
|
|
||
|
if (c > context->next) {
|
||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (c == context->next) {
|
||
|
|
||
|
/* c == next is allowed, by some strange reason */
|
||
|
if (context->bufferindex <= 0) {
|
||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
context->buffer[--context->bufferindex] = context->lastdata;
|
||
|
c = context->lastcode;
|
||
|
}
|
||
|
|
||
|
while (c >= context->clear) {
|
||
|
|
||
|
/* Copy data string to buffer (beginning from right) */
|
||
|
|
||
|
if (context->bufferindex <= 0 || c >= LZWTABLE) {
|
||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
context->buffer[--context->bufferindex] =
|
||
|
context->data[c];
|
||
|
c = context->link[c];
|
||
|
}
|
||
|
|
||
|
context->lastdata = c;
|
||
|
|
||
|
if (context->next < LZWTABLE) {
|
||
|
|
||
|
/* While we still have room for it, add this
|
||
|
symbol to the table. */
|
||
|
context->data[context->next] = c;
|
||
|
context->link[context->next] = context->lastcode;
|
||
|
|
||
|
context->next++;
|
||
|
|
||
|
if (context->next == context->codemask &&
|
||
|
context->codesize < LZWBITS) {
|
||
|
|
||
|
/* Expand code size */
|
||
|
context->codesize++;
|
||
|
context->codemask = (1 << context->codesize) - 1;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
context->lastcode = thiscode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Update the output image */
|
||
|
for (c = 0; c < i; c++) {
|
||
|
|
||
|
state->buffer[state->x] = p[c];
|
||
|
|
||
|
if (++state->x >= state->bytes) {
|
||
|
|
||
|
int x, bpp;
|
||
|
|
||
|
/* Apply filter */
|
||
|
switch (context->filter) {
|
||
|
case 2:
|
||
|
/* Horizontal differing ("prior") */
|
||
|
bpp = (state->bits + 7) / 8;
|
||
|
for (x = bpp; x < state->bytes; x++)
|
||
|
state->buffer[x] += state->buffer[x-bpp];
|
||
|
}
|
||
|
|
||
|
/* Got a full line, unpack it */
|
||
|
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||
|
state->xoff * im->pixelsize, state->buffer,
|
||
|
state->xsize);
|
||
|
|
||
|
state->x = 0;
|
||
|
|
||
|
if (++state->y >= state->ysize)
|
||
|
/* End of file (errcode = 0) */
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ptr - buf;
|
||
|
}
|