Skip to content

Instantly share code, notes, and snippets.

@brouberol
Created January 29, 2025 14:49
Show Gist options
  • Save brouberol/689b3aadda9d3476ae7b1a83d5963fc8 to your computer and use it in GitHub Desktop.
Save brouberol/689b3aadda9d3476ae7b1a83d5963fc8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import argparse
import os
from pathlib import Path
from PIL import Image, ImageFilter, ImageDraw
A4_WIDTH_MM = 210
A4_HEIGHT_MM = 297
INCH_IN_MM = 25.4
def mm_to_px(dim_mm: int, dpi: int) -> int:
return int(dim_mm * dpi / INCH_IN_MM)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-i", "--input", help="The input image(s)", required=True, nargs="+"
)
parser.add_argument("-o", "--output-dir", help="The output directory", type=Path)
parser.add_argument("--dpi", type=int, help="The output image DPI", default=300)
parser.add_argument(
"--background-gaussian-blur-radius",
type=int,
help="The background gaussian blur radius",
default=19,
)
parser.add_argument(
"--background-zoom-factor",
type=float,
help="Background image zoom factor",
default=1.4,
)
parser.add_argument(
"--bleed-margin-mm", type=int, help="Bleed margins, in mm", default=2
)
parser.add_argument("--flip", action='store_true', default=False)
return parser.parse_args()
def generate_spread_from_dungeondraft_image(image_path: str, args: argparse.Namespace):
print(f"Generating pages for {image_path}")
filepath = Path(image_path)
filename, extension = args.output_dir / filepath.stem, filepath.suffix
# Open the input image
original_image = Image.open(image_path)
# Set A4 dimensions
a4_width, a4_height = mm_to_px(
A4_WIDTH_MM + 2 * args.bleed_margin_mm, args.dpi
), mm_to_px(
A4_HEIGHT_MM + 2 * args.bleed_margin_mm, args.dpi
) # A4 dimensions in pixels
# Create white A4 background
a4_image = Image.new("RGB", (a4_width, a4_height), color="white")
# Calculate centering coordinates
x_offset = 3 if 'left' in filename.name else 1.5
center_x = int((a4_width - original_image.width) // x_offset)
center_y = (a4_height - original_image.height) // 2
# Resize the image
resized_image = original_image.resize(
(
int(original_image.width * args.background_zoom_factor),
int(original_image.height * args.background_zoom_factor),
)
)
# Apply Gaussian blur
blurred_image = resized_image.filter(
ImageFilter.GaussianBlur(radius=args.background_gaussian_blur_radius)
)
# Paste the blurred image onto the A4 page
a4_image.paste(blurred_image, (-100, -100), mask=blurred_image)
# Paste the original image
a4_image.paste(original_image, (center_x, center_y))
# draw = ImageDraw.ImageDraw(a4_image)
# draw.rectangle(
# [
# (
# mm_to_px(args.bleed_margin_mm, args.dpi),
# mm_to_px(args.bleed_margin_mm, args.dpi),
# ),
# (
# mm_to_px(args.bleed_margin_mm + A4_WIDTH_MM, args.dpi),
# mm_to_px(args.bleed_margin_mm + A4_HEIGHT_MM, args.dpi),
# ),
# ],
# outline="black",
# width=3,
# )
# Save the final A4-sized image with the centered zoomed-in image
a4_image.save(f"{filename}-A4{extension}", dpi=(args.dpi, args.dpi))
if args.flip:
# Save the same image but reversed vertically
flipped_image = a4_image.transpose(Image.FLIP_LEFT_RIGHT)
flipped_image.save(f"{filename}-A4-flipped{extension}", dpi=(args.dpi, args.dpi))
def main():
args = parse_args()
if not args.output_dir.exists():
args.output_dir.mkdir()
for image in args.input:
generate_spread_from_dungeondraft_image(image, args)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment