From b5f86faf7e6932feb164ae64a84290a42b6ef1e2 Mon Sep 17 00:00:00 2001 From: henriquenakashima Date: Fri, 30 Jun 2023 01:21:24 -0400 Subject: [PATCH] Create SheetLayout, make cards per sheet dynamic --- crop_card.py | 92 ++++++++++++++++++++++++++++++++----------------- sheet_layout.py | 0 2 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 sheet_layout.py diff --git a/crop_card.py b/crop_card.py index ab107cb..8cb5a1a 100644 --- a/crop_card.py +++ b/crop_card.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import List, Optional +from typing import List, Optional, Tuple from PIL import Image, ImageDraw @@ -10,7 +10,6 @@ W_INCHES_EXPECTED = 2.72 H_INCHES_EXPECTED = 3.7 BLEED_INCHES_EXPECTED = 0.12 LEAVE_BLEED_INCHES = 0.04 -CORNER_RADIUS_INCHES = 0.12 BASE_DIR = Path(__file__).parent @@ -116,46 +115,73 @@ def crop_all_inputs(files_to_crop: List[Path]): 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_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 +CARD_W_INCHES = 2.48031 # 63mm +CARD_H_INCHES = 3.46457 # 88mm - 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 filenames_iter = cropped_filepaths.__iter__() - for y in range(CARD_ROWS): - for x in range(CARD_COLUMNS): + for y in range(sheet_layout.cards_per_column): + for x in range(sheet_layout.cards_per_row): try: filepath = filenames_iter.__next__() except StopIteration: break with Image.open(filepath) as card_im: - card_im = card_im.resize((CROPPED_IMAGE_DEST_W, CROPPED_IMAGE_DEST_H), resample = Image.Resampling.LANCZOS) - sheet.paste(card_im, (BLANK_SPACE_W + (CROPPED_IMAGE_DEST_W + SPACING) * x, BLANK_SPACE_H + (CROPPED_IMAGE_DEST_H + SPACING) * y)) - + card_im = card_im.resize((sheet_layout.cropped_image_dest_w, sheet_layout.cropped_image_dest_h), + resample = Image.Resampling.LANCZOS) + sheet.paste(card_im, sheet_layout.topleft_of_card(y, x)) # 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(): @@ -177,9 +203,11 @@ def main(): print(f'Now there are {len(already_cropped_cards)} 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.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 = [ # 'Svella, Ice Shaper (Extended Andrew Mar).crop.jpg', # 'Icon of Ancestry.crop.png', @@ -192,7 +220,7 @@ def main(): # ] 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}') diff --git a/sheet_layout.py b/sheet_layout.py new file mode 100644 index 0000000..e69de29