"""End-to-end orientation-detection tests against synthetic text pages. Skipped automatically if the tesseract binary isn't installed. """ from __future__ import annotations import shutil import cv2 import numpy as np import pytest from PIL import Image, ImageDraw, ImageFont from paperpod.vision.orient import apply_rotation, auto_rotate pytestmark = pytest.mark.skipif( shutil.which("tesseract") is None, reason="tesseract binary not installed" ) _FONT_CANDIDATES = [ "/System/Library/Fonts/Helvetica.ttc", "/System/Library/Fonts/Supplemental/Arial.ttf", ] def _font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: for path in _FONT_CANDIDATES: try: return ImageFont.truetype(path, size) except OSError: continue return ImageFont.load_default() def _text_page() -> np.ndarray: """A tall white page with a few lines of real words (upright, 0 degrees). Rendered with a real TrueType font (not cv2.putText's blocky stroke font), which produces normal glyph shapes; cv2.putText text fragments into dozens of spurious single-character "words" when rotated sideways, which isn't representative of real documents/photos. """ img = Image.new("RGB", (400, 600), (255, 255, 255)) draw = ImageDraw.Draw(img) font = _font(22) lines = [ "INVOICE FROM ACME CORP", "Date: January 5, 2024", "Description of services rendered", "Thank you for your business", "Please remit payment within 30 days", ] for i, line in enumerate(lines): draw.text((20, 80 + i * 60), line, fill=(0, 0, 0), font=font) return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) @pytest.mark.parametrize("applied_rotation", [0, 90, 180, 270]) def test_auto_rotate_corrects_known_rotation(applied_rotation): """Rotating upright text by N clockwise needs (360-N) clockwise to undo.""" upright = _text_page() rotated_input = apply_rotation(upright, applied_rotation) corrected, result = auto_rotate(rotated_input) assert result.rotation == (360 - applied_rotation) % 360 assert corrected.shape == upright.shape def test_apply_rotation_identity_at_zero(): page = _text_page() assert np.array_equal(apply_rotation(page, 0), page) def test_apply_rotation_180_is_involutive(): page = _text_page() twice = apply_rotation(apply_rotation(page, 180), 180) assert np.array_equal(twice, page)