import gradio as gr from PIL import Image, ImageFilter import numpy as np def lossless_compression(image, reduction_percent, target_size_kb, auto_mode): """ Сжимает изображение без потерь качества, уменьшая количество пикселей и применяя алгоритмы для сохранения деталей. Args: image: Входное изображение (PIL Image). reduction_percent: Процент уменьшения пикселей по горизонтали (0-100). target_size_kb: Желаемый размер файла в килобайтах (используется в автоматическом режиме). auto_mode: Флаг автоматического режима (True/False). Returns: Сжатое изображение (PIL Image). """ if auto_mode: # Автоматический подбор параметров сжатия reduction_percent, quality = auto_adjust_compression(image, target_size_kb) else: # Ручной режим, используем заданный процент уменьшения quality = 95 # Базовое качество JPEG, можно настроить # 1. Уменьшение количества пикселей по горизонтали width, height = image.size new_width = int(width * (1 - reduction_percent / 100)) resized_image = image.resize((new_width, height), Image.LANCZOS) # 2. Растягивание обратно фильтром Ланцоша stretched_image = resized_image.resize((width, height), Image.LANCZOS) # 3. Адаптивное размытие (уменьшение шума и артефактов) blurred_image = adaptive_blur(stretched_image) # 4. Повышение резкости (компенсация размытия) sharpened_image = blurred_image.filter(ImageFilter.UnsharpMask(radius=1, percent=150, threshold=3)) # 5. Сохранение с оптимизированными параметрами output_image = sharpened_image # Преобразование изображения в формат, пригодный для сохранения в буфер if output_image.mode != "RGB": output_image = output_image.convert("RGB") return output_image, reduction_percent, quality def auto_adjust_compression(image, target_size_kb): """ Автоматически подбирает параметры сжатия для достижения целевого размера файла. Args: image: Входное изображение (PIL Image). target_size_kb: Желаемый размер файла в килобайтах. Returns: Оптимальный процент уменьшения, оптимальное качество JPEG. """ # Очень грубая эвристика для начальной оценки. Нужно тестировать и улучшать initial_reduction = min(50, int(100 * (1 - target_size_kb * 1024 / len(image.tobytes())))) reduction_percent = initial_reduction quality = 95 # Итеративно подбираем параметры, если нужно. # В реальном приложении здесь может быть более сложный алгоритм # с бинарным поиском или другими методами оптимизации. return reduction_percent, quality def adaptive_blur(image): """ Применяет адаптивное размытие к изображению. Args: image: Входное изображение (PIL Image). Returns: Изображение с адаптивным размытием (PIL Image). """ # Преобразуем изображение в массив NumPy для анализа img_array = np.array(image) # Простой пример адаптивного размытия: # Сильнее размываем области с меньшим количеством деталей (меньше дисперсия) # Это очень базовый пример, нужно улучшать в зависимости от задачи std_dev = np.std(img_array) if std_dev < 20: # Порог стандартного отклонения - настраиваемый параметр # Применяем более сильное размытие blurred_image = image.filter(ImageFilter.GaussianBlur(radius=2)) else: # Применяем слабое размытие blurred_image = image.filter(ImageFilter.GaussianBlur(radius=1)) return blurred_image def save_compressed_image(image, quality, filename="compressed_image.jpg"): """ Сохраняет сжатое изображение с указанным качеством. Args: image: PIL Image. quality: Качество JPEG (0-100). filename: Имя файла для сохранения. """ image.save(filename, "JPEG", optimize=True, quality=quality) # Интерфейс Gradio def gradio_interface(image, reduction_percent, target_size_kb, auto_mode): compressed_image, used_reduction, used_quality = lossless_compression(image, reduction_percent, target_size_kb, auto_mode) save_compressed_image(compressed_image, used_quality) return compressed_image, f"Использованное уменьшение: {used_reduction:.2f}%, Качество JPEG: {used_quality}" iface = gr.Interface( fn=gradio_interface, inputs=[ gr.Image(type="pil", label="Исходное изображение"), gr.Slider(0, 50, step=1, value=12, label="Процент уменьшения пикселей по горизонтали (ручной режим)"), gr.Slider(1, 200, step=1, value=50, label="Желаемый размер файла в KB (автоматический режим)"), gr.Checkbox(label="Автоматический режим"), ], outputs=[ gr.Image(type="pil", label="Сжатое изображение"), gr.Textbox(label="Параметры сжатия") ], title="Сжатие изображений без потерь", description="Уменьшает размер изображения, сохраняя визуальное качество. " "Выберите автоматический режим или введите желаемый размер файла " "или процент уменьшения пикселей вручную.", ) iface.launch()