Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added signed option when saving JPEG2000 images #6709

Merged
merged 3 commits into from Dec 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions Tests/test_file_jpeg2k.py
Expand Up @@ -252,6 +252,20 @@ def test_mct():
assert_image_similar(im, jp2, 1.0e-3)


def test_sgnd(tmp_path):
outfile = str(tmp_path / "temp.jp2")

im = Image.new("L", (1, 1))
im.save(outfile)
with Image.open(outfile) as reloaded:
assert reloaded.getpixel((0, 0)) == 0

im = Image.new("L", (1, 1))
im.save(outfile, signed=True)
with Image.open(outfile) as reloaded_signed:
assert reloaded_signed.getpixel((0, 0)) == 128


def test_rgba():
# Arrange
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
Expand Down
5 changes: 5 additions & 0 deletions docs/handbook/image-file-formats.rst
Expand Up @@ -568,6 +568,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
encoded using RLCP mode will have increasing resolutions decoded as they
arrive, and so on.

**signed**
If true, then tell the encoder to save the image as signed.

.. versionadded:: 9.4.0

**cinema_mode**
Set the encoder to produce output compliant with the digital cinema
specifications. The options here are ``"no"`` (the default),
Expand Down
6 changes: 6 additions & 0 deletions docs/releasenotes/9.4.0.rst
Expand Up @@ -45,6 +45,12 @@ removes the hidden RGB values for better compression by default in libwebp 0.5
or later. By setting this option to ``True``, the encoder will keep the hidden
RGB values.

Added ``signed`` option when saving JPEG2000
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the ``signed`` keyword argument is present and true when saving JPEG2000
images, then tell the encoder to save the image as signed.

Added IFD, Interop and LightSource ExifTags enums
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions src/PIL/Jpeg2KImagePlugin.py
Expand Up @@ -321,6 +321,7 @@ def _save(im, fp, filename):
progression = info.get("progression", "LRCP")
cinema_mode = info.get("cinema_mode", "no")
mct = info.get("mct", 0)
signed = info.get("signed", False)
fd = -1

if hasattr(fp, "fileno"):
Expand All @@ -342,6 +343,7 @@ def _save(im, fp, filename):
progression,
cinema_mode,
mct,
signed,
fd,
)

Expand Down
5 changes: 4 additions & 1 deletion src/encode.c
Expand Up @@ -1212,11 +1212,12 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
char *cinema_mode = "no";
OPJ_CINEMA_MODE cine_mode;
char mct = 0;
int sgnd = 0;
Py_ssize_t fd = -1;

if (!PyArg_ParseTuple(
args,
"ss|OOOsOnOOOssbn",
"ss|OOOsOnOOOssbbn",
&mode,
&format,
&offset,
Expand All @@ -1231,6 +1232,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
&progression,
&cinema_mode,
&mct,
&sgnd,
&fd)) {
return NULL;
}
Expand Down Expand Up @@ -1329,6 +1331,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
context->progression = prog_order;
context->cinema_mode = cine_mode;
context->mct = mct;
context->sgnd = sgnd;

return (PyObject *)encoder;
}
Expand Down
3 changes: 3 additions & 0 deletions src/libImaging/Jpeg2K.h
Expand Up @@ -85,6 +85,9 @@ typedef struct {
/* Set multiple component transformation */
char mct;

/* Signed */
int sgnd;

/* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
OPJ_PROG_ORDER progression;

Expand Down
2 changes: 1 addition & 1 deletion src/libImaging/Jpeg2KEncode.c
Expand Up @@ -343,7 +343,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
image_params[n].x0 = image_params[n].y0 = 0;
image_params[n].prec = prec;
image_params[n].bpp = bpp;
image_params[n].sgnd = 0;
image_params[n].sgnd = context->sgnd == 0 ? 0 : 1;
}

image = opj_image_create(components, image_params, color_space);
Expand Down