mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-26 08:40:36 +03:00
Fix RLE decompression by chunks
This commit is contained in:
parent
9caf8c5889
commit
c5565fc7f0
16
decode.c
16
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;
|
||||
}
|
||||
|
|
|
@ -447,6 +447,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,
|
||||
|
|
31
libImaging/Sgi.h
Normal file
31
libImaging/Sgi.h
Normal file
|
@ -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;
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user