Skip to content

Commit

Permalink
fixed saving not a current frame when saving from Pillow.
Browse files Browse the repository at this point in the history
  • Loading branch information
bigcat88 committed Jun 10, 2022
1 parent 35982b2 commit c2feaa2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 42 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ All notable changes to this project will be documented in this file.

### Fixed

- Minor usage fixes.
- Speed optimizations.
- (HeifImagePlugin) - `save` bug, when first frame was saved instead of current.
- Minor usage fixes and optimizations.

## [0.2.5 - 2022-05-30]

Expand Down
85 changes: 45 additions & 40 deletions pillow_heif/heif.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,48 +542,53 @@ def add_from_pillow(self, pil_image: Image.Image, load_one=False, ignore_primary
:param load_one: should be only one frame loaded. Default=``False``
:param ignore_primary: force ``PrimaryImage=False`` flag to all added images."""

for frame in ImageSequence.Iterator(pil_image):
if frame.width > 0 and frame.height > 0:
additional_info = {}
supported_info_keys = (
"exif",
"xmp",
"metadata",
"primary",
"icc_profile",
"icc_profile_type",
"nclx_profile",
)
for k in supported_info_keys:
if k in frame.info:
additional_info[k] = frame.info[k]
if ignore_primary:
additional_info["primary"] = False
if "xmp" not in additional_info and "XML:com.adobe.xmp" in frame.info:
additional_info["xmp"] = frame.info["XML:com.adobe.xmp"]
if "xmp" in additional_info and isinstance(additional_info["xmp"], str):
additional_info["xmp"] = additional_info["xmp"].encode("utf-8")
original_orientation = set_orientation(additional_info)
if frame.mode == "P":
mode = "RGBA" if frame.info.get("transparency") else "RGB"
frame = frame.convert(mode=mode)
elif frame.mode == "LA":
frame = frame.convert(mode="RGBA")
elif frame.mode == "L":
frame = frame.convert(mode="RGB")

if original_orientation is not None and original_orientation != 1:
frame = ImageOps.exif_transpose(frame)
# check image.bits / pallete.rawmode to detect > 8 bit or maybe something else?
_bit_depth = 8
added_image = self._add_frombytes(
_bit_depth, frame.mode, frame.size, frame.tobytes(), add_info={**additional_info}
)
added_image.copy_thumbnails(frame.info.get("thumbnails", []), **kwargs)
if load_one:
break
if load_one:
self.__add_frame_from_pillow(pil_image, ignore_primary, **kwargs)
else:
for frame in ImageSequence.Iterator(pil_image):
self.__add_frame_from_pillow(frame, ignore_primary, **kwargs)
return self

def __add_frame_from_pillow(self, frame: Image.Image, ignore_primary: bool, **kwargs) -> None:
if frame.width <= 0 or frame.height <= 0:
return
additional_info = {}
supported_info_keys = (
"exif",
"xmp",
"metadata",
"primary",
"icc_profile",
"icc_profile_type",
"nclx_profile",
)
for k in supported_info_keys:
if k in frame.info:
additional_info[k] = frame.info[k]
if ignore_primary:
additional_info["primary"] = False
if "xmp" not in additional_info and "XML:com.adobe.xmp" in frame.info:
additional_info["xmp"] = frame.info["XML:com.adobe.xmp"]
if "xmp" in additional_info and isinstance(additional_info["xmp"], str):
additional_info["xmp"] = additional_info["xmp"].encode("utf-8")
original_orientation = set_orientation(additional_info)
if frame.mode == "P":
mode = "RGBA" if frame.info.get("transparency") else "RGB"
frame = frame.convert(mode=mode)
elif frame.mode == "LA":
frame = frame.convert(mode="RGBA")
elif frame.mode == "L":
frame = frame.convert(mode="RGB")

if original_orientation is not None and original_orientation != 1:
frame = ImageOps.exif_transpose(frame)
# check image.bits / pallete.rawmode to detect > 8 bit or maybe something else?
_bit_depth = 8
added_image = self._add_frombytes(
_bit_depth, frame.mode, frame.size, frame.tobytes(), add_info={**additional_info}
)
added_image.copy_thumbnails(frame.info.get("thumbnails", []), **kwargs)

def add_from_heif(self, heif_image, load_one=False, ignore_primary=True, **kwargs):
"""Add image(s) to container.
Expand Down
3 changes: 3 additions & 0 deletions tests/opener_encoder_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def test_gif():
out_heic = BytesIO()
gif_pillow.save(out_heic, format="HEIF")
imagehash.compare_hashes([gif_pillow, out_heic], hash_type="dhash")
# save second gif frame
ImageSequence.Iterator(gif_pillow)[1].save(out_heic, format="HEIF")
imagehash.compare_hashes([gif_pillow, out_heic], hash_type="dhash")
# convert all frames of gif(pillow_heif does not skip identical frames and saves all frames like in source)
out_all_heic = BytesIO()
gif_pillow.save(out_all_heic, format="HEIF", save_all=True, quality=80)
Expand Down

0 comments on commit c2feaa2

Please sign in to comment.