Skip to content

Instantly share code, notes, and snippets.

@pszemraj
Created December 1, 2022 23:23
Show Gist options
  • Save pszemraj/730ff33464050e946d10b360c508e985 to your computer and use it in GitHub Desktop.
Save pszemraj/730ff33464050e946d10b360c508e985 to your computer and use it in GitHub Desktop.
image to pdf processing for printing art
"""
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