mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 09:56:17 +03:00
Pure Python MSP Decoder
This commit is contained in:
parent
069ad8cbb0
commit
949932f45f
|
@ -1,6 +1,5 @@
|
|||
#
|
||||
# The Python Imaging Library.
|
||||
# $Id$
|
||||
#
|
||||
# MSP file handling
|
||||
#
|
||||
|
@ -9,9 +8,11 @@
|
|||
# History:
|
||||
# 95-09-05 fl Created
|
||||
# 97-01-03 fl Read/write MSP images
|
||||
# 17-02-21 es Fixed RLE interpretation
|
||||
#
|
||||
# Copyright (c) Secret Labs AB 1997.
|
||||
# Copyright (c) Fredrik Lundh 1995-97.
|
||||
# Copyright (c) Eric Soroos 2017.
|
||||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
@ -20,9 +21,11 @@
|
|||
# Figure 205. Windows Paint Version 1: "DanM" Format
|
||||
# Figure 206. Windows Paint Version 2: "LinS" Format. Used in Windows V2.03
|
||||
#
|
||||
# See also: http://www.fileformat.info/format/mspaint/egff.htm
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16le as i16, o16le as o16
|
||||
import struct, io
|
||||
|
||||
__version__ = "0.1"
|
||||
|
||||
|
@ -64,7 +67,91 @@ class MspImageFile(ImageFile.ImageFile):
|
|||
if s[:4] == b"DanM":
|
||||
self.tile = [("raw", (0, 0)+self.size, 32, ("1", 0, 1))]
|
||||
else:
|
||||
self.tile = [("msp", (0, 0)+self.size, 32+2*self.size[1], None)]
|
||||
self.tile = [("MSP", (0, 0)+self.size, 32, None)]
|
||||
|
||||
|
||||
class MspDecoder(ImageFile.PyDecoder):
|
||||
# The algo for the MSP decoder is from
|
||||
# http://www.fileformat.info/format/mspaint/egff.htm
|
||||
# cc-by-attribution -- That page references is taken from the
|
||||
# Encyclopedia of Graphics File Formats and is licensed by
|
||||
# O'Reilly under the Creative Common/Attribution license
|
||||
#
|
||||
# For RLE encoded files, the 32byte header is followed by a scan
|
||||
# line map, encoded as one 16bit word of encoded byte length per
|
||||
# line.
|
||||
#
|
||||
# NOTE: the encoded length of the line can be 0. This was not
|
||||
# handled in the previous version of this encoder, and there's no
|
||||
# mention of how to handle it in the documentation. From the few
|
||||
# examples I've seen, I've assumed that it is a fill of the
|
||||
# background color, in this case, white.
|
||||
#
|
||||
#
|
||||
# Pseudocode of the decoder:
|
||||
# Read a BYTE value as the RunType
|
||||
# If the RunType value is zero
|
||||
# Read next byte as the RunCount
|
||||
# Read the next byte as the RunValue
|
||||
# Write the RunValue byte RunCount times
|
||||
# If the RunType value is non-zero
|
||||
# Use this value as the RunCount
|
||||
# Read and write the next RunCount bytes literally
|
||||
#
|
||||
# e.g.:
|
||||
# 0x00 03 ff 05 00 01 02 03 04
|
||||
# would yield the bytes:
|
||||
# 0xff ff ff 00 01 02 03 04
|
||||
#
|
||||
# which are then interpreted as a bit packed mode '1' image
|
||||
|
||||
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer):
|
||||
|
||||
img = io.BytesIO()
|
||||
blank_line = bytearray((0xff,)*((self.state.xsize+7)//8))
|
||||
try:
|
||||
last_pos = 0
|
||||
self.fd.seek(32)
|
||||
rowmap = struct.unpack_from("<%dH" % (self.state.ysize),
|
||||
self.fd.read(self.state.ysize*2))
|
||||
except struct.error:
|
||||
raise IOError("Truncated MSP file in row map")
|
||||
|
||||
for x, rowlen in enumerate(rowmap):
|
||||
try:
|
||||
if rowlen == 0:
|
||||
img.write(blank_line)
|
||||
continue
|
||||
row = self.fd.read(rowlen)
|
||||
if len(row) != rowlen:
|
||||
raise IOError("Truncated MSP file, expected %d bytes on row %s",
|
||||
(rowlen, x))
|
||||
idx = 0
|
||||
while idx < rowlen:
|
||||
runtype = row[idx]
|
||||
idx += 1
|
||||
if runtype == 0:
|
||||
(runcount, runval) = struct.unpack("Bc", row[idx:idx+2])
|
||||
img.write(runval * runcount)
|
||||
idx += 2
|
||||
else:
|
||||
runcount = runtype
|
||||
img.write(row[idx:idx+runcount])
|
||||
idx += runcount
|
||||
|
||||
except struct.error:
|
||||
raise IOError("Corrupted MSP file in row %d" %x)
|
||||
|
||||
self.set_as_raw(img.getvalue(), ("1", 0, 1))
|
||||
|
||||
return 0,0
|
||||
|
||||
|
||||
Image.register_decoder('MSP', MspDecoder)
|
||||
|
||||
|
||||
#
|
||||
# write MSP files (uncompressed only)
|
||||
|
|
|
@ -3290,7 +3290,6 @@ extern PyObject* PyImaging_JpegDecoderNew(PyObject* self, PyObject* args);
|
|||
extern PyObject* PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_MspDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_PcxDecoderNew(PyObject* self, PyObject* args);
|
||||
|
@ -3368,7 +3367,6 @@ static PyMethodDef functions[] = {
|
|||
{"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
|
||||
{"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
|
||||
#endif
|
||||
{"msp_decoder", (PyCFunction)PyImaging_MspDecoderNew, 1},
|
||||
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1},
|
||||
{"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, 1},
|
||||
{"pcx_decoder", (PyCFunction)PyImaging_PcxDecoderNew, 1},
|
||||
|
|
21
decode.c
21
decode.c
|
@ -557,27 +557,6 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* MSP */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
PyObject*
|
||||
PyImaging_MspDecoderNew(PyObject* self, PyObject* args)
|
||||
{
|
||||
ImagingDecoderObject* decoder;
|
||||
|
||||
decoder = PyImaging_DecoderNew(0);
|
||||
if (decoder == NULL)
|
||||
return NULL;
|
||||
|
||||
if (get_unpacker(decoder, "1", "1") < 0)
|
||||
return NULL;
|
||||
|
||||
decoder->decode = ImagingMspDecode;
|
||||
|
||||
return (PyObject*) decoder;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* PackBits */
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* The Python Imaging Library.
|
||||
* $Id$
|
||||
*
|
||||
* decoder for MSP version 2 data.
|
||||
*
|
||||
* history:
|
||||
* 97-01-03 fl Created
|
||||
*
|
||||
* 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
|
||||
ImagingMspDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||
{
|
||||
int n;
|
||||
UINT8* ptr;
|
||||
|
||||
ptr = buf;
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (bytes < 1)
|
||||
return ptr - buf;
|
||||
|
||||
if (ptr[0] == 0) {
|
||||
|
||||
/* Run (3 bytes block) */
|
||||
if (bytes < 3)
|
||||
break;
|
||||
|
||||
n = ptr[1];
|
||||
|
||||
if (state->x + n > state->bytes) {
|
||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(state->buffer + state->x, ptr[2], n);
|
||||
|
||||
ptr += 3;
|
||||
bytes -= 3;
|
||||
|
||||
} else {
|
||||
|
||||
/* Literal (1+n bytes block) */
|
||||
n = ptr[0];
|
||||
|
||||
if (bytes < 1 + n)
|
||||
break;
|
||||
|
||||
if (state->x + n > state->bytes) {
|
||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(state->buffer + state->x, ptr + 1, n);
|
||||
|
||||
ptr += 1 + n;
|
||||
bytes -= 1 + n;
|
||||
|
||||
}
|
||||
|
||||
state->x += n;
|
||||
|
||||
if (state->x >= state->bytes) {
|
||||
|
||||
/* Got a full line, unpack it */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize, state->buffer,
|
||||
state->xsize);
|
||||
|
||||
state->x = 0;
|
||||
|
||||
if (++state->y >= state->ysize) {
|
||||
/* End of file (errcode = 0) */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ptr - buf;
|
||||
}
|
2
setup.py
2
setup.py
|
@ -32,7 +32,7 @@ _LIB_IMAGING = (
|
|||
"Draw", "Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode",
|
||||
"Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode", "Histo",
|
||||
"JpegDecode", "JpegEncode", "LzwDecode", "Matrix", "ModeFilter",
|
||||
"MspDecode", "Negative", "Offset", "Pack", "PackDecode", "Palette", "Paste",
|
||||
"Negative", "Offset", "Pack", "PackDecode", "Palette", "Paste",
|
||||
"Quant", "QuantOctree", "QuantHash", "QuantHeap", "PcdDecode", "PcxDecode",
|
||||
"PcxEncode", "Point", "RankFilter", "RawDecode", "RawEncode", "Storage",
|
||||
"SunRleDecode", "TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask",
|
||||
|
|
Loading…
Reference in New Issue
Block a user