Spaces:
Sleeping
Sleeping
jslmmfboom-coder
Add cover bg, scene mode selector, single image upload, demo hides upload, about page format
7347923 | """示例场景图片管理 — 优先使用真实图片,缺失时生成合成图片 | |
| 真实图片位于 test_imgs/complex/ 目录(通过 Git LFS 推送) | |
| 文本场景示例由合成生成(模拟合同文档) | |
| """ | |
| import os | |
| from PIL import Image, ImageDraw, ImageFont, ImageFilter | |
| def _get_font(size): | |
| try: | |
| return ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size) | |
| except Exception: | |
| try: | |
| return ImageFont.truetype("DejaVuSans.ttf", size) | |
| except Exception: | |
| return ImageFont.load_default() | |
| def _generate_text_scene(path1, path2): | |
| """生成文本场景示例:模拟合同文档 | |
| 两张图内容相同,但图2做了亮度调整和水平偏移,模拟不同角度拍摄 | |
| """ | |
| w, h = 600, 800 | |
| for path, brightness, offset_x in [(path1, 0, 0), (path2, 30, 5)]: | |
| img = Image.new('RGB', (w, h), (255, 255, 255)) | |
| draw = ImageDraw.Draw(img) | |
| # 标题区域 | |
| draw.rectangle([50 + offset_x, 40, 550 + offset_x, 80], fill=(30, 30, 30)) | |
| # 正文行 | |
| for i in range(25): | |
| y = 120 + i * 25 | |
| x_start = 50 + offset_x | |
| x_end = 550 - (i % 5) * 20 + offset_x | |
| draw.rectangle([x_start, y, x_end, y + 12], fill=(60, 60, 60)) | |
| # 模拟印章(红色圆形) | |
| draw.ellipse([400 + offset_x, 650, 500 + offset_x, 750], | |
| outline=(180, 30, 30), width=3) | |
| draw.text((420 + offset_x, 680), "SEAL", fill=(180, 30, 30), | |
| font=_get_font(20)) | |
| # 亮度调整 | |
| if brightness > 0: | |
| import numpy as np | |
| arr = np.array(img).astype(int) + brightness | |
| arr = np.clip(arr, 0, 255).astype('uint8') | |
| img = Image.fromarray(arr) | |
| img.save(path, 'JPEG', quality=85) | |
| def _scan_real_images(directory): | |
| """扫描目录中的真实图片文件""" | |
| if not os.path.isdir(directory): | |
| return [] | |
| exts = {'.jpg', '.jpeg', '.png', '.bmp', '.webp'} | |
| imgs = [] | |
| for f in sorted(os.listdir(directory)): | |
| if os.path.splitext(f)[1].lower() in exts: | |
| imgs.append(os.path.join(directory, f)) | |
| return imgs | |
| def ensure_demo_images(base_dir): | |
| """确保示例图片存在,优先使用真实图片 | |
| Args: | |
| base_dir: 项目根目录 | |
| Returns: | |
| dict: {'text': [path1, path2], 'complex': [path1, path2]} 或 None | |
| """ | |
| demo_dir = os.path.join(base_dir, 'test_imgs') | |
| os.makedirs(demo_dir, exist_ok=True) | |
| # === 复杂场景:优先使用真实图片 === | |
| complex_dir = os.path.join(demo_dir, 'complex') | |
| real_complex = _scan_real_images(complex_dir) | |
| if len(real_complex) >= 2: | |
| complex_imgs = real_complex[:2] | |
| else: | |
| # Fallback:生成合成图片 | |
| c1 = os.path.join(demo_dir, 'demo_complex_1.jpg') | |
| c2 = os.path.join(demo_dir, 'demo_complex_2.jpg') | |
| if not os.path.exists(c1): | |
| try: | |
| _generate_complex_scene(c1, c2) | |
| print("[示例] 已生成合成复杂场景图片") | |
| except Exception as e: | |
| print(f"[示例] 合成复杂场景生成失败: {e}") | |
| return None | |
| complex_imgs = [c1, c2] | |
| # === 文本场景:优先使用真实图片 === | |
| text_dir = os.path.join(demo_dir, 'text') | |
| real_text = _scan_real_images(text_dir) | |
| if len(real_text) >= 2: | |
| text_imgs = real_text[:2] | |
| else: | |
| # Fallback:生成合成图片 | |
| t1 = os.path.join(demo_dir, 'demo_text_1.jpg') | |
| t2 = os.path.join(demo_dir, 'demo_text_2.jpg') | |
| if not os.path.exists(t1): | |
| try: | |
| _generate_text_scene(t1, t2) | |
| print("[示例] 已生成合成文本场景图片") | |
| except Exception as e: | |
| print(f"[示例] 合成文本场景生成失败: {e}") | |
| return None | |
| text_imgs = [t1, t2] | |
| return { | |
| 'text': text_imgs, | |
| 'complex': complex_imgs, | |
| } | |
| def _generate_complex_scene(path1, path2): | |
| """生成复杂场景示例:模拟实景照片(fallback 用)""" | |
| w, h = 600, 450 | |
| for path, shift_x, color_shift in [(path1, 0, 0), (path2, 15, 20)]: | |
| img = Image.new('RGB', (w, h)) | |
| draw = ImageDraw.Draw(img) | |
| # 天空渐变 | |
| for y in range(h // 2): | |
| r = int(100 + y * 0.3 + color_shift) | |
| g = int(150 + y * 0.2) | |
| b = int(200 + y * 0.15) | |
| draw.line([(0, y), (w, y)], fill=(min(r, 255), min(g, 255), min(b, 255))) | |
| # 地面渐变 | |
| for y in range(h // 2, h): | |
| r = int(80 + (y - h // 2) * 0.3) | |
| g = int(120 + (y - h // 2) * 0.2) | |
| b = int(60 + (y - h // 2) * 0.1) | |
| draw.line([(0, y), (w, y)], fill=(min(r, 255), min(g, 255), min(b, 255))) | |
| # 太阳 | |
| sun_x = 450 + shift_x | |
| draw.ellipse([sun_x - 40, 50, sun_x + 40, 130], | |
| fill=(255, 220, 100)) | |
| # 山脉 | |
| draw.polygon([(0, 225), (150 + shift_x, 150), (300 + shift_x, 200), | |
| (450 + shift_x, 160), (600, 220), (600, 225)], | |
| fill=(80, 100, 80)) | |
| # 建筑 | |
| draw.rectangle([100 + shift_x, 250, 200 + shift_x, 400], | |
| fill=(120, 100, 90)) | |
| draw.rectangle([250 + shift_x, 280, 350 + shift_x, 400], | |
| fill=(100, 110, 100)) | |
| draw.rectangle([400 + shift_x, 260, 480 + shift_x, 400], | |
| fill=(90, 80, 100)) | |
| # 轻微模糊模拟不同焦距 | |
| if shift_x > 0: | |
| img = img.filter(ImageFilter.GaussianBlur(radius=0.8)) | |
| img.save(path, 'JPEG', quality=85) | |