Added signed option when saving JPEG2000 images

This commit is contained in:
Andrew Murray 2022-11-03 18:26:31 +11:00
parent a4ec9f331c
commit 6ddbe4cbf0
6 changed files with 29 additions and 2 deletions

View File

@ -252,6 +252,20 @@ def test_mct():
assert_image_similar(im, jp2, 1.0e-3) 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(): 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:

View File

@ -563,6 +563,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
encoded using RLCP mode will have increasing resolutions decoded as they encoded using RLCP mode will have increasing resolutions decoded as they
arrive, and so on. arrive, and so on.
**signed**
If true, then tell the encoder to save the image as signed.
.. versionadded:: 9.4.0
**cinema_mode** **cinema_mode**
Set the encoder to produce output compliant with the digital cinema Set the encoder to produce output compliant with the digital cinema
specifications. The options here are ``"no"`` (the default), specifications. The options here are ``"no"`` (the default),

View File

@ -321,6 +321,7 @@ def _save(im, fp, filename):
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) mct = info.get("mct", 0)
signed = info.get("signed", False)
fd = -1 fd = -1
if hasattr(fp, "fileno"): if hasattr(fp, "fileno"):
@ -342,6 +343,7 @@ def _save(im, fp, filename):
progression, progression,
cinema_mode, cinema_mode,
mct, mct,
signed,
fd, fd,
) )

View File

@ -1188,11 +1188,12 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
char *cinema_mode = "no"; char *cinema_mode = "no";
OPJ_CINEMA_MODE cine_mode; OPJ_CINEMA_MODE cine_mode;
char mct = 0; char mct = 0;
int sgnd = 0;
Py_ssize_t fd = -1; Py_ssize_t fd = -1;
if (!PyArg_ParseTuple( if (!PyArg_ParseTuple(
args, args,
"ss|OOOsOnOOOssbn", "ss|OOOsOnOOOssbbn",
&mode, &mode,
&format, &format,
&offset, &offset,
@ -1207,6 +1208,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
&progression, &progression,
&cinema_mode, &cinema_mode,
&mct, &mct,
&sgnd,
&fd)) { &fd)) {
return NULL; return NULL;
} }
@ -1305,6 +1307,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) {
context->progression = prog_order; context->progression = prog_order;
context->cinema_mode = cine_mode; context->cinema_mode = cine_mode;
context->mct = mct; context->mct = mct;
context->sgnd = sgnd;
return (PyObject *)encoder; return (PyObject *)encoder;
} }

View File

@ -85,6 +85,9 @@ typedef struct {
/* Set multiple component transformation */ /* Set multiple component transformation */
char mct; char mct;
/* Signed */
int sgnd;
/* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */ /* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
OPJ_PROG_ORDER progression; OPJ_PROG_ORDER progression;

View File

@ -343,7 +343,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
image_params[n].x0 = image_params[n].y0 = 0; image_params[n].x0 = image_params[n].y0 = 0;
image_params[n].prec = prec; image_params[n].prec = prec;
image_params[n].bpp = bpp; 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); image = opj_image_create(components, image_params, color_space);