Reparatur der venv.
This commit is contained in:
@@ -42,6 +42,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
from typing import IO, Any
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16be as i16
|
||||
@@ -54,7 +55,7 @@ from .JpegPresets import presets
|
||||
# Parser
|
||||
|
||||
|
||||
def Skip(self, marker):
|
||||
def Skip(self: JpegImageFile, marker: int) -> None:
|
||||
n = i16(self.fp.read(2)) - 2
|
||||
ImageFile._safe_read(self.fp, n)
|
||||
|
||||
@@ -94,6 +95,8 @@ def APP(self, marker):
|
||||
else:
|
||||
self.info["exif"] = s
|
||||
self._exif_offset = self.fp.tell() - n + 6
|
||||
elif marker == 0xFFE1 and s[:29] == b"http://ns.adobe.com/xap/1.0/\x00":
|
||||
self.info["xmp"] = s.split(b"\x00", 1)[1]
|
||||
elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
|
||||
# extract FlashPix information (incomplete)
|
||||
self.info["flashpix"] = s # FIXME: value will change
|
||||
@@ -158,40 +161,8 @@ def APP(self, marker):
|
||||
# plus constant header size
|
||||
self.info["mpoffset"] = self.fp.tell() - n + 4
|
||||
|
||||
# If DPI isn't in JPEG header, fetch from EXIF
|
||||
if "dpi" not in self.info and "exif" in self.info:
|
||||
try:
|
||||
exif = self.getexif()
|
||||
resolution_unit = exif[0x0128]
|
||||
x_resolution = exif[0x011A]
|
||||
try:
|
||||
dpi = float(x_resolution[0]) / x_resolution[1]
|
||||
except TypeError:
|
||||
dpi = x_resolution
|
||||
if math.isnan(dpi):
|
||||
msg = "DPI is not a number"
|
||||
raise ValueError(msg)
|
||||
if resolution_unit == 3: # cm
|
||||
# 1 dpcm = 2.54 dpi
|
||||
dpi *= 2.54
|
||||
self.info["dpi"] = dpi, dpi
|
||||
except (
|
||||
struct.error,
|
||||
KeyError,
|
||||
SyntaxError,
|
||||
TypeError,
|
||||
ValueError,
|
||||
ZeroDivisionError,
|
||||
):
|
||||
# struct.error for truncated EXIF
|
||||
# KeyError for dpi not included
|
||||
# SyntaxError for invalid/unreadable EXIF
|
||||
# ValueError or TypeError for dpi being an invalid float
|
||||
# ZeroDivisionError for invalid dpi rational value
|
||||
self.info["dpi"] = 72, 72
|
||||
|
||||
|
||||
def COM(self, marker):
|
||||
def COM(self: JpegImageFile, marker: int) -> None:
|
||||
#
|
||||
# Comment marker. Store these in the APP dictionary.
|
||||
n = i16(self.fp.read(2)) - 2
|
||||
@@ -202,7 +173,7 @@ def COM(self, marker):
|
||||
self.applist.append(("COM", s))
|
||||
|
||||
|
||||
def SOF(self, marker):
|
||||
def SOF(self: JpegImageFile, marker: int) -> None:
|
||||
#
|
||||
# Start of frame marker. Defines the size and mode of the
|
||||
# image. JPEG is colour blind, so we use some simple
|
||||
@@ -250,7 +221,7 @@ def SOF(self, marker):
|
||||
self.layer.append((t[0], t[1] // 16, t[1] & 15, t[2]))
|
||||
|
||||
|
||||
def DQT(self, marker):
|
||||
def DQT(self: JpegImageFile, marker: int) -> None:
|
||||
#
|
||||
# Define quantization table. Note that there might be more
|
||||
# than one table in each marker.
|
||||
@@ -344,7 +315,7 @@ MARKER = {
|
||||
}
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
# Magic number was taken from https://en.wikipedia.org/wiki/JPEG
|
||||
return prefix[:3] == b"\xFF\xD8\xFF"
|
||||
|
||||
@@ -408,7 +379,9 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||
msg = "no marker found"
|
||||
raise SyntaxError(msg)
|
||||
|
||||
def load_read(self, read_bytes):
|
||||
self._read_dpi_from_exif()
|
||||
|
||||
def load_read(self, read_bytes: int) -> bytes:
|
||||
"""
|
||||
internal: read more image data
|
||||
For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker
|
||||
@@ -424,13 +397,15 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||
|
||||
return s
|
||||
|
||||
def draft(self, mode, size):
|
||||
def draft(
|
||||
self, mode: str | None, size: tuple[int, int] | None
|
||||
) -> tuple[str, tuple[int, int, float, float]] | None:
|
||||
if len(self.tile) != 1:
|
||||
return
|
||||
return None
|
||||
|
||||
# Protect from second call
|
||||
if self.decoderconfig:
|
||||
return
|
||||
return None
|
||||
|
||||
d, e, o, a = self.tile[0]
|
||||
scale = 1
|
||||
@@ -460,7 +435,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||
box = (0, 0, original_size[0] / scale, original_size[1] / scale)
|
||||
return self.mode, box
|
||||
|
||||
def load_djpeg(self):
|
||||
def load_djpeg(self) -> None:
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
||||
|
||||
f, path = tempfile.mkstemp()
|
||||
@@ -491,29 +466,43 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||
|
||||
self.tile = []
|
||||
|
||||
def _getexif(self):
|
||||
def _getexif(self) -> dict[str, Any] | None:
|
||||
return _getexif(self)
|
||||
|
||||
def _read_dpi_from_exif(self) -> None:
|
||||
# If DPI isn't in JPEG header, fetch from EXIF
|
||||
if "dpi" in self.info or "exif" not in self.info:
|
||||
return
|
||||
try:
|
||||
exif = self.getexif()
|
||||
resolution_unit = exif[0x0128]
|
||||
x_resolution = exif[0x011A]
|
||||
try:
|
||||
dpi = float(x_resolution[0]) / x_resolution[1]
|
||||
except TypeError:
|
||||
dpi = x_resolution
|
||||
if math.isnan(dpi):
|
||||
msg = "DPI is not a number"
|
||||
raise ValueError(msg)
|
||||
if resolution_unit == 3: # cm
|
||||
# 1 dpcm = 2.54 dpi
|
||||
dpi *= 2.54
|
||||
self.info["dpi"] = dpi, dpi
|
||||
except (
|
||||
struct.error, # truncated EXIF
|
||||
KeyError, # dpi not included
|
||||
SyntaxError, # invalid/unreadable EXIF
|
||||
TypeError, # dpi is an invalid float
|
||||
ValueError, # dpi is an invalid float
|
||||
ZeroDivisionError, # invalid dpi rational value
|
||||
):
|
||||
self.info["dpi"] = 72, 72
|
||||
|
||||
def _getmp(self):
|
||||
return _getmp(self)
|
||||
|
||||
def getxmp(self):
|
||||
"""
|
||||
Returns a dictionary containing the XMP tags.
|
||||
Requires defusedxml to be installed.
|
||||
|
||||
:returns: XMP tags in a dictionary.
|
||||
"""
|
||||
|
||||
for segment, content in self.applist:
|
||||
if segment == "APP1":
|
||||
marker, xmp_tags = content.split(b"\x00")[:2]
|
||||
if marker == b"http://ns.adobe.com/xap/1.0/":
|
||||
return self._getxmp(xmp_tags)
|
||||
return {}
|
||||
|
||||
|
||||
def _getexif(self):
|
||||
def _getexif(self) -> dict[str, Any] | None:
|
||||
if "exif" not in self.info:
|
||||
return None
|
||||
return self.getexif()._get_merged_dict()
|
||||
@@ -641,7 +630,7 @@ def get_sampling(im):
|
||||
return samplings.get(sampling, -1)
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
if im.width == 0 or im.height == 0:
|
||||
msg = "cannot write empty image as JPEG"
|
||||
raise ValueError(msg)
|
||||
@@ -824,7 +813,7 @@ def _save(im, fp, filename):
|
||||
ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
|
||||
|
||||
|
||||
def _save_cjpeg(im, fp, filename):
|
||||
def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||
tempfile = im._dump()
|
||||
subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
|
||||
@@ -841,6 +830,10 @@ def jpeg_factory(fp=None, filename=None):
|
||||
try:
|
||||
mpheader = im._getmp()
|
||||
if mpheader[45057] > 1:
|
||||
for segment, content in im.applist:
|
||||
if segment == "APP1" and b' hdrgm:Version="' in content:
|
||||
# Ultra HDR images are not yet supported
|
||||
return im
|
||||
# It's actually an MPO
|
||||
from .MpoImagePlugin import MpoImageFile
|
||||
|
||||
|
||||
Reference in New Issue
Block a user