Created
December 1, 2022 23:23
-
-
Save pszemraj/730ff33464050e946d10b360c508e985 to your computer and use it in GitHub Desktop.
image to pdf processing for printing art
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
a script in Python that given a directory path as input, converts all images in the directory to PDF files. Several other argswitches are available for convenience. | |
""" | |
import argparse | |
import logging | |
import os | |
import pprint as pp | |
import sys | |
from pathlib import Path | |
from PIL import Image | |
from tqdm.auto import tqdm | |
from utils import setup_logging | |
Image.MAX_IMAGE_PIXELS = None | |
ALLOWED_EXTENSIONS = [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff", ".tif"] | |
def get_printing_info( | |
image_path: str or Path, | |
resolution: int = 300, | |
imperial_units: bool = True, | |
max_dim: int = None, | |
): | |
""" | |
print_resolutions - given a path to an image, prints the resolution and the dimensions of the image at the specified resolution. | |
:param strorPath image_path: Path to the image. | |
:param int resolution: Resolution at which to print the dimensions. | |
:param bool imperial_units: If True, the dimensions will be printed in metric units (cm). If False, the dimensions will be printed in imperial units (inches). | |
:param int max_dim: If specified, the dimensions will be printed at the specified resolution, but the image will be resized to the specified maximum dimension preserving the aspect ratio. | |
""" | |
image_path = Path(image_path) | |
im = Image.open(image_path) | |
width, height = im.size | |
width = ( | |
int(width // resolution) if imperial_units else int(width // resolution * 2.54) | |
) | |
height = ( | |
int(height // resolution) | |
if imperial_units | |
else int(height // resolution * 2.54) | |
) | |
unit_str = "inches" if imperial_units else "cm" | |
if max_dim and any([width > max_dim, height > max_dim]): | |
# resize image to max_dim in the unit | |
if width == height: | |
width = height = max_dim | |
elif width > height: | |
scale_ratio = max_dim / width | |
width = max_dim | |
height = int(height * scale_ratio) | |
else: | |
scale_ratio = max_dim / height | |
height = max_dim | |
width = int(width * scale_ratio) | |
logging.info( | |
f"Resized image to {width} x {height} {unit_str} at {resolution} dpi" | |
) | |
print(f"\nDetails for {image_path.name}:") | |
print(f"Resolution: {resolution}") | |
print(f"Dimensions (pixels): {im.size}") | |
print(f"Dimensions: {width}x{height} {unit_str}") | |
# check if there is a log file being used and if so, print to it | |
if logging.getLogger().hasHandlers(): | |
logging.info(f"Details for {image_path.name}:") | |
logging.info(f"Resolution: {resolution}") | |
logging.info(f"Dimensions: {width}x{height} {unit_str}") | |
def dir2pdf( | |
dir_path: str or Path, | |
output_path: str or Path = None, | |
delete_images: bool = False, | |
resolution: int = 300, | |
printing_info: bool = False, | |
imperial_units: bool = True, | |
max_dim: int = None, | |
): | |
""" | |
Converts all images in a directory to PDF files. | |
Args: | |
dir_path (str): Path to the directory containing the images. | |
output_path (str): Path to the directory where the PDF files will be saved. | |
delete_images (bool): If True, the images will be deleted after conversion. | |
resolution (int): Resolution of the PDF files. | |
printing_info (bool): If True, prints the resolution and dimensions of the images. | |
imperial_units (bool): If True, the dimensions will be printed in imperial units (inches). If False, the dimensions will be printed in metric units (cm). | |
max_dim (int): If specified, the dimensions will be printed at the specified resolution, but the image will be resized to the specified maximum dimension preserving the aspect ratio. | |
Returns: | |
None | |
""" | |
dir_path = Path(dir_path) | |
output_path = Path(output_path) if output_path else dir_path / "converted-pdf" | |
output_path.mkdir(parents=True, exist_ok=True) | |
logging.info(f"Converting images in {dir_path} to PDF files.") | |
if not dir_path.is_dir(): | |
logging.error("The input path is not a directory.") | |
sys.exit(1) | |
if not output_path.is_dir(): | |
logging.error("The output path is not a directory.") | |
sys.exit(1) | |
files = [f for f in dir_path.iterdir() if f.suffix.lower() in ALLOWED_EXTENSIONS] | |
logging.info(f"Found {len(files)} images in {dir_path}.") | |
for image_path in tqdm(files, desc="Converting images to PDF files"): | |
if printing_info: | |
get_printing_info( | |
image_path=image_path, | |
resolution=resolution, | |
imperial_units=imperial_units, | |
max_dim=max_dim, | |
) # print to log file | |
try: | |
author = os.getlogin() | |
except: | |
author = "Unknown" | |
pdf_path = output_path / (image_path.stem + ".pdf") | |
with open(pdf_path, "wb") as f: | |
im = Image.open(image_path) | |
im.save( | |
f, | |
"PDF", | |
resolution=resolution, | |
save_all=True, | |
title=image_path.stem, | |
author=author, | |
) | |
if delete_images: | |
logging.info(f"Deleting {str(image_path)}") | |
image_path.unlink() | |
logging.info(f"Finished converting images in {dir_path} to PDF files.") | |
def get_parser(): | |
""" | |
Creates a new argument parser. | |
Returns: | |
ArgumentParser: ArgumentParser object. | |
""" | |
parser = argparse.ArgumentParser() | |
parser.add_argument( | |
"-i", | |
"--input", | |
help="Path to the directory containing the images.", | |
required=True, | |
) | |
parser.add_argument( | |
"-o", | |
"--output", | |
help="Path to the directory where the PDF files will be saved. If not specified, the PDF files will be saved in the same directory as the images under the name 'converted-pdf'.", | |
required=False, | |
default=None, | |
) | |
parser.add_argument( | |
"-d", | |
"--delete", | |
help="If True, the images will be deleted after conversion.", | |
action="store_true", | |
) | |
parser.add_argument( | |
"-r", | |
"--resolution", | |
help="Resolution of the PDF files.", | |
type=int, | |
default=300, | |
) | |
parser.add_argument( | |
"-print", | |
"--print-resolutions", | |
help="If True, prints the resolution and dimensions of the images.", | |
action="store_true", | |
) | |
parser.add_argument( | |
"-metric", | |
"--metric-units", | |
help="If True, the dimensions will be printed in metric units (cm). If False, the dimensions will be printed in imperial units (inches).", | |
action="store_true", | |
) | |
parser.add_argument( | |
"-md", | |
"--max-dim", | |
help="If specified, the dimensions will be printed at the specified resolution, but the image will be resized to the specified maximum dimension preserving the aspect ratio.", | |
type=int, | |
default=None, | |
) | |
parser.add_argument( | |
"-v", | |
"--verbose", | |
dest="loglevel", | |
help="set loglevel to INFO", | |
action="store_const", | |
const=logging.INFO, | |
) | |
parser.add_argument( | |
"-vv", | |
"--very-verbose", | |
dest="loglevel", | |
help="set loglevel to DEBUG", | |
action="store_const", | |
const=logging.DEBUG, | |
) | |
parser.add_argument( | |
"-lf", | |
"--log-file", | |
help="Path to the log file.", | |
required=False, | |
default=None, | |
) | |
return parser | |
if __name__ == "__main__": | |
args = get_parser().parse_args() | |
setup_logging(args.loglevel, args.log_file) | |
logging.info(f"Arguments: {args}") | |
dir2pdf( | |
dir_path=args.input, | |
output_path=args.output, | |
delete_images=args.delete, | |
resolution=args.resolution, | |
printing_info=args.print_resolutions, | |
imperial_units=not args.metric_units, | |
max_dim=args.max_dim, | |
) | |
print("Finished running dir2pdf.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment