Create SheetLayout, make cards per sheet dynamic

This commit is contained in:
henriquenakashima 2023-06-30 01:21:24 -04:00
parent 5003c625ba
commit b5f86faf7e
2 changed files with 60 additions and 32 deletions

View file

@ -1,6 +1,6 @@
import os import os
from pathlib import Path from pathlib import Path
from typing import List, Optional from typing import List, Optional, Tuple
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
@ -10,7 +10,6 @@ W_INCHES_EXPECTED = 2.72
H_INCHES_EXPECTED = 3.7 H_INCHES_EXPECTED = 3.7
BLEED_INCHES_EXPECTED = 0.12 BLEED_INCHES_EXPECTED = 0.12
LEAVE_BLEED_INCHES = 0.04 LEAVE_BLEED_INCHES = 0.04
CORNER_RADIUS_INCHES = 0.12
BASE_DIR = Path(__file__).parent BASE_DIR = Path(__file__).parent
@ -116,46 +115,73 @@ def crop_all_inputs(files_to_crop: List[Path]):
crop(input_filepath) crop(input_filepath)
def create_sheet(cropped_filepaths: List[Path], sheet_filepath: Path):
# Create sheet
LETTER_PAGE_W_INCHES = 11
LETTER_PAGE_H_INCHES = 8.5
CARD_W_INCHES = 2.48031 # 63mm CARD_W_INCHES = 2.48031 # 63mm
CARD_H_INCHES = 3.46457 # 88mm CARD_H_INCHES = 3.46457 # 88mm
DPI = 1200
PAGE_W = round(LETTER_PAGE_W_INCHES * DPI)
PAGE_H = round(LETTER_PAGE_H_INCHES * DPI)
CARD_W = round(CARD_W_INCHES * DPI)
CARD_H = round(CARD_H_INCHES * DPI)
CROPPED_IMAGE_DEST_W = round((CARD_W_INCHES + LEAVE_BLEED_INCHES) * DPI)
CROPPED_IMAGE_DEST_H = round((CARD_H_INCHES + LEAVE_BLEED_INCHES) * DPI)
SPACING_INCHES = 0.05
SPACING = round(SPACING_INCHES * DPI)
CARD_COLUMNS = 4
CARD_ROWS = 2
TOTAL_W_CONTENT = CROPPED_IMAGE_DEST_W * CARD_COLUMNS + SPACING * (CARD_COLUMNS - 1)
TOTAL_H_CONTENT = CROPPED_IMAGE_DEST_H * CARD_ROWS + SPACING * (CARD_ROWS - 1)
BLANK_SPACE_W = (PAGE_W - TOTAL_W_CONTENT) // 2
BLANK_SPACE_H = (PAGE_H - TOTAL_H_CONTENT) // 2
sheet = Image.new('RGB', (PAGE_W, PAGE_H), 'white')
class SheetLayout:
def __init__(self, dpi: int, w_inches: float, h_inches: float):
self.dpi = dpi
self.card_w_inches = CARD_W_INCHES
self.card_h_inches = CARD_H_INCHES
self.card_w = self.in_to_px(self.card_w_inches)
self.card_h = self.in_to_px(self.card_h_inches)
self.w_inches = w_inches
self.h_inches = h_inches
self.w = self.in_to_px(self.w_inches)
self.h = self.in_to_px(self.h_inches)
self.cropped_image_dest_w = self.in_to_px(self.card_w_inches + LEAVE_BLEED_INCHES)
self.cropped_image_dest_h = self.in_to_px(self.card_h_inches + LEAVE_BLEED_INCHES)
self.spacing_inches = 0.05
self.spacing = self.in_to_px(self.spacing_inches)
self.min_padding_inches = 0.12
self.min_padding = self.in_to_px(self.min_padding_inches)
self.cards_per_row = ((self.w - self.min_padding * 2 + self.spacing)
// (self.cropped_image_dest_w + self.spacing))
self.cards_per_column = ((self.h - self.min_padding * 2 + self.spacing)
// (self.cropped_image_dest_h + self.spacing))
self.cards_per_sheet = self.cards_per_row * self.cards_per_column
self.total_w_content = self.cropped_image_dest_w * self.cards_per_row + self.spacing * (self.cards_per_row - 1)
self.total_h_content = self.cropped_image_dest_h * self.cards_per_column + self.spacing * (self.cards_per_column - 1)
self.blank_space_w = (self.w - self.total_w_content) // 2
self.blank_space_h = (self.h - self.total_h_content) // 2
def in_to_px(self, inches: float) -> float:
return round(inches * self.dpi)
def topleft_of_card(self, y_index: int, x_index: int) -> Tuple[int, int]:
assert 0 <= x_index < self.cards_per_row
assert 0 <= y_index < self.cards_per_column
x = self.blank_space_w + (self.cropped_image_dest_w + self.spacing) * x_index
y = self.blank_space_h + (self.cropped_image_dest_h + self.spacing) * y_index
return (x, y)
def create_sheet(cropped_filepaths: List[Path], sheet_filepath: Path, sheet_layout: SheetLayout):
sheet = Image.new('RGB', (sheet_layout.w, sheet_layout.h), 'white')
# Draw cards # Draw cards
filenames_iter = cropped_filepaths.__iter__() filenames_iter = cropped_filepaths.__iter__()
for y in range(CARD_ROWS): for y in range(sheet_layout.cards_per_column):
for x in range(CARD_COLUMNS): for x in range(sheet_layout.cards_per_row):
try: try:
filepath = filenames_iter.__next__() filepath = filenames_iter.__next__()
except StopIteration: except StopIteration:
break break
with Image.open(filepath) as card_im: with Image.open(filepath) as card_im:
card_im = card_im.resize((CROPPED_IMAGE_DEST_W, CROPPED_IMAGE_DEST_H), resample = Image.Resampling.LANCZOS) card_im = card_im.resize((sheet_layout.cropped_image_dest_w, sheet_layout.cropped_image_dest_h),
sheet.paste(card_im, (BLANK_SPACE_W + (CROPPED_IMAGE_DEST_W + SPACING) * x, BLANK_SPACE_H + (CROPPED_IMAGE_DEST_H + SPACING) * y)) resample = Image.Resampling.LANCZOS)
sheet.paste(card_im, sheet_layout.topleft_of_card(y, x))
# Save sheet # Save sheet
sheet.save(sheet_filepath, 'JPEG', dpi=(DPI, DPI), quality=100, subsampling=0) sheet.save(sheet_filepath, 'JPEG', dpi=(sheet_layout.dpi, sheet_layout.dpi), quality=100, subsampling=0)
def main(): def main():
@ -177,9 +203,11 @@ def main():
print(f'Now there are {len(already_cropped_cards)} cropped cards:') print(f'Now there are {len(already_cropped_cards)} cropped cards:')
print(already_cropped_cards) print(already_cropped_cards)
#sheet_layout = SheetLayout(1200, 11, 8.5)
sheet_layout = SheetLayout(1200, 8.5, 11)
sheets_dir = BASE_DIR / 'sheets' sheets_dir = BASE_DIR / 'sheets'
sheets_dir.mkdir(parents=True, exist_ok=True) sheets_dir.mkdir(parents=True, exist_ok=True)
for i, cards_in_sheet in enumerate(util.batched(all_cropped_cards, 8), 1): for i, cards_in_sheet in enumerate(util.batched(all_cropped_cards, sheet_layout.cards_per_sheet), 1):
# cards_in_sheet = [ # cards_in_sheet = [
# 'Svella, Ice Shaper (Extended Andrew Mar).crop.jpg', # 'Svella, Ice Shaper (Extended Andrew Mar).crop.jpg',
# 'Icon of Ancestry.crop.png', # 'Icon of Ancestry.crop.png',
@ -192,7 +220,7 @@ def main():
# ] # ]
sheet_filepath = sheets_dir / f'sheet{i:03d}.jpg' sheet_filepath = sheets_dir / f'sheet{i:03d}.jpg'
create_sheet(cards_in_sheet, sheet_filepath) create_sheet(cards_in_sheet, sheet_filepath, sheet_layout)
print(f'Output {sheet_filepath}') print(f'Output {sheet_filepath}')

0
sheet_layout.py Normal file
View file