Pillow/libImaging/SgiRleDecode.c
2017-09-29 09:13:22 +00:00

140 lines
3.1 KiB
C

/*
* The Python Imaging Library.
* $Id$
*
* decoder for Sgi RLE data.
*
* history:
* 2017-07-20 mb created
*
* Copyright (c) Mickael Bonfill 2017.
*
* See the README file for information on usage and redistribution.
*/
#include "Imaging.h"
#include "stdio.h"
static unsigned long getlong(UINT8 *buf)
{
return (unsigned long)(buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
}
static void readlongtab(UINT8** buf, int n, unsigned long *tab)
{
int i;
for (i = 0; i < n; i++) {
tab[i] = getlong(*buf);
*buf += 4;
}
}
static void expandrow(UINT8* optr,UINT8* iptr, int z)
{
UINT8 pixel, count;
optr += z;
while(1) {
pixel = *iptr++;
if ( !(count = (pixel & 0x7f)) )
return;
if(pixel & 0x80) {
while(count--)
*optr++ = *iptr++;
} else {
pixel = *iptr++;
while(count--)
*optr++ = pixel;
}
}
}
int
ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
UINT8* buf, int bytes)
{
UINT8* ptr;
ptr = buf;
if (state->state == 0) {
/* check image orientation */
if (state->ystep < 0) {
state->y = state->ysize-1;
state->ystep = -1;
} else
state->ystep = 1;
state->state = 1;
}
/* get the channels count */
int zsize = state->bits / state->count;
/* allocate memory for the buffer used for full lines later */
state->buffer = (UINT8*)malloc(sizeof(UINT8) * state->xsize * zsize);
/* get RLE offset and length tabs */
unsigned long *starttab, *lengthtab;
int tablen = state->ysize * zsize * sizeof(unsigned long);
starttab = (unsigned long *)malloc(tablen);
lengthtab = (unsigned long *)malloc(tablen);
readlongtab(&ptr, state->ysize * zsize, starttab);
readlongtab(&ptr, state->ysize * zsize, lengthtab);
/* get scanlines informations */
int rowno;
for (rowno = 0; rowno < state->ysize; ++rowno) {
int channo;
for (channo = 0; channo < zsize; ++channo) {
unsigned long rleoffset = starttab[rowno + channo * state->ysize];
/*
* we also need to substract the file header and RLE tabs length
* from the offset
*/
rleoffset -= 512;
rleoffset -= tablen;
unsigned long rlelength = lengthtab[rowno + channo * state->ysize];
UINT8* rledata;
rledata = (UINT8*)malloc(sizeof(UINT8) * rlelength);
memcpy(rledata, &ptr[rleoffset], rlelength * sizeof(UINT8));
UINT8* scanline;
scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
/* decompress raw data */
expandrow(scanline, rledata, 0);
/* populate the state buffer */
int x;
for (x = 0; x < state->xsize; ++x) {
state->buffer[x * zsize + channo] = scanline[x];
}
free(rledata);
free(scanline);
}
/* 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);
state->y += state->ystep;
}
free(starttab);
free(lengthtab);
return -1;
}