Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Last active June 22, 2025 06:38
Show Gist options
  • Save WomB0ComB0/f872f11ebe29679a192976c98fb21ce2 to your computer and use it in GitHub Desktop.
Save WomB0ComB0/f872f11ebe29679a192976c98fb21ce2 to your computer and use it in GitHub Desktop.
webp.py and related files - with AI-generated descriptions
#!/usr/bin/env python3
import os
import subprocess
from pathlib import Path
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
from time import perf_counter
import shutil
import logging
from typing import List, Set
import sys
# Constants
EXTENSIONS: tuple[str, ...] = (".png", ".jpg", ".jpeg")
QUALITY: int = 100
# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
def get_images(directory: Path) -> List[Path]:
"""Get all images in the directory with the specified extensions."""
try:
# Debug: Print the current directory
logging.info("Scanning directory: %s", directory)
# Debug: List all files in the directory
all_files: List[Path] = list(directory.iterdir())
logging.info("All files in directory: %s", [f.name for f in all_files])
# Filter images with the specified extensions
images: List[Path] = [
image for image in all_files if image.suffix.lower() in EXTENSIONS
]
logging.info("Found images: %s", [img.name for img in images])
return images
except (FileNotFoundError, PermissionError) as e:
logging.error("Error getting images: %s", e)
return []
def convert_to_webp(image: Path) -> None:
"""Convert an image to WebP format using cwebp."""
try:
output_file: Path = image.with_suffix(".webp")
if not shutil.which("cwebp"):
# see: https://github.com/Yukioru/cwebp-cli
logging.error("cwebp is not installed, visit: https://github.com/Yukioru/cwebp-cli")
return
command: List[str] = [
"cwebp",
"-q",
str(QUALITY),
str(image),
"-o",
str(output_file),
]
result: subprocess.CompletedProcess[str] = subprocess.run(
command, capture_output=True, text=True, check=True
)
if result.returncode != 0:
logging.error("Error converting %s: %s", image.name, result.stderr.strip())
else:
logging.info("Converted %s to %s", image.name, output_file.name)
except (subprocess.CalledProcessError, FileNotFoundError, PermissionError) as e:
logging.error("Error converting %s: %s", image.name, e)
def get_missing_images(directory: Path, original_images: List[Path]) -> List[Path]:
"""Get images that do not have a corresponding WebP file."""
try:
webp_files: Set[str] = {
file.stem for file in directory.iterdir() if file.suffix.lower() == ".webp"
}
return [image for image in original_images if image.stem not in webp_files]
except (FileNotFoundError, PermissionError) as e:
logging.error("Error checking for missing images: %s", e)
return []
def main() -> None:
"""Main function to convert images to WebP format."""
# Determine the target directory
if len(sys.argv) > 1:
# Use the first command-line argument as the target directory
target_directory: Path = Path(sys.argv[1]).resolve()
else:
# Default to the script's directory if no argument is provided
target_directory: Path = Path(__file__).parent.absolute()
# Change to the target directory
os.chdir(target_directory)
# Debug: Print the target directory
logging.info("Target directory: %s", target_directory)
original_images: List[Path] = get_images(target_directory)
if not original_images:
logging.info("No images found in the directory.")
return
missing_images: List[Path] = get_missing_images(target_directory, original_images)
if missing_images:
logging.info(
"Found %s missing WebP conversions. Starting conversion...",
len(missing_images),
)
else:
logging.info("No missing WebP conversions found. Converting all images...")
missing_images = original_images
start_time: float = perf_counter()
# Use ThreadPoolExecutor for parallel conversion
with ThreadPoolExecutor() as executor:
futures: List[Future[None]] = [
executor.submit(convert_to_webp, image) for image in missing_images
]
for future in as_completed(futures):
future.result() # Wait for each task to complete
elapsed_time: float = perf_counter() - start_time
logging.info("Task completed in %.4f seconds", elapsed_time)
if __name__ == "__main__":
main()

webp.py Description

File Type: py

Generated Description:

webp.py Analysis

1. Summary

The Python script webp.py converts images in a specified directory to the WebP format using the cwebp command-line tool. It efficiently handles multiple images by utilizing a thread pool for parallel processing. The script focuses on converting only images that lack a corresponding WebP file, optimizing processing time. Comprehensive logging provides feedback throughout the process, including error handling and performance metrics.

2. Key Components and Functions

  • get_images(directory: Path) -> List[Path]: This function scans a given directory and returns a list of image file paths, supporting .png, .jpg, and .jpeg extensions. It includes robust error handling for file-related exceptions.

  • convert_to_webp(image: Path) -> None: This function converts a single image file to WebP using the cwebp command. It checks for the existence of cwebp before attempting conversion and provides informative error logging if conversion fails. It utilizes subprocess.run for efficient command execution.

  • get_missing_images(directory: Path, original_images: List[Path]) -> List[Path]: This function identifies images in the directory that do not have a corresponding WebP conversion already present. It helps to avoid redundant conversions.

  • main() -> None: The main function orchestrates the entire process:

    • Sets the working directory to the script's location.
    • Calls get_images to find image files.
    • Calls get_missing_images to identify images needing conversion.
    • Employs concurrent.futures.ThreadPoolExecutor for parallel conversion of images using convert_to_webp.
    • Measures and logs the total execution time.

3. Notable Patterns and Techniques

  • Parallel Processing: The script leverages concurrent.futures.ThreadPoolExecutor to significantly speed up the conversion process by converting multiple images concurrently. This is particularly beneficial when dealing with a large number of images.

  • Robust Error Handling: The script uses try-except blocks to handle potential errors such as FileNotFoundError, PermissionError, and subprocess.CalledProcessError, providing informative log messages to aid debugging.

  • Logging: The script uses the logging module to provide detailed logging information at the INFO level, facilitating monitoring and debugging.

  • Functional Decomposition: The script is well-structured with clearly defined functions, promoting code readability and maintainability.

  • Type Hints: The use of type hints (typing.List, typing.Set, etc.) improves code readability and helps catch errors during development.

  • Pathlib: Uses pathlib.Path for more intuitive and safer file path manipulation.

  • Checking for cwebp: The script explicitly checks if the cwebp command is available on the system before attempting conversions. This prevents runtime errors and provides a helpful message to the user on how to obtain it.

4. Potential Use Cases

  • Batch Image Conversion: This script is ideal for automating the conversion of a large number of images to the WebP format, which offers smaller file sizes and better compression compared to traditional formats like JPEG and PNG.

  • Web Development: Web developers can use it to optimize images for web pages, improving site loading times and reducing bandwidth usage.

  • Image Processing Pipelines: The script can be integrated into larger image processing workflows where WebP conversion is a necessary step.

  • Command-Line Tool: The script could be easily adapted into a command-line tool allowing users to specify the input directory as a command-line argument.

Description generated on 6/7/2025, 1:49:13 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment