#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Генератор Deep Zoom Image (DZI) тайлов из PNG для быстрого просмотра больших чертежей. Использует PIL — не требует внешних зависимостей. Использование: python generate_dzi.py [--tile-size 256] [--format png] Результат: .dzi — XML-дескриптор _files/ — папка с тайлами level/col_row.png """ import sys import os import math from pathlib import Path from PIL import Image def generate_dzi(png_path: Path, tile_size: int = 256, fmt: str = "png"): """Генерирует DZI тайлы из PNG.""" png_path = Path(png_path) if not png_path.exists(): print(f"[ERR] Файл не найден: {png_path}") sys.exit(1) base = png_path.stem files_dir = png_path.parent / f"{base}_files" files_dir.mkdir(exist_ok=True) print(f"[INFO] Открываем {png_path}...") img = Image.open(png_path) orig_w, orig_h = img.size print(f"[INFO] Размер: {orig_w}x{orig_h}") # DZI uses power-of-2 levels, starting from 1x1 at level 0 max_dim = max(orig_w, orig_h) max_level = math.ceil(math.log2(max_dim)) print(f"[INFO] Уровней: {max_level + 1} (0..{max_level})") # Process from largest to smallest (build pyramid top-down) current = img.convert("RGBA" if fmt == "png" else "RGB") for level in range(max_level, -1, -1): # Calculate size at this level scale = 2 ** (max_level - level) level_w = math.ceil(orig_w / scale) level_h = math.ceil(orig_h / scale) # Resize current image to level size if current.size != (level_w, level_h): current = current.resize((level_w, level_h), Image.LANCZOS) # Save tiles cols = math.ceil(level_w / tile_size) rows = math.ceil(level_h / tile_size) level_dir = files_dir / str(level) level_dir.mkdir(exist_ok=True) for row in range(rows): for col in range(cols): x = col * tile_size y = row * tile_size w = min(tile_size, level_w - x) h = min(tile_size, level_h - y) tile = current.crop((x, y, x + w, y + h)) tile_path = level_dir / f"{col}_{row}.{fmt}" if fmt == "png": tile.save(tile_path, "PNG", compress_level=3) else: tile.save(tile_path, "JPEG", quality=85) print(f" Level {level}: {level_w}x{level_h}, {cols}x{rows} tiles") # Write DZI descriptor dzi_path = png_path.parent / f"{base}.dzi" dzi_xml = f''' ''' dzi_path.write_text(dzi_xml, encoding="utf-8") print(f"[OK] DZI создан: {dzi_path}") print(f" Тайлы: {files_dir}") print(f" Уровней: {max_level + 1}, TileSize: {tile_size}") return dzi_path, files_dir def main(): if len(sys.argv) < 2: print("Usage: python generate_dzi.py [tile_size] [format]") sys.exit(1) png = Path(sys.argv[1]) tile_size = int(sys.argv[2]) if len(sys.argv) > 2 else 256 fmt = sys.argv[3] if len(sys.argv) > 3 else "png" generate_dzi(png, tile_size, fmt) if __name__ == "__main__": main()