mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-05 04:13:11 +03:00
Merge pull request #5500 from scaramallion/dev-j2k
This commit is contained in:
commit
703f54c847
|
@ -209,6 +209,49 @@ def test_layers():
|
||||||
assert_image_similar(im, test_card, 0.4)
|
assert_image_similar(im, test_card, 0.4)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"name, args, offset, data",
|
||||||
|
(
|
||||||
|
("foo.j2k", {}, 0, b"\xff\x4f"),
|
||||||
|
("foo.jp2", {}, 4, b"jP"),
|
||||||
|
(None, {"no_jp2": True}, 0, b"\xff\x4f"),
|
||||||
|
("foo.j2k", {"no_jp2": True}, 0, b"\xff\x4f"),
|
||||||
|
("foo.jp2", {"no_jp2": True}, 0, b"\xff\x4f"),
|
||||||
|
("foo.j2k", {"no_jp2": False}, 0, b"\xff\x4f"),
|
||||||
|
("foo.jp2", {"no_jp2": False}, 4, b"jP"),
|
||||||
|
("foo.jp2", {"no_jp2": False}, 4, b"jP"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_no_jp2(name, args, offset, data):
|
||||||
|
out = BytesIO()
|
||||||
|
if name:
|
||||||
|
out.name = name
|
||||||
|
test_card.save(out, "JPEG2000", **args)
|
||||||
|
out.seek(offset)
|
||||||
|
assert out.read(2) == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_mct():
|
||||||
|
# Three component
|
||||||
|
for val in (0, 1):
|
||||||
|
out = BytesIO()
|
||||||
|
test_card.save(out, "JPEG2000", mct=val, no_jp2=True)
|
||||||
|
|
||||||
|
assert out.getvalue()[59] == val
|
||||||
|
with Image.open(out) as im:
|
||||||
|
assert_image_similar(im, test_card, 1.0e-3)
|
||||||
|
|
||||||
|
# Single component should have MCT disabled
|
||||||
|
for val in (0, 1):
|
||||||
|
out = BytesIO()
|
||||||
|
with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
|
||||||
|
jp2.save(out, "JPEG2000", mct=val, no_jp2=True)
|
||||||
|
|
||||||
|
assert out.getvalue()[53] == 0
|
||||||
|
with Image.open(out) as im:
|
||||||
|
assert_image_similar(im, jp2, 1.0e-3)
|
||||||
|
|
||||||
|
|
||||||
def test_rgba():
|
def test_rgba():
|
||||||
# Arrange
|
# Arrange
|
||||||
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
|
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
|
||||||
|
|
|
@ -504,9 +504,18 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||||
and must be greater than the code-block size.
|
and must be greater than the code-block size.
|
||||||
|
|
||||||
**irreversible**
|
**irreversible**
|
||||||
If ``True``, use the lossy Irreversible Color Transformation
|
If ``True``, use the lossy discrete waveform transformation DWT 9-7.
|
||||||
followed by DWT 9-7. Defaults to ``False``, which means to use the
|
Defaults to ``False``, which uses the lossless DWT 5-3.
|
||||||
Reversible Color Transformation with DWT 5-3.
|
|
||||||
|
**mct**
|
||||||
|
If ``1`` then enable multiple component transformation when encoding,
|
||||||
|
otherwise use ``0`` for no component transformation (default). If MCT is
|
||||||
|
enabled and ``irreversible`` is ``True`` then the Irreversible Color
|
||||||
|
Transformation will be applied, otherwise encoding will use the
|
||||||
|
Reversible Color Transformation. MCT works best with a ``mode`` of
|
||||||
|
``RGB`` and is only applicable when the image data has 3 components.
|
||||||
|
|
||||||
|
.. versionadded:: 9.1.0
|
||||||
|
|
||||||
**progression**
|
**progression**
|
||||||
Controls the progression order; must be one of ``"LRCP"``, ``"RLCP"``,
|
Controls the progression order; must be one of ``"LRCP"``, ``"RLCP"``,
|
||||||
|
@ -526,6 +535,13 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||||
for compliant 4K files, *at least one* of the dimensions must match
|
for compliant 4K files, *at least one* of the dimensions must match
|
||||||
4096 x 2160.
|
4096 x 2160.
|
||||||
|
|
||||||
|
**no_jp2**
|
||||||
|
If ``True`` then don't wrap the raw codestream in the JP2 file format when
|
||||||
|
saving, otherwise the extension of the filename will be used to determine
|
||||||
|
the format (default).
|
||||||
|
|
||||||
|
.. versionadded:: 9.1.0
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
To enable JPEG 2000 support, you need to build and install the OpenJPEG
|
To enable JPEG 2000 support, you need to build and install the OpenJPEG
|
||||||
|
|
|
@ -146,12 +146,24 @@ At present, the information within each block is merely returned as a dictionary
|
||||||
"data" entry. This will allow more useful information to be added in the future without
|
"data" entry. This will allow more useful information to be added in the future without
|
||||||
breaking backwards compatibility.
|
breaking backwards compatibility.
|
||||||
|
|
||||||
Added rawmode argument to Image.getpalette()
|
Added mct and no_jp2 options for saving JPEG 2000
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
By default, :py:meth:`~PIL.Image.Image.getpalette` returns RGB data from the palette.
|
The :py:meth:`PIL.Image.Image.save` method now supports the following options for
|
||||||
A ``rawmode`` argument has been added, to allow the mode to be chosen instead. ``None``
|
JPEG 2000:
|
||||||
can be used to return data in the current mode of the palette.
|
|
||||||
|
**mct**
|
||||||
|
If ``1`` then enable multiple component transformation when encoding,
|
||||||
|
otherwise use ``0`` for no component transformation (default). If MCT is
|
||||||
|
enabled and ``irreversible`` is ``True`` then the Irreversible Color
|
||||||
|
Transformation will be applied, otherwise encoding will use the
|
||||||
|
Reversible Color Transformation. MCT works best with a ``mode`` of
|
||||||
|
``RGB`` and is only applicable when the image data has 3 components.
|
||||||
|
|
||||||
|
**no_jp2**
|
||||||
|
If ``True`` then don't wrap the raw codestream in the JP2 file format when
|
||||||
|
saving, otherwise the extension of the filename will be used to determine
|
||||||
|
the format (default).
|
||||||
|
|
||||||
Added PyEncoder
|
Added PyEncoder
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -290,14 +290,14 @@ def _accept(prefix):
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
if filename.endswith(".j2k"):
|
# Get the keyword arguments
|
||||||
|
info = im.encoderinfo
|
||||||
|
|
||||||
|
if filename.endswith(".j2k") or info.get("no_jp2", False):
|
||||||
kind = "j2k"
|
kind = "j2k"
|
||||||
else:
|
else:
|
||||||
kind = "jp2"
|
kind = "jp2"
|
||||||
|
|
||||||
# Get the keyword arguments
|
|
||||||
info = im.encoderinfo
|
|
||||||
|
|
||||||
offset = info.get("offset", None)
|
offset = info.get("offset", None)
|
||||||
tile_offset = info.get("tile_offset", None)
|
tile_offset = info.get("tile_offset", None)
|
||||||
tile_size = info.get("tile_size", None)
|
tile_size = info.get("tile_size", None)
|
||||||
|
@ -320,6 +320,7 @@ def _save(im, fp, filename):
|
||||||
irreversible = info.get("irreversible", False)
|
irreversible = info.get("irreversible", False)
|
||||||
progression = info.get("progression", "LRCP")
|
progression = info.get("progression", "LRCP")
|
||||||
cinema_mode = info.get("cinema_mode", "no")
|
cinema_mode = info.get("cinema_mode", "no")
|
||||||
|
mct = info.get("mct", 0)
|
||||||
fd = -1
|
fd = -1
|
||||||
|
|
||||||
if hasattr(fp, "fileno"):
|
if hasattr(fp, "fileno"):
|
||||||
|
@ -340,6 +341,7 @@ def _save(im, fp, filename):
|
||||||
irreversible,
|
irreversible,
|
||||||
progression,
|
progression,
|
||||||
cinema_mode,
|
cinema_mode,
|
||||||
|
mct,
|
||||||
fd,
|
fd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1187,11 +1187,12 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
|
||||||
OPJ_PROG_ORDER prog_order;
|
OPJ_PROG_ORDER prog_order;
|
||||||
char *cinema_mode = "no";
|
char *cinema_mode = "no";
|
||||||
OPJ_CINEMA_MODE cine_mode;
|
OPJ_CINEMA_MODE cine_mode;
|
||||||
|
char mct = 0;
|
||||||
Py_ssize_t fd = -1;
|
Py_ssize_t fd = -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(
|
if (!PyArg_ParseTuple(
|
||||||
args,
|
args,
|
||||||
"ss|OOOsOnOOOssn",
|
"ss|OOOsOnOOOssbn",
|
||||||
&mode,
|
&mode,
|
||||||
&format,
|
&format,
|
||||||
&offset,
|
&offset,
|
||||||
|
@ -1205,6 +1206,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
|
||||||
&irreversible,
|
&irreversible,
|
||||||
&progression,
|
&progression,
|
||||||
&cinema_mode,
|
&cinema_mode,
|
||||||
|
&mct,
|
||||||
&fd)) {
|
&fd)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1302,6 +1304,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
|
||||||
context->irreversible = PyObject_IsTrue(irreversible);
|
context->irreversible = PyObject_IsTrue(irreversible);
|
||||||
context->progression = prog_order;
|
context->progression = prog_order;
|
||||||
context->cinema_mode = cine_mode;
|
context->cinema_mode = cine_mode;
|
||||||
|
context->mct = mct;
|
||||||
|
|
||||||
return (PyObject *)encoder;
|
return (PyObject *)encoder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,9 @@ typedef struct {
|
||||||
/* Compression style */
|
/* Compression style */
|
||||||
int irreversible;
|
int irreversible;
|
||||||
|
|
||||||
|
/* Set multiple component transformation */
|
||||||
|
char mct;
|
||||||
|
|
||||||
/* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
|
/* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
|
||||||
OPJ_PROG_ORDER progression;
|
OPJ_PROG_ORDER progression;
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,9 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
params.irreversible = context->irreversible;
|
params.irreversible = context->irreversible;
|
||||||
|
if (components == 3) {
|
||||||
|
params.tcp_mct = context->mct;
|
||||||
|
}
|
||||||
|
|
||||||
params.prog_order = context->progression;
|
params.prog_order = context->progression;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user