#!/usr/bin/env python3 import os import subprocess import json # Standard crop for 1300x1733 images (banner is ~400px tall) CROP_TOP_400 = 400 # Main category images CROP_TOP_80 = 80 # Smaller banners SKIP_CROP = 0 # Special: (crop_top, crop_bottom) for images needing both top and bottom crop CROP_BOTH = "both" IMAGES_WITH_BANNERS = [ # Main category images (1300x1733, 400px top banner) ("2021/03/durgo_000C.jpg", CROP_TOP_400), ("2021/03/valve_000C.jpg", (400, 400)), # Has "Valve KITZ" at bottom too ("2021/03/water-pump_000C.jpg", CROP_TOP_400), ("2021/03/water-treatment_000C.jpg", CROP_TOP_400), ("2021/03/grilles_000C.jpg", CROP_TOP_400), ("2021/03/realflex_000C.jpg", CROP_TOP_400), ("2021/03/extinguishers_000C.jpg", CROP_TOP_400), ("2025/01/fencing_000C.jpg", CROP_TOP_400), ("2025/01/balljet-cover_000C.jpg", CROP_TOP_400), ("2025/01/thermobrek_cover_000C.jpg", CROP_TOP_400), ("2025/01/pipe-and-other_000.jpg", CROP_TOP_400), ("2025/01/pipe-coupling-machine_000.jpg", CROP_TOP_400), ("2025/01/Hanger-Clamp-Bolt_000.jpg", CROP_TOP_400), ("2025/09/IMG-cover-309251.png", CROP_TOP_400), # Pipe subcategory images (1300x1733, 400px top banner) ("2021/03/ppr-pipe_000C.jpg", CROP_TOP_400), ("2021/03/hdpe-pipe_000C.jpg", CROP_TOP_400), ("2021/03/upvc-pipe_000C.jpg", CROP_TOP_400), ("2021/03/poloplast_000C.jpg", CROP_TOP_400), ("2021/03/syler_000C.jpg", CROP_TOP_400), ("2021/03/pvc-pipe_000C.jpg", CROP_TOP_400), ("2021/03/xylent_000C.jpg", (400, 400)), # Has "เงียบ! 22 dB" at bottom ("2021/03/hdpe-welding_000C-1.jpg", CROP_TOP_400), # Hanger images (different dimensions, 400px top banner) ("2024/02/ADJUSTABLE_SPLIT_RING_HANGER_cover_01.jpg", CROP_TOP_400), ("2024/02/ADJUSTABLE_CLEVIS_HANGER_cover_01.jpg", CROP_TOP_400), ("2024/02/THREADED_ROD_cover_01.jpg", CROP_TOP_400), # Special cases - skip for now, handle separately ("2021/02/Valve-KITZ.jpg", SKIP_CROP), # 800x648, different layout ("2021/02/Grilles01logo.jpg", CROP_TOP_80), ("2021/02/Banner-HDPE-wel-1024x382.jpg", SKIP_CROP), # Side text ] BASE_DIR = "/Users/kunthawatgreethong/Gitea/dealplustech/public/images" OUTPUT_DIR = "/Users/kunthawatgreethong/Gitea/dealplustech/public/images-clean" os.makedirs(OUTPUT_DIR, exist_ok=True) def get_dimensions(img_path): result = subprocess.run( ["identify", "-format", "%w %h", img_path], capture_output=True, text=True ) w, h = result.stdout.strip().split() return int(w), int(h) def crop_image(input_path, output_path, crop_amount): if crop_amount == 0: subprocess.run(["cp", input_path, output_path], check=True) return w, h = get_dimensions(input_path) if isinstance(crop_amount, tuple): crop_top, crop_bottom = crop_amount new_h = h - crop_top - crop_bottom cmd = [ "magick", "convert", input_path, "-crop", f"{w}x{new_h}+0+{crop_top}", "+repage", output_path, ] else: new_h = h - crop_amount cmd = [ "magick", "convert", input_path, "-crop", f"{w}x{new_h}+0+{crop_amount}", "+repage", output_path, ] subprocess.run(cmd, check=True) for rel_path, crop_amount in IMAGES_WITH_BANNERS: input_path = os.path.join(BASE_DIR, rel_path) output_path = os.path.join(OUTPUT_DIR, os.path.basename(rel_path)) if not os.path.exists(input_path): print(f"SKIP: {rel_path} (not found)") continue try: crop_image(input_path, output_path, crop_amount) print(f"OK: {os.path.basename(rel_path)} (cropped {crop_amount}px from top)") except Exception as e: print(f"FAIL: {rel_path} - {e}") print("\nDone!")