CLI tool for converting images between different formats and creating GIFs from image sequences, directories, or video files. Supports JPG, PNG, BMP, and WebP.
Project description
transimage - image format conversion and GIF creation
Description
transimage is a Python package and CLI tool for converting images between different formats and creating GIFs from image sequences, directories, or video files. It uses Pillow for image operations and OpenCV for video frame extraction.
send your PR based god🙏🏻
Features
- Convert images between JPG, PNG, BMP, and WebP formats
- Batch conversion of multiple images or entire directories
- Create GIFs from a list of images, a directory of images, or a video file
- Configurable GIF parameters: FPS, size, crop, loop, and video trim
- Preserves aspect ratio on resize and handles transparency
- Simple command-line interface with subcommands
- Skips conversion if the input and output formats are the same
Dependencies
- Pillow >= 11.0.0
- Poetry
Optional dependency for creating GIFs:
- opencv-python-headless
Setup
Development Environment
- Clone the repository
- Install Poetry:
pip install poetry - Install all dependencies:
poetry install - (Optional) For video -> GIF support:
poetry install --extras opencv
Usage
All commands are run from the project root using Poetry’s virtual environment. Replace poetry run python -m transimage with transimage if you installed the package globally.
Image Conversion
Convert a single image or all images in a directory:
poetry run python -m transimage convert <input_path> <output_path> <output_format>
<input_path>: Path to a single image file or a directory of images<output_path>: Directory where converted images will be saved (do not include file name)<output_format>: Target format (jpg, png, bmp, webp)
Examples
poetry run python -m transimage convert ./photo.jpg ./output png
poetry run python -m transimage convert ./images/ ./converted webp
GIF Creation
Create a GIF from images or video:
poetry run python -m transimage gif <input> -o <output.gif> [options]
<input>: A directory path, a video file path, or a list of image file paths (list them after the command)-o, --output: Output GIF file path (required)
Options
| Option | Type | Default | Description |
|---|---|---|---|
--fps |
float | 24 | Frames per second |
--size |
int int | - | Max width and height (aspect ratio preserved) |
--crop |
int int int int | - | Pixels to cut from each edge: left top right bottom. e.g. 0 20 0 20 trims 20px from top & bottom |
--loop |
int | 0 | Loop count (0 = infinite) |
--start-time |
float | - | Start time in seconds (video only) |
--end-time |
float | - | End time in seconds (video only) |
--skip-frames |
int | 1 | Only use every Nth frame (video only) |
--colors |
int | 256 | Maximum number of colors in the GIF palette (256 = full 8‑bit) |
--no-dither |
flag | False | Disable dithering; may create sharper edges in solid areas but can cause banding |
Understanding --skip-frames and frame rate
--skip-frames can help lower output file size, but there's more to it than that. It controls how motion translates from video to GIF.
To produce a GIF that preserves the input's original speed, use the formula: target_fps = video_fps / skip_frames
This should make it look like a real-time playback.
The following table applies the formula to a 30 FPS video:
--fps (real‑time) |
--skip-frames |
Effect |
|---|---|---|
| 30 | 1 | smooth "real-time" playback |
| 15 | 2 | every 2nd frame, natural motion |
| 10 | 3 | arguably fluid |
| 2.5 | 1 | slow motion |
Eliminate near‑duplicates
Screen recordings and static scenes often have consecutive identical frames. Skipping a few frames (--skip-frames 2 or 3) removes those stills, making the GIF appear more responsive.
Examples
From a directory of images (sorted by name):
poetry run python -m transimage gif ./frames -o movie.gif --fps 12 --size 640 480
From a list of explicit image files:
poetry run python -m transimage gif a.jpg b.jpg c.jpg -o combined.gif --fps 2 --loop 0
From a video file (requires the opencv extra):
poetry run python -m transimage gif video.mp4 -o clip.gif --fps 15 --start-time 2.5 --end-time 5 --size 320 240
Reduce palette to 64 colors and turn off dithering for a crisp, retro look
poetry run python -m transimage gif ./frames -o movie.gif --fps 12 --colors 64 --no-dither
Remove 20px from top and bottom, resize to fit 640x480
poetry run python -m transimage gif ./frames -o movie.gif --fps 12 --size 640 480 --crop 0 20 0 20
Programmatic Usage
Inside a script or interactive session, you can use the package directly after installing it in your environment.
Import the needed functions:
from transimage import ImageConverter, convert_image, collect_images, GIFCreator, create_gif
Image Conversion
converter = ImageConverter('input.jpg', 'output.png', 'png')
converter.convert()
Batch conversion:
import os
from transimage import collect_images, convert_image
input_dir = 'images/'
output_dir = 'converted/'
fmt = 'png'
for img_path in collect_images(input_dir):
name = os.path.splitext(os.path.basename(img_path))[0]
out_path = os.path.join(output_dir, f"{name}.{fmt}")
convert_image(img_path, out_path, fmt)
GIF Creation
Using the convenience function:
create_gif(
input=['a.jpg', 'b.jpg', 'c.jpg'], # or a directory path, or a video file path
output='animation.gif',
fps=10,
size=(320, 240),
loop=0
)
Or with the class for more control:
creator = GIFCreator(
sources='video.mp4',
output_path='clip.gif',
fps=15,
size=(480, 360),
start_time=2.0,
end_time=5.0,
skip_frames=2
)
creator.create()
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Please submit issues regarding any oversight you see. Pull requests for improvements are welcome.
Set up
- Install the developer dependencies: poetry install (dev deps are included by default)
- Add your changes
- Test your code: poetry run pytest tests/
- Format and lint:
- Format: poetry run black src/transimage tests
- Lint: poetry run flake8 src/transimage tests
- Run all together: poetry run black src/transimage tests && poetry run flake8 src/transimage tests && poetry run pytest tests
- Rise and repeat until finished.
Changelog
3.0.0 (25-06-2026)
- Revamped
--cropto be more intuitive. Crop now takes the number of pixels to cut off, instead of requiring the user to provide the exact measurements of
2.1.0 (24-06-2026)
- Added
--colorsand--no-ditherarguments to give the user more control over a GIF's output file size.
2.0.1 (20-06-2026)
- Clarified README
- provided a more thorough explanation of how
--fpsand--skip-framesaffect GIF output - changed indented code examples to true code blocks
- clarified why
opencvis optional in Development Environment section
- provided a more thorough explanation of how
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file transimage-3.0.0.tar.gz.
File metadata
- Download URL: transimage-3.0.0.tar.gz
- Upload date:
- Size: 12.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.12.10 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
208b53cfaebf6672d90d138ddd4251736cb7c609e7f976c12e07075274e57323
|
|
| MD5 |
db8ea8b1236dcb7ba2ea51f1fa8f8034
|
|
| BLAKE2b-256 |
7eef58a0fad82cfa3fa4a68f8be8d220b8e275dc1b0b915b648cf3307d1b63b9
|
File details
Details for the file transimage-3.0.0-py3-none-any.whl.
File metadata
- Download URL: transimage-3.0.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.12.10 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db57641ca70c3fc7915d194477d65b7338e7b80a060df388f6dd3fb2b40d6bba
|
|
| MD5 |
a22d7eb25badf8c7dd5a06a512a487a9
|
|
| BLAKE2b-256 |
32ee7a2eb19e1fa77f1a7d705665737430763da86066758e17faec60e4f5e30a
|