Skip to main content

Python image processing package for converting, downscaling, and optionally upscaling images using Pillow.

Project description

imgtools_m8

Python package PyPI package codecov Codacy Badge Downloads Known Vulnerabilities

Python image processing package for converting, downscaling, and optionally upscaling images using Pillow. DNN-based super-resolution upscaling (via OpenCV) is available as an optional extra.

Installation

# Core install (Pillow + Pydantic + NumPy only)
pip install imgtools_m8 --upgrade

# With DNN upscaling support (adds opencv-contrib-python)
pip install "imgtools_m8[dnn]" --upgrade

# With CLI color output (adds colorama)
pip install "imgtools_m8[cli]" --upgrade

# Everything at once
pip install "imgtools_m8[dnn,cli]" --upgrade

# From GitHub
pip install "git+https://github.com/mano8/imgtools_m8" --upgrade

Dependencies

Package Required Notes
Pillow>=12.2.0 yes Core image I/O and format conversion
pydantic>=2.13.4 yes Config validation
numpy>=2.4.6 yes Array support
opencv-contrib-python>=4.13.0.92 no DNN upscaling only — pip install imgtools_m8[dnn]
colorama>=0.4.6 no Colored CLI output — pip install imgtools_m8[cli]

Quick start

from imgtools_m8.image_process import ImageProcessing

obj = ImageProcessing(
    conf={
        "source_path": "./tests/sources_test/recien_llegado.jpg",
        "output_path": "./output",
        "output_options": [
            {
                "formats": [
                    {"ext": "JPEG", "quality": 80, "progressive": True, "optimize": True},
                    {"ext": "WEBP", "quality": 70},
                    {"ext": "PNG"},
                ]
            }
        ],
    }
)
obj.run()

Usage

ImageProcessing is the main class. It accepts a conf dict validated by ImageProcessingSchema.

Configuration structure

conf = {
    # Required
    "source_path": "/path/to/image.jpg",   # or a directory
    "output_path": "/path/to/output/",

    # Optional
    "include_subdirs": False,   # scan subdirectories when source is a dir
    "flatten_output": False,    # write all outputs flat (no subdir mirror)

    # At least one of output_options or global_options is required
    "output_options": [...],    # per-size output rules (see below)
    "global_options": {...},    # fallback formats/byte-limit for all options
}

output_options entries

Each entry in output_options may specify:

Field Type Description
image_size OutputSize Resize spec (see below)
allow_upscale bool Allow upscaling when image is smaller than target
max_byte_size int Hard byte ceiling per output file (binary-search on quality)
formats list[FormatConfig] Output formats for this size

image_size variants (mutually exclusive where noted)

Field Description
fixed_width Resize to exact width, keep aspect ratio
fixed_height Resize to exact height, keep aspect ratio
fixed_width + fixed_height Fit within bounding box, keep aspect ratio
fixed_size Constrain longest side to N pixels
fixed_downscale Divide each dimension by factor (2–10)
fixed_upscale Multiply each dimension by factor (2–10); uses DNN model when available

Supported output formats

ext value Notes
"JPEG" quality, optimize, progressive, subsampling
"WEBP" quality, lossless, method
"PNG" optimize, compression_level, interlace
"GIF" optimize
"AVIF" quality, lossless

Example 1 — convert to multiple formats without resizing

from imgtools_m8.image_process import ImageProcessing

obj = ImageProcessing(
    conf={
        "source_path": "./tests/sources_test/recien_llegado.jpg",
        "output_path": "./output",
        "output_options": [
            {
                "formats": [
                    {"ext": "JPEG", "quality": 80, "progressive": True, "optimize": True},
                    {"ext": "WEBP", "quality": 70},
                    {"ext": "PNG"},
                ]
            }
        ],
    }
)
obj.run()

Example 2 — downscale to a fixed bounding box

The image is 340×216 px. With fixed_width=300, fixed_height=200, the wider constraint wins (width ratio = 300/340 ≈ 88 %; height ratio = 200/216 ≈ 93 %), so the output is 300×190 px.

from imgtools_m8.image_process import ImageProcessing

obj = ImageProcessing(
    conf={
        "source_path": "./tests/sources_test/recien_llegado.jpg",
        "output_path": "./output",
        "output_options": [
            {
                "image_size": {"fixed_width": 300, "fixed_height": 200},
                "formats": [
                    {"ext": "JPEG", "quality": 80, "progressive": True, "optimize": True}
                ],
            }
        ],
    }
)
obj.run()

Example 3 — upscale then downscale (DNN model)

Requires pip install imgtools_m8[dnn]. The EDSR model (included) is used automatically.

from imgtools_m8.image_process import ImageProcessing

obj = ImageProcessing(
    conf={
        "source_path": "./tests/sources_test/recien_llegado.jpg",
        "output_path": "./output",
        "output_options": [
            {
                "image_size": {"fixed_width": 1200},
                "allow_upscale": True,
                "formats": [
                    {"ext": "JPEG", "quality": 80, "progressive": True, "optimize": True}
                ],
            }
        ],
    }
)
obj.run()

Example 4 — process a whole directory with subdirectory mirroring

from imgtools_m8.image_process import ImageProcessing

obj = ImageProcessing(
    conf={
        "source_path": "./tests/sources_test/",
        "output_path": "./output",
        "include_subdirs": True,
        "output_options": [
            {
                "image_size": {"fixed_size": 800},
                "max_byte_size": 200_000,
                "formats": [
                    {"ext": "WEBP", "quality": 85}
                ],
            }
        ],
    }
)
obj.run()

Example 5 — multiprocessing batch with resource monitoring

from imgtools_m8.multiprocess import MultiProcessImage

obj = MultiProcessImage(
    conf={
        "source_path": "./tests/sources_test/",
        "output_path": "./output",
        "include_subdirs": True,
        "output_options": [
            {
                "image_size": {"fixed_width": 800},
                "formats": [{"ext": "WEBP", "quality": 80}],
            }
        ],
    },
    max_cpu_percent=75,
    user_cpu_percent=50,
    batch_size=32,
)
obj.run_multiple()

CLI

After installation, an imgtools command is available:

# Convert to WEBP at 80% quality (default when no --format is given)
imgtools --source ./images --output ./out

# Resize to 1920 px wide and save as JPEG + WEBP
imgtools --source ./images --output ./out --width 1920 --format jpg:95 --format webp:80

# Process subdirectories in parallel with 4 workers
imgtools --source ./images --output ./out --subdirs --workers 4

# Load a full conf dict from a JSON file
imgtools --source ./images --output ./out --config ./my_conf.json

# Enable debug logging
imgtools --source ./images --output ./out --debug

Install [cli] to get colored log output:

pip install "imgtools_m8[cli]"

Run imgtools --help for the full argument reference. The --workers flag switches from single-process (ImageProcessing) to multiprocess (MultiProcessImage); the worker count is clamped to cpu_count - 1 to avoid saturating the system.

In-memory API

Process images without any file I/O using process_image:

from imgtools_m8 import process_image

with open("photo.jpg", "rb") as f:
    src_bytes = f.read()

results = process_image(
    src_bytes,
    [{"image_size": {"fixed_width": 200}, "formats": [{"ext": "WEBP", "quality": 80}]}],
)

for r in results:
    print(r.name, r.width, r.height, r.size_bytes)
    # write r.data to a file or upload directly

process_image returns a list[VariantResult]; each result carries name, data (raw bytes), width, height, size_bytes, and format. No disk paths required.

DNN upscaling note

When opencv-contrib-python is not installed, fixed_upscale falls back to PIL bicubic scaling. Install the [dnn] extra to enable DNN upscaling:

pip install "imgtools_m8[dnn]"

Models (DNN upscaling)

The EDSR .pb models are not bundled in the wheel (saves ~111 MB). After installing the [dnn] extra, fetch them once with:

imgtools download-models

Models are SHA256-verified and stored in the platform cache directory. To use a custom location, set IMGTOOLS_M8_MODELS_DIR to a directory that contains an opencv/ subdirectory with the .pb files. If the models are absent when upscaling is attempted, a ModelNotFoundError is raised with a reminder to run imgtools download-models.

Custom models in .pb format can be loaded by passing a model_conf dict to ImageProcessing:

obj = ImageProcessing(
    conf={...},
    model_conf={
        "path": "/path/to/model/directory",
        "model_name": "espcn",   # model prefix, e.g. espcn, edsr, lapsrn
        "scale": 4,              # fixed scale (omit for AUTO_SCALE)
    },
)

Docker (CUDA-accelerated DNN upscaling)

A Dockerfile is provided to build a CUDA-enabled image that compiles OpenCV from source with GPU support, enabling hardware-accelerated DNN upscaling.

Requirements: Docker + NVIDIA Container Toolkit.

# Build with defaults (CUDA 13.3 / Ubuntu 24.04 / OpenCV 4.13)
docker build -t imgtools_m8 .

# Target a specific GPU compute capability (much faster compile)
docker build --build-arg CUDA_ARCH_BIN=8.9 -t imgtools_m8 .

# Run with GPU access
docker run --gpus all imgtools_m8 --help

Find your GPU's compute capability at developer.nvidia.com/cuda-gpus: RTX 30xx → 8.6, RTX 40xx → 8.9, RTX 50xx → 10.0.

Build arguments (OPENCV_VERSION, CUDA_ARCH_BIN) are documented in .env.example. A docker-compose.yml for multi-volume GPU batch processing is in docker_compose/imgtools_dev/.

Input/Output Example

Input Image

The source file is 340×216 px.

Recien Llegado @Cezar llañez

Recien llegado by @Cezar yañez

License

This project is licensed under the Apache 2 License — see the LICENSE file for details.

Authors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

imgtools_m8-2.0.0.tar.gz (68.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

imgtools_m8-2.0.0-py3-none-any.whl (55.6 kB view details)

Uploaded Python 3

File details

Details for the file imgtools_m8-2.0.0.tar.gz.

File metadata

  • Download URL: imgtools_m8-2.0.0.tar.gz
  • Upload date:
  • Size: 68.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for imgtools_m8-2.0.0.tar.gz
Algorithm Hash digest
SHA256 c9f8b817fd99164f7ea292576318618dab77080c58e66f66faca37f567b4a6d3
MD5 4eeba99c647b8a20863599e9f1fd7a29
BLAKE2b-256 0e5974f3a51d1ca5d22ed831702e2a1837399d60dcaadb2acbb2a5d2de8ff010

See more details on using hashes here.

File details

Details for the file imgtools_m8-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: imgtools_m8-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 55.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for imgtools_m8-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f464500f60d14ea59fb4c9666a6aa207ebd5d930c656d1834092360a6b549040
MD5 c218c3b4b9200c5769a34a3618417a3d
BLAKE2b-256 db167becf23c3fb6890800c046d51b8eb03f942e111c766257b5011846e95897

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page