From 3f5848c273566a70f44065f5b9cd540f93def73a Mon Sep 17 00:00:00 2001 From: Mickael B Date: Sun, 23 Jul 2017 14:41:48 -0400 Subject: [PATCH] Add uncompressed 16bits read for SGI Images --- PIL/SgiImagePlugin.py | 67 ++++++++++++++++++++++++++++++--------- libImaging/SgiRleDecode.c | 64 ++++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/PIL/SgiImagePlugin.py b/PIL/SgiImagePlugin.py index bdb327411..c01594cf6 100644 --- a/PIL/SgiImagePlugin.py +++ b/PIL/SgiImagePlugin.py @@ -34,9 +34,20 @@ def _accept(prefix): 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. - class SgiImageFile(ImageFile.ImageFile): format = "SGI" @@ -74,16 +85,17 @@ class SgiImageFile(ImageFile.ImageFile): layout = bpc, dimension, zsize # determine mode from bits/zsize - if layout == (1, 2, 1) or layout == (1, 1, 1): - self.mode = "L" - elif layout == (1, 3, 3): - self.mode = "RGB" - elif layout == (1, 3, 4): - self.mode = "RGBA" - else: + rawmode = "" + try: + rawmode = MODES[layout] + except KeyError: + pass + + if rawmode == "": raise ValueError("Unsupported SGI image mode") self.size = xsize, ysize + self.mode = rawmode.split(";")[0] # orientation -1 : scanlines begins at the bottom-left corner orientation = -1 @@ -91,13 +103,17 @@ class SgiImageFile(ImageFile.ImageFile): # decoder info if compression == 0: pagesize = xsize * ysize * bpc - self.tile = [] - offset = headlen - for layer in self.mode: - self.tile.append( - ("raw", (0, 0) + self.size, - offset, (layer, 0, orientation))) - offset += pagesize + if bpc == 2: + self.tile = [("SGI16", (0, 0) + self.size, + headlen, (self.mode, 0, orientation))] + else: + self.tile = [] + offset = headlen + for layer in self.mode: + self.tile.append( + ("raw", (0, 0) + self.size, + offset, (layer, 0, orientation))) + offset += pagesize elif compression == 1: self.tile = [("sgi_rle", (0, 0) + self.size, headlen, (self.mode, orientation, bpc * 8))] @@ -165,9 +181,30 @@ def _save(im, fp, filename): 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 + +Image.register_decoder("SGI16", SGI16Decoder) Image.register_open(SgiImageFile.format, SgiImageFile, _accept) Image.register_save(SgiImageFile.format, _save) Image.register_mime(SgiImageFile.format, "image/sgi") diff --git a/libImaging/SgiRleDecode.c b/libImaging/SgiRleDecode.c index 9f8b4141a..d6031aa8a 100644 --- a/libImaging/SgiRleDecode.c +++ b/libImaging/SgiRleDecode.c @@ -12,16 +12,17 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.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; for (i = 0; i < n; i++) { @@ -54,10 +55,17 @@ int ImagingSgiRleDecode(Imaging im, ImagingCodecState state, 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; + /* get the channels count */ + zsize = im->bands; + prevrlelength = (ULONG)state->xsize; + if (state->state == 0) { /* check image orientation */ @@ -67,62 +75,58 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, } else state->ystep = 1; - state->state = 1; - - } - - /* get the channels count */ - int zsize = state->bits / state->count; + free(state->buffer); /* allocate memory for the buffer used for full lines later */ 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 */ - unsigned long *starttab, *lengthtab; - int tablen = state->ysize * zsize * sizeof(unsigned long); + tablen = state->ysize * zsize * sizeof(ULONG); - starttab = (unsigned long *)malloc(tablen); - lengthtab = (unsigned long *)malloc(tablen); + starttab = (ULONG*)malloc(tablen); + lengthtab = (ULONG*)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]; + 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 -= 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)); - 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 */ @@ -132,9 +136,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, state->y += state->ystep; } - + + free(rledata); + free(scanline); free(starttab); free(lengthtab); - return -1; + return -1; /* end of file (errcode=0) */ } \ No newline at end of file