diff --git a/decode.c b/decode.c index f4ca5330f..b225084d8 100644 --- a/decode.c +++ b/decode.c @@ -38,6 +38,7 @@ #include "Lzw.h" #include "Raw.h" #include "Bit.h" +#include "Sgi.h" /* -------------------------------------------------------------------- */ @@ -683,11 +684,11 @@ PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args) char* mode; char* rawmode; int ystep = 1; - int depth = 8; - if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &depth)) + int bpc = 1; + if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &bpc)) return NULL; - decoder = PyImaging_DecoderNew(0); + decoder = PyImaging_DecoderNew(sizeof(SGISTATE)); if (decoder == NULL) return NULL; @@ -695,9 +696,14 @@ PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args) return NULL; decoder->decode = ImagingSgiRleDecode; - + decoder->cleanup = ImagingSgiRleDecodeCleanup; decoder->state.ystep = ystep; - decoder->state.count = depth; + + ((SGISTATE*)decoder->state.context)->bpc = bpc; + ((SGISTATE*)decoder->state.context)->rowno = 0; + ((SGISTATE*)decoder->state.context)->channo = 0; + ((SGISTATE*)decoder->state.context)->starttabidx = 0; + ((SGISTATE*)decoder->state.context)->lengthtabidx = 0; return (PyObject*) decoder; } diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 07177732c..a2bec89a9 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -446,6 +446,7 @@ extern int ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); extern int ImagingSgiRleDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); +extern int ImagingSgiRleDecodeCleanup(ImagingCodecState state); extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, diff --git a/libImaging/Sgi.h b/libImaging/Sgi.h new file mode 100644 index 000000000..8d850b306 --- /dev/null +++ b/libImaging/Sgi.h @@ -0,0 +1,31 @@ +/* Sgi.h */ + +typedef struct { + + /* CONFIGURATION */ + + /* Number of bytes per pixel per channel */ + int bpc; + + /* Number of UINT32 data in RLE tables */ + int tablen; + + /* Current row index */ + int rowno; + + /* Current channel index */ + int channo; + + /* Offsets table */ + uint32_t* starttab; + + /* Lengths table */ + uint32_t* lengthtab; + + /* Offsets table index */ + int starttabidx; + + /* Lengths table index */ + int lengthtabidx; + +} SGISTATE; \ No newline at end of file diff --git a/libImaging/SgiRleDecode.c b/libImaging/SgiRleDecode.c index 02cb5fc16..ad013f0b5 100644 --- a/libImaging/SgiRleDecode.c +++ b/libImaging/SgiRleDecode.c @@ -5,7 +5,7 @@ * decoder for Sgi RLE data. * * history: - * 2017-07-20 mb created + * 2017-07-20 mb created * * Copyright (c) Mickael Bonfill 2017. * @@ -13,121 +13,193 @@ */ #include "Imaging.h" -#include "stdio.h" +#include "Sgi.h" +#include +#include +#include -#define SGI_HEAD_LEN 512 +#define SGI_HEADER_SIZE 512 +#define SGI_MAGIC 0x01DA +#define RLE_COPY_FLAG 0x80 +#define RLE_MAX_RUN 0x7f -static UINT32 getlong(UINT8 *buf) +static void read4B(uint32_t* dest, UINT8* buf) { - return (UINT32)(buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0); + *dest = (uint32_t)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); } -static void expandrow(UINT8* optr,UINT8* iptr, int ooffset, int ioffset) +static int expandrow(UINT8* dest, UINT8* src, int n) { UINT8 pixel, count; + + for (;n > 0; n--) + { + pixel = *src++; + if (n == 1 && pixel != 0) + return n; + count = pixel & RLE_MAX_RUN; + if (!count) + return count; + if (pixel & RLE_COPY_FLAG) { + while(count--) { + *dest++ = *src++; + } + + } + else { + pixel = *src++; + while (count--) { + *dest++ = pixel; + } + } + + } + return 0; +} - optr += ooffset; - iptr += ioffset; - while(1) { - pixel = *iptr++; - if ( !(count = (pixel & 0x7f)) ) - return; - if(pixel & 0x80) { - while(count--) - *optr++ = *iptr++; - } else { - pixel = *iptr++; - while(count--) - *optr++ = pixel; +static int expandrow2(UINT16* dest, UINT16* src, int n) +{ + UINT8 pixel, count; + + for (;n > 0; n--) + { + pixel = ((UINT8*)src)[1]; + ++src; + if (n == 1 && pixel != 0) + return n; + count = pixel & RLE_MAX_RUN; + if (!count) + return count; + if (pixel & RLE_COPY_FLAG) { + while(count--) { + *dest++ = *src++; + } + } + else { + while (count--) { + *dest++ = *src; + } + ++src; } } + return 0; } int ImagingSgiRleDecode(Imaging im, ImagingCodecState state, - UINT8* buf, int bytes) + UINT8* buf, int bytes) { - UINT8 *ptr, *scanline; - UINT32 *starttab, *lengthtab; - UINT32 rleoffset, rlelength; - int zsize, tablen, rowno, channo; + SGISTATE *context; + UINT8 *ptr; + uint32_t rleoffset, rlelength; + + context = (SGISTATE*)state->context; + // oldcount = context->bytescount; - /* "working copy" of buffer pointer */ ptr = buf; - /* get the channels count */ - zsize = im->bands; + switch (state->state) + { + case 0: + /* decoder initialization */ + if (state->ystep < 0) + state->y = im->ysize - 1; + else + state->ystep = 1; - /* initialization */ - if (state->state == 0) { + context->tablen = im->ysize * im->bands; + context->starttab = calloc(context->tablen, sizeof(uint32_t)); + context->lengthtab = calloc(context->tablen, sizeof(uint32_t)); - /* check image orientation */ - if (state->ystep < 0) { - state->y = state->ysize-1; - state->ystep = -1; - } else { - state->ystep = 1; - state->y = 0; - } + state->state++; + break; + case 1: + /* read offsets table */ + for (; context->starttabidx < context->tablen; + context->starttabidx++, ptr+=4, bytes-=4) { - state->state = 1; - - } + /* check overflow */ + if (bytes < 4) + return ptr - buf; - /* allocate memory for compressed and uncompressed rows */ - scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize); - - /* allocate memory for rle tabs */ - tablen = state->ysize * zsize * sizeof(UINT32); - - starttab = (UINT32*)malloc(tablen); - lengthtab = (UINT32*)malloc(tablen); - - - /* get RLE offset and length tabs */ - int i; - for (i = 0; i < state->ysize * zsize; i++) { - starttab[i] = getlong(&ptr[i * 4]); - } - for (i = 0; i < state->ysize * zsize; i++) { - lengthtab[i] = getlong(&ptr[tablen + i * 4]); - } - - /* get scanlines informations */ - for (rowno = 0; rowno < state->ysize; ++rowno) { - - for (channo = 0; channo < zsize; ++channo) { - - rleoffset = starttab[rowno + channo * state->ysize]; - rlelength = lengthtab[rowno + channo * state->ysize]; - - /* - * we also need to substract the file header and RLE tabs length - * from the offset - */ - rleoffset -= SGI_HEAD_LEN; - - /* decompress raw data */ - expandrow(scanline, ptr, 0, rleoffset); - - /* populate the state buffer */ - for (state->x = 0; state->x < sizeof(*scanline) * state->xsize; state->x += 1) { - state->buffer[state->x * zsize + channo] = (UINT8)(scanline[state->x]); + read4B(&context->starttab[context->starttabidx], ptr); } + state->state++; + break; + case 2: + /* read lengths table */ + for (; context->lengthtabidx < context->tablen; + context->lengthtabidx++, ptr+=4, bytes-=4) { - } + /* check overflow */ + if (bytes < 4) + return ptr - buf; - /* Unpack the full line stored in the state buffer */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); + read4B(&context->lengthtab[context->lengthtabidx], ptr); + } + state->state++; + break; + case 3: + /* rows decompression */ + for (; context->rowno < im->ysize * im->bands; + context->rowno++, state->y += state->ystep ) + { + context->channo = (int)(context->rowno / im->ysize); + rleoffset = context->starttab[context->rowno]; + rleoffset -= SGI_HEADER_SIZE; + rlelength = context->lengthtab[context->rowno]; - state->y += state->ystep; + /* check overflow */ + if (rlelength > bytes) + return ptr - buf; + + if (context->bpc == 1) { + if(expandrow(state->buffer, ptr, rlelength)) { + /* err: compressed row doesn't finish with 0 */ + state->errcode = IMAGING_CODEC_OVERRUN; + return ptr - buf; + } + + } + else { + if(expandrow2((UINT16*)state->buffer, (UINT16*)ptr, rlelength)) { + /* err: compressed row doesn't finish with 0 */ + state->errcode = IMAGING_CODEC_OVERRUN; + return ptr - buf; + } + } + + /* reset index */ + if (state->y == -1) + state->y = im->ysize - 1; + if (state->y == im->ysize) + state->y = 0; + + /* set image data */ + for (state->x = context->channo; state->x < im->xsize * im->pixelsize; state->x+=im->pixelsize) + ((UINT8*)im->image[state->y])[state->x] = *state->buffer++; + + state->buffer -= im->xsize; + + bytes -= rlelength; + ptr += rlelength; + } + return -1; /* no error */ + default: + break; } + + return ptr - buf; +} - free(scanline); - free(starttab); - free(lengthtab); +int ImagingSgiRleDecodeCleanup(ImagingCodecState state) { - return -1; /* end of file (errcode=0) */ + // SGISTATE *context; + // context = (SGISTATE*)state->context; + + // free(context->starttab); + // free(context->lengthtab); + // // free(context); + + return -1; } \ No newline at end of file