Add uncompressed 16bits read for SGI Images

This commit is contained in:
Mickael B 2017-07-23 14:41:48 -04:00 committed by Eric Soroos
parent e162963064
commit bec76fdb42
2 changed files with 87 additions and 44 deletions

View File

@ -34,9 +34,20 @@ def _accept(prefix):
return len(prefix) >= 2 and i16(prefix) == 474 return len(prefix) >= 2 and i16(prefix) == 474
MODES = {
(1, 1, 1): "L",
(1, 2, 1): "L",
(2, 1, 1): "L;16B",
(2, 2, 1): "L;16B",
(1, 3, 3): "RGB",
(2, 3, 3): "RGB;16B",
(1, 3, 4): "RGBA",
(2, 3, 4): "RGBA;16B"
}
## ##
# Image plugin for SGI images. # Image plugin for SGI images.
class SgiImageFile(ImageFile.ImageFile): class SgiImageFile(ImageFile.ImageFile):
format = "SGI" format = "SGI"
@ -74,16 +85,17 @@ class SgiImageFile(ImageFile.ImageFile):
layout = bpc, dimension, zsize layout = bpc, dimension, zsize
# determine mode from bits/zsize # determine mode from bits/zsize
if layout == (1, 2, 1) or layout == (1, 1, 1): rawmode = ""
self.mode = "L" try:
elif layout == (1, 3, 3): rawmode = MODES[layout]
self.mode = "RGB" except KeyError:
elif layout == (1, 3, 4): pass
self.mode = "RGBA"
else: if rawmode == "":
raise ValueError("Unsupported SGI image mode") raise ValueError("Unsupported SGI image mode")
self.size = xsize, ysize self.size = xsize, ysize
self.mode = rawmode.split(";")[0]
# orientation -1 : scanlines begins at the bottom-left corner # orientation -1 : scanlines begins at the bottom-left corner
orientation = -1 orientation = -1
@ -91,6 +103,10 @@ class SgiImageFile(ImageFile.ImageFile):
# decoder info # decoder info
if compression == 0: if compression == 0:
pagesize = xsize * ysize * bpc pagesize = xsize * ysize * bpc
if bpc == 2:
self.tile = [("SGI16", (0, 0) + self.size,
headlen, (self.mode, 0, orientation))]
else:
self.tile = [] self.tile = []
offset = headlen offset = headlen
for layer in self.mode: for layer in self.mode:
@ -165,9 +181,30 @@ def _save(im, fp, filename):
fp.close() fp.close()
class SGI16Decoder(ImageFile.PyDecoder):
_pulls_fd = False
def decode(self, buffer):
pagesize = self.state.xsize * self.state.ysize
zsize = len(self.mode)
data = bytearray(pagesize * zsize)
i = 0
for y in reversed(range(self.state.ysize)):
for x in range(self.state.xsize):
for z in range(zsize):
bi = (x + y * self.state.xsize + z * pagesize) * 2
pixel = i16(buffer, o=bi)
pixel = int(pixel // 256)
data[i] = o8(pixel)
i += 1
self.set_as_raw(bytes(data))
return -1, 0
# #
# registry # registry
Image.register_decoder("SGI16", SGI16Decoder)
Image.register_open(SgiImageFile.format, SgiImageFile, _accept) Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
Image.register_save(SgiImageFile.format, _save) Image.register_save(SgiImageFile.format, _save)
Image.register_mime(SgiImageFile.format, "image/sgi") Image.register_mime(SgiImageFile.format, "image/sgi")

View File

@ -12,16 +12,17 @@
* See the README file for information on usage and redistribution. * See the README file for information on usage and redistribution.
*/ */
#include "Imaging.h" #include "Imaging.h"
#include "stdio.h" #include "stdio.h"
static unsigned long getlong(UINT8 *buf) typedef unsigned long ULONG;
static ULONG getlong(UINT8 *buf)
{ {
return (unsigned long)(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, unsigned long *tab) static void readlongtab(UINT8** buf, int n, ULONG *tab)
{ {
int i; int i;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@ -54,10 +55,17 @@ int
ImagingSgiRleDecode(Imaging im, ImagingCodecState state, ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
UINT8* buf, int bytes) UINT8* buf, int bytes)
{ {
UINT8* ptr; UINT8 *ptr, *rledata, *scanline;
ULONG *starttab, *lengthtab;
ULONG rleoffset, rlelength, prevrlelength;
int zsize, tablen, rowno, channo, x;
ptr = buf; ptr = buf;
/* get the channels count */
zsize = im->bands;
prevrlelength = (ULONG)state->xsize;
if (state->state == 0) { if (state->state == 0) {
/* check image orientation */ /* check image orientation */
@ -67,35 +75,35 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
} else } else
state->ystep = 1; state->ystep = 1;
state->state = 1; free(state->buffer);
}
/* get the channels count */
int zsize = state->bits / state->count;
/* allocate memory for the buffer used for full lines later */ /* allocate memory for the buffer used for full lines later */
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 */
rledata = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
state->state = 1;
}
/* get RLE offset and length tabs */ /* get RLE offset and length tabs */
unsigned long *starttab, *lengthtab; tablen = state->ysize * zsize * sizeof(ULONG);
int tablen = state->ysize * zsize * sizeof(unsigned long);
starttab = (unsigned long *)malloc(tablen); starttab = (ULONG*)malloc(tablen);
lengthtab = (unsigned long *)malloc(tablen); lengthtab = (ULONG*)malloc(tablen);
readlongtab(&ptr, state->ysize * zsize, starttab); readlongtab(&ptr, state->ysize * zsize, starttab);
readlongtab(&ptr, state->ysize * zsize, lengthtab); readlongtab(&ptr, state->ysize * zsize, lengthtab);
/* get scanlines informations */ /* get scanlines informations */
int rowno;
for (rowno = 0; rowno < state->ysize; ++rowno) { for (rowno = 0; rowno < state->ysize; ++rowno) {
int channo;
for (channo = 0; channo < zsize; ++channo) { for (channo = 0; channo < zsize; ++channo) {
unsigned long rleoffset = starttab[rowno + channo * state->ysize]; rleoffset = starttab[rowno + channo * state->ysize];
rlelength = lengthtab[rowno + channo * state->ysize];
/* /*
* we also need to substract the file header and RLE tabs length * we also need to substract the file header and RLE tabs length
@ -104,25 +112,21 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
rleoffset -= 512; rleoffset -= 512;
rleoffset -= tablen; rleoffset -= tablen;
unsigned long rlelength = lengthtab[rowno + channo * state->ysize]; if (prevrlelength != rlelength)
rledata = (UINT8*)realloc(rledata, sizeof(UINT8) * rlelength);
prevrlelength = rlelength;
UINT8* rledata;
rledata = (UINT8*)malloc(sizeof(UINT8) * rlelength);
memcpy(rledata, &ptr[rleoffset], rlelength * sizeof(UINT8)); memcpy(rledata, &ptr[rleoffset], rlelength * sizeof(UINT8));
UINT8* scanline;
scanline = (UINT8*)malloc(sizeof(UINT8) * state->xsize);
/* decompress raw data */ /* decompress raw data */
expandrow(scanline, rledata, 0); expandrow(scanline, rledata, 0);
/* populate the state buffer */ /* populate the state buffer */
int x;
for (x = 0; x < state->xsize; ++x) { for (x = 0; x < state->xsize; ++x) {
state->buffer[x * zsize + channo] = scanline[x]; state->buffer[x * zsize + channo] = scanline[x];
} }
free(rledata);
free(scanline);
} }
/* Unpack the full line stored in the state buffer */ /* Unpack the full line stored in the state buffer */
@ -133,8 +137,10 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
state->y += state->ystep; state->y += state->ystep;
} }
free(rledata);
free(scanline);
free(starttab); free(starttab);
free(lengthtab); free(lengthtab);
return -1; return -1; /* end of file (errcode=0) */
} }