This commit is contained in:
Mateusz Gruszczyński committed 2026-10-23 16:06:29 +02:00
1 parent 6a821c7512
commit 594d9e1df3
5 files changed
+173 -5

No files matched your search

+16 -4
View File
@@ -26,6 +26,7 @@ from PIL import Image
from drupal_lookup import DrupalReferenceLookup, node_url, search_url
from image_optimizer import create_optimized_candidate
from image_safety import DEFAULT_MAX_IMAGE_PIXELS, safe_image_open
def build_parser():
@@ -75,6 +76,8 @@ def build_parser():
change.add_argument('--jpeg-quality', type=int, default=92, help='Poczatkowa jakosc JPEG')
change.add_argument('--min-jpeg-quality', type=int, default=85, help='Minimalna dopuszczalna jakosc JPEG')
change.add_argument('--min-gain-percent', type=float, default=5.0, help='Minimalne zmniejszenie objetosci w procentach')
change.add_argument('--max-image-mpixels', type=float, default=DEFAULT_MAX_IMAGE_PIXELS / 1_000_000,
help='Limit megapikseli oryginalnego obrazu; powyzej tego progu plik bedzie pominiety (ochrona RAM)')
report = parser.add_argument_group('Raporty')
report.add_argument('--report-csv', help='CSV z plikami i linkami (UTF-8 BOM, otwiera sie w Excelu)')
@@ -93,6 +96,8 @@ def validate_args(args, parser):
parser.error('--min-gain-percent musi byc w przedziale 0..100')
if args.max_changes < 0 or args.optimize_top < 0:
parser.error('--max-changes i --optimize-top nie moga byc ujemne')
if not (0 < args.max_image_mpixels <= 500):
parser.error('--max-image-mpixels musi byc w zakresie (0, 500]')
if args.apply and not (args.optimize or args.update_db):
parser.error('--apply wymaga --optimize lub --update-db')
if args.apply and args.optimize and not args.backup_dir:
@@ -203,9 +208,12 @@ def sha256_file(path):
return digest.hexdigest()
def file_resolution(path):
def file_resolution(path, *, max_pixels=DEFAULT_MAX_IMAGE_PIXELS):
try:
with Image.open(path) as im:
# W metadanych mozemy odczytac wymiary nawet wtedy, gdy uzytkownik
# ustawi niski prog optymalizacji. Nie dekodujemy pikseli.
with safe_image_open(path, max_pixels=max(max_pixels, DEFAULT_MAX_IMAGE_PIXELS),
check_pixels=False) as im:
return im.size
except Exception:
return (0, 0)
@@ -257,7 +265,7 @@ def collect_images(connection, config, args):
if stat_result.st_size < args.min_size_mb * 1024 * 1024:
continue
if full_path not in groups:
width, height = file_resolution(full_path)
width, height = file_resolution(full_path, max_pixels=int(args.max_image_mpixels * 1_000_000))
groups[full_path] = {
'path': full_path,
'rel_path': rel_path,
@@ -286,6 +294,7 @@ def collect_images(connection, config, args):
def is_candidate(image, args):
return (
not image['width'] or not image['height'] or
image['width'] > args.max_width or
image['height'] > args.max_height or
image['before_size'] > args.max_file_mb * 1024 * 1024
@@ -465,6 +474,7 @@ def process_changes(connection, config, args, images, table_prefix):
min_jpeg_quality=args.min_jpeg_quality,
min_gain_percent=args.min_gain_percent,
temp_dir=os.path.dirname(image['path']) if args.apply else None,
max_pixels=int(args.max_image_mpixels * 1_000_000),
)
image['optimization_reason'] = result['reason']
image['optimize_status'] = result['status']
@@ -475,7 +485,9 @@ def process_changes(connection, config, args, images, table_prefix):
print(f'[ERROR] {image["rel_path"]}: {result["reason"]}')
continue
if result['status'] == 'skip':
if args.debug:
if 'przekracza --max-image-mpixels' in result['reason'] or 'Pillow odrzucil' in result['reason']:
print(f'[SKIP-LIMIT] {image["rel_path"]}: {result["reason"]}')
elif args.debug:
print(f'[SKIP] {image["rel_path"]}: {result["reason"]}')
# Opcjonalny sync DB dla plikow, ktorych optymalizacja sie nie udala.
if args.update_db and mismatched_rows: