decode_base64_to_image: don't crash if EXIF data is broken (#4764)

* decode_base64_to_image: don't crash when if EXIF data is broken

* Simplify EXIF transposition to not read the EXIF data twice

---------

Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
Aarni Koskela 2023-07-06 18:35:08 +03:00 committed by GitHub
parent bc97b7ba96
commit 87e14e38b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 4 deletions

View File

@ -35,6 +35,7 @@
- Fixes `gr.Dropdown` being cutoff at the bottom by [@abidlabs](https://github.com/abidlabs) in [PR 4691](https://github.com/gradio-app/gradio/pull/4691).
- Scroll top when clicking "View API" in spaces by [@pngwn](https://github.com/pngwn) in [PR 4714](https://github.com/gradio-app/gradio/pull/4714)
- Fix bug where `show_label` was hiding the entire component for `gr.Label` by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 4713](https://github.com/gradio-app/gradio/pull/4713)
- Don't crash when uploaded image has broken EXIF data, by [@akx](https://github.com/akx) in [PR 4764](https://github.com/gradio-app/gradio/pull/4764)
- Place toast messages at the top of the screen by [@pngwn](https://github.com/pngwn) in [PR 4796](https://github.com/gradio-app/gradio/pull/4796)
- Fix regressed styling of Login page when auth is enabled by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 4797](https://github.com/gradio-app/gradio/pull/4797)

View File

@ -2,6 +2,7 @@ from __future__ import annotations
import base64
import json
import logging
import os
import shutil
import subprocess
@ -24,6 +25,7 @@ with warnings.catch_warnings():
warnings.simplefilter("ignore") # Ignore pydub warning if ffmpeg is not installed
from pydub import AudioSegment
log = logging.getLogger(__name__)
#########################
# GENERAL
@ -55,10 +57,15 @@ def extract_base64_data(x: str) -> str:
def decode_base64_to_image(encoding: str) -> Image.Image:
image_encoded = extract_base64_data(encoding)
img = Image.open(BytesIO(base64.b64decode(image_encoded)))
exif = img.getexif()
# 274 is the code for image rotation and 1 means "correct orientation"
if exif.get(274, 1) != 1 and hasattr(ImageOps, "exif_transpose"):
img = ImageOps.exif_transpose(img)
try:
if hasattr(ImageOps, "exif_transpose"):
img = ImageOps.exif_transpose(img)
except Exception:
log.warning(
"Failed to transpose image %s based on EXIF data.",
img,
exc_info=True,
)
return img

View File

@ -1,3 +1,6 @@
import base64
import io
import logging
import os
import shutil
import tempfile
@ -261,3 +264,20 @@ class TestVideoProcessing:
)
# If the conversion succeeded it'd be .mp4
assert Path(playable_vid).suffix == ".avi"
def test_decode_base64_to_image_does_not_crash_when_image_has_bogus_exif_data(caplog):
from PIL.PngImagePlugin import PngInfo
caplog.set_level(logging.WARNING)
i = Image.new("RGB", (32, 32), "orange")
bio = io.BytesIO()
# since `exif` is the `.info` key for EXIF data parsed from a JPEG,
# adding an iTXt chunk with the same name should trigger the warning
pi = PngInfo()
pi.add_text("exif", "bogus")
i.save(bio, format="png", pnginfo=pi)
bio.seek(0)
encoded = base64.b64encode(bio.getvalue()).decode()
assert processing_utils.decode_base64_to_image(encoded).size == (32, 32)
assert "Failed to transpose image" in caplog.text