Image_Compressor / utils /compressor.py
DILSHAD737's picture
Upload 3 files
cd922fb verified
Raw
History Blame Contribute Delete
5.26 kB
import io
import subprocess
from PIL import Image, ImageOps
import cv2
import numpy as np
from pathlib import Path
import piexif
class ImageCompressor:
def __init__(self):
self.supported_formats = {'.jpg', '.jpeg', '.png', '.webp', '.gif', '.bmp', '.tiff'}
def compress(self, input_path, output_path, method="auto", **kwargs):
"""Main compression entry point"""
img = Image.open(input_path)
original_size = Path(input_path).stat().st_size
# Get original format
original_format = img.format
if method == "auto":
# Use AI analyzer to determine best method
from .ai_analyzer import ContentAnalyzer
analyzer = ContentAnalyzer()
_, strategy = analyzer.analyze(input_path)
method = strategy.get("method", "avif")
kwargs = {**kwargs, **strategy}
# Apply compression based on method
if method == "avif":
compressed = self._compress_avif(img, kwargs.get('quality', 75))
output_path = str(output_path).replace(Path(output_path).suffix, '.avif')
elif method == "webp_lossless":
compressed = self._compress_webp_lossless(img, kwargs.get('quality', 90))
output_path = str(output_path).replace(Path(output_path).suffix, '.webp')
elif method == "png_optimized":
compressed = self._compress_png_optimized(img, kwargs.get('colors', 256))
output_path = str(output_path).replace(Path(output_path).suffix, '.png')
elif method == "png_quantized":
compressed = self._compress_png_quantized(img, kwargs.get('colors', 128))
output_path = str(output_path).replace(Path(output_path).suffix, '.png')
elif method == "jpeg_high_quality":
compressed = self._compress_jpeg(img, kwargs.get('quality', 85))
output_path = str(output_path).replace(Path(output_path).suffix, '.jpg')
else:
# Default to WebP
compressed = self._compress_webp(img, kwargs.get('quality', 80))
output_path = str(output_path).replace(Path(output_path).suffix, '.webp')
# Save compressed image
with open(output_path, 'wb') as f:
f.write(compressed)
compressed_size = Path(output_path).stat().st_size
ratio = (1 - compressed_size / original_size) * 100
return output_path, ratio
def _compress_avif(self, img, quality=75):
"""AVIF compression - best for photos"""
output = io.BytesIO()
# Convert RGBA to RGB if needed (AVIF doesn't support alpha well)
if img.mode == 'RGBA':
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1])
img = background
# Save as AVIF (requires pillow-avif-plugin)
img.save(output, format='AVIF', quality=quality, speed=4)
return output.getvalue()
def _compress_webp_lossless(self, img, quality=90):
"""Lossless WebP for text/screenshots"""
output = io.BytesIO()
img.save(output, format='WEBP', lossless=True, quality=quality, method=6)
return output.getvalue()
def _compress_webp(self, img, quality=80):
"""Standard WebP compression"""
output = io.BytesIO()
img.save(output, format='WEBP', quality=quality, method=4)
return output.getvalue()
def _compress_png_optimized(self, img, colors=256):
"""PNG with color palette reduction"""
output = io.BytesIO()
# Convert to palette mode
if colors < 256:
img = img.quantize(colors=colors, method=Image.MEDIANCUT)
img.save(output, format='PNG', optimize=True)
else:
img.save(output, format='PNG', optimize=True)
return output.getvalue()
def _compress_png_quantized(self, img, colors=128):
"""Heavy PNG quantization for graphics"""
output = io.BytesIO()
# Reduce colors dramatically
img_quantized = img.quantize(colors=colors, method=Image.FASTOCTREE)
img_quantized.save(output, format='PNG', optimize=True)
return output.getvalue()
def _compress_jpeg(self, img, quality=85):
"""JPEG compression"""
output = io.BytesIO()
# Convert to RGB if needed
if img.mode in ('RGBA', 'LA', 'P'):
img = img.convert('RGB')
img.save(output, format='JPEG', quality=quality, optimize=True, progressive=True)
return output.getvalue()
def smart_resize(self, img, target_dimension=2048):
"""Intelligently resize if image is too large"""
width, height = img.size
max_dim = max(width, height)
if max_dim > target_dimension:
scale = target_dimension / max_dim
new_size = (int(width * scale), int(height * scale))
return img.resize(new_size, Image.Resampling.LANCZOS)
return img
def remove_metadata(self, image_path):
"""Strip all EXIF metadata"""
piexif.remove(str(image_path))