def test_template_with_max_attribute_can_render(self): c1 = ColorLayer("color1", content="Green", left=NA(0), width=NA(50), top=NA(0), height=NA(50)) c2 = ColorLayer("color2", content="Blue", left=NA(0), width=NA(60), top=SA("color1.bottom"), height=NA(50)) text = PTL("test", "Arial", 15, "Black", content="Hello World", left=MinA(SA("color1.right"), SA("color2.right")), top=SA("color2.bottom")) bg = ColorBackgroundLayer("name", content="White") layers = [c1, c2, bg, text] temp = Template("temp", *layers, left=NA(0), top=NA(0), width=NA(300), height=NA(300)) temp.update_bounds() assert text["left"] == 60
def test_can_order_layers_for_rendering(self): kwargs = { "left": SA("parent.left"), "right": SA("parent.right"), "top": SA("parent.top"), "bottom": SA("parent.bottom") } l1 = ColorLayer("layer_1", content="#FF0000", order=1, **kwargs) l2 = ColorLayer("layer_1", content="#00FF00", order=2, **kwargs) temp = Template("temp", l1, l2, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() green_above = temp.render() color_of_top_left_most_pixel = green_above.export_pixels(width=1, height=1) # RGBA, [1] is green assert color_of_top_left_most_pixel[:3] == [0, 255, 0] l1.order = 3 # move red above red_above = temp.render() color_of_top_left_most_pixel = red_above.export_pixels(width=1, height=1) assert color_of_top_left_most_pixel[:3] == [255, 0, 0]
def test_can_unset_attributes_evaluated_values(self): """Because the content of pt is changing per iteration, the left of square should change as well (top should change due to p in people).""" content_list = ["hello world", "people"] square_lefts = [] # stores left values per iteration square_tops = [] pt = PTL("pt", "Arial", 15, "Black", left=NA(0), top=NA(0)) square = ColorLayer("square", content="Red", left=AA(SA("pt.right")), top=SA("pt.bottom"), width=NA(20), height=NA(20)) bg = ColorBackgroundLayer("bg", content="White") temp = Template("temp", pt, square, bg, left=NA(0), top=NA(0), height=NA(100), width=NA(100)) for i, content in enumerate(content_list): pt.pre_render = None pt.content = content temp.unset_bounds_and_attributes() temp.update_bounds() temp.render().save( filename= f"tests/images/{i}_test_can_unset_attributes_evaluated_values.png" ) square_lefts.append(temp.get_layer("square")["left"]) square_tops.append(temp.get_layer("square")["top"]) assert square_lefts[0] != square_lefts[1] assert square_tops[0] != square_tops[1]
def __init__(self, name, *args, width=None, height=None, **kwargs): initial_width = SA("self.initial_width") initial_height = SA("self.initial_height") ratio_attr = MaxA(DivA(width, initial_width), DivA(height, initial_height)) super().__init__(name, *args, width=MulA(initial_width, ratio_attr), height=MulA(initial_height, ratio_attr), **kwargs)
def test_can_have_templates_within_templates(self): pt = PointTextLayer("point_text_layer", content="Point Text Layer", font="Arial", size=35, color="Black", left=NA(0), top=NA(0)) bg = ColorLayer("bg", content="Red", left=NA(0), width=SA("parent.width"), height=SA("parent.height"), top=NA(0)) temp = Template("temp", pt, bg, left=NA(0), right=SA("point_text_layer.right"), top=NA(0), height=NA(100)) temp2 = Template("temp", temp, left=NA(0), right=SA("point_text_layer.right"), top=NA(0), height=NA(500)) temp2.update_bounds()
def test_this_configuration_can_render(self): pt = PointTextLayer("ptl", "Arial", 15, "Black", content="Hello World", left=AA(SA("parent.left"), NA(5)), top=SA("parent.top")) bg = ColorBackgroundLayer("bg", content="Green") temp = Template("temp", pt, bg, left=NA(10), right=SA("ptl.right"), top=SA("parent.top"), height=NA(100)) temp2 = Template("temp2", temp, left=NA(0), right=NA(100), top=NA(0), height=NA(100)) temp2.update_bounds() image = temp2.render()
def test_template_variable_get_set_correctly(self): pt = PointTextLayer("ptl", "Arial", 15, "Black", content="Hello World", left=AA(SA("parent.left"), NA(5)), top=SA("parent.top")) bg = ColorBackgroundLayer("bg", content="Green") temp = Template("temp", pt, bg, left=NA(10), right=SA("ptl.right"), top=SA("parent.top"), height=NA(100)) temp2 = Template("temp2", temp, left=NA(0), right=NA(100), top=NA(0), height=NA(100)) assert pt.template == bg.template assert pt.parent == temp assert pt.template == temp2 assert pt.template == temp.template
def test_can_render_color_overlay(self): pt = PTL("pt", "Arial", 15, "Black", content="PT", left=NA(0), top=NA(0)) pt2 = PTL("pt2", "Arial", 15, "Black", content="PT2", left=NA(0), top=AA(SA("pt.bottom"), NA(5))) bg = ColorBackgroundLayer("bg", content="Red") temp = Template("temp", pt, pt2, bg, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() image = temp.render() image.save(filename="tests/images/test_can_render_color_overlay_1.png") overlay = pt2.color_overlay("Blue") image.composite(overlay, int(pt2["left"]), int(pt2["top"])) image.save(filename="tests/images/test_can_render_color_overlay_2.png")
def test_can_render_shadow(self): pt = PTL("pt", "Arial", 15, "Black", content="PT", left=NA(0), top=NA(0)) pt2 = PTL("pt2", "Arial", 15, "Black", content="PT2", left=NA(0), top=AA(SA("pt.bottom"), NA(5))) bg = ColorBackgroundLayer("bg", content="White") temp = Template("temp", pt, pt2, bg, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() image = temp.render() image.save(filename="tests/images/test_can_render_shadow_1.png") shadow = pt2.shadow(2, 2, radius=4, sigma=2) image.composite(shadow, 0, 0) image.save(filename="tests/images/test_can_render_shadow_2.png")
def test_idm_works_for_text_layer_without_content(self): bg = ColorBackgroundLayer("bg", content="White") # content is None layer = PointTextLayer("layer", "Arial", 12, "Black", left=NA(0), base=NA(40)) square = ColorLayer("sqr", content="Red", width=NA(20), height=NA(20), bottom=SA("layer.cap"), left=NA(25)) temp = Template("temp", layer, square, bg, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() temp.render().save( filename= "tests/images/test_idm_works_for_text_layer_without_content.png")
def test_template_with_add_attribute_can_render(self): title = PTL("title", "Arial", 15, "Black", content="Hello World", left=NA(0), top=NA(0)) sub_title = PTL("sub_title", "Arial", 15, "Black", content="Bottom Text", left=NA(10), bottom=AA(SA("template.height"), NA(45, negative=True))) bg = ColorBackgroundLayer("bg", content="White") temp = Template("temp", title, sub_title, bg, left=NA(0), top=NA(0), width=NA(200), height=NA(200)) temp.update_bounds() image = temp.render() image.save( filename= f"tests/images/test_template_with_add_attribute_can_render.jpg")
def test_can_make_a_text_layer_with_percent_bounds(self): l = PointTextLayer("layer", "Arial", 12, "Black", YP40=NA(30), XP50_50=SA("title.left"))
def test_cannot_make_text_layer_with_bad_coords(self): with pytest.raises(ValueError): PointTextLayer("layer", "Arial", 12, "Black", test=SA("parent.height"), wow=NA(12))
def test_layers_passed_in_first_without_order_are_rendered_first( self, save_images): kwargs = { "left": SA("parent.left"), "right": SA("parent.right"), "top": SA("parent.top"), "bottom": SA("parent.bottom") } l1 = ColorLayer("layer_1", content="#FF0000", **kwargs) # red l2 = ColorLayer("layer_1", content="#00FF00", **kwargs) # green # l1 is first, is rendered first; therefore l2 (green) should be on top temp = Template("temp", l1, l2, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() green_above = temp.render() color_of_top_left_most_pixel = green_above.export_pixels(width=1, height=1) assert color_of_top_left_most_pixel[:3] == [0, 255, 0] # RGBA, [1] is green # remake template, now l2 is first, l1 rendered last temp = Template("temp", l2, l1, left=NA(0), width=NA(50), top=NA(0), height=NA(50)) temp.update_bounds() red_above = temp.render() color_of_top_left_most_pixel = red_above.export_pixels(width=1, height=1) assert color_of_top_left_most_pixel[:3] == [255, 0, 0] if save_images: green_above.save(filename="tests/images/green_above.png") red_above.save(filename="tests/images/red_above.png")
def test_can_get_mean_indepth_font_metrics_for_ptl(self): bg = ColorBackgroundLayer("bg", content="White") l = PointTextLayer("l", "Arial", 12, "Black", content="Hpqrs", left=NA(0), base=NA(20)) l2 = PointTextLayer("l2", "Arial", 12, "Black", content="e", left=NA(10), median=NA(50)) # l3 = PointTextLayer("l3", "Arial", 12, "Black", content="l", left=NA(20), descender=NA(50)) l4 = PointTextLayer("l4", "Arial", 12, "Black", content="l", left=NA(30), cap=NA(50)) # l5 = PointTextLayer("l5", "Arial", 12, "Black", content="o", left=NA(40), ascender=NA(50)) temp = Template( "temp", l, l2, bg, left=NA(0), # temp = Template("temp", l, l2, l3, l4, l5, left=NA(0), # right=SA("l5.right"), top=NA(0), bottom=SA("l5.bottom")) right=SA("l.right"), top=NA(0), bottom=SA("l.bottom")) temp.update_bounds() temp.render().save( filename= "tests/images/test_can_get_mean_indepth_font_metrics_for_ptl.png")
def test_can_make_negative_numeric_attribute(self): """Tests if negative NAs can be initialised and if the different conventions will produce the same result""" negative_num_attr_1 = NA(-30) negative_num_attr_2 = NA(30, True) # test_layer_1 and test_layer_2 will have same left value title = PTL("title", "Arial", 15, "Black", content="Hello World", left=NA(0), top=NA(0)) test_layer_1 = ColorLayer("test_layer_1", content="Blue", left=negative_num_attr_1, right=SA("parent.right"), top=SA("title.top"), height=NA(20)) test_layer_2 = ColorLayer("test_layer_2", content="Green", left=negative_num_attr_2, right=SA("parent.right"), top=SA("test_layer_1.top"), height=NA(20)) temp = Template("temp", title, test_layer_1, test_layer_2, left=NA(0), width=NA(100), top=NA(0), height=NA(100)) temp.update_bounds() assert test_layer_1["left"] == test_layer_2["left"]
def test_exception_raised_if_no_existant_layer_is_referenced_in_SA(self): with pytest.raises(LayerDoesNotExistError): pt = PTL("test", "Arial", 15, "Black", content="Hello", left=NA(0), top=NA(0)) sq = ColorLayer("square", content="Red", left=NA(0), top=SA("doesnotexist.bottom"), width=NA(20), height=NA(20)) bg = ColorBackgroundLayer("bg", content="Green") bg2 = ColorBackgroundLayer("bg2", content="White") temp2 = Template("temp2", sq, bg, left=NA(0), width=NA(25), top=NA(0), height=NA(25)) temp = Template("temp", pt, bg2, temp2, left=NA(0), width=NA(100), top=NA(0), height=NA(100)) temp.update_bounds() # from pprint import pprint # pprint(temp.get_layer("temp2").__dict__) temp.render().save( filename= "tests/images/test_exception_raised_if_no_existant_layer_is_referenced_in_SA.png" )
def __init__(self, deckName): self.RESOURCE_DIR = join(os.getcwd(), "resources") # self.TEST_DIR = "test_images" # FONTS self.MPLANTIN = join(self.RESOURCE_DIR, "fonts", "MPlantin.ttf") self.BELEREN_SC = join(self.RESOURCE_DIR, "fonts", "Beleren_small_caps.ttf") self.BELEREN = join(self.RESOURCE_DIR, "fonts", "Jace_Beleren_bold.ttf") self.MPLANTIN_BOLD = join(self.RESOURCE_DIR, "fonts", "MPlantin_bold.ttf") self.MPLANTIN_ITAL = join(self.RESOURCE_DIR, "fonts", "MPlantin_italic.ttf") self.RELAY = join(self.RESOURCE_DIR, "fonts", "Relay_medium.ttf") self.FC = "White" self.FLAVOR_SPLIT_COLOR = "RGBA(255, 255, 255, 0.6)" self.SHADOW_COLOR = "#181510" self.FLAVOR_SPLIT_OFFSET = 40 self.SET_DOT_LANG_WIDTH = 5 self.INFO_SIZE = 18 self.NAME_SIZE = 38 self.FLAVOR_NAME_SIZE = 25 self.TYPE_SIZE = 33 self.PT_LOYAL_SIZE = 40 self.RULES_TEXT_SIZE = 25 self.INNER_BORDER = 40 self.INNER_RULES_BORDER = 50 self.INNER_HEIGHT = 1040 self.INNER_WIDTH = 745 self.HEIGHT = 1080 self.WIDTH = 773 self.SPLIT_CENTER = 460 self.SPLIT_END = 870 self.SPLIT_HEIGHT = self.SPLIT_END - self.SPLIT_CENTER self.SPLIT_SHADOW_SIZE = 50 self.OUTER_X_BORDER = (self.WIDTH - self.INNER_WIDTH) / 2 self.TOTAL_Y_BORDER = (self.HEIGHT - self.INNER_HEIGHT) self.OUTER_Y_BOTTOM_BORDER = 21 self.TOP_OUTER_BORDER = 20 self.STANDARD_BORDER = 40 self.BORDER = self.STANDARD_BORDER + self.OUTER_X_BORDER self.TOP_BORDER = self.STANDARD_BORDER + self.TOP_OUTER_BORDER self.BOTTOM_BORDER = self.STANDARD_BORDER + self.OUTER_Y_BOTTOM_BORDER self.RULES_BORDER = 50 + self.OUTER_X_BORDER self.BORDER_PATH = join(self.RESOURCE_DIR, "Border5.png") self.B = 29 self.MIN_ART_HEIGHT = 850 - self.B self.B_ART_WIDTH = self.WIDTH self.rarity_colors = { "M": "#D15003", "R": "#DFBD6C", "U": "#C8C8C8", "C": self.FC, "L": self.FC, "T": self.FC, } self.la = AA(MA(SA("language.right"), SA("number.right")), NA(3)) self.lmiddle = AA( NA(self.WIDTH / 2), DivA(AA(SA("artist_brush.width"), NA(3), SA("artist.width")), NA(2), negative=True)) self.BOTTOM_BASE_INFO = NA(self.HEIGHT - 45) self.TOP_BASE_INFO = AA(SA("set.cap"), NA(-3)) self.pdf = Image(filename=join(self.RESOURCE_DIR, "PrintPdf.png")) self.text_to_use = "text" self.PDF_SAVE_LOCATION = join("test_images", "pdfs", deckName) if not os.path.exists(self.PDF_SAVE_LOCATION): os.makedirs(self.PDF_SAVE_LOCATION)
def layers(self, card): art_layers = { "bg": ColorBackgroundLayer("bg", content=Color(self.SHADOW_COLOR)), "art": FillIL("art", order=-5, XP50=NA(self.WIDTH / 2), top=NA(self.B + self.TOP_OUTER_BORDER), width=NA(self.B_ART_WIDTH), height=NA(self.MIN_ART_HEIGHT)), "border": ImageLayer("border", content=self.BORDER_PATH, left=NA(0), top=NA(0)) } layers = { "dot": PTL("dot", self.RELAY, 25, self.FC, content=".", left=AA(SA("set.right"), NA(self.SET_DOT_LANG_WIDTH)), ycenter=SA("set.ycenter")), "language": PTL("language", self.RELAY, self.INFO_SIZE, self.FC, content="EN", left=AA(SA("dot.right"), NA(self.SET_DOT_LANG_WIDTH)), base=self.BOTTOM_BASE_INFO), "artist_brush": ResizeIL("artist_brush", content=join(self.RESOURCE_DIR, "artist_brush_white.png"), width=NA(20), left=self.lmiddle, height=SA("set.height"), bottom=self.BOTTOM_BASE_INFO), "copyright": PTL("copyright", self.MPLANTIN, self.INFO_SIZE - 5, self.FC, right=NA(self.WIDTH - self.BORDER), bottom=self.BOTTOM_BASE_INFO), "name": PTL("name", self.BELEREN, self.NAME_SIZE, self.FC, left=NA(self.BORDER), base=NA(70 + self.TOP_OUTER_BORDER)), "flavor_name": PTL("flavor_name", self.MPLANTIN_ITAL, self.FLAVOR_NAME_SIZE, self.FC, left=SA("name.left"), base=AA(SA("name.base"), NA(self.FLAVOR_NAME_SIZE + 4))), "PT": PTL("PT", self.BELEREN, self.PT_LOYAL_SIZE, self.FC, right=NA(self.WIDTH - self.BORDER), base=self.BOTTOM_BASE_INFO), "loyalty": PTL("loyalty", self.BELEREN, self.PT_LOYAL_SIZE, self.FC, right=NA(self.WIDTH - self.BORDER), base=self.BOTTOM_BASE_INFO), "set": PTL("set", self.RELAY, self.INFO_SIZE, self.FC, left=NA(self.BORDER), base=self.BOTTOM_BASE_INFO), "number": PTL("number", self.RELAY, self.INFO_SIZE, self.FC, left=NA(self.BORDER), base=self.TOP_BASE_INFO), "rarity": PTL("rarity", self.RELAY, self.INFO_SIZE, self.FC, left=SA("artist_brush.left"), base=self.TOP_BASE_INFO), "artist": PTL("artist", self.BELEREN_SC, self.INFO_SIZE, self.FC, left=AA(SA("artist_brush.right"), NA(3)), base=self.BOTTOM_BASE_INFO), "mana_cost": ManaCost("mana_cost", font=self.BELEREN, font_size=self.NAME_SIZE, font_color=self.FC, right=NA(self.WIDTH - self.BORDER), bottom=AA(SA("name.base"), NA(4))), } standard_rules = { "type": PTL("type", self.BELEREN, self.TYPE_SIZE, self.FC, left=NA(self.BORDER), base=AA(SA("rules.top"), NA(-10))), "rules": RulesText("rules", self.MPLANTIN, self.MPLANTIN_ITAL, self.RULES_TEXT_SIZE, self.FC, self.RULES_TEXT_SIZE - 4, left=NA(self.RULES_BORDER), right=NA(self.WIDTH - self.RULES_BORDER), base=AA(SA("rarity.cap"), NA(-6))) } split_text_layers = { "split_name": PTL("split_name", self.BELEREN, self.NAME_SIZE, self.FC, left=SA("name.left"), base=NA(self.SPLIT_CENTER + self.NAME_SIZE)), "split_mana_cost": ManaCost("split_mana_cost", font=self.BELEREN, font_size=self.NAME_SIZE, font_color=self.FC, right=SA("mana_cost.right"), bottom=AA(SA("split_name.base"), NA(4))), "split_type": PTL("split_type", self.BELEREN, self.TYPE_SIZE, self.FC, left=SA("type.left"), base=AA(SA("split_rules.top"), NA(-10))), "split_rules": RulesText("split_rules", self.MPLANTIN, self.MPLANTIN_ITAL, self.RULES_TEXT_SIZE, self.FC, self.RULES_TEXT_SIZE - 4, left=SA("rules.left"), right=SA("rules.right"), base=AA(SA("split_name.cap"), NA(-6))) } split_kwargs = { "left": NA(0), "order": -5, "width": NA(self.B_ART_WIDTH), "height": NA(self.SPLIT_HEIGHT) } top_split_kwargs = { **split_kwargs, "YP50": NA((self.B + self.TOP_OUTER_BORDER + self.SPLIT_CENTER) / 2) } bottom_split_kwargs = { **split_kwargs, "YP50": NA((self.SPLIT_CENTER + self.SPLIT_END - 2) / 2) } split_art_layers = { "split_divider_top": GradL("split_divider_top", start="RGBA(0,0,0,0.0)", end=self.SHADOW_COLOR, left=NA(0), width=NA(self.WIDTH), bottom=NA(self.SPLIT_CENTER), height=NA(self.SPLIT_SHADOW_SIZE)), "split_divider_bottom": GradL("split_divider_bottom", start=self.SHADOW_COLOR, end="RGBA(0,0,0,0.0)", left=NA(0), width=NA(self.WIDTH), top=NA(self.SPLIT_CENTER - 1), height=NA(self.SPLIT_SHADOW_SIZE)), "split_art_top": Mask("split_art_top_mask", FillIL("split_art_top", **top_split_kwargs), **top_split_kwargs), "split_art_bottom": Mask("split_art_bottom_mask", FillIL("split_art_bottom", **bottom_split_kwargs), **bottom_split_kwargs) } adventure_rules = { "rules_box": Template( "rules_box", *[ RulesText("rules", self.MPLANTIN, self.MPLANTIN_ITAL, self.RULES_TEXT_SIZE, self.FC, self.RULES_TEXT_SIZE - 4, left=AA(SA("parent.xcenter"), NA(5)), right=AA(SA("parent.right"), NA(self.RULES_BORDER, negative=True)), ycenter=SA("template.ycenter")), Template("adventure_box", *[ RulesText("adventure_rules", self.MPLANTIN, self.MPLANTIN_ITAL, self.RULES_TEXT_SIZE, self.FC, self.RULES_TEXT_SIZE - 4, left=NA(0), right=AA(SA("parent.width"), NA(-5)), top=AA(SA("adventure_type.base"), NA(6))), PTL("adventure_type", self.MPLANTIN, self.RULES_TEXT_SIZE + 3, self.FC, left=SA("adventure_name.left"), cap=AA(SA("adventure_name.base"), NA(6))), PTL("adventure_name", self.MPLANTIN, self.RULES_TEXT_SIZE + 5, self.FC, left=NA(0), cap=NA(3)), ManaCost("adventure_mana_cost", font=self.BELEREN, font_size=self.RULES_TEXT_SIZE, font_color=self.FC, right=SA("adventure_rules.right"), top=NA(0), mana_size=self.RULES_TEXT_SIZE), ], left=NA(self.RULES_BORDER), right=AA(SA("rules.left"), NA(-10)), ycenter=SA("template.ycenter"), height=SA("null.height")), ], left=NA(0), width=NA(self.WIDTH), base=AA( SA("self.height"), SA("rarity.cap"), NA(-6), MA(SA("rules.bottom"), SA("adventure_box.bottom"), negative=True)), height=SA("template.height")), "type": PTL("type", self.BELEREN, self.TYPE_SIZE, self.FC, left=NA(self.BORDER), base=AA(SA("rules_box.top"), MinA(SA("adventure_box.top"), SA("rules.top")), NA(-10))), } if card['layout'] == 'adventure': layers = {**layers, **adventure_rules} elif card["layout"] == "split": layers = {**layers, **standard_rules, **split_text_layers} art_layers = {**art_layers, **split_art_layers} else: layers = {**layers, **standard_rules} return list(art_layers.values()), list(layers.values())
env["FLAVOR_SPLIT_OFFSET"] = 40 env["MIN_ART_HEIGHT"] = 850 - env["B"] env["B_ART_WIDTH"] = env["WIDTH"] env["OUTER_X_BORDER"] = (env["WIDTH"] - env["INNER_WIDTH"]) / 2 env["TOTAL_Y_BORDER"] = (env["HEIGHT"] - env["INNER_HEIGHT"]) env["BORDER"] = env["STANDARD_BORDER"] + env["OUTER_X_BORDER"] env["TOP_BORDER"] = env["STANDARD_BORDER"] + env["TOP_OUTER_BORDER"] env["BOTTOM_BORDER"] = env["STANDARD_BORDER"] + env["OUTER_Y_BOTTOM_BORDER"] env["RULES_BORDER"] = 50 + env["OUTER_X_BORDER"] env["BORDER_PATH"] = join(env["RESOURCE_DIR"], "Border5.png") return env[key] la = AA(MA(SA("language.right"), SA("number.right")), NA(3)) lmiddle = AA( NA(env("WIDTH") / 2), DivA(AA(SA("artist_brush.width"), NA(3), SA("artist.width")), NA(2), negative=True)) BOTTOM_BASE_INFO = NA(env("HEIGHT") - 45) TOP_BASE_INFO = AA(SA("set.cap"), NA(-3)) art_layers = { "bg": ColorBackgroundLayer("bg", content=Color("#181510")), "art": FillIL("art", order=-5,
def test_can_make_string_attribute(self): SA("layer.width") SA("parent.XP40") SA("template.right")
def test_can_make_add_attribute(self): add_attr = AA(SA("template.height"), NA(-45))
def main(): RESOURCE_DIR = join(os.getcwd(), "resources") SETS = join(RESOURCE_DIR, "card_data", "sets.json") TEST_DIR = "test_images" MPLANTIN = join(RESOURCE_DIR, "fonts", "MPlantin.ttf") BELEREN_SC = join(RESOURCE_DIR, "fonts", "Beleren_small_caps.ttf") BELEREN = join(RESOURCE_DIR, "fonts", "Jace_Beleren_bold.ttf") MPLANTIN_BOLD = join(RESOURCE_DIR, "fonts", "MPlantin_bold.ttf") MPLANTIN_ITAL = join(RESOURCE_DIR, "fonts", "MPlantin_italic.ttf") RELAY = join(RESOURCE_DIR, "fonts", "Relay_medium.ttf") FC = "White" FLAVOR_SPLIT_COLOR = "RGBA(255, 255, 255, 0.6)" FLAVOR_SPLIT_OFFSET = 40 if os.path.isfile(SETS): with open(SETS, "r") as f: sets = json.load(f) else: raise ValueError("sets.json not found.") myset = "WAR" # JSON = join(RESOURCE_DIR, "card_data", f"{myset}.json") # JSON = join(RESOURCE_DIR, "card_data", f"mardu_aristocrats_M20.json") # TOKENS = join(RESOURCE_DIR, "card_data", f"tokens.json") # ANGELS = join(RESOURCE_DIR, "card_data", f"mardu_angels_M20.json") JSON = join(RESOURCE_DIR, "set_data", f"{myset}.json") # SULTAI_FLASH = join(RESOURCE_DIR, "card_data", f"sultai_flash.json") SAVE_LOCATION = myset # SAVE_LOCATION = "sultai_flash" # JSON = SULTAI_FLASH # JSON = TOKENS """make directory in art""" # if not os.path.isdir(join(RESOURCE_DIR, "art", myset)): # dir does not exist # os.mkdir(join(RESOURCE_DIR, "art", myset)) """make directory in render dir""" if not os.path.isdir(join("test_images", "all_render", SAVE_LOCATION)): # dir does not exist os.mkdir(join("test_images", "all_render", SAVE_LOCATION)) """load cards""" with open(JSON, "r") as f: cards = json.load(f) """load tokens""" # with open(TOKENS, "r") as f: # tokens = json.load(f) BORDER = 45 RULES_BORDER = 52 HEIGHT = 1050 WIDTH = 752 SET_DOT_LANG_WIDTH = 5 INFO_SIZE = 18 # FONT_SIZE = 40 NAME_SIZE = 38 TYPE_SIZE = 33 PT_LOYAL_SIZE = 40 RULES_TEXT_SIZE = 25 la = AA(MA(SA("language.right"), SA("number.right")), NA(3)) lmiddle = AA( NA(WIDTH / 2), DivA(AA(SA("artist_brush.width"), NA(3), SA("artist.width")), NA(2), negative=True)) art_layers = { "bg": ColorBackgroundLayer("bg", content=Color("Black")), "art": FillIL("art", order=-5, XP50=NA(WIDTH / 2), YP50=NA(HEIGHT / 2), width=NA(WIDTH), height=NA(HEIGHT)), "shadow1": ColorLayer("shadow1", content="RGBA(0,0,0,0.4)", left=NA(0), width=NA(WIDTH), top=NA(0), bottom=SA("shadow2.top")), "shadow2": GradL("shadow2", start="RGBA(0,0,0,0.4)", end="RGBA(0,0,0,0.0)", left=NA(0), width=NA(WIDTH), top=SA("name.bottom"), height=NA(200)), "shadow3": GradL("shadow3", start="RGBA(0,0,0,0.0)", end="RGBA(0,0,0,0.7)", left=NA(0), width=NA(WIDTH), bottom=SA("shadow4.top"), top=AA(SA("type.cap"), NA(-150))), "shadow4": ColorLayer("shadow4", content="RGBA(0,0,0,0.7)", left=NA(0), width=NA(WIDTH), bottom=NA(HEIGHT + 1), top=SA("rules.YP70")) } no_content_reset = { "dot": PTL("dot", RELAY, 25, FC, content=".", left=AA(SA("set.right"), NA(SET_DOT_LANG_WIDTH)), ycenter=SA("set.ycenter")), "language": PTL("language", RELAY, INFO_SIZE, FC, content="EN", left=AA(SA("dot.right"), NA(SET_DOT_LANG_WIDTH)), base=NA(HEIGHT - BORDER)), "artist_brush": ResizeIL("artist_brush", content=join(RESOURCE_DIR, "artist_brush_white.png"), width=NA(20), left=lmiddle, height=SA("set.height"), bottom=NA(HEIGHT - BORDER)), "copyright": PTL("copyright", MPLANTIN, INFO_SIZE - 5, FC, right=NA(WIDTH - BORDER), bottom=SA("set.bottom")), } layers = { "name": PTL("name", BELEREN, NAME_SIZE, FC, left=NA(BORDER), base=NA(80)), "type": PTL("type", BELEREN, TYPE_SIZE, FC, left=NA(BORDER), base=AA(SA("rules.top"), NA(-10))), "PT": PTL("PT", BELEREN, PT_LOYAL_SIZE, FC, right=NA(WIDTH - BORDER), base=SA("set.base")), "loyalty": PTL("loyalty", BELEREN, PT_LOYAL_SIZE, FC, right=NA(WIDTH - BORDER), base=SA("set.base")), "set": PTL("set", RELAY, INFO_SIZE, FC, left=NA(BORDER), base=NA(HEIGHT - BORDER)), "number": PTL("number", RELAY, INFO_SIZE, FC, left=NA(BORDER), base=AA(SA("set.cap"), NA(-3))), "rarity": PTL("rarity", RELAY, INFO_SIZE, FC, left=SA("artist_brush.left"), base=SA("number.base")), "artist": PTL("artist", BELEREN_SC, INFO_SIZE, FC, left=AA(SA("artist_brush.right"), NA(3)), base=SA("set.base")), "mana_cost": ManaCost("mana_cost", font=BELEREN, font_size=NAME_SIZE, font_color=FC, right=NA(WIDTH - BORDER), bottom=AA(SA("name.base"), NA(4))), "rules": RulesText("rules", MPLANTIN, MPLANTIN_ITAL, RULES_TEXT_SIZE, FC, RULES_TEXT_SIZE - 4, left=NA(RULES_BORDER), right=NA(WIDTH - RULES_BORDER), bottom=AA(SA("PT.bottom"), NA(-PT_LOYAL_SIZE), NA(-5))), # "flavor_split": ColorLayer("flavor_split", left=NA(RULES_BORDER + FLAVOR_SPLIT_OFFSET), # right=NA(WIDTH - RULES_BORDER - FLAVOR_SPLIT_OFFSET), height=NA(2), # bottom=AA(SA("flavor.top"), NA(-5))), # "flavor": RulesText("flavor", MPLANTIN, MPLANTIN_ITAL, RULES_TEXT_SIZE, FC, # RULES_TEXT_SIZE - 4, left=NA(RULES_BORDER), right=NA(WIDTH-RULES_BORDER), # bottom=AA(SA("PT.bottom"), NA(-PT_LOYAL_SIZE), NA(-5))), } text_template = Template("text_temp", *layers.values(), *no_content_reset.values(), left=NA(0), width=NA(WIDTH), top=NA(0), height=NA(HEIGHT)) art_template = Template("art_temp", *art_layers.values(), order=-5, left=NA(0), width=NA(WIDTH), top=NA(0), height=NA(HEIGHT)) name = text_template.get_layer("name") with_art = list(os.listdir(join(RESOURCE_DIR, "art", myset))) cards = [c for c in cards if f"{c['name']}_{c['id']}.jpg" in with_art] cards = [c for c in cards if c['name'] == "Nicol Bolas, Dragon-God"] print(len(cards)) # no_content_reset["copyright"].content = f"™ & © {datetime.now().year} Wizards of the Coast" # no_content_reset["copyright"].content = f"™ & © {datetime.now().year} WOTC" loga = math.ceil(math.log10(len(cards))) temp = Template("template", text_template, art_template, left=NA(0), width=NA(WIDTH), top=NA(0), height=NA(HEIGHT)) temp.mana_image_format = "svg" temp.resource_dir = RESOURCE_DIR max_card_length = max(len(c['name']) for c in cards) row = f"| {{:0{loga}}}/{{:0{loga}}} | {{}} | {{}} | {{:07.3f}} |" total = 0 for i, card in enumerate(sorted(cards, key=lambda x: x['name'])): start_time = time.time() for shadow in ["shadow3", "shadow4"]: l = temp.get_layer(shadow) l.pre_render = None reset_layers = list(layers) + ["art"] for name in reset_layers: layer = temp.get_layer(name) layer.unset_content_and_pre_render() # layer.content = None # layer.pre_render = None if layer.name in card: layer.content = card[layer.name] temp.get_layer("artist_brush").pre_shadow = None if "Creature" in card["types"]: layers["PT"].content = f"{card['power']}/{card['toughness']}" # print(card) # print(repr(temp.get_layer("name").content)) count = 999 sset = [s for s in sets if s['code'] == card['set']] if len(sset) == 1: count = sset[0]["count"] number = card['number'].upper().zfill(3) layers["number"].content = f"{number}/{count:03}" rarity_colors = { "M": "#D15003", "R": "#DFBD6C", "U": "#C8C8C8", "C": FC, "L": FC, "T": FC, } rarity = card["rarity"][0].upper() layers["rarity"].color = rarity_colors[rarity] layers["rarity"].content = rarity rules = "" text_to_use = "text" if card[text_to_use] is not None: rules = card[text_to_use] if card["flavor"] is not None: flavor = "\n".join( [f"<i>{f}</i>" for f in card['flavor'].split('\n')]) if rules == "": rules = flavor else: rules += "\n" + flavor if rules != "": temp.get_layer("rules").content = rules art_path = join(RESOURCE_DIR, "art", card['set'], f"{card['name']}_{card['id']}.jpg") \ .replace("//", "__") temp.get_layer("art").content = art_path if os.path.isfile( art_path) else None temp.update_bounds() render_bg = temp.get_layer("art_temp").render() image = render_bg.clone() if temp.get_layer("art").content is not None: render_text_shadow = temp.get_layer("text_temp").shadow( -4, 4, sigma=2, radius=4, color="Black") image.composite(render_text_shadow, left=0, top=0) render_text = temp.get_layer("text_temp").render() render_text.save(filename="test.png") image.composite(render_text, left=0, top=0) # xb = Bounds(start=BORDER - 10, end=WIDTH - BORDER + 10) # yb = Bounds(start=temp.get_layer("type")["top"] - 10, # end=temp.get_layer("rules")['bottom'] + 10) # exp = render_bg.export_pixels(x=int(xb['start']), y=int(yb['start']), # width=int(xb['full']), height=int(yb['full'])) # with Image(width=int(xb['full']), height=int(yb['full']), # background=Color("Transparent")) as blur_image: # blur_image.import_pixels(width=int(xb['full']), height=int(yb['full']), # channel_map="RGBA", storage="char", data=exp) # with Image(width=blur_image.width, height=blur_image.height, # background=Color("RGBA(0,0,0,0.2)")) as dark: # blur_image.composite(dark, 0, 0) # blur_image.blur(radius=10, sigma=5) # with Image(width=blur_image.width, height=blur_image.height, # background=Color("Black")) as mask: # with Drawing() as ctx: # ctx.fill_color = Color("White") # ctx.rectangle(0, 0, width=mask.width, # height=mask.height, radius=15) # ctx(mask) # apply_mask(blur_image, mask) # image.composite(blur_image, left=int(xb['start']), top=int(yb['start'])) image.save(filename=join( "test_images", "all_render", f"{SAVE_LOCATION}", f"{card['name']}_{card['id']}.jpg").replace("//", "__")) # image.save(filename=join("test_images", "all_render", "Printing", f"{SAVE_LOCATION}", f"{card['name']}_{card['id']}.jpg").replace("//", "__")) # image.save(filename=join("test_images", "all_render", "Printing", f"{SAVE_LOCATION}", f"{card['name']}.jpg").replace("//", "__")) temp.unset_bounds_and_attributes() delta = time.time() - start_time total += delta if delta < .250: color = "green" elif delta < .500: color = "yellow" else: color = "red" print(f"\r{row}".format( i, len(cards) - 1, colored(f"{card['name']: <{max_card_length}}", color), colored(f"{delta:03.3f}", color), total))