2017-07-22 10:34:06 +03:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
#define SGI_HEAD_LEN 512
|
|
|
|
|
2017-07-23 21:41:48 +03:00
|
|
|
typedef unsigned long ULONG;
|
|
|
|
|
|
|
|
static ULONG getlong(UINT8 *buf)
|
2017-07-22 10:34:06 +03:00
|
|
|
{
|
2017-07-23 21:41:48 +03:00
|
|
|
return (ULONG)(buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
|
2017-07-22 10:34:06 +03:00
|
|
|
}
|
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
static void expandrow(UINT8* optr,UINT8* iptr, int ooffset, int ioffset)
|
2017-07-22 10:34:06 +03:00
|
|
|
{
|
|
|
|
UINT8 pixel, count;
|
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
optr += ooffset;
|
|
|
|
iptr += ioffset;
|
2017-07-22 10:34:06 +03:00
|
|
|
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)
|
|
|
|
{
|
2017-07-25 08:19:20 +03:00
|
|
|
UINT8 *ptr, *scanline;
|
2017-07-23 21:41:48 +03:00
|
|
|
ULONG *starttab, *lengthtab;
|
2017-07-25 08:19:20 +03:00
|
|
|
ULONG rleoffset, rlelength;
|
|
|
|
int zsize, tablen, rowno, channo, bpc;
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* "working copy" of buffer pointer */
|
2017-07-22 10:34:06 +03:00
|
|
|
ptr = buf;
|
|
|
|
|
2017-07-23 21:41:48 +03:00
|
|
|
/* get the channels count */
|
|
|
|
zsize = im->bands;
|
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* get bytes channel per pixel */
|
|
|
|
bpc = state->count;
|
|
|
|
|
|
|
|
/* initialization */
|
2017-07-22 10:34:06 +03:00
|
|
|
if (state->state == 0) {
|
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* check image orientation */
|
|
|
|
if (state->ystep < 0) {
|
|
|
|
state->y = state->ysize-1;
|
|
|
|
state->ystep = -1;
|
|
|
|
} else {
|
|
|
|
state->ystep = 1;
|
|
|
|
state->y = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(state->buffer);
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* allocate memory for the buffer used for full lines later */
|
|
|
|
state->buffer = (UINT8*)malloc(sizeof(UINT8) * state->xsize * zsize);
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* allocate memory for compressed and uncompressed rows */
|
|
|
|
scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
/* allocate memory for rle tabs */
|
|
|
|
tablen = state->ysize * zsize * sizeof(ULONG);
|
2017-07-23 21:41:48 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
starttab = (ULONG*)malloc(tablen);
|
|
|
|
lengthtab = (ULONG*)malloc(tablen);
|
2017-07-23 21:41:48 +03:00
|
|
|
|
2017-07-25 08:19:20 +03:00
|
|
|
state->state = 1;
|
2017-07-23 21:41:48 +03:00
|
|
|
}
|
2017-07-22 10:34:06 +03:00
|
|
|
|
|
|
|
/* get RLE offset and length tabs */
|
2017-07-25 08:19:20 +03:00
|
|
|
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]);
|
|
|
|
}
|
2017-07-22 10:34:06 +03:00
|
|
|
|
|
|
|
/* get scanlines informations */
|
2017-07-22 10:56:01 +03:00
|
|
|
for (rowno = 0; rowno < state->ysize; ++rowno) {
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-22 10:56:01 +03:00
|
|
|
for (channo = 0; channo < zsize; ++channo) {
|
2017-07-22 10:34:06 +03:00
|
|
|
|
2017-07-23 21:41:48 +03:00
|
|
|
rleoffset = starttab[rowno + channo * state->ysize];
|
|
|
|
rlelength = lengthtab[rowno + channo * state->ysize];
|
2017-07-22 10:34:06 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we also need to substract the file header and RLE tabs length
|
|
|
|
* from the offset
|
|
|
|
*/
|
2017-07-25 08:19:20 +03:00
|
|
|
rleoffset -= SGI_HEAD_LEN;
|
2017-07-22 10:34:06 +03:00
|
|
|
|
|
|
|
/* decompress raw data */
|
2017-07-25 08:19:20 +03:00
|
|
|
expandrow(scanline, ptr, 0, rleoffset);
|
2017-07-22 10:34:06 +03:00
|
|
|
|
|
|
|
/* populate the state buffer */
|
2017-07-25 08:19:20 +03:00
|
|
|
for (state->x = 0; state->x < sizeof(*scanline) * state->xsize; state->x += 1) {
|
|
|
|
state->buffer[state->x * zsize + channo] = (UINT8)(scanline[state->x]);
|
2017-07-22 10:34:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2017-07-23 21:41:48 +03:00
|
|
|
|
|
|
|
free(scanline);
|
2017-07-22 10:34:06 +03:00
|
|
|
free(starttab);
|
|
|
|
free(lengthtab);
|
|
|
|
|
2017-07-23 21:41:48 +03:00
|
|
|
return -1; /* end of file (errcode=0) */
|
2017-07-22 10:34:06 +03:00
|
|
|
}
|