Skip to content

Commit

Permalink
Merge pull request #6709 from radarhere/signed
Browse files Browse the repository at this point in the history
Added signed option when saving JPEG2000 images
  • Loading branch information
hugovk committed Dec 29, 2022
2 parents dc30ccc + cd351c4 commit f452f9a
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 2 deletions.
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

0 comments on commit f452f9a

Please sign in to comment.