def get_main_plane_coeffs(plane_size, ratio, height): card_height = mm_to_px(0.36 * height) shrink_x = (plane_size[0] - (plane_size[0] * ratio)) / 2 return find_coefficients( [ (shrink_x, - card_height * ratio), (plane_size[0] - shrink_x, - card_height * ratio), (plane_size[0], plane_size[1] * ratio - card_height), (0, plane_size[1] * ratio - card_height) ], [(0, 0), (plane_size[0], 0), (plane_size[0], plane_size[1]), (0, plane_size[1])] )
def transform_play_board(board, height): scale = 5 board = resize(board, (int(board.width / scale), int(board.height / scale))) height /= 5 coeffs = get_main_plane_coeffs(board.size, .5, height) res = get_play_board() board = rotate(board, 80) board = transform(board, board.size, Image.PERSPECTIVE, coeffs) res.paste(board, mm_to_px(-15, 10), mask=board) return res
def dashed_line(draw, xy, fill, width): dir = (xy[1][0] - xy[0][0], xy[1][1] - xy[0][1]) total_dist = sqrt(pow(dir[0], 2) + pow(dir[1], 2)) step_dist = mm_to_px(1) step = (dir[0] * step_dist / total_dist, dir[1] * step_dist / total_dist) dist = 0 pos = xy[0] while dist + step_dist < total_dist: draw.line((pos, (pos[0] + step[0], pos[1] + step[1])), fill, width) pos = (pos[0] + 2 * step[0], pos[1] + 2 * step[1]) dist += 2 * step_dist if dist < total_dist: draw.line((pos, xy[1]), fill, width)
def get_card(self): card = super().get_card() draw = ImageDraw.Draw(card) if self.has_title(): font = get_font(self.title_size) colors = get_source_code_coloring(self.title) for color in colors: draw.text((mm_to_px(10), self.top), colors[color], font=font, fill=getrgb(color)) height = draw.textsize("A", font)[1] self.top += height * 2.05 if self.has_title() or not self.should_resize: font = get_font(self.text_size) colors = get_source_code_coloring(self.text) for color in colors: draw.text((mm_to_px(10), self.top), colors[color], font=font, fill=getrgb(color), spacing=mm_to_px(.8)) else: sc_size = get_source_code_position_n_size(card, self.text, draw) font = get_font(sc_size) w, h = draw.textsize(self.text, font, spacing=mm_to_px(0.6)) colors = get_source_code_coloring(self.text) for color in colors: draw.text( (mm_to_px(10), (card.size[1] - h) // 2 - mm_to_px(2)), colors[color], font=font, fill=getrgb(color), spacing=mm_to_px(0.8)) if self.is_upside_down: card = card.rotate(180) return card
def get_round_rectangle(size, color, radius): if isinstance(color, str): color = getrgb(color) if not isinstance(color, tuple): color = tuple(color) rectangle = Image.new('RGBA', mm_to_px(size), (*color, 0)) draw = ImageDraw.Draw(rectangle) draw.rectangle(mm_to_px(radius / 2, 0, size[0] - (radius / 2), size[1]), fill=color) draw.rectangle(mm_to_px(0, radius / 2, size[0], size[1] - (radius / 2)), fill=color) draw.ellipse(mm_to_px(0, 0, radius, radius), fill=color) draw.ellipse(mm_to_px(size[0] - radius, 0, size[0], radius), fill=color) draw.ellipse(mm_to_px(0, size[1] - radius, radius, size[1]), fill=color) draw.ellipse(mm_to_px(size[0] - radius, size[1] - radius, size[0], size[1]), fill=color) return rectangle
def draw_lines(self, draw): lines = self.text.get_lines() font = get_font(self.font_size) spacing = mm_to_px(self.font_size / 15.) hyphen_size = draw.textsize("-", font)[0] space_size = draw.textsize(" ", font)[0] line_height = draw.textsize("A", font)[1] + spacing x = y = 0 disable_x_reset = False help_tone_font = get_font(get_max_font_size(draw, "A", space_size, None, self.font_size)[0]) chords = set() if len(lines) > 0 and lines[0].text.startswith("[capo"): capo_font = get_font(self.list_font_size) width, height = draw.textsize(lines[0].text, capo_font) draw.text( ( self.text_pos[0] + self.max_width - width - mm_to_px(self.delta) // 2, self.text_pos[1] - 1.9 * height ), lines[0].text, font=capo_font, fill=(0, 0, 0)) lines.pop(0) if len(lines) > 0 and lines[0].is_empty(): lines.pop(0) for i, line in enumerate(lines): if line.is_empty(): disable_x_reset = False if not disable_x_reset: x = 0 previous_line = None if i - 1 < 0 else lines[i - 1] next_line = None if i + 1 == len(lines) else lines[i + 1] next_next_line = None if i + 2 >= len(lines) else lines[i + 2] if line.is_chord_line() and previous_line is not None and previous_line.is_text_line() and not line.is_tag_line(): y += spacing / 2 if line.is_text_line() and previous_line is not None and previous_line.is_chord_line() and not previous_line.is_tag_line(): continue if re.match(r"\[\d+x]", line.text) or ( line.is_tag_line() and next_line is not None and next_line.is_chord_line() and not next_line.is_tag_line() and next_next_line is not None and next_next_line.is_chord_line() ): tag = line.text.split(" ")[0] + " " extra = line_height if not next_line.is_text_line() and next_next_line is not None and next_next_line.is_text_line() else 0 draw.text((self.text_pos[0] + x, self.text_pos[1] + y + extra), tag, font=font, fill=(0, 0, 0)) line.text = line.text[len(tag):] x = draw.textsize(tag, font)[0] disable_x_reset = True y -= line_height if line.is_chord_line() and next_line is not None and next_line.is_text_line() and not line.is_tag_line(): parts = line.get_parts_with_indexes() text_parts = next_line.get_parts_by_indexes([i for i, _ in parts], False) chord_parts = line.get_parts_by_indexes([i for i, _ in parts], False) if parts[0][0] != 0: chord_parts.insert(0, (0, "")) text_parts.insert(0, (0, next_line.text[:parts[0][0]])) extra = -space_size if next_line.text.startswith(" ") else 0 for i in range(len(chord_parts)): chord = chord_parts[i][1].replace("_", " ").replace("—", "-") while chord.endswith(" "): chord = chord[:-1] text = text_parts[i][1].replace("_", " ").replace("—", "-") while text != text.replace("--", "-"): text = text.replace("--", "-") chord_size = draw.textsize(chord, font)[0] text_size = draw.textsize(text, font)[0] dx = max(chord_size, text_size) if i < len(chord_parts) - 1 and \ len(text) > 0 and \ text[-1] not in " _," and \ len(text_parts[i + 1][1]) > 0 and \ text_parts[i + 1][1][0] not in " _,": while text_size + hyphen_size <= dx: text_size += hyphen_size text += "-" if text_parts[i + 1][1][0] == "-": text_parts[i + 1] = (text_parts[i + 1][0], " " + text_parts[i + 1][1][1:]) if text_size + hyphen_size <= dx + draw.textsize(" ", font)[0]: text += "-" draw.text((self.text_pos[0] + x + extra, self.text_pos[1] + y), chord, font=font, fill=(0, 0, 0)) draw.text((self.text_pos[0] + x + extra, self.text_pos[1] + y + line_height), text, font=font, fill=(0, 0, 0)) chord = chord.strip() if len(chord) > 0: if Chord.is_chord(chord): chords.add(str(Chord(chord).tone)) # draw.text((self.text_pos[0] + x + extra + chord_size, # self.text_pos[1] + y), # str(chord.tone), font=help_tone_font, fill=(0, 0, 0)) extra += dx y += line_height else: line.text = line.text.replace("_", " ").replace("—", "-").rstrip() draw.text((self.text_pos[0] + x, self.text_pos[1] + y), line.text, font=font, fill=(0, 0, 0)) y += line_height print("chords:", len(chords), chords)
def get_page(self): page = Image.new("RGB", mm_to_px(self.page_size), (255, 255, 255)) draw = ImageDraw.Draw(page) self.draw_lines(draw) return page
class RenderedText(object): page_size = (210, 297) delta = 15 draw = ImageDraw.Draw(Image.new("RGB", mm_to_px(page_size), (255, 255, 255))) title_font_size = get_max_font_size(draw, "A", None, mm_to_px(delta * .7), 100)[0] author_font_size = title_font_size * 30 // 40 text_font_size = title_font_size * 25 // 40 list_font_size = title_font_size * 20 // 40 note_font_size = title_font_size * 15 // 40 max_width = mm_to_px(page_size[0] - 2 * delta) max_height = mm_to_px(page_size[1] - 4.5 * delta) text_pos = mm_to_px(delta, 3 * delta) def __init__(self, text, min_font_size, transposed_by, font_size=text_font_size): self.text = SongText(None, text) self.transposed_by = transposed_by self.font_size, self.problems = get_max_font_size( self.draw, self.text.get_text_to_size(), self.max_width, self.max_height, font_size, min_font_size=min_font_size) def get_page(self): page = Image.new("RGB", mm_to_px(self.page_size), (255, 255, 255)) draw = ImageDraw.Draw(page) self.draw_lines(draw) return page def draw_lines(self, draw): lines = self.text.get_lines() font = get_font(self.font_size) spacing = mm_to_px(self.font_size / 15.) hyphen_size = draw.textsize("-", font)[0] space_size = draw.textsize(" ", font)[0] line_height = draw.textsize("A", font)[1] + spacing x = y = 0 disable_x_reset = False help_tone_font = get_font(get_max_font_size(draw, "A", space_size, None, self.font_size)[0]) chords = set() if len(lines) > 0 and lines[0].text.startswith("[capo"): capo_font = get_font(self.list_font_size) width, height = draw.textsize(lines[0].text, capo_font) draw.text( ( self.text_pos[0] + self.max_width - width - mm_to_px(self.delta) // 2, self.text_pos[1] - 1.9 * height ), lines[0].text, font=capo_font, fill=(0, 0, 0)) lines.pop(0) if len(lines) > 0 and lines[0].is_empty(): lines.pop(0) for i, line in enumerate(lines): if line.is_empty(): disable_x_reset = False if not disable_x_reset: x = 0 previous_line = None if i - 1 < 0 else lines[i - 1] next_line = None if i + 1 == len(lines) else lines[i + 1] next_next_line = None if i + 2 >= len(lines) else lines[i + 2] if line.is_chord_line() and previous_line is not None and previous_line.is_text_line() and not line.is_tag_line(): y += spacing / 2 if line.is_text_line() and previous_line is not None and previous_line.is_chord_line() and not previous_line.is_tag_line(): continue if re.match(r"\[\d+x]", line.text) or ( line.is_tag_line() and next_line is not None and next_line.is_chord_line() and not next_line.is_tag_line() and next_next_line is not None and next_next_line.is_chord_line() ): tag = line.text.split(" ")[0] + " " extra = line_height if not next_line.is_text_line() and next_next_line is not None and next_next_line.is_text_line() else 0 draw.text((self.text_pos[0] + x, self.text_pos[1] + y + extra), tag, font=font, fill=(0, 0, 0)) line.text = line.text[len(tag):] x = draw.textsize(tag, font)[0] disable_x_reset = True y -= line_height if line.is_chord_line() and next_line is not None and next_line.is_text_line() and not line.is_tag_line(): parts = line.get_parts_with_indexes() text_parts = next_line.get_parts_by_indexes([i for i, _ in parts], False) chord_parts = line.get_parts_by_indexes([i for i, _ in parts], False) if parts[0][0] != 0: chord_parts.insert(0, (0, "")) text_parts.insert(0, (0, next_line.text[:parts[0][0]])) extra = -space_size if next_line.text.startswith(" ") else 0 for i in range(len(chord_parts)): chord = chord_parts[i][1].replace("_", " ").replace("—", "-") while chord.endswith(" "): chord = chord[:-1] text = text_parts[i][1].replace("_", " ").replace("—", "-") while text != text.replace("--", "-"): text = text.replace("--", "-") chord_size = draw.textsize(chord, font)[0] text_size = draw.textsize(text, font)[0] dx = max(chord_size, text_size) if i < len(chord_parts) - 1 and \ len(text) > 0 and \ text[-1] not in " _," and \ len(text_parts[i + 1][1]) > 0 and \ text_parts[i + 1][1][0] not in " _,": while text_size + hyphen_size <= dx: text_size += hyphen_size text += "-" if text_parts[i + 1][1][0] == "-": text_parts[i + 1] = (text_parts[i + 1][0], " " + text_parts[i + 1][1][1:]) if text_size + hyphen_size <= dx + draw.textsize(" ", font)[0]: text += "-" draw.text((self.text_pos[0] + x + extra, self.text_pos[1] + y), chord, font=font, fill=(0, 0, 0)) draw.text((self.text_pos[0] + x + extra, self.text_pos[1] + y + line_height), text, font=font, fill=(0, 0, 0)) chord = chord.strip() if len(chord) > 0: if Chord.is_chord(chord): chords.add(str(Chord(chord).tone)) # draw.text((self.text_pos[0] + x + extra + chord_size, # self.text_pos[1] + y), # str(chord.tone), font=help_tone_font, fill=(0, 0, 0)) extra += dx y += line_height else: line.text = line.text.replace("_", " ").replace("—", "-").rstrip() draw.text((self.text_pos[0] + x, self.text_pos[1] + y), line.text, font=font, fill=(0, 0, 0)) y += line_height print("chords:", len(chords), chords)
resample=ANTIALIASING)) f3.write( img.resize(mm_to_px((210 / 2, 297 / 2)), resample=ANTIALIASING)) # songs = songs[:2] # songs = [song for song in songs if song.title.startswith("A")] # songs.sort(key=lambda song: len(song.text.text.split("\n"))) draw = ImageDraw.Draw(Image.new("RGB", (0, 0), (255, 255, 255))) num_of_pages = 1 while True: i = (len(songs) + 1) // num_of_pages list_font_size = get_max_font_size( draw, "\n".join(["A" for a in range(i // 2)]), None, mm_to_px(RenderedText.page_size[1] - RenderedText.delta * 5), RenderedText.text_font_size)[0] if list_font_size >= RenderedText.list_font_size: break num_of_pages += 1 f.counter = num_of_pages * 2 + 1 f2.counter = num_of_pages * 2 + 1 f3.counter = num_of_pages * 2 + 1 single_song_waiting_for_another = None worst = [] written_songs = [] c = 0
def generate_pdf(name, cards): random.seed(10) with PdfWriter(name) as writer: counter = 0 space = .05 base_point = int(mm_to_px(210) / 2 - mm_to_px(Card.base_width) - mm_to_px(space / 2)), \ int(mm_to_px(297) / 2 - 2.5 * mm_to_px(Card.base_height) - mm_to_px(space * 2)) while len(cards) > 0: front_canvas = Image.new("RGB", mm_to_px(210, 297), (255, 255, 255)) back_canvas = Image.new("RGB", mm_to_px(210, 297), (255, 255, 255)) for i in range(len(cards[:10])): card = cards.pop(0) counter += 1 print("{} Generating {}. card".format(datetime.now(), counter)) sys.stdout.flush() card = card.get_card() offset_x = mm_to_px(Card.base_width + space) if i % 2 == 1 else 0 offset_y = mm_to_px(Card.base_height + space) * (i // 2) if card[0].size[0] > 0: front_canvas.paste( card[0], (base_point[0] + offset_x, base_point[1] + offset_y), mask=card[0]) offset_x = mm_to_px(Card.base_width + space) if i % 2 == 0 else 0 background = Card.get_round_rectangle( ((card[1].size[0] // mm_to_px(Card.base_width)) * Card.base_width + 4, (card[1].size[1] // mm_to_px(Card.base_height)) * Card.base_height + 4), "true_black", 0) if card[1].size[0] > 0: back_canvas.paste(background, (base_point[0] + offset_x - mm_to_px(2), base_point[1] + offset_y - mm_to_px(2)), mask=background) back_canvas.paste( card[1], (base_point[0] + offset_x, base_point[1] + offset_y), mask=card[1]) if not all([p == (255, 255, 255) for p in front_canvas.getdata()]): writer.write(front_canvas) if not all([p == (255, 255, 255) for p in back_canvas.getdata()]): writer.write(back_canvas)
def generate_box(name): with PdfWriter(name) as f: extra_space_around_cards = 1 extra_space_because_of_how_box_is_folded = 2 for diff in [0, 1]: w = mm_to_px(Card.base_width + diff + extra_space_around_cards) l = mm_to_px((Card.base_height + diff) * 2 + extra_space_around_cards + extra_space_because_of_how_box_is_folded) h = mm_to_px(22) mx = max(w // 2, h * 2) mn = min(w // 2, h * 2) margin = mm_to_px(30) for i in range(2): cropping = mm_to_px(2) if i == 0 else 0 page = Image.new("RGB", mm_to_px(210, 297), (255, 255, 255)) draw = ImageDraw.Draw(page) color = getrgb("black") if diff == 0 else getrgb("true_black") draw.rectangle( ((margin - cropping, margin + mx - w // 2 - cropping), (margin + h + w + h + cropping, margin + mx + l + w // 2 + cropping)), color) draw.rectangle( ((margin + h - cropping, margin + mx - h * 2 - cropping), (margin + h + w + cropping, margin + mx + l + h * 2 + cropping)), color) if i == 0 and diff == 1: card = BackCard(px_to_mm(w), px_to_mm(l), True, "orange").get_card() page.paste(card, (margin + h, margin + mx), mask=card) if i == 1: line_color = getrgb("white") line_width = mm_to_px(.05) draw.line(( (margin + h, margin + mx + l + mn), (margin + h, margin + mx + l), ), line_color, line_width) draw.line(( (margin + h + w, margin + mx + l), (margin + h + w, margin + mx + l + mn), ), line_color, line_width) draw.line(( (margin + h + w, margin + mx - mn), (margin + h + w, margin + mx), ), line_color, line_width) draw.line(( (margin + h, margin + mx - mn), (margin + h, margin + mx), ), line_color, line_width) dashed_line(draw, ((margin + h, margin + mx - h), (margin + h + w, margin + mx - h)), line_color, line_width) dashed_line(draw, ((margin, margin + mx), (margin + h, margin + mx)), line_color, line_width) dashed_line(draw, ((margin + h, margin + mx), (margin + h + w, margin + mx)), line_color, line_width) dashed_line(draw, ((margin + h + w, margin + mx), (margin + h + w + h, margin + mx)), line_color, line_width) dashed_line(draw, ((margin, margin + mx + l), (margin + h, margin + mx + l)), line_color, line_width) dashed_line(draw, ((margin + h, margin + mx + l), (margin + h + w, margin + mx + l)), line_color, line_width) dashed_line(draw, ((margin + h + w, margin + mx + l), (margin + h + w + h, margin + mx + l)), line_color, line_width) dashed_line(draw, ((margin + h, margin + mx + l + h), (margin + h + w, margin + mx + l + h)), line_color, line_width) dashed_line(draw, ((margin + h, margin + mx), (margin + h, margin + mx + l)), line_color, line_width) dashed_line(draw, ((margin + h + w, margin + mx), (margin + h + w, margin + mx + l)), line_color, line_width) if i == 1: page = page.transpose(FLIP_LEFT_RIGHT) f.write(page)
def get_blank(self): return Image.new("RGBA", mm_to_px(self.size()), (0, 0, 0, 0))
class TextHelpCard(HelpCard): delta = mm_to_px(10) title_size = 14 text_size = 11 def __init__(self, color, title, text): self.should_resize = False self.title = title self.text = text self.title = self.title.strip() self.top = self.delta super().__init__(color) self.check_sizes() self.is_upside_down = False def has_title(self): return len(self.title) > 0 def get_card(self): card = super().get_card() draw = ImageDraw.Draw(card) if self.has_title(): font = get_font(self.title_size) colors = get_source_code_coloring(self.title) for color in colors: draw.text((mm_to_px(10), self.top), colors[color], font=font, fill=getrgb(color)) height = draw.textsize("A", font)[1] self.top += height * 2.05 if self.has_title() or not self.should_resize: font = get_font(self.text_size) colors = get_source_code_coloring(self.text) for color in colors: draw.text((mm_to_px(10), self.top), colors[color], font=font, fill=getrgb(color), spacing=mm_to_px(.8)) else: sc_size = get_source_code_position_n_size(card, self.text, draw) font = get_font(sc_size) w, h = draw.textsize(self.text, font, spacing=mm_to_px(0.6)) colors = get_source_code_coloring(self.text) for color in colors: draw.text( (mm_to_px(10), (card.size[1] - h) // 2 - mm_to_px(2)), colors[color], font=font, fill=getrgb(color), spacing=mm_to_px(0.8)) if self.is_upside_down: card = card.rotate(180) return card def check_sizes(self): if len(self.title) > 31: logging.warning(f"Title {self.title} is too long! (31 chars max)") lines = self.text.split("\n") lines.sort(reverse=True, key=lambda line: len(line)) line = lines[0] if len(line) > 42: logging.warning(f"Line {line} is too long! (42 chars max)") if len(lines) > (27 if self.has_title() else 29): logging.warning( f"There is too many lines ({len(lines)}), max. lines count is 27 (29), in {self}" ) def __repr__(self): if self.has_title(): return self.title return self.text.split("\n")[0]
def get_first_image(): background = ImageColor.getrgb(color_codes["lighter_black"]) fn = Image.new("RGBA", mm_to_px(200, 150), (*background, 0)) fn_back = rotate(PlayingCardBack("yellow").get_card(), 90) fn.paste(fn_back, mm_to_px(00, 45), fn_back) value = Image.new("RGBA", mm_to_px(200, 150), (*background, 0)) value_back = rotate(PlayingCardBack("blue").get_card(), 90) value.paste(value_back, mm_to_px(70, 45), value_back) corner_size = 20 cropped_fn = Image.new("RGBA", mm_to_px(200, 150), (*background, 0)) cropped_fn_back = rotate(PlayingCardBack("yellow").get_card(), 90) for w in range(cropped_fn_back.width): for h in range(cropped_fn_back.height): if w - h > mm_to_px(Card.base_height - corner_size): cropped_fn_back.putpixel((w, h), (0, 0, 0, 0)) cropped_fn.paste(cropped_fn_back, mm_to_px(00, 45), cropped_fn_back) cropped_fn_corner = Image.new("RGBA", mm_to_px(200, 150), (*background, 0)) cropped_fn_corner_back = rotate(ValueCard("green", values["green"][0]).get_card(), 90) for w in range(cropped_fn_corner_back.width): for h in range(cropped_fn_corner_back.height): if w - h <= mm_to_px(Card.base_height - corner_size - 0.1): cropped_fn_corner_back.putpixel((w, h), (0, 0, 0, 0)) continue if w - h <= mm_to_px(Card.base_height - corner_size): pix = list(cropped_fn_corner_back.getpixel((w, h))) for i in range(len(pix)): pix[i] //= 2 pix[-1] = 255 cropped_fn_corner_back.putpixel((w, h), tuple(pix)) cropped_fn_corner_back = rotate(cropped_fn_corner_back, 180, expand=False, center=mm_to_px(Card.base_height - corner_size // 2, corner_size // 2)) cropped_fn_corner.paste(cropped_fn_corner_back, mm_to_px(00, 45), cropped_fn_corner_back) plane = Image.new("RGB", mm_to_px(200, 150), (*background,)) blank = Image.new("RGBA", mm_to_px(200, 150), (*background, 255)) for height in range(16): ratio = .8 coeffs = get_main_plane_coeffs(plane.size, ratio, height - 0.5) transformed = transform(value, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(blank, mask=transformed) if height < 13: transformed = transform(fn, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(blank, mask=transformed) if height == 13: transformed = transform(cropped_fn, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(blank, mask=transformed) if height == 14: transformed = transform(cropped_fn_corner, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(blank, mask=transformed) coeffs = get_main_plane_coeffs(plane.size, ratio, height) transformed = transform(value, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(transformed, mask=transformed) if height <= 14: if height < 13: transformed = transform(fn, plane.size, Image.PERSPECTIVE, coeffs) if height == 13: transformed = transform(cropped_fn, plane.size, Image.PERSPECTIVE, coeffs) if height == 14: transformed = transform(cropped_fn_corner, plane.size, Image.PERSPECTIVE, coeffs) plane.paste(transformed, mask=transformed) plane = resize(plane, (plane.width // 2, plane.height // 2)) return plane
def get_play( fns_count, values_count, input_value_index, output_value_index, used_fn_indexes, front_hand_count, right_hand_count, front_played_count=0, right_played_count=0, add_thumb=False ): background = ImageColor.getrgb(color_codes["lighter_black"]) base = Image.new("RGB", mm_to_px(87 - PictureHelpCard.DX, 87 - PictureHelpCard.DX), (*background,)) x1 = 30 x2 = 230 y1 = 30 y2 = 100 table = get_play_board() table.putalpha(100) table = transform_play_board(table, 0) base.paste(table, mask=table) blank = get_play_board() fn = get_play_board() fn_card = PlayingCardBack("yellow").get_card() fn.paste(fn_card, mm_to_px(x2, y1), fn_card) for i in range(fns_count): transformed = transform_play_board(fn, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(fn, i) base.paste(transformed, mask=transformed) value = get_play_board() value_card = PlayingCardBack("blue").get_card() value.paste(value_card, mm_to_px(x1, y1), value_card) for i in range(values_count): transformed = transform_play_board(value, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(value, i) base.paste(transformed, mask=transformed) used_value = get_play_board() used_value_card = ValueCard("green", values["green"][0]).get_card() used_value.paste(used_value_card, mm_to_px(x1, y2), used_value_card) for i in range(14 - values_count - 1): transformed = transform_play_board(used_value, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(used_value, i) base.paste(transformed, mask=transformed) if input_value_index is not None: input_value = get_play_board() input_value_card = ValueCard("green", values["green"][input_value_index]).get_card() input_value.paste(input_value_card, mm_to_px(x1, y2), input_value_card) i = 14 - values_count - 1 transformed = transform_play_board(input_value, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(input_value, i) base.paste(transformed, mask=transformed) if output_value_index is not None: output_value = get_play_board() output_value_card = ValueCard("green", values["green"][output_value_index]).get_card() output_value.paste(output_value_card, mm_to_px(x2, y2), output_value_card) i = 0 transformed = transform_play_board(output_value, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(output_value, i) base.paste(transformed, mask=transformed) for i in range(right_hand_count): right_hand = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) right_hand_tmp = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) right_hand_card = PlayingCardBack("yellow").get_card() right_hand_tmp.paste(right_hand_card, mm_to_px(50, 50), right_hand_card) # right_hand_tmp = resize(right_hand_tmp, (2 * right_hand_tmp.size[0], 2 * right_hand_tmp.size[1])) right_hand_tmp = rotate(right_hand_tmp, 13 + (-i - 1) * 8, expand=False, center=mm_to_px((Card.base_width + 50, 50))) right_hand.paste(right_hand_tmp, mm_to_px(0, 80), right_hand_tmp) right_hand = rotate(right_hand, 180) coeffs = find_coefficients( [ (mm_to_px(140), mm_to_px(20)), (right_hand.size[0] - mm_to_px(20), mm_to_px(40)), (right_hand.size[0] - mm_to_px(20), right_hand.size[1] - mm_to_px(130)), (mm_to_px(160), right_hand.size[1] - mm_to_px(140)) ], [(0, 0), (right_hand.size[0], 0), (right_hand.size[0], right_hand.size[1]), (0, right_hand.size[1])] ) right_hand = transform(right_hand, right_hand.size, Image.PERSPECTIVE, coeffs) scale = 1.5 right_hand = resize(right_hand, (int(right_hand.width / scale), int(right_hand.height / scale))) base.paste(right_hand, mm_to_px(-110 / scale + 23, -30 / scale + 2), mask=right_hand) if add_thumb: thumb = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) thumb_tmp = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) thumb_card = Image.open("help/arrows/thumb.png").convert("RGBA") scale = 3. * 80 / ANTIALIASING / RESOLUTION_DPI thumb_card = resize(thumb_card, (int(thumb_card.width / scale), int(thumb_card.height / scale))) thumb_card = rotate(thumb_card, 180) color = getrgb("grey") for x in range(thumb_card.width): for y in range(thumb_card.height): thumb_card.putpixel((x, y), (*color, thumb_card.getpixel((x, y))[3])) thumb_tmp.paste(thumb_card, mm_to_px(70, 50), thumb_card) thumb_tmp = rotate(thumb_tmp, 13, expand=False, center=mm_to_px((Card.base_width + 50, 50))) thumb.paste(thumb_tmp, mm_to_px(0, 80), thumb_tmp) thumb = rotate(thumb, 180) coeffs = find_coefficients( [ (mm_to_px(140), mm_to_px(20)), (thumb.size[0] - mm_to_px(20), mm_to_px(40)), (thumb.size[0] - mm_to_px(20), thumb.size[1] - mm_to_px(130)), (mm_to_px(160), thumb.size[1] - mm_to_px(140)) ], [(0, 0), (thumb.size[0], 0), (thumb.size[0], thumb.size[1]), (0, thumb.size[1])] ) thumb = transform(thumb, thumb.size, Image.PERSPECTIVE, coeffs) scale = 1.5 thumb = resize(thumb, (int(thumb.width / scale), int(thumb.height / scale))) base.paste(thumb, mm_to_px(-110 / scale + 23, -30 / scale + 2), mask=thumb) for i in range(len(used_fn_indexes)): used_fn = get_play_board() used_fn_card = FunctionCard("green", get_rules()["green"][used_fn_indexes[i]]).get_card() used_fn_card = rotate(used_fn_card, randint(0, 360)) used_fn.paste(used_fn_card, mm_to_px(x1 / 2 + x2 / 2 - 5, y2 + 30), used_fn_card) transformed = transform_play_board(used_fn, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(used_fn, i) base.paste(transformed, mask=transformed) for i in range(front_played_count): i += 1 front_player_fn = get_play_board() front_player_fn_card = PlayingCardBack("yellow").get_card() front_player_fn_card = rotate(front_player_fn_card, 97 + 10 * -i) front_player_fn.paste(front_player_fn_card, mm_to_px(x1 - 10 + 2 * i + randint(-3, 3), 200 + 20 * i + randint(-3, 3)), front_player_fn_card) transformed = transform_play_board(front_player_fn, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(front_player_fn, i) base.paste(transformed, mask=transformed) for i in range(right_played_count): i += 1 right_player_fn = get_play_board() right_player_fn_card = PlayingCardBack("yellow").get_card() right_player_fn_card = rotate(right_player_fn_card, 51 + 8 * -i) right_player_fn.paste(right_player_fn_card, mm_to_px(x2 + 20 + 8 * i + randint(-3, 3), 300 - 20 * i + randint(-3, 3)), right_player_fn_card) transformed = transform_play_board(right_player_fn, i - 0.5) base.paste(blank, mask=transformed) transformed = transform_play_board(right_player_fn, i) base.paste(transformed, mask=transformed) for i in range(front_hand_count): front_hand = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) front_hand_tmp = Image.new("RGBA", mm_to_px(200, 200), (0, 0, 0, 0)) front_hand_card = ValueCard("green", values["green"][0]).get_card() front_hand_tmp.paste(front_hand_card, mm_to_px(50, 50), front_hand_card) # front_hand_tmp = resize(front_hand_tmp, (2 * front_hand_tmp.size[0], 2 * front_hand_tmp.size[1])) front_hand_tmp = rotate(front_hand_tmp, -2 + (-i - 1) * 5, expand=False, center=mm_to_px((Card.base_width + 50, Card.base_height + 50))) front_hand.paste(front_hand_tmp, mm_to_px(0, 0), front_hand_tmp) coeffs = get_main_plane_coeffs(front_hand.size, .9, i) front_hand = transform(front_hand, front_hand.size, Image.PERSPECTIVE, coeffs) scale = 2 front_hand = resize(front_hand, (int(front_hand.width / scale), int(front_hand.height / scale))) base.paste(front_hand, mm_to_px(-12, 46), mask=front_hand) return base
def get_play_board(): return Image.new("RGBA", mm_to_px(400, 400), (0, 0, 0, 0))