Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions Tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import logging
import os
import shutil
import subprocess
import sys
import tempfile
from functools import lru_cache
Expand Down Expand Up @@ -282,16 +281,6 @@ def _cached_hopper(mode: str) -> Image.Image:
return im


def djpeg_available() -> bool:
if shutil.which("djpeg"):
try:
subprocess.check_call(["djpeg", "-version"])
return True
except subprocess.CalledProcessError: # pragma: no cover
return False
return False


def netpbm_available() -> bool:
return bool(shutil.which("ppmquant") and shutil.which("ppmtogif"))

Expand Down
8 changes: 0 additions & 8 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
assert_image_equal_tofile,
assert_image_similar,
assert_image_similar_tofile,
djpeg_available,
hopper,
is_win32,
mark_if_feature_version,
Expand Down Expand Up @@ -730,13 +729,6 @@ def test_restart_markers(self, blocks: int, rows: int, markers: int) -> None:
)
assert len(re.findall(b"\xff[\xd0-\xd7]", out.getvalue())) == markers

@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
def test_load_djpeg(self) -> None:
with Image.open(TEST_FILE) as img:
assert isinstance(img, JpegImagePlugin.JpegImageFile)
img.load_djpeg()
assert_image_similar_tofile(img, TEST_FILE, 5)

def test_no_duplicate_0x1001_tag(self) -> None:
# Arrange
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
Expand Down
15 changes: 2 additions & 13 deletions Tests/test_shell_injection.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from __future__ import annotations

import shutil
from io import BytesIO

import pytest

from PIL import GifImagePlugin, Image, JpegImagePlugin
from PIL import GifImagePlugin, Image

from .helper import djpeg_available, is_win32, netpbm_available
from .helper import is_win32, netpbm_available

TYPE_CHECKING = False
if TYPE_CHECKING:
Expand Down Expand Up @@ -36,16 +35,6 @@ def assert_save_filename_check(
with Image.open(dest_file) as im:
im.load()

@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
def test_load_djpeg_filename(self, tmp_path: Path) -> None:
for filename in test_filenames:
src_file = tmp_path / filename
shutil.copy(TEST_JPG, src_file)

with Image.open(src_file) as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
im.load_djpeg()

@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
def test_save_netpbm_filename_bmp_mode(self, tmp_path: Path) -> None:
with Image.open(TEST_GIF) as im:
Expand Down
26 changes: 26 additions & 0 deletions docs/releasenotes/13.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ ImageCms.ImageCmsProfile.product_name and .product_info
``.product_info`` attributes have been removed. They were set to ``None`` since Pillow
2.3.0.

JpegImageFile.load_djpeg()
^^^^^^^^^^^^^^^^^^^^^^^^^^

``JpegImageFile.load_djpeg()`` has been removed.

It was undocumented, and delegated JPEG decoding to the external IJG ``djpeg``
command line utility, requiring the image to be present as a file on disk.

Pillow decodes JPEG images with libjpeg directly,
so :py:meth:`~PIL.Image.Image.load()` can be used instead::

from PIL import Image
with Image.open("hopper.jpg") as im:
im.load()

If ``djpeg`` is still desired, it can be invoked directly.
It writes PPM to standard output, which Pillow can read::

import subprocess
from io import BytesIO
from PIL import Image

data = subprocess.check_output(["djpeg", "hopper.jpg"])
with Image.open(BytesIO(data)) as im:
im.load()

Deprecations
============

Expand Down
34 changes: 0 additions & 34 deletions src/PIL/JpegImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@
import array
import io
import math
import os
import struct
import subprocess
import sys
import tempfile
import warnings

from . import Image, ImageFile
Expand Down Expand Up @@ -465,37 +462,6 @@ def draft(
box = (0, 0, original_size[0] / scale, original_size[1] / scale)
return self.mode, box

def load_djpeg(self) -> None:
# ALTERNATIVE: handle JPEGs via the IJG command line utilities

f, path = tempfile.mkstemp()
os.close(f)
if os.path.exists(self.filename):
subprocess.check_call(["djpeg", "-outfile", path, self.filename])
else:
try:
os.unlink(path)
except OSError:
pass

msg = "Invalid Filename"
raise ValueError(msg)

try:
with Image.open(path) as _im:
_im.load()
self.im = _im.im
finally:
try:
os.unlink(path)
except OSError:
pass

self._mode = self.im.mode
self._size = self.im.size

self.tile = []

def _getexif(self) -> dict[int, Any] | None:
return _getexif(self)

Expand Down
5 changes: 2 additions & 3 deletions winbuild/build_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,16 @@ def cmd_msbuild(
},
"build": [
*cmds_cmake(
("jpeg-static", "djpeg-static"),
("jpeg-static",),
"-DENABLE_SHARED:BOOL=FALSE",
"-DWITH_JPEG8:BOOL=TRUE",
"-DWITH_CRT_DLL:BOOL=TRUE",
),
cmd_copy("jpeg-static.lib", "libjpeg.lib"),
cmd_copy("djpeg-static.exe", "djpeg.exe"),
],
"headers": ["jconfig.h", r"src\j*.h"],
"libs": ["libjpeg.lib"],
"bins": ["djpeg.exe"],
"bins": [],
},
"zlib": {
"url": f"https://github.com/zlib-ng/zlib-ng/archive/refs/tags/{V['zlib-ng']}.tar.gz",
Expand Down
Loading