Create SheetLayout, make cards per sheet dynamic
This commit is contained in:
parent
5003c625ba
commit
b5f86faf7e
2 changed files with 60 additions and 32 deletions
92
crop_card.py
92
crop_card.py
|
|
@ -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):
|
CARD_W_INCHES = 2.48031 # 63mm
|
||||||
# Create sheet
|
CARD_H_INCHES = 3.46457 # 88mm
|
||||||
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
|
|
||||||
|
|
||||||
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
0
sheet_layout.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue