Skip to content

Commit

Permalink
Merge pull request #2952 from activeloopai/upgrade_pillow
Browse files Browse the repository at this point in the history
Upgrade pillow
  • Loading branch information
activesoull committed Sep 17, 2024
2 parents 1e33651 + bc58942 commit 165a9e0
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 34 deletions.
8 changes: 4 additions & 4 deletions deeplake/core/chunk/sample_compressed_chunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@ def read_sample( # type: ignore
return sample

if squeeze:
sample = sample.squeeze(0)
sample = sample.squeeze(0) # type: ignore

if cast and sample.dtype != self.dtype:
sample = sample.astype(self.dtype)
elif copy and not sample.flags["WRITEABLE"]:
if cast and sample.dtype != self.dtype: # type: ignore
sample = sample.astype(self.dtype) # type: ignore
elif copy and not sample.flags["WRITEABLE"]: # type: ignore
sample = sample.copy()
return sample

Expand Down
21 changes: 13 additions & 8 deletions deeplake/core/compression.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
_STRUCT_II = struct.Struct(">ii")


def to_image(array: np.ndarray) -> Image:
def to_image(array: np.ndarray) -> Image.Image:
shape = array.shape
if len(shape) == 3 and shape[0] != 1 and shape[2] == 1:
# convert (X,Y,1) grayscale to (X,Y) for pillow compatibility
Expand Down Expand Up @@ -116,17 +116,22 @@ def _compress_apng(array: np.ndarray) -> bytes:

def _decompress_apng(buffer: Union[bytes, memoryview]) -> np.ndarray:
img = Image.open(BytesIO(buffer))

n_frames = getattr(img, "n_frames", 1)

if n_frames == 1:
raise ValueError("Image does not support multiple frames.")
frame0 = np.array(img)
if frame0.ndim == 2:
ret = np.zeros(frame0.shape + (img.n_frames,), dtype=frame0.dtype)
ret = np.zeros(frame0.shape + (n_frames,), dtype=frame0.dtype)
ret[:, :, 0] = frame0
for i in range(1, img.n_frames):
for i in range(1, n_frames):
img.seek(i)
ret[:, :, i] = np.array(img)
else:
ret = np.zeros((img.n_frames,) + frame0.shape, dtype=frame0.dtype)
ret = np.zeros((n_frames,) + frame0.shape, dtype=frame0.dtype)
ret[0] = frame0
for i in range(1, img.n_frames):
for i in range(1, n_frames):
img.seek(i)
ret[i] = np.array(img)
return ret
Expand Down Expand Up @@ -420,9 +425,9 @@ def decompress_multiple(
next_x = 0
for shape in shapes:
if shape == (0, 0, 0):
arrays.append(np.zeros(shape, dtype=canvas.dtype))
arrays.append(np.zeros(shape, dtype=canvas.dtype)) # type: ignore
else:
arrays.append(canvas[: shape[0], next_x : next_x + shape[1]])
arrays.append(canvas[: shape[0], next_x : next_x + shape[1]]) # type: ignore
next_x += shape[1]
return arrays

Expand Down Expand Up @@ -728,7 +733,7 @@ def read_meta_from_compressed_file(
else:
img = Image.open(f) if isfile else Image.open(BytesIO(f)) # type: ignore
shape, typestr = Image._conv_type_shape(img)
compression = img.format.lower()
compression = None if img.format is None else img.format.lower()
return compression, shape, typestr # type: ignore
finally:
if close:
Expand Down
10 changes: 5 additions & 5 deletions deeplake/core/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,10 @@ def _decompress(self, to_pil: bool = False):
compression=compression,
shape=self.shape,
dtype=self.dtype,
)
self._uncompressed_bytes = self._array.tobytes()
self._typestr = self._array.__array_interface__["typestr"]
self._dtype = np.dtype(self._typestr).name
) # type: ignore
self._uncompressed_bytes = self._array.tobytes() # type: ignore
self._typestr = self._array.__array_interface__["typestr"] # type: ignore
self._dtype = np.dtype(self._typestr).name # type: ignore

def uncompressed_bytes(self) -> Optional[bytes]:
"""Returns uncompressed bytes."""
Expand All @@ -420,7 +420,7 @@ def array(self) -> np.ndarray: # type: ignore
return self._array # type: ignore

@property
def pil(self) -> Image.Image: # type: ignore
def pil(self) -> Optional[Image.Image]: # type: ignore
"""Return PIL image corresponding to the sample. Decompresses the sample if necessary.
Example:
Expand Down
2 changes: 1 addition & 1 deletion deeplake/requirements/common.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
numpy<2.0
pillow~=10.2.0
pillow~=10.4.0
boto3
click
google-cloud-storage~=1.42.0
Expand Down
4 changes: 2 additions & 2 deletions deeplake/requirements/plugins.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
--find-links https://download.openmmlab.com/mmcv/dist/cpu/torch1.13/index.html
--find-links https://download.openmmlab.com/mmcv/dist/cpu/torch1.12/index.html
torch
torchvision
tensorflow
tensorflow_datasets
pickle5>=0.0.11; python_version < "3.8" and python_version >= "3.6"
datasets~=1.17
mmcv-full==1.7.1; platform_system == "Linux" and python_version >= "3.7"
mmcv-full==1.7.1; platform_system == "Linux" and python_version >= "3.7" --find-links https://download.openmmlab.com/mmcv/dist/cpu/torch1.12/index.html
mmdet==2.28.1; platform_system == "Linux" and python_version >= "3.7"
mmsegmentation==0.30.0; platform_system == "Linux" and python_version >= "3.7"
mmengine
Expand Down
2 changes: 1 addition & 1 deletion deeplake/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def get_actual_compression_from_buffer(buffer: memoryview) -> Optional[str]:
try:
bio = BytesIO(buffer)
img = Image.open(bio)
return img.format.lower()
return None if img.format is None else img.format.lower()

except UnidentifiedImageError:
return None
Expand Down
6 changes: 3 additions & 3 deletions deeplake/util/downsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def needs_downsampling(sample, factor: int):
if isinstance(sample, Image.Image):
dimensions = sample.size
elif isinstance(sample, np.ndarray):
dimensions = sample.shape
dimensions = sample.shape # type: ignore
if len(dimensions) == 3 and dimensions[2] == 0:
return False
dimensions = dimensions[:2]
Expand Down Expand Up @@ -62,7 +62,7 @@ def downsample_sample(
elif isinstance(sample, SampleTiles):
sample = sample.arr or PartialSample(
sample.sample_shape, sample.tile_shape, sample.dtype
)
) # type: ignore

if isinstance(sample, PartialSample):
return sample.downsample(factor)
Expand Down Expand Up @@ -126,7 +126,7 @@ def downsample_link_tiled(
if compression is None:
return arr
with io.BytesIO() as f:
Image.fromarray(arr).save(f, format=compression)
Image.fromarray(arr).save(f, format=compression) # type: ignore
image_bytes = f.getvalue()
return deeplake.core.sample.Sample(buffer=image_bytes, compression=compression)

Expand Down
26 changes: 17 additions & 9 deletions deeplake/util/exif.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fractions import Fraction
from typing import Any, Dict

from PIL import Image # type: ignore
import PIL.ExifTags # type: ignore
Expand Down Expand Up @@ -41,22 +42,23 @@
}


def getexif(image: Image):
raw_exif = image._getexif()
def getexif(image: Image.Image) -> Dict[str, Any]:
raw_exif = image.getexif()
if not raw_exif:
return {}

exif = {}
for k, v in raw_exif.items():
tag = k
k = PIL.ExifTags.TAGS.get(k, k)
v = _process_exif_value(k, v)
key = str(PIL.ExifTags.TAGS.get(k, k))
v = _process_exif_value(key, v)
if v is None:
continue
exif[k] = v
exif[key] = v
return exif


def _process_exif_value(k: str, v):
def _process_exif_value(k: str, v: Any) -> Any:
if hasattr(v, "numerator"): # Rational
v = v.numerator / v.denominator if v.denominator else 0
if k == "ExposureTime":
Expand All @@ -67,12 +69,18 @@ def _process_exif_value(k: str, v):
except ValueError: # nan
pass
return v

elif k in _LOOKUPS:
return _LOOKUPS[k][v]
elif isinstance(v, bytes):
if isinstance(_LOOKUPS[k], dict):
return _LOOKUPS[k].get(v, v) # type: ignore
elif isinstance(_LOOKUPS[k], tuple):
return _LOOKUPS[k][v] if v < len(_LOOKUPS[k]) else v

elif isinstance(v, bytes): # Handle byte data
return str(v) if len(v) < 16 else "<bytes>"
elif isinstance(v, (list, tuple)):
return type(v)(_process_exif_value("_", x) for x in v)
elif isinstance(v, dict):
return {k: _process_exif_value("_", x) for k, x in v.items()}
return {key: _process_exif_value("_", x) for key, x in v.items()}

return str(v)
2 changes: 1 addition & 1 deletion deeplake/util/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def convert_sample(image_sample: Sample, mode: str) -> Sample:
image.close()
return image_sample

image = image.convert(mode)
image = image.convert(mode) # type: ignore
image_bytes = BytesIO()
image.save(image_bytes, format=image_sample.compression)
converted = Sample(
Expand Down

0 comments on commit 165a9e0

Please sign in to comment.