rename jxl -> jpegxl

This commit is contained in:
olokelo 2024-03-19 22:17:35 +01:00
parent 6048520fcf
commit 8fa280f6a5
11 changed files with 73 additions and 74 deletions

View File

@ -4,7 +4,7 @@ import re
import pytest
from PIL import Image, JxlImagePlugin, features
from PIL import Image, JpegXlImagePlugin, features
from .helper import (
assert_image_similar_tofile,
@ -12,39 +12,38 @@ from .helper import (
)
try:
from PIL import _jxl
from PIL import _jpegxl
HAVE_JXL = True
HAVE_JPEGXL = True
except ImportError:
HAVE_JXL = False
HAVE_JPEGXL = False
# cjxl v0.9.2 41b8cdab
# hopper.jxl: cjxl hopper.png hopper.jxl -q 75 -e 8
class TestUnsupportedJxl:
class TestUnsupportedJpegXl:
def test_unsupported(self) -> None:
if HAVE_JXL:
JxlImagePlugin.SUPPORTED = False
if HAVE_JPEGXL:
JpegXlImagePlugin.SUPPORTED = False
file_path = "Tests/images/hopper.jxl"
with pytest.warns(UserWarning):
with pytest.raises(OSError):
with Image.open(file_path):
pass
with pytest.raises(OSError):
with Image.open(file_path):
pass
if HAVE_JXL:
JxlImagePlugin.SUPPORTED = True
if HAVE_JPEGXL:
JpegXlImagePlugin.SUPPORTED = True
@skip_unless_feature("jxl")
class TestFileJxl:
@skip_unless_feature("jpegxl")
class TestFileJpegXl:
def setup_method(self) -> None:
self.rgb_mode = "RGB"
def test_version(self) -> None:
_jxl.JxlDecoderVersion()
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("jxl"))
_jpegxl.JpegXlDecoderVersion()
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("jpegxl"))
def test_read_rgb(self) -> None:
"""
@ -63,10 +62,10 @@ class TestFileJxl:
# djxl hopper.jxl hopper_jxl_bits.ppm
assert_image_similar_tofile(image, "Tests/images/hopper_jxl_bits.ppm", 1.0)
def test_JxlDecode_with_invalid_args(self) -> None:
def test_JpegXlDecode_with_invalid_args(self) -> None:
"""
Calling decoder functions with no arguments should result in an error.
"""
with pytest.raises(TypeError):
_jxl.PILJxlDecoder()
_jpegxl.PILJpegXlDecoder()

View File

@ -6,7 +6,7 @@ from PIL import Image
from .helper import assert_image_similar_tofile
_webp = pytest.importorskip("PIL._jxl", reason="JXL support not installed")
_jpegxl = pytest.importorskip("PIL._jpegxl", reason="JPEG XL support not installed")
def test_read_rgba() -> None:

View File

@ -10,7 +10,7 @@ from .helper import (
)
pytestmark = [
skip_unless_feature("jxl"),
skip_unless_feature("jpegxl"),
]

View File

@ -9,7 +9,7 @@ from PIL import Image
from .helper import skip_unless_feature
pytestmark = [
skip_unless_feature("jxl"),
skip_unless_feature("jpegxl"),
]
ElementTree: ModuleType | None

View File

@ -9,8 +9,8 @@ from .helper import PillowLeakTestCase, skip_unless_feature
TEST_FILE = "Tests/images/hopper.jxl"
@skip_unless_feature("jxl")
class TestJxlLeaks(PillowLeakTestCase):
@skip_unless_feature("jpegxl")
class TestJpegXlLeaks(PillowLeakTestCase):
mem_limit = 6 * 1024 # kb
iterations = 1000

View File

@ -286,7 +286,7 @@ class pil_build_ext(build_ext):
features = [
"zlib",
"jpeg",
"jxl",
"jpegxl",
"tiff",
"freetype",
"raqm",
@ -695,13 +695,13 @@ class pil_build_ext(build_ext):
feature.jpeg2000 = "openjp2"
feature.openjpeg_version = ".".join(str(x) for x in best_version)
if feature.want("jxl"):
_dbg("Looking for jxl")
if feature.want("jpegxl"):
_dbg("Looking for jpegxl")
if _find_include_file(self, "jxl/encode.h") and _find_include_file(
self, "jxl/decode.h"
):
if _find_library_file(self, "jxl"):
feature.jxl = "jxl jxl_threads"
feature.jpegxl = "jxl jxl_threads"
if feature.want("imagequant"):
_dbg("Looking for imagequant")
@ -786,14 +786,14 @@ class pil_build_ext(build_ext):
# alternate Windows name.
feature.lcms = "lcms2_static"
if feature.jxl:
if feature.jpegxl:
# jxl and jxl_threads are required
libs = feature.jxl.split()
libs = feature.jpegxl.split()
defs = []
self._update_extension("PIL._jxl", libs, defs)
self._update_extension("PIL._jpegxl", libs, defs)
else:
self._remove_extension("PIL._jxl")
self._remove_extension("PIL._jpegxl")
if feature.want("webp"):
_dbg("Looking for webp")
@ -955,7 +955,7 @@ class pil_build_ext(build_ext):
(feature.freetype, "FREETYPE2"),
(feature.raqm, "RAQM (Text shaping)", raqm_extra_info),
(feature.lcms, "LITTLECMS2"),
(feature.jxl, "JXL"),
(feature.jpegxl, "JPEG XL"),
(feature.webp, "WEBP"),
(feature.webpmux, "WEBPMUX"),
(feature.xcb, "XCB (X protocol)"),
@ -1000,7 +1000,7 @@ ext_modules = [
Extension("PIL._imaging", files),
Extension("PIL._imagingft", ["src/_imagingft.c"]),
Extension("PIL._imagingcms", ["src/_imagingcms.c"]),
Extension("PIL._jxl", ["src/_jxl.c"]),
Extension("PIL._jpegxl", ["src/_jpegxl.c"]),
Extension("PIL._webp", ["src/_webp.c"]),
Extension("PIL._imagingtk", ["src/_imagingtk.c", "src/Tk/tkImaging.c"]),
Extension("PIL._imagingmath", ["src/_imagingmath.c"]),

View File

@ -6,7 +6,7 @@ from io import BytesIO
from . import Image, ImageFile
try:
from . import _jxl
from . import _jpegxl
SUPPORTED = True
except ImportError:
@ -33,14 +33,14 @@ def _accept(prefix: bytes) -> bool:
return is_jxl
class JxlImageFile(ImageFile.ImageFile):
class JpegXlImageFile(ImageFile.ImageFile):
format = "JPEG XL"
format_description = "JPEG XL image"
__loaded = 0
__logical_frame = 0
def _open(self) -> None:
self._decoder = _jxl.PILJxlDecoder(self.fp.read())
self._decoder = _jpegxl.PILJpegXlDecoder(self.fp.read())
width, height, mode, has_anim, tps_num, tps_denom, n_loops, n_frames = (
self._decoder.get_info()
@ -174,6 +174,6 @@ class JxlImageFile(ImageFile.ImageFile):
return self.__logical_frame
Image.register_open(JxlImageFile.format, JxlImageFile, _accept)
Image.register_extension(JxlImageFile.format, ".jxl")
Image.register_mime(JxlImageFile.format, "image/jxl")
Image.register_open(JpegXlImageFile.format, JpegXlImageFile, _accept)
Image.register_extension(JpegXlImageFile.format, ".jxl")
Image.register_mime(JpegXlImageFile.format, "image/jxl")

View File

@ -47,7 +47,7 @@ _plugins = [
"IptcImagePlugin",
"JpegImagePlugin",
"Jpeg2KImagePlugin",
"JxlImagePlugin",
"JpegXlImagePlugin",
"McIdasImagePlugin",
"MicImagePlugin",
"MpegImagePlugin",

View File

@ -14,7 +14,7 @@ modules = {
"tkinter": ("PIL._tkinter_finder", "tk_version"),
"freetype2": ("PIL._imagingft", "freetype2_version"),
"littlecms2": ("PIL._imagingcms", "littlecms_version"),
"jxl": ("PIL._jxl", "libjxl_version"),
"jpegxl": ("PIL._jpegxl", "libjxl_version"),
"webp": ("PIL._webp", "webpdecoder_version"),
}
@ -269,7 +269,7 @@ def pilinfo(out=None, supported_formats=True):
("transp_webp", "WEBP Transparency"),
("webp_mux", "WEBPMUX"),
("webp_anim", "WEBP Animation"),
("jxl", "JPEG XL"),
("jpegxl", "JPEG XL"),
("jpg", "JPEG"),
("jpg_2000", "OPENJPEG (JPEG2000)"),
("zlib", "ZLIB (PNG/ZIP)"),

View File

@ -83,13 +83,13 @@ typedef struct {
Py_ssize_t n_frames;
char *mode;
} PILJxlDecoderObject;
} PILJpegXlDecoderObject;
static PyTypeObject PILJxlDecoder_Type;
static PyTypeObject PILJpegXlDecoder_Type;
void
_jxl_decoder_dealloc(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
if (decp->jxl_data) {
free(decp->jxl_data);
@ -131,7 +131,7 @@ _jxl_decoder_dealloc(PyObject *self) {
// sets input jxl bitstream loaded into jxl_data
// has to be called after every rewind
void _jxl_decoder_set_input(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
decp->status = JxlDecoderSetInput(decp->decoder, decp->jxl_data,
decp->jxl_data_len);
@ -144,7 +144,7 @@ void _jxl_decoder_set_input(PyObject *self) {
PyObject *
_jxl_decoder_rewind(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
JxlDecoderRewind(decp->decoder);
Py_RETURN_NONE;
@ -152,7 +152,7 @@ _jxl_decoder_rewind(PyObject *self) {
bool
_jxl_decoder_count_frames(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
decp->n_frames = 0;
@ -179,8 +179,8 @@ PyObject *
_jxl_decoder_new(PyObject *self, PyObject *args) {
PyBytesObject *jxl_string;
PILJxlDecoderObject *decp = NULL;
decp = PyObject_New(PILJxlDecoderObject, &PILJxlDecoder_Type);
PILJpegXlDecoderObject *decp = NULL;
decp = PyObject_New(PILJpegXlDecoderObject, &PILJpegXlDecoder_Type);
decp->mode = NULL;
decp->jxl_data = NULL;
decp->jxl_data_len = 0;
@ -202,7 +202,7 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
return NULL;
}
// this data needs to be copied to PILJxlDecoderObject
// this data needs to be copied to PILJpegXlDecoderObject
// so that input bitstream is preserved across calls
const uint8_t *_tmp_jxl_data;
Py_ssize_t _tmp_jxl_data_len;
@ -393,7 +393,7 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
PyObject *
_jxl_decoder_get_info(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
return Py_BuildValue(
"IIsiIIII",
@ -411,7 +411,7 @@ _jxl_decoder_get_info(PyObject *self) {
PyObject *
_jxl_decoder_get_next(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
PyObject *bytes;
PyObject *ret;
JxlFrameHeader fhdr = {};
@ -500,7 +500,7 @@ _jxl_decoder_get_next(PyObject *self) {
PyObject *
_jxl_decoder_get_icc(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
if (!decp->jxl_icc) Py_RETURN_NONE;
@ -509,7 +509,7 @@ _jxl_decoder_get_icc(PyObject *self) {
PyObject *
_jxl_decoder_get_exif(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
if (!decp->jxl_exif) Py_RETURN_NONE;
@ -518,15 +518,15 @@ _jxl_decoder_get_exif(PyObject *self) {
PyObject *
_jxl_decoder_get_xmp(PyObject *self) {
PILJxlDecoderObject *decp = (PILJxlDecoderObject *)self;
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
if (!decp->jxl_xmp) Py_RETURN_NONE;
return PyBytes_FromStringAndSize((const char *)decp->jxl_xmp, decp->jxl_xmp_len);
}
// PILJxlDecoder methods
static struct PyMethodDef _jxl_decoder_methods[] = {
// PILJpegXlDecoder methods
static struct PyMethodDef _jpegxl_decoder_methods[] = {
{"get_info", (PyCFunction)_jxl_decoder_get_info, METH_NOARGS, "get_info"},
{"get_next", (PyCFunction)_jxl_decoder_get_next, METH_NOARGS, "get_next"},
{"get_icc", (PyCFunction)_jxl_decoder_get_icc, METH_NOARGS, "get_icc"},
@ -536,10 +536,10 @@ static struct PyMethodDef _jxl_decoder_methods[] = {
{NULL, NULL} /* sentinel */
};
// PILJxlDecoder type definition
static PyTypeObject PILJxlDecoder_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "PILJxlDecoder", /*tp_name */
sizeof(PILJxlDecoderObject), /*tp_basicsize */
// PILJpegXlDecoder type definition
static PyTypeObject PILJpegXlDecoder_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "PILJpegXlDecoder", /*tp_name */
sizeof(PILJpegXlDecoderObject), /*tp_basicsize */
0, /*tp_itemsize */
/* methods */
(destructor)_jxl_decoder_dealloc, /*tp_dealloc*/
@ -565,7 +565,7 @@ static PyTypeObject PILJxlDecoder_Type = {
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
_jxl_decoder_methods, /*tp_methods*/
_jpegxl_decoder_methods, /*tp_methods*/
0, /*tp_members*/
0, /*tp_getset*/
};
@ -573,13 +573,13 @@ static PyTypeObject PILJxlDecoder_Type = {
// Return libjxl decoder version available as integer:
// MAJ*1_000_000 + MIN*1_000 + PATCH
PyObject *
JxlDecoderVersion_wrapper() {
JpegXlDecoderVersion_wrapper() {
return Py_BuildValue("i", JxlDecoderVersion());
}
// Version as string
const char *
JxlDecoderVersion_str(void) {
JpegXlDecoderVersion_str(void) {
static char version[20];
int version_number = JxlDecoderVersion();
sprintf(
@ -592,22 +592,22 @@ JxlDecoderVersion_str(void) {
return version;
}
static PyMethodDef jxlMethods[] = {
{"JxlDecoderVersion", JxlDecoderVersion_wrapper, METH_NOARGS, "JxlVersion"},
{"PILJxlDecoder", _jxl_decoder_new, METH_VARARGS, "PILJxlDecoder"},
static PyMethodDef jpegxlMethods[] = {
{"JpegXlDecoderVersion", JpegXlDecoderVersion_wrapper, METH_NOARGS, "JpegXlVersion"},
{"PILJpegXlDecoder", _jxl_decoder_new, METH_VARARGS, "PILJpegXlDecoder"},
{NULL, NULL}
};
static int
setup_module(PyObject *m) {
if (PyType_Ready(&PILJxlDecoder_Type) < 0) {
if (PyType_Ready(&PILJpegXlDecoder_Type) < 0) {
return -1;
}
// TODO(oloke) ready object types?
PyObject *d = PyModule_GetDict(m);
PyObject *v = PyUnicode_FromString(JxlDecoderVersion_str());
PyObject *v = PyUnicode_FromString(JpegXlDecoderVersion_str());
PyDict_SetItemString(d, "libjxl_version", v ? v : Py_None);
Py_XDECREF(v);
@ -615,15 +615,15 @@ setup_module(PyObject *m) {
}
PyMODINIT_FUNC
PyInit__jxl(void) {
PyInit__jpegxl(void) {
PyObject *m;
static PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
"_jxl", /* m_name */
"_jpegxl", /* m_name */
NULL, /* m_doc */
-1, /* m_size */
jxlMethods, /* m_methods */
jpegxlMethods, /* m_methods */
};
m = PyModule_Create(&module_def);