2010-07-31 06:52:47 +04:00
|
|
|
/*
|
|
|
|
* THIS IS WORK IN PROGRESS
|
|
|
|
*
|
|
|
|
* The Python Imaging Library.
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* decoder for SUN RLE data.
|
|
|
|
*
|
|
|
|
* history:
|
2016-11-20 04:39:30 +03:00
|
|
|
* 97-01-04 fl Created
|
2010-07-31 06:52:47 +04:00
|
|
|
*
|
|
|
|
* Copyright (c) Fredrik Lundh 1997.
|
|
|
|
* Copyright (c) Secret Labs AB 1997.
|
|
|
|
*
|
|
|
|
* See the README file for information on usage and redistribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "Imaging.h"
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-04-15 10:33:28 +03:00
|
|
|
ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
|
2010-07-31 06:52:47 +04:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
UINT8* ptr;
|
2016-11-20 04:39:30 +03:00
|
|
|
UINT8 extra_data = 0;
|
|
|
|
UINT8 extra_bytes = 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
ptr = buf;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (bytes < 1) {
|
2016-11-20 04:39:30 +03:00
|
|
|
return ptr - buf;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (ptr[0] == 0x80) {
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2020-05-10 12:56:36 +03:00
|
|
|
if (bytes < 2) {
|
2016-11-20 04:39:30 +03:00
|
|
|
break;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
n = ptr[1];
|
2010-07-31 06:52:47 +04:00
|
|
|
|
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (n == 0) {
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
/* Literal 0x80 (2 bytes) */
|
|
|
|
n = 1;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
state->buffer[state->x] = 0x80;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
ptr += 2;
|
|
|
|
bytes -= 2;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
/* Run (3 bytes) */
|
2020-05-10 12:56:36 +03:00
|
|
|
if (bytes < 3) {
|
2016-11-20 04:39:30 +03:00
|
|
|
break;
|
2020-05-10 12:56:36 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2017-02-14 12:27:02 +03:00
|
|
|
/* from (https://www.fileformat.info/format/sunraster/egff.htm)
|
2016-11-20 06:12:30 +03:00
|
|
|
|
|
|
|
For example, a run of 100 pixels with the value of
|
|
|
|
0Ah would encode as the values 80h 64h 0Ah. A
|
|
|
|
single pixel value of 80h would encode as the
|
|
|
|
values 80h 00h. The four unencoded bytes 12345678h
|
|
|
|
would be stored in the RLE stream as 12h 34h 56h
|
|
|
|
78h. 100 pixels, n=100, not 100 pixels, n=99.
|
|
|
|
|
2017-02-14 12:27:02 +03:00
|
|
|
But Wait! There's More!
|
|
|
|
(https://www.fileformat.info/format/sunraster/spec/598a59c4fac64c52897585d390d86360/view.htm)
|
2016-11-20 06:12:30 +03:00
|
|
|
|
|
|
|
If the first byte is 0x80, and the second byte is
|
|
|
|
not zero, the record is three bytes long. The
|
|
|
|
second byte is a count and the third byte is a
|
|
|
|
value. Output (count+1) pixels of that value.
|
|
|
|
|
|
|
|
2 specs, same site, but Imagemagick and GIMP seem
|
|
|
|
to agree on the second one.
|
|
|
|
*/
|
2017-02-14 12:27:02 +03:00
|
|
|
n += 1;
|
2013-07-01 02:42:19 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (state->x + n > state->bytes) {
|
|
|
|
extra_bytes = n; /* full value */
|
|
|
|
n = state->bytes - state->x;
|
|
|
|
extra_bytes -= n;
|
|
|
|
extra_data = ptr[2];
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
memset(state->buffer + state->x, ptr[2], n);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
ptr += 3;
|
|
|
|
bytes -= 3;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
} else {
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2017-02-14 12:27:02 +03:00
|
|
|
/* Literal byte */
|
|
|
|
n = 1;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
state->buffer[state->x] = ptr[0];
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
ptr += 1;
|
|
|
|
bytes -= 1;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
for (;;) {
|
|
|
|
state->x += n;
|
2017-02-14 12:27:02 +03:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (state->x >= state->bytes) {
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
/* Got a full line, unpack it */
|
|
|
|
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
|
|
|
state->xoff * im->pixelsize, state->buffer,
|
|
|
|
state->xsize);
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
state->x = 0;
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (++state->y >= state->ysize) {
|
|
|
|
/* End of file (errcode = 0) */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2017-02-14 12:27:02 +03:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (extra_bytes == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (state->x > 0) {
|
|
|
|
break; // assert
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
|
2016-11-20 04:39:30 +03:00
|
|
|
if (extra_bytes >= state->bytes) {
|
|
|
|
n = state->bytes;
|
|
|
|
} else {
|
|
|
|
n = extra_bytes;
|
|
|
|
}
|
|
|
|
memset(state->buffer + state->x, extra_data, n);
|
|
|
|
extra_bytes -= n;
|
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ptr - buf;
|
|
|
|
}
|