Avoid memory reallocation and support Y orientation in 16bits uncompressed read

This commit is contained in:
Mickael B 2017-07-25 01:19:20 -04:00 committed by Eric Soroos
parent bec76fdb42
commit f833cd7f38
2 changed files with 52 additions and 51 deletions

View File

@ -116,7 +116,7 @@ class SgiImageFile(ImageFile.ImageFile):
offset += pagesize offset += pagesize
elif compression == 1: elif compression == 1:
self.tile = [("sgi_rle", (0, 0) + self.size, self.tile = [("sgi_rle", (0, 0) + self.size,
headlen, (self.mode, orientation, bpc * 8))] headlen, (rawmode, orientation, bpc))]
def _save(im, fp, filename): def _save(im, fp, filename):
@ -185,18 +185,24 @@ class SGI16Decoder(ImageFile.PyDecoder):
_pulls_fd = False _pulls_fd = False
def decode(self, buffer): def decode(self, buffer):
rawmode, stride, orientation = self.args
pagesize = self.state.xsize * self.state.ysize pagesize = self.state.xsize * self.state.ysize
zsize = len(self.mode) zsize = len(self.mode)
data = bytearray(pagesize * zsize) data = bytearray(pagesize * zsize)
i = 0 i = 0
for y in reversed(range(self.state.ysize)): y = 0
if orientation < 0:
y = self.state.ysize - 1
while y >= 0 and y < self.state.ysize:
for x in range(self.state.xsize): for x in range(self.state.xsize):
for z in range(zsize): for z in range(zsize):
bi = (x + y * self.state.xsize + z * pagesize) * 2 bi = (x + y * self.state.xsize +
y * stride + z * pagesize) * 2
pixel = i16(buffer, o=bi) pixel = i16(buffer, o=bi)
pixel = int(pixel // 256) pixel = int(pixel // 256)
data[i] = o8(pixel) data[i] = o8(pixel)
i += 1 i += 1
y += orientation
self.set_as_raw(bytes(data)) self.set_as_raw(bytes(data))
return -1, 0 return -1, 0

View File

@ -15,6 +15,8 @@
#include "Imaging.h" #include "Imaging.h"
#include "stdio.h" #include "stdio.h"
#define SGI_HEAD_LEN 512
typedef unsigned long ULONG; typedef unsigned long ULONG;
static ULONG getlong(UINT8 *buf) static ULONG getlong(UINT8 *buf)
@ -22,20 +24,12 @@ static ULONG getlong(UINT8 *buf)
return (ULONG)(buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0); return (ULONG)(buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
} }
static void readlongtab(UINT8** buf, int n, ULONG *tab) static void expandrow(UINT8* optr,UINT8* iptr, int ooffset, int ioffset)
{
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; UINT8 pixel, count;
optr += z; optr += ooffset;
iptr += ioffset;
while(1) { while(1) {
pixel = *iptr++; pixel = *iptr++;
if ( !(count = (pixel & 0x7f)) ) if ( !(count = (pixel & 0x7f)) )
@ -55,25 +49,31 @@ int
ImagingSgiRleDecode(Imaging im, ImagingCodecState state, ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
UINT8* buf, int bytes) UINT8* buf, int bytes)
{ {
UINT8 *ptr, *rledata, *scanline; UINT8 *ptr, *scanline;
ULONG *starttab, *lengthtab; ULONG *starttab, *lengthtab;
ULONG rleoffset, rlelength, prevrlelength; ULONG rleoffset, rlelength;
int zsize, tablen, rowno, channo, x; int zsize, tablen, rowno, channo, bpc;
/* "working copy" of buffer pointer */
ptr = buf; ptr = buf;
/* get the channels count */ /* get the channels count */
zsize = im->bands; zsize = im->bands;
prevrlelength = (ULONG)state->xsize;
/* get bytes channel per pixel */
bpc = state->count;
/* initialization */
if (state->state == 0) { if (state->state == 0) {
/* check image orientation */ /* check image orientation */
if (state->ystep < 0) { if (state->ystep < 0) {
state->y = state->ysize-1; state->y = state->ysize-1;
state->ystep = -1; state->ystep = -1;
} else } else {
state->ystep = 1; state->ystep = 1;
state->y = 0;
}
free(state->buffer); free(state->buffer);
@ -81,21 +81,25 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
state->buffer = (UINT8*)malloc(sizeof(UINT8) * state->xsize * zsize); state->buffer = (UINT8*)malloc(sizeof(UINT8) * state->xsize * zsize);
/* allocate memory for compressed and uncompressed rows */ /* allocate memory for compressed and uncompressed rows */
rledata = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize); scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
state->state = 1; /* allocate memory for rle tabs */
}
/* get RLE offset and length tabs */
tablen = state->ysize * zsize * sizeof(ULONG); tablen = state->ysize * zsize * sizeof(ULONG);
starttab = (ULONG*)malloc(tablen); starttab = (ULONG*)malloc(tablen);
lengthtab = (ULONG*)malloc(tablen); lengthtab = (ULONG*)malloc(tablen);
readlongtab(&ptr, state->ysize * zsize, starttab); state->state = 1;
readlongtab(&ptr, state->ysize * zsize, lengthtab); }
/* 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 */ /* get scanlines informations */
for (rowno = 0; rowno < state->ysize; ++rowno) { for (rowno = 0; rowno < state->ysize; ++rowno) {
@ -109,22 +113,14 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
* we also need to substract the file header and RLE tabs length * we also need to substract the file header and RLE tabs length
* from the offset * from the offset
*/ */
rleoffset -= 512; rleoffset -= SGI_HEAD_LEN;
rleoffset -= tablen;
if (prevrlelength != rlelength)
rledata = (UINT8*)realloc(rledata, sizeof(UINT8) * rlelength);
prevrlelength = rlelength;
memcpy(rledata, &ptr[rleoffset], rlelength * sizeof(UINT8));
/* decompress raw data */ /* decompress raw data */
expandrow(scanline, rledata, 0); expandrow(scanline, ptr, 0, rleoffset);
/* populate the state buffer */ /* populate the state buffer */
for (x = 0; x < state->xsize; ++x) { for (state->x = 0; state->x < sizeof(*scanline) * state->xsize; state->x += 1) {
state->buffer[x * zsize + channo] = scanline[x]; state->buffer[state->x * zsize + channo] = (UINT8)(scanline[state->x]);
} }
} }
@ -137,7 +133,6 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
state->y += state->ystep; state->y += state->ystep;
} }
free(rledata);
free(scanline); free(scanline);
free(starttab); free(starttab);
free(lengthtab); free(lengthtab);