small-projects/image-format/convert.py
2025-04-10 20:15:38 -05:00

80 lines
2.8 KiB
Python

# converter.py
import sys
import os
import argparse
from PIL import Image # Requires Pillow (pip install pillow)
from tqdm import tqdm # For the progress bar (pip install tqdm)
import codec
def human_readable_size(size, decimal_places=2):
"""
Convert a size in bytes to a human readable format.
"""
for unit in ['B','KB','MB','GB','TB']:
if size < 1024:
return f"{size:.{decimal_places}f} {unit}"
size /= 1024
def png_to_simimg(png_path, output_path, use_transparency):
"""
Loads a PNG file, converts it to a 2D pixel list (RGB or RGBA based on transparency setting),
and encodes it to our custom SIMIMG format.
Also displays a progress bar during conversion and prints original/new file sizes and compression ratio.
Args:
png_path: Input PNG filename.
output_path: Output SIMIMG filename.
use_transparency (bool): If True, converts image to RGBA (retaining transparency);
if False, converts to RGB.
"""
# Get and show the original PNG file size.
orig_size = os.path.getsize(png_path)
print(f"Original PNG size: {human_readable_size(orig_size)}")
with Image.open(png_path) as img:
# Convert based on transparency flag.
if use_transparency:
img = img.convert("RGBA")
else:
img = img.convert("RGB")
width, height = img.size
pixels = list(img.getdata())
# Convert flat pixel list to a 2D list (row-major order) with a progress bar.
image_pixels = []
for i in tqdm(range(height), desc="Converting rows", unit="row"):
row = pixels[i * width:(i + 1) * width]
image_pixels.append(row)
# Encode the image into our custom SIMIMG format.
simimg_data = codec.encode(image_pixels)
# Write the SIMIMG file.
with open(output_path, "wb") as f:
f.write(simimg_data)
# Get the new file size.
new_size = os.path.getsize(output_path)
print(f"Converted SIMIMG size: {human_readable_size(new_size)}")
# Calculate and display the compression ratio.
# (Note: Ratio as new_size/orig_size. Values below 1.0 indicate compression.)
compression_ratio = new_size / orig_size
print(f"Compression Ratio: {compression_ratio:.2f}")
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="Convert a PNG image to the custom SIMIMG format."
)
parser.add_argument("input", help="Input PNG file.")
parser.add_argument("output", help="Output SIMIMG file.")
parser.add_argument(
"--transparency",
action="store_true",
help="Convert image with transparency (RGBA); otherwise use RGB."
)
args = parser.parse_args()
png_to_simimg(args.input, args.output, use_transparency=args.transparency)