transimage 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- transimage/__init__.py +2 -0
- transimage/__main__.py +81 -0
- transimage/image_collector.py +40 -0
- transimage/image_converter.py +130 -0
- transimage-1.0.0.dist-info/METADATA +100 -0
- transimage-1.0.0.dist-info/RECORD +9 -0
- transimage-1.0.0.dist-info/WHEEL +4 -0
- transimage-1.0.0.dist-info/entry_points.txt +4 -0
- transimage-1.0.0.dist-info/licenses/LICENSE +7 -0
transimage/__init__.py
ADDED
transimage/__main__.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main module for image conversion. Handles both single image and directory processing.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from transimage.image_collector import collect_images
|
|
10
|
+
from transimage.image_converter import convert_image
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def process_images(input_path: str, output_path: str, output_format: str) -> List[str]:
|
|
14
|
+
"""
|
|
15
|
+
Process images based on whether the input path is a single image or a directory.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
input_path (str): Path to the input image file or directory.
|
|
19
|
+
output_path (str): Path to save the converted image file or directory.
|
|
20
|
+
output_format (str): Desired output format (e.g., 'jpg', 'png', 'bmp', 'webp').
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
List[str]: A list of paths to the converted images.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: If the input path does not exist.
|
|
27
|
+
"""
|
|
28
|
+
if not os.path.exists(input_path):
|
|
29
|
+
raise ValueError(f"Input path does not exist: {input_path}")
|
|
30
|
+
|
|
31
|
+
converted_images = []
|
|
32
|
+
|
|
33
|
+
if os.path.isfile(input_path):
|
|
34
|
+
# Single image processing
|
|
35
|
+
output_filename = (
|
|
36
|
+
f"{os.path.splitext(os.path.basename(input_path))[0]}.{output_format}"
|
|
37
|
+
)
|
|
38
|
+
output_file_path = os.path.join(output_path, output_filename)
|
|
39
|
+
convert_image(input_path, output_file_path, output_format)
|
|
40
|
+
if os.path.exists(output_file_path):
|
|
41
|
+
converted_images.append(output_file_path)
|
|
42
|
+
elif os.path.isdir(input_path):
|
|
43
|
+
# Directory processing
|
|
44
|
+
os.makedirs(output_path, exist_ok=True)
|
|
45
|
+
image_files = collect_images(input_path)
|
|
46
|
+
|
|
47
|
+
for file_path in image_files:
|
|
48
|
+
output_filename = (
|
|
49
|
+
f"{os.path.splitext(os.path.basename(file_path))[0]}.{output_format}"
|
|
50
|
+
)
|
|
51
|
+
output_file_path = os.path.join(output_path, output_filename)
|
|
52
|
+
try:
|
|
53
|
+
convert_image(file_path, output_file_path, output_format)
|
|
54
|
+
if os.path.exists(output_file_path):
|
|
55
|
+
converted_images.append(output_file_path)
|
|
56
|
+
except ValueError as e:
|
|
57
|
+
print(f"Error converting {file_path}: {str(e)}")
|
|
58
|
+
|
|
59
|
+
return converted_images
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
parser = argparse.ArgumentParser(
|
|
64
|
+
description="Convert images to a specified format."
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument("input_path", help="Path to input image or directory")
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"output_path", help="Path to output directory. Do not include file name."
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"output_format", help="Desired output format (jpg, png, bmp, webp)"
|
|
72
|
+
)
|
|
73
|
+
args = parser.parse_args()
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
converted_files = process_images(
|
|
77
|
+
args.input_path, args.output_path, args.output_format
|
|
78
|
+
)
|
|
79
|
+
print(f"Successfully converted {len(converted_files)} images.")
|
|
80
|
+
except ValueError as e:
|
|
81
|
+
print(f"Error: {str(e)}")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functionality to collect images from a directory.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
from .image_converter import ImageConverter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def collect_images(input_dir: str) -> List[str]:
|
|
12
|
+
"""
|
|
13
|
+
Collects all supported image files from the input directory.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
input_dir (str): Path to the input directory containing images.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
List[str]: A list of paths to the supported image files.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
ValueError: If the input directory does not exist.
|
|
23
|
+
"""
|
|
24
|
+
if not os.path.isdir(input_dir):
|
|
25
|
+
raise ValueError(f"Input directory does not exist: {input_dir}")
|
|
26
|
+
|
|
27
|
+
supported_extensions = set(
|
|
28
|
+
ImageConverter.SUPPORTED_CONVERSIONS.keys()
|
|
29
|
+
) # {'.jpg', '.jpeg', '.png', '.bmp', '.webp'}
|
|
30
|
+
image_files = []
|
|
31
|
+
|
|
32
|
+
for filename in os.listdir(input_dir):
|
|
33
|
+
file_path = os.path.join(input_dir, filename)
|
|
34
|
+
if (
|
|
35
|
+
os.path.isfile(file_path)
|
|
36
|
+
and os.path.splitext(filename)[1].lower() in supported_extensions
|
|
37
|
+
):
|
|
38
|
+
image_files.append(file_path)
|
|
39
|
+
|
|
40
|
+
return image_files
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides a class for converting images to different formats using Pillow. It also has a function to simplify implementing the conversion logic.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from PIL import Image
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ImageConverter:
|
|
11
|
+
SUPPORTED_CONVERSIONS = {
|
|
12
|
+
".jpg": {".jpg", ".png", ".bmp", ".webp"},
|
|
13
|
+
".png": {".jpg", ".png", ".bmp", ".webp"},
|
|
14
|
+
".bmp": {".jpg", ".png", ".bmp", ".webp"},
|
|
15
|
+
".webp": {".jpg", ".png", ".bmp", ".webp"},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def __init__(self, input_path: str, output_path: str, output_format: str):
|
|
19
|
+
"""
|
|
20
|
+
Initializes a new instance of the ImageConverter class.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
input_path (str): Path to the input image file.
|
|
24
|
+
output_path (str): Path to save the converted image file.
|
|
25
|
+
output_format (str): Desired output format (e.g., 'png', 'jpg', 'bmp', 'webp').
|
|
26
|
+
"""
|
|
27
|
+
self.input_path = input_path
|
|
28
|
+
self.output_path = output_path
|
|
29
|
+
self.output_format = output_format.lower()
|
|
30
|
+
|
|
31
|
+
def convert(self) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Converts an image to the desired format.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If the input file format is not supported or the conversion is not possible.
|
|
37
|
+
"""
|
|
38
|
+
input_ext = os.path.splitext(self.input_path)[1].lower()
|
|
39
|
+
output_ext = os.path.splitext(self.output_path)[1].lower()
|
|
40
|
+
|
|
41
|
+
if input_ext not in self.SUPPORTED_CONVERSIONS:
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"Unsupported input file format: {input_ext}. {self.supported_conversions()}"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if output_ext not in self.SUPPORTED_CONVERSIONS[input_ext]:
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"Unsupported conversion: {input_ext} to {output_ext}. {self.supported_conversions()}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if input_ext == output_ext:
|
|
52
|
+
# If the input and output formats are the same, move the file instead of re-saving it
|
|
53
|
+
# self._move_or_error()
|
|
54
|
+
print(
|
|
55
|
+
f"Skipping conversion for {self.input_path} (already in {self.output_format} format)"
|
|
56
|
+
)
|
|
57
|
+
return
|
|
58
|
+
else:
|
|
59
|
+
# Handle JPG conversion separately
|
|
60
|
+
if self.output_format.lower() == "jpg":
|
|
61
|
+
self._convert_to_jpg(input_ext, output_ext)
|
|
62
|
+
else:
|
|
63
|
+
self._convert_image(input_ext, output_ext)
|
|
64
|
+
|
|
65
|
+
def _convert_to_jpg(self, input_ext: str, output_ext: str) -> None:
|
|
66
|
+
img = Image.open(self.input_path)
|
|
67
|
+
|
|
68
|
+
# Ensure the output format is actually JPG
|
|
69
|
+
if output_ext.lower() != "jpg":
|
|
70
|
+
output_ext = "jpg"
|
|
71
|
+
|
|
72
|
+
# Save transparency metadata for palette images w/ transparency
|
|
73
|
+
if img.mode == "P" and img.info.get("transparency"):
|
|
74
|
+
img = img.convert("RGBA")
|
|
75
|
+
|
|
76
|
+
# Convert to RGB
|
|
77
|
+
rgb_img = img.convert("RGB")
|
|
78
|
+
|
|
79
|
+
# Save as JPG with quality 95 (adjust as needed)
|
|
80
|
+
rgb_img.save(self.output_path, "JPEG", quality=95)
|
|
81
|
+
|
|
82
|
+
def _convert_image(self, input_ext: str, output_ext: str) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Converts the input image to the specified output format using Pillow.
|
|
85
|
+
"""
|
|
86
|
+
img = Image.open(self.input_path)
|
|
87
|
+
img.save(self.output_path)
|
|
88
|
+
|
|
89
|
+
def _move_or_error(self) -> None:
|
|
90
|
+
"""
|
|
91
|
+
If the input and output paths are the same, move the file instead of re-saving it.
|
|
92
|
+
"""
|
|
93
|
+
if self.input_path != self.output_path:
|
|
94
|
+
os.replace(self.input_path, self.output_path)
|
|
95
|
+
else:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"Input and output paths are the same: {self.input_path}. Please provide a different output path."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def supported_conversions() -> str:
|
|
102
|
+
"""
|
|
103
|
+
Returns a string with the supported file formats and conversions.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
str: A string with the supported file formats and conversions.
|
|
107
|
+
"""
|
|
108
|
+
return (
|
|
109
|
+
"Supported file formats and conversions:\n"
|
|
110
|
+
"JPEG: can be converted to JPEG, PNG, BMP, WebP\n"
|
|
111
|
+
"PNG: can be converted to JPEG, PNG, BMP, WebP\n"
|
|
112
|
+
"BMP: can be converted to JPEG, PNG, BMP, WebP\n"
|
|
113
|
+
"WebP: can be converted to JPEG, PNG, BMP, WebP"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def convert_image(input_path: str, output_path: str, output_format: str) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Converts an image to the desired format.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
input_path (str): Path to the input image file.
|
|
123
|
+
output_path (str): Path to save the converted image file.
|
|
124
|
+
output_format (str): Desired output format (e.g., 'png', 'jpg', 'bmp', 'webp').
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
ValueError: If the input file format is not supported or the conversion is not possible.
|
|
128
|
+
"""
|
|
129
|
+
converter = ImageConverter(input_path, output_path, output_format)
|
|
130
|
+
converter.convert()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: transimage
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Converts images from one format to another using Pillow. Supports JPG, PNG, BMP, and WebP.
|
|
5
|
+
Author-Email: Daethyra <109057945+Daethyra@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: <4.0,>=3.13
|
|
8
|
+
Requires-Dist: pillow<12.0.0,>=11.0.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# transimage - image format conversion
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
`transimage` is a Python package and CLI tool for converting images between different formats using the Pillow library. It supports conversions between JPG, PNG, BMP, and WebP formats.
|
|
15
|
+
|
|
16
|
+
>> send your PR based god🙏🏻
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
- Convert images between JPG, PNG, BMP, and WebP formats
|
|
20
|
+
- Batch conversion of multiple images
|
|
21
|
+
- Simple command-line interface
|
|
22
|
+
- Skips conversion if the input and output formats are the same
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
#### Dependencies
|
|
27
|
+
- Pillow >= 11.0.0
|
|
28
|
+
|
|
29
|
+
#### Setup
|
|
30
|
+
To set up the development environment:
|
|
31
|
+
|
|
32
|
+
1. Clone the repository
|
|
33
|
+
2. Install PDM if you haven't already: `pip install pdm`
|
|
34
|
+
3. Install dependencies: `pdm install`
|
|
35
|
+
4. Convert images: `python src/____main____.py ./input_image.jpg ./output_image.png png`
|
|
36
|
+
|
|
37
|
+
### Using `____main____.py` directly as a CLI tool (Recommended)
|
|
38
|
+
|
|
39
|
+
Once you've cloned the repository or downloaded the source code, you can use the `__main__.py` file directly by using the following: `python __main__.py <input_path> <output_path> <output_format>`
|
|
40
|
+
|
|
41
|
+
**Input target may be a single file or directory.**
|
|
42
|
+
|
|
43
|
+
- `<input_path>`: Path to the input image file or directory
|
|
44
|
+
- `<output_path>`: Path to save the converted image(s)
|
|
45
|
+
- `<output_format>`: Desired output format (jpg, png, bmp, or webp)
|
|
46
|
+
|
|
47
|
+
### Using the transimage package in your own projects
|
|
48
|
+
|
|
49
|
+
You may test the transimage package is properly installed by running it directly from the command line: `python -m transimage <input_path> <output_path> <output_format>`
|
|
50
|
+
|
|
51
|
+
1. First, ensure you're working within a virtual environment with PDM:
|
|
52
|
+
|
|
53
|
+
`pdm install`
|
|
54
|
+
|
|
55
|
+
2. In your Python script, import the necessary functions:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from transimage import collect_images, ImageConverter
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
To convert a single image, use the ImageConverter class directly:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
converter = ImageConverter('path/to/input/image.jpg', 'path/to/output/image.png', 'png')
|
|
65
|
+
converter.convert()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For batch conversion, you can pass in directories as arguments instead of individual image paths. Then, use the collect_images function and loop through the results:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from transimage import collect_images, ImageConverter
|
|
72
|
+
|
|
73
|
+
input_directory = 'path/to/input/directory'
|
|
74
|
+
output_directory = 'path/to/output/directory'
|
|
75
|
+
output_format = 'png'
|
|
76
|
+
|
|
77
|
+
image_files = collect_images(input_directory)
|
|
78
|
+
|
|
79
|
+
for input_path in image_files:
|
|
80
|
+
filename = os.path.basename(input_path)
|
|
81
|
+
name, _ = os.path.splitext(filename)
|
|
82
|
+
output_path = os.path.join(output_directory, f"{name}.{output_format}")
|
|
83
|
+
convert_image(input_path, output_path, output_format)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
88
|
+
|
|
89
|
+
## Contributing
|
|
90
|
+
Like I said, send your PR. Based. God.
|
|
91
|
+
|
|
92
|
+
### Set up
|
|
93
|
+
1. Install the developer dependencies: `pdm install -G dev`
|
|
94
|
+
2. Add your changes
|
|
95
|
+
3. Test your code(`pdm run pytest tests/`)
|
|
96
|
+
4. Iterate, repeat until finished.
|
|
97
|
+
5. Run the `all` script to lint and format the code: `pdm run all`
|
|
98
|
+
|
|
99
|
+
## Version
|
|
100
|
+
1.0.0
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
transimage-1.0.0.dist-info/METADATA,sha256=NZ100YR3xoMCwM2mBCLT2h7Tpl-C8Ei3wgJe1h8JiBk,3321
|
|
2
|
+
transimage-1.0.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
transimage-1.0.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
|
4
|
+
transimage-1.0.0.dist-info/licenses/LICENSE,sha256=lXSkLpKZGkYhctmRNNY1ybZoIo04o1hQHj_T0ou2hsI,1068
|
|
5
|
+
transimage/__init__.py,sha256=ieV6mfszVz9fRF6WVwyQfsGY3Qole1DRLkAKRV5-q0s,105
|
|
6
|
+
transimage/__main__.py,sha256=yWE3evRAMBTYNO0Zk7NK6-gGSb6K-6Jz54lQVDm_qc8,2945
|
|
7
|
+
transimage/image_collector.py,sha256=QLKZ_tq9Gho-giy7ov4bYHEdxgFdtHSctwnrcY-BqyE,1137
|
|
8
|
+
transimage/image_converter.py,sha256=X04snJNxAiWSDxRbrcWJU3vwMnNPqhJVcXMDe8Lq3Zk,4892
|
|
9
|
+
transimage-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025 Daethyra Carino
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|