mirror of
https://github.com/RapidAI/RapidOCR.git
synced 2026-11-10 13:03:58 +08:00
fix(python): honor EXIF orientation for bytes and PIL images (#755)
This commit is contained in:
2 files changed
+62
-3
No files matched your search
@@ -81,14 +81,15 @@ class LoadImage:
|
||||
return img
|
||||
|
||||
if isinstance(img, bytes):
|
||||
img = self.img_to_ndarray(Image.open(BytesIO(img)))
|
||||
img = self.exif_transpose(Image.open(BytesIO(img)))
|
||||
img = self.img_to_ndarray(img)
|
||||
return img
|
||||
|
||||
if isinstance(img, np.ndarray):
|
||||
return img
|
||||
|
||||
if isinstance(img, Image.Image):
|
||||
return self.img_to_ndarray(img)
|
||||
return self.img_to_ndarray(self.exif_transpose(img))
|
||||
|
||||
if isinstance(img, MemoryImage):
|
||||
try:
|
||||
@@ -116,7 +117,7 @@ class LoadImage:
|
||||
if img_corrected is None:
|
||||
return img
|
||||
return img_corrected
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
return img
|
||||
|
||||
def img_to_ndarray(self, img: Image.Image) -> np.ndarray:
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from PIL import Image
|
||||
from rapidocr.utils.load_image import LoadImage
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_type", ["bytes", "pil"])
|
||||
@pytest.mark.parametrize("orientation", [1, 3, 6, 8])
|
||||
def test_exif_input_types_match_path(tmp_path, input_type, orientation):
|
||||
pixels = np.arange(18, dtype=np.uint8).reshape(2, 3, 3)
|
||||
image = Image.fromarray(pixels)
|
||||
exif = image.getexif()
|
||||
exif[274] = orientation
|
||||
path = tmp_path / "oriented.png"
|
||||
image.save(path, exif=exif)
|
||||
loader = LoadImage()
|
||||
rotations = {1: 0, 3: 2, 6: 3, 8: 1}
|
||||
expected = np.rot90(pixels, rotations[orientation])[..., ::-1]
|
||||
np.testing.assert_array_equal(loader(path), expected)
|
||||
|
||||
if input_type == "bytes":
|
||||
actual = loader(path.read_bytes())
|
||||
else:
|
||||
with Image.open(path) as pil_image:
|
||||
original_pixels = np.array(pil_image)
|
||||
actual = loader(pil_image)
|
||||
assert pil_image.getexif()[274] == orientation
|
||||
np.testing.assert_array_equal(np.array(pil_image), original_pixels)
|
||||
np.testing.assert_array_equal(actual, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_type", ["bytes", "pil"])
|
||||
def test_exif_existing_jpeg_matches_path(input_type):
|
||||
path = Path(__file__).parent / "test_files" / "img_exif_orientation.jpg"
|
||||
loader = LoadImage()
|
||||
expected = loader(path)
|
||||
if input_type == "bytes":
|
||||
actual = loader(path.read_bytes())
|
||||
else:
|
||||
with Image.open(path) as image:
|
||||
actual = loader(image)
|
||||
np.testing.assert_array_equal(actual, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_type", ["bytes", "pil"])
|
||||
def test_input_without_exif_preserves_pixels(tmp_path, input_type):
|
||||
pixels = np.arange(18, dtype=np.uint8).reshape(2, 3, 3)
|
||||
image = Image.fromarray(pixels)
|
||||
path = tmp_path / "unoriented.png"
|
||||
image.save(path)
|
||||
loader = LoadImage()
|
||||
if input_type == "bytes":
|
||||
actual = loader(path.read_bytes())
|
||||
else:
|
||||
actual = loader(image)
|
||||
np.testing.assert_array_equal(actual, pixels[..., ::-1])
|
||||
Reference in new issue
Block a user