def GenerateCard5Titles(Language, item): card = Image.new("RGBA", (384, 50)) canvas = ImageDraw.Draw(card) if Language == "ja": font = ImageFont.truetype('assets/Fonts/NotoSansJP-Bold.otf', 15) elif Language == "ko": font = ImageFont.truetype('assets/Fonts/NotoSansKR-Regular.otf', 15) else: font = ImageFont.truetype('assets/Fonts/burbanksmall-black.otf', 15) title = item["title"] title = title.upper() icon = item["image"] icon = ImageUtil.Download(item, icon) icon = ImageUtil.RatioResize(item, icon, 384, 216) card.paste(icon, ImageUtil.CenterX(item, icon.width, card.width)) ### 1920 * 1080 = 384 try: TINT_COLOR = (0, 0, 205) # Black TRANSPARENCY = 0.7 # Degree of transparency, 0-100% OPACITY = int(255 * TRANSPARENCY) cardBottom = Image.new("RGBA", (384, 360), TINT_COLOR) draw = ImageDraw.Draw(cardBottom) draw.rectangle(((384, 360), (0, 0)), fill=TINT_COLOR + (OPACITY, )) except Exception as e: print(e) card.paste(cardBottom, (0, 0), cardBottom) textWidth, _ = font.getsize(title) if textWidth >= 364: # Ensure that the item name does not overflow if Language == "ja": font, textWidth = ImageUtil.FitTextX2(item, title, 16, 1920) elif Language == "ko": font, textWidth = ImageUtil.FitTextX1(item, title, 16, 1920) else: font, textWidth = ImageUtil.FitTextX(item, title, 16, 1920) canvas.text( ImageUtil.CenterX(item, textWidth, card.width, 15), title, (255, 255, 255), font=font, ) return card
def GenerateImage(self, date: str, itemShop: dict): """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ try: featured = itemShop["featured"]["entries"] daily = itemShop["daily"]["entries"] if (len(featured) <= 0) or (len(daily) <= 0): raise Exception( f"Featured: {len(featured)}, Daily: {len(daily)}") if (len(featured) >= 1): width = 6 height = max(ceil(len(featured) / 3), ceil(len(daily) / 3)) rowsDaily = 3 rowsFeatured = 3 dailyStartX = ((340 * 3)) if (len(featured) >= 18): width = 9 height = max(ceil(len(featured) / 6), ceil(len(daily) / 6)) rowsDaily = 3 rowsFeatured = 6 dailyStartX = ((340 * 6)) if (len(featured) >= 18) and (len(daily) >= 18): width = 12 height = max(ceil(len(featured) / 6), ceil(len(daily) / 6)) rowsDaily = 6 rowsFeatured = 6 dailyStartX = ((340 * 6) + 100) except Exception as e: log.critical( f"Failed to parse Item Shop Featured and Daily items, {e}") return False # Determine the max amount of rows required for the current # Item Shop when there are 3 columns for both Featured and Daily. # This allows us to determine the image height. # rows = max(ceil(len(featured) / 3), ceil(len(daily) / 3)) shopImage = Image.new("RGB", (((340 * width) - 30), (530 * height) + 350)) try: background = ImageUtil.Open(self, "background.png").convert("RGBA") background = ImageUtil.RatioResize(self, background, shopImage.width, shopImage.height) shopImage.paste( background, ImageUtil.CenterX(self, background.width, shopImage.width)) except FileNotFoundError: log.warn("Failed to open background.png, defaulting to dark gray") shopImage.paste((18, 18, 18), [0, 0, shopImage.size[0], shopImage.size[1]]) logo = ImageUtil.Open(self, "logo.png").convert("RGBA") logo = ImageUtil.RatioResize(self, logo, 0, 210) shopImage.paste( logo, ImageUtil.CenterX(self, logo.width, shopImage.width, 20), logo) canvas = ImageDraw.Draw(shopImage) font = ImageUtil.Font(self, 48) textWidth, _ = font.getsize(date) canvas.text( ImageUtil.CenterX(self, textWidth, shopImage.width, 255), date, (255, 255, 255), font=font, ) canvas.text((20, 255), "Destacados", (255, 255, 255), font=font) textWidth, _ = font.getsize("Daily") canvas.text( (shopImage.width - (textWidth + 30), 255), "Diario", (255, 255, 255), font=font, ) # Track grid position i = 0 for item in featured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (20 + ((i % rowsFeatured) * (310 + 20))), (350 + ((i // rowsFeatured) * (510 + 20))), ), card, ) i += 1 # Reset grid position i = 0 for item in daily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (dailyStartX + ((i % rowsDaily) * (310 + 20))), (350 + ((i // rowsDaily) * (510 + 20))), ), card, ) i += 1 try: shopImage.save("itemshop.png") log.info("Imagen generada de la Tienda de Objetos") return True except Exception as e: log.critical(f"Failed to save Item Shop image, {e}")
def GenerateCard(self, item: dict): """Return the card image for the provided Fortnite Item Shop item.""" try: name = item["items"][0]["name"] rarity = item["items"][0]["rarity"]["value"] category = item["items"][0]["type"]["value"] price = item["finalPrice"] if item["items"][0]["images"]["featured"] is not None: icon = item["items"][0]["images"]["featured"] else: icon = item["items"][0]["images"]["icon"] except Exception as e: log.error(f"Failed to parse item {name}, {e}") return if rarity == "frozen": blendColor = (148, 223, 255) elif rarity == "lava": blendColor = (234, 141, 35) elif rarity == "legendary": blendColor = (211, 120, 65) elif rarity == "dark": blendColor = (251, 34, 223) elif rarity == "starwars": blendColor = (231, 196, 19) elif rarity == "marvel": blendColor = (197, 51, 52) elif rarity == "slurp": blendColor = (0, 242, 213) elif rarity == "dc": blendColor = (84, 117, 199) elif rarity == "icon": blendColor = (54, 183, 183) elif rarity == "shadow": blendColor = (113, 113, 113) elif rarity == "epic": blendColor = (177, 91, 226) elif rarity == "rare": blendColor = (73, 172, 242) elif rarity == "uncommon": blendColor = (96, 170, 58) elif rarity == "common": blendColor = (190, 190, 190) elif rarity == "gaminglegends": blendColor = (42, 0, 168) else: blendColor = (255, 255, 255) card = Image.new("RGBA", (300, 545)) try: layer = ImageUtil.Open( self, f"shopitem_background_{rarity}.png").convert("RGBA") except FileNotFoundError: log.warn( f"Failed to open shopitem_background_{rarity}.png, defaulted to Common" ) layer = ImageUtil.Open(self, "shopitem_background_common.png") card.paste(layer) icon = ImageUtil.Download(self, icon).convert("RGBA") if (category == "outfit") or (category == "emote"): icon = ImageUtil.RatioResize(self, icon, 285, 365) elif category == "wrap": icon = ImageUtil.RatioResize(self, icon, 230, 310) else: icon = ImageUtil.RatioResize(self, icon, 310, 390) if (category == "outfit") or (category == "emote"): card.paste(icon, ImageUtil.CenterX(self, icon.width, card.width), icon) else: card.paste(icon, ImageUtil.CenterX(self, icon.width, card.width, 15), icon) if len(item["items"]) > 1: # Track grid position i = 0 # Start at position 1 in items array for extra in item["items"][1:]: try: extraRarity = extra["rarity"]["value"] extraIcon = extra["images"]["smallIcon"] except Exception as e: log.error(f"Failed to parse item {name}, {e}") return try: layer = ImageUtil.Open( self, f"box_bottom_{extraRarity}.png").convert("RGBA") except FileNotFoundError: log.warn( f"Failed to open box_bottom_{extraRarity}.png, defaulted to Common" ) layer = ImageUtil.Open(self, "box_bottom_common.png") card.paste( layer, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * (layer.height))), ), ) extraIcon = ImageUtil.Download(self, extraIcon).convert("RGBA") extraIcon = ImageUtil.RatioResize(self, extraIcon, 75, 75) card.paste( extraIcon, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * (extraIcon.height))), ), extraIcon, ) try: layer = ImageUtil.Open(self, f"box_faceplate_{extraRarity}.png") except FileNotFoundError: log.warn( f"Failed to open box_faceplate_{extraRarity}.png, defaulted to Common" ) layer = ImageUtil.Open(self, "box_faceplate_common.png") card.paste( layer, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * (layer.height))), ), layer, ) i += 1 try: layer = ImageUtil.Open( self, f"shopitem_card_{rarity}.png").convert("RGBA") except FileNotFoundError: log.warn( f"Failed to open shopitem_card_{rarity}.png, defaulted to Common" ) layer = ImageUtil.Open(self, "cshopitem_card_common.png") card.paste(layer, layer) card.paste(layer, layer) canvas = ImageDraw.Draw(card) font = ImageUtil.Font(self, 33) textWidth, _ = font.getsize(f"{category} {rarity}") canvas.text( ImageUtil.CenterX(self, textWidth, card.width, 385), f"", blendColor, font=font, ) vbucks = ImageUtil.Open(self, "vbucks_card.png").convert("RGBA") vbucks = ImageUtil.RatioResize(self, vbucks, 49, 49) price = str(f"{price:,}") textWidth, _ = font.getsize(price) canvas.text( ImageUtil.CenterX(self, ((textWidth + 15) - vbucks.width), card.width, 450), price, blendColor, font=font, ) card.paste( vbucks, ImageUtil.CenterX(self, (vbucks.width + (textWidth - 290)), card.width, 436), vbucks, ) font = ImageUtil.Font(self, 56) textWidth, _ = font.getsize(name) change = 0 if textWidth >= 270: # Ensure that the item name does not overflow font, textWidth, change = ImageUtil.FitTextX(self, name, 56, 260) canvas.text( ImageUtil.CenterX(self, textWidth, card.width, (380 + (change / 2))), name, (255, 255, 255), font=font, ) return card
def GenerateImage(self, date: str, itemShop: dict): """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ try: featured = itemShop["featured"] daily = itemShop["daily"] # Ensure both Featured and Daily have at least 1 item if (len(featured) <= 0) or (len(daily) <= 0): raise Exception( f"Featured: {len(featured)}, Daily: {len(daily)}") except Exception as e: log.critical( f"Failed to parse Item Shop Featured and Daily items, {e}") return False # Determine the max amount of rows required for the current # Item Shop when there are 3 columns for both Featured and Daily. # This allows us to determine the image height. featured_length = (FEATURED_COLUMNS * CARD_WIDTH) + ( (FEATURED_COLUMNS - 1) * CARD_OFFSET) daily_length = (DAILY_COLUMNS * CARD_WIDTH) + ( (DAILY_COLUMNS - 1) * CARD_OFFSET) columns_length = featured_length + daily_length rows = max(ceil(len(featured) / FEATURED_COLUMNS), ceil(len(daily) / DAILY_COLUMNS)) shopImage = Image.new( IMAGE_LOAD_TYPE, (columns_length + SECTION_SPACING, ((CARD_HEIGHT * rows) + 340) + (rows - 1) * CARD_OFFSET + logo_footer_offset + logo_footer_height)) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize(self, background, shopImage.width, shopImage.height) shopImage.paste( background, ImageUtil.CenterX(self, background.width, shopImage.width)) except FileNotFoundError: log.warning( "Failed to open background.png, defaulting to dark gray") shopImage.paste((18, 18, 18), [0, 0, shopImage.size[0], shopImage.size[1]]) logo = ImageUtil.Open(self, logo_header_name) logo = ImageUtil.RatioResize(self, logo, 0, logo_header_height) shopImage.paste( logo, ImageUtil.CenterX(self, logo.width, shopImage.width, 20), logo) logo_footer = ImageUtil.Open(self, logo_footer_name) logo_footer = ImageUtil.RatioResize(self, logo_footer, 0, logo_footer_height) shopImage.paste( logo_footer, ImageUtil.CenterX(self, logo_footer.width, shopImage.width, shopImage.height - logo_footer.height - 20), logo_footer) canvas = ImageDraw.Draw(shopImage) font = ImageUtil.Font(self, 58) textWidth, _ = font.getsize(date.upper()) canvas.text( ImageUtil.CenterX(self, textWidth, shopImage.width, 255), date.upper(), (255, 255, 255), font=font, ) canvas.text((LEFT_OFFSET, 255), "IN EVIDENZA", (255, 255, 255), font=font) textWidth, _ = font.getsize("GIORNALIERO") canvas.text( (shopImage.width - (textWidth + LEFT_OFFSET), 255), "GIORNALIERO", (255, 255, 255), font=font, ) # Track grid position i = 0 for item in featured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (LEFT_OFFSET + ((i % FEATURED_COLUMNS) * (card.width + CARD_OFFSET))), (LEADING_OFFSET + ((i // FEATURED_COLUMNS) * (card.height + CARD_OFFSET))), ), card, ) i += 1 # Reset grid position i = 0 DAILY_SPACING = SECTION_SPACING + featured_length - LEFT_OFFSET for item in daily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (DAILY_SPACING + ((i % DAILY_COLUMNS) * (card.width + CARD_OFFSET))), (LEADING_OFFSET + ((i // DAILY_COLUMNS) * (card.height + CARD_OFFSET))), ), card, ) i += 1 try: shopImage.save(image_saved_name) log.info("Generated Item Shop image") return True except Exception as e: log.critical(f"Failed to save Item Shop image, {e}")
def GenerateImage(self, date: str, itemShop: dict): """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ try: featured = itemShop["featured"] daily = itemShop["daily"] # Ensure both Featured and Daily have at least 1 item if (len(featured) <= 0) or (len(daily) <= 0): raise Exception( f"Featured: {len(featured)}, Daily: {len(daily)}") except Exception as e: Log.Error( self, f"Failed to parse Item Shop Featured and Daily items, {e}") return False # Determine the max amount of rows required for the current # Item Shop when there are 3 columns for both Featured and Daily. # This allows us to determine the image height. rows = max(ceil(len(featured) / 3), ceil(len(daily) / 3)) shopImage = Image.new("RGB", (1920, ((545 * rows) + 340))) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize(self, background, shopImage.width, shopImage.height) shopImage.paste( background, ImageUtil.CenterX(self, background.width, shopImage.width)) except FileNotFoundError: Log.Warn(self, "Failed to open background.png, defaulting to dark gray") shopImage.paste((18, 18, 18), [0, 0, shopImage.size[0], shopImage.size[1]]) logo = ImageUtil.Open(self, "logo.png") logo = ImageUtil.RatioResize(self, logo, 0, 210) shopImage.paste( logo, ImageUtil.CenterX(self, logo.width, shopImage.width, 20), logo) canvas = ImageDraw.Draw(shopImage) font = ImageUtil.Font(self, 48) textWidth, _ = font.getsize(date) canvas.text( ImageUtil.CenterX(self, textWidth, shopImage.width, 255), date, (255, 255, 255), font=font, ) canvas.text((20, 255), "Featured", (255, 255, 255), font=font) textWidth, _ = font.getsize("Daily") canvas.text( (shopImage.width - (textWidth + 20), 255), "Daily", (255, 255, 255), font=font, ) # Track grid position i = 0 for item in featured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (20 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 # Reset grid position i = 0 for item in daily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (990 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 try: shopImage.save("itemshop.png") Log.Success(self, "Generated Item Shop image") return True except Exception as e: Log.Error(self, f"Failed to save Item Shop image, {e}")
def GenerateCard(self, item: dict): """Return the card image for the provided Fortnite Item Shop item.""" try: name = item["items"][0]["name"] rarity = item["items"][0]["rarity"] displayrarity = item["items"][0]["displayRarity"] category = item["items"][0]["type"] price = str(item["finalPrice"]) if (category == "outfit") or (category == "wrap"): if item["items"][0]["images"]["featured"] is not None: icon = item["items"][0]["images"]["featured"]["url"] else: icon = item["items"][0]["images"]["icon"]["url"] else: icon = item["items"][0]["images"]["icon"]["url"] except Exception as e: Log.Error(self, f"Failed to parse item {name}, {e}") return if rarity == "common": blendColor = (190, 190, 190) elif rarity == "uncommon": blendColor = (96, 170, 58) elif rarity == "rare": blendColor = (73, 172, 242) elif rarity == "epic": blendColor = (177, 91, 226) elif rarity == "legendary": blendColor = (211, 120, 65) elif rarity == "marvel": blendColor = (197, 51, 52) elif rarity == "dark": blendColor = (251, 34, 223) elif rarity == "dc": blendColor = (84, 117, 199) else: blendColor = (255, 255, 255) card = Image.new("RGBA", (300, 545)) try: layer = ImageUtil.Open(self, f"card_top_{rarity.lower()}.png") except FileNotFoundError: Log.Warn( self, f"Failed to open card_top_{rarity.lower()}.png, defaulted to Common", ) layer = ImageUtil.Open(self, "card_top_common.png") card.paste(layer) if category == 'glider': x = 285 / 1.1 y = 365 / 1.8 distanceTop = 60 elif category == 'music': x = 285 / 1.1 y = 365 / 1.6 distanceTop = 55 elif category == 'pickaxe': x = 285 / 1.1 y = 365 / 1.3 distanceTop = 40 elif category == 'wrap': x = 285 / 1.1 y = 365 / 1.3 distanceTop = 40 else: x = 285 y = 365 distanceTop = 10 icon = ImageUtil.Download(self, icon) icon = ImageUtil.RatioResize(self, icon, x, y) card.paste( icon, ImageUtil.CenterX(self, icon.width, card.width, distanceTop=distanceTop), icon) if len(item["items"]) > 1: # Track grid position i = 0 # Start at position 1 in items array for extra in item["items"][1:]: try: extraRarity = extra["rarity"] extraIcon = extra["images"]["smallIcon"]["url"] except Exception as e: Log.Error(self, f"Failed to parse item {name}, {e}") return try: layer = ImageUtil.Open( self, f"box_bottom_{extraRarity.lower()}.png") except FileNotFoundError: Log.Warn( self, f"Failed to open box_bottom_{extraRarity.lower()}.png, defaulted to Common", ) layer = ImageUtil.Open(self, "box_bottom_common.png") card.paste(layer, (17, (17 + ((i // 1) * (layer.height))))) extraIcon = ImageUtil.Download(self, extraIcon) extraIcon = ImageUtil.RatioResize(self, extraIcon, 75, 75) card.paste(extraIcon, (17, (17 + ((i // 1) * (extraIcon.height)))), extraIcon) try: layer = ImageUtil.Open( self, f"box_faceplate_{extraRarity.lower()}.png") except FileNotFoundError: Log.Warn( self, f"Failed to open box_faceplate_{extraRarity.lower()}.png, defaulted to Common", ) layer = ImageUtil.Open(self, "box_faceplate_common.png") card.paste(layer, (17, (17 + ((i // 1) * (layer.height)))), layer) i += 1 try: layer = ImageUtil.Open(self, f"card_faceplate_{rarity.lower()}.png") except FileNotFoundError: Log.Warn( self, f"Failed to open card_faceplate_{rarity.lower()}.png, defaulted to Common", ) layer = ImageUtil.Open(self, "card_faceplate_common.png") card.paste(layer, layer) try: layer = ImageUtil.Open(self, f"card_bottom_{rarity.lower()}.png") except FileNotFoundError: Log.Warn( self, f"Failed to open card_bottom_{rarity.lower()}.png, defaulted to Common", ) layer = ImageUtil.Open(self, "card_bottom_common.png") card.paste(layer, layer) canvas = ImageDraw.Draw(card) font = ImageUtil.Font(self, 30) textWidth, _ = font.getsize(f"{displayrarity} {category.title()}") canvas.text( ImageUtil.CenterX(self, textWidth, card.width, 385), f"{displayrarity} {category.title()}", blendColor, font=font, ) vbucks = ImageUtil.Open(self, "vbucks.png") vbucks = ImageUtil.RatioResize(self, vbucks, 25, 25) textWidth, _ = font.getsize(price) canvas.text( ImageUtil.CenterX(self, ((textWidth - 5) - vbucks.width), card.width, 495), price, (255, 255, 255), font=font, ) card.paste( vbucks, ImageUtil.CenterX(self, (vbucks.width + (textWidth + 5)), card.width, 495), vbucks, ) font = ImageUtil.Font(self, 56) textWidth, _ = font.getsize(name) if textWidth >= 270: # Ensure that the item name does not overflow font, textWidth = ImageUtil.FitTextX(self, name, 56, 265) canvas.text( ImageUtil.CenterX(self, textWidth, card.width, 425), name, (255, 255, 255), font=font, ) return card
def GenerateImage(self, date: str, itemShop: dict): """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ try: featured = itemShop["featured"] + itemShop["specialFeatured"] daily = itemShop["daily"] + itemShop["specialDaily"] if (len(featured) <= 0) or (len(daily) <= 0): raise Exception( f"Featured: {len(featured)}, Daily: {len(daily)}") if (len(featured) >= 1): width = 6 height = max(ceil(len(featured) / 3), ceil(len(daily) / 3)) rowsDaily = 3 rowsFeatured = 3 dailyStartX = ((340 * 3)) if (len(featured) >= 18): width = 9 height = max(ceil(len(featured) / 6), ceil(len(daily) / 6)) rowsDaily = 3 rowsFeatured = 6 dailyStartX = ((340 * 6)) if (len(featured) >= 18) and (len(daily) >= 18): width = 12 height = max(ceil(len(featured) / 6), ceil(len(daily) / 6)) rowsDaily = 6 rowsFeatured = 6 dailyStartX = ((340 * 6) + 100) except Exception as e: log.critical(f"Failed to parse Item Shop Featured and Daily items, {e}") return False # Determine the max amount of rows required for the current # Item Shop when there are 3 columns for both Featured and Daily. # This allows us to determine the image height. shopImage = Image.new("RGB", (((340 * width) - 30), (530 * height) + 350)) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize( self, background, shopImage.width, shopImage.height ) shopImage.paste( background, ImageUtil.CenterX( self, background.width, shopImage.width) ) except FileNotFoundError: log.warning( "Failed to open background.png, defaulting to dark gray") shopImage.paste( (34, 37, 40), [0, 0, shopImage.size[0], shopImage.size[1]]) canvas = ImageDraw.Draw(shopImage) font = ImageUtil.Font(self, 80) textWidth, _ = font.getsize("FORTNITE ITEM SHOP") canvas.text(ImageUtil.CenterX(self, textWidth, shopImage.width, 30), "FORTNITE ITEM SHOP", (255, 255, 255), font=font) textWidth, _ = font.getsize(date.upper()) canvas.text(ImageUtil.CenterX(self, textWidth, shopImage.width, 120), date.upper(), (255, 255, 255), font=font) canvas.text((20, 240), "FEATURED", (255, 255, 255), font=font, anchor=None, spacing=4, align="left") canvas.text((shopImage.width - 230, 240), "DAILY", (255, 255, 255), font=font, anchor=None, spacing=4, align="right") # Track grid position i = 0 for item in featured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (20 + ((i % rowsFeatured) * (310 + 20))), (350 + ((i // rowsFeatured) * (510 + 20))), ), card, ) i += 1 # Reset grid position i = 0 for item in daily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (dailyStartX + ((i % rowsDaily) * (310 + 20))), (350 + ((i // rowsDaily) * (510 + 20))), ), card, ) i += 1 try: shopImage.save("itemshop.jpeg", optimize=True,quality=85) if(itemShop["fullShop"] == False): log.info("Some cosmetics are missing from this shop!") log.info("Generated Item Shop image") return True except Exception as e: log.critical(f"Failed to save Item Shop image, {e}")
def GenerateCard(self, item: dict): """Return the card image for the provided Fortnite Item Shop item.""" try: name = item["name"].lower() rarity = item["rarity"].lower() category = item["type"].lower() price = item["price"] if (item["image"]): icon = item["image"] else: icon = item["icon"] except Exception as e: log.error(f"Failed to parse item {name}, {e}") return if rarity == "frozen series": blendColor = (148, 223, 255) rarity = "Frozen" elif rarity == "lava series": blendColor = (234, 141, 35) rarity = "Lava" elif rarity == "legendary": blendColor = (211, 120, 65) rarity = "Legendary" elif rarity == "slurp series": blendColor = (0, 233, 176) rarity = "Slurp" elif rarity == "dark": blendColor = (251, 34, 223) rarity = "Dark" elif rarity == "star wars series": blendColor = (231, 196, 19) rarity = "Star Wars" elif rarity == "marvel": blendColor = (197, 51, 52) rarity = "Marvel" elif rarity == "dc": blendColor = (84, 117, 199) rarity = "DC" elif rarity == "icon series": blendColor = (54, 183, 183) rarity = "Icon" elif rarity == "shadow series": blendColor = (113, 113, 113) rarity = "Shadow" elif rarity == "platform series": blendColor = (117,129,209) rarity = "GamingLegends" elif rarity == "epic": blendColor = (177, 91, 226) rarity = "Epic" elif rarity == "rare": blendColor = (73, 172, 242) rarity = "Rare" elif rarity == "uncommon": blendColor = (96, 170, 58) rarity = "Uncommon" elif rarity == "common": blendColor = (190, 190, 190) rarity = "Common" else: blendColor = (255, 255, 255) rarity = "Unknown" card = Image.new("RGBA", (310, 510)) try: layer = ImageUtil.Open( self, f"./shopTemplates/{rarity.capitalize()}BG.png") except FileNotFoundError: log.warn( f"Failed to open {rarity.capitalize()}BG.png, defaulted to Common") layer = ImageUtil.Open(self, "./shopTemplates/CommonBG.png") card.paste(layer) icon = ImageUtil.Download(self, icon) if (category == "outfit") or (category == "emote"): icon = ImageUtil.RatioResize(self, icon, 285, 365) elif category == "wrap": icon = ImageUtil.RatioResize(self, icon, 230, 310) else: icon = ImageUtil.RatioResize(self, icon, 310, 390) if (category == "outfit") or (category == "emote"): card.paste(icon, ImageUtil.CenterX(self, icon.width, card.width), icon) else: card.paste(icon, ImageUtil.CenterX(self, icon.width, card.width, 15), icon) try: layer = ImageUtil.Open( self, f"./shopTemplates/{rarity.capitalize()}OV.png") except FileNotFoundError: log.warn( f"Failed to open {rarity.capitalize()}OV.png, defaulted to Common") layer = ImageUtil.Open(self, "./shopTemplates/CommonOV.png") card.paste(layer, layer) canvas = ImageDraw.Draw(card) vbucks = ImageUtil.Open(self, "vbucks.png") vbucks = ImageUtil.RatioResize(self, vbucks, 40, 40) font = ImageUtil.Font(self, 40) price = str(f"{price:,}") textWidth, _ = font.getsize(price) canvas.text(ImageUtil.CenterX(self, ((textWidth - 5) - vbucks.width), card.width, 347), price, (255, 255, 255), font=font) card.paste(vbucks,ImageUtil.CenterX(self, (vbucks.width + (textWidth + 5)), card.width, 350),vbucks) font = ImageUtil.Font(self, 40) itemName = name.upper().replace(" OUTFIT", "").replace(" PICKAXE", "").replace(" BUNDLE", "") if(category == "bundle"): itemName = name.upper().replace(" BUNDLE", "") textWidth, _ = font.getsize(itemName) change = 0 if textWidth >= 280: # Ensure that the item name does not overflow font, textWidth, change = ImageUtil.FitTextX(self, itemName, 40, 260) canvas.text(ImageUtil.CenterX(self, textWidth, card.width, (400 + (change / 2))), itemName, (255, 255, 255), font=font) font = ImageUtil.Font(self, 40) textWidth, _ = font.getsize(f"{category.upper()}") change = 0 if textWidth >= 280: # Ensure that the item rarity/type does not overflow font, textWidth, change = ImageUtil.FitTextX(self, f"{category.upper()}", 30, 260) canvas.text(ImageUtil.CenterX(self, textWidth, card.width, (450 + (change / 2))), f"{category.upper()}", blendColor, font=font) return card
def GenerateCard(self, card: dict, namefont: str, categoryfont: str) -> ("PIL Image", None): Card = Image.new("RGB", (300, 545)) name = card["items"][0]["name"] category = card["items"][0]["type"] displaycategory = card["items"][0]["displayType"] rarity = card["items"][0]["rarity"] backend_rarity = card["items"][0]["backendRarity"].replace( "EFortRarity::", "", 1).lower() regularprice = card["regularPrice"] finalprice = card["finalPrice"] regularprice = str(f"{regularprice:,}") finalprice = str(f"{finalprice:,}") banner = card["banner"] if category == "outfit" or category == "wrap" or category == "banner": if card["items"][0]["images"]["featured"] is not None: icon = card["items"][0]["images"]["featured"]["url"] else: log.debug("featured image not found, changing to icon") icon = card["items"][0]["images"]["icon"]["url"] else: icon = card["items"][0]["images"]["icon"]["url"] icon = ImageUtil.GET_Image(self, icon).convert("RGBA") if category == "backpack" or category == "pickaxe" or category == "glider" or category == "wrap" or category == "music": icon = ImageUtil.RatioResize(self, icon, Card.width // 1.6, Card.height // 1.6) else: icon = ImageUtil.RatioResize(self, icon, Card.width, Card.height) try: try: image = ImageUtil.Open( self, f"color_{rarity}.png").convert("RGBA").resize( (Card.width, Card.height)).convert("RGBA") except FileNotFoundError as e: log.warning( f"Rarity {rarity} not found, defaulted to backend {backend_rarity}" ) image = ImageUtil.Open( self, f"color_{backend_rarity}.png").convert("RGBA").resize( (Card.width, Card.height)).convert("RGBA") Card.paste(image, (0, 0), image) if category == "backpack" or category == "pickaxe" or category == "glider" or category == "wrap" or category == "music": Card.paste( icon, ImageUtil.CenterX(self, icon.width, Card.width, icon.width // 6), icon) else: Card.paste(icon, ImageUtil.CenterX(self, icon.width, Card.width), icon) image = ImageUtil.Open(self, f"card_plate_{rarity}.png").convert("RGBA") Card.paste(image, (0, 0), image) image = ImageUtil.Open(self, f"card_mask_{rarity}.png").convert("RGBA") Card.paste(image, (0, 0), image) canvas = ImageDraw.Draw(Card) font = ImageUtil.OpenFont( self, ImageUtil.FontSize(self, Card.width, 28, name), namefont) textwidth, _ = font.getsize(f"{name}") canvas.text(ImageUtil.CenterX(self, textwidth, Card.width, 430), f"{name}", font=font) font = ImageUtil.OpenFont( self, ImageUtil.FontSize(self, Card.width, 20, category), categoryfont) textwidth, _ = font.getsize(f"{displaycategory}") canvas.text(ImageUtil.CenterX(self, textwidth, Card.width, 458), f"{displaycategory}", (160, 160, 160), font=font) vbucks = ImageUtil.Open(self, "vbucks.png") vbucks = ImageUtil.RatioResize(self, vbucks, 35, 35) if regularprice == finalprice: regularfont = ImageUtil.OpenFont(self, 28, categoryfont) textWidth, _ = font.getsize(regularprice) canvas.text(ImageUtil.CenterX(self, ((textWidth - 5) - vbucks.width), Card.width, 494), regularprice, font=regularfont) Card.paste( vbucks, ImageUtil.CenterX(self, (vbucks.width + (textWidth + 5)), Card.width, 499), vbucks) else: finalfont = ImageUtil.OpenFont(self, 28, categoryfont) regularfont = ImageUtil.OpenFont(self, 22, categoryfont) regularWidth, regularHeight = regularfont.getsize(regularprice) Width, Height = regularfont.getsize( regularprice.replace(",", " ")) finalWidth, finalHeight = finalfont.getsize(finalprice) discount = ImageUtil.Open(self, "discount.png") discount = discount.resize((Width, Height - 5)) canvas.text(ImageUtil.CenterX( self, ((finalWidth + regularWidth - 5) - vbucks.width), Card.width, 494), finalprice, font=finalfont) Card.paste( vbucks, ImageUtil.CenterX(self, (vbucks.width + (finalWidth + regularWidth + 5)), Card.width, 499), vbucks) pos = ImageUtil.CenterX(self, (finalWidth + regularWidth - 5) - vbucks.width, Card.width, 499) canvas.text((pos[0] + 60, pos[1]), regularprice, (160, 160, 160), font=regularfont) pos2 = ImageUtil.CenterX( self, (finalWidth + regularWidth - 5) - vbucks.width, Card.width, 497 + (discount.height // 2)) Card.paste(discount, (pos2[0] + 60, pos2[1]), discount) if banner is not None: font = ImageUtil.OpenFont(self, 20, namefont) bannerWidth, bannerHeight = font.getsize(banner) banner_middle = ImageUtil.Open( self, "banner_middle.png").convert("RGBA") banner_middle = banner_middle.resize((bannerWidth + 45, 35)) banner_rear = ImageUtil.Open(self, "banner_rear.png").convert("RGBA") banner_rear = ImageUtil.RatioResize_NoAA( self, banner_rear, 0, 35) banner_front = ImageUtil.Open( self, "banner_front.png").convert("RGBA") banner_front = banner_front.resize((bannerWidth + 45, 35)) Card.paste(banner_middle, (0, 0), banner_middle) Card.paste(banner_rear, (0, 0), banner_rear) Card.paste(banner_front, (0, 0), banner_front) canvas.text((8, 8), banner, font=font) return Card except Exception as e: log.error(self, f"Failed to generate card, {e}") return None
def GenerateImage(self, data: dict, date: str, text_override: dict = {}, specialoffer: str = "Special Offers", namefont: str = "", categoryfont: str = "") -> bool: try: Splited = Utility.Split_Special(self, data=data) Sorted = Utility.Sort_Item(self, data=Splited) Overrided = Utility.Text_Override( self, data=Sorted, text_override=text_override['categories']) Extracted = Utility.Extract_ItemShop(self, Overrided) if len(Extracted['featured']) > 1 or len( Extracted['daily']) > 1 or len(Extracted['special']) > 1: if len(Extracted['special']) > 1: rows = max(ceil(len(Extracted['featured']) / 4), ceil(len(Extracted['daily']) / 4), ceil(len(Extracted['special']) / 4)) ShopImage = Image.new("RGBA", (3800, ((545 * rows) + 365))) else: rows = max(ceil(len(Extracted['featured']) / 4), ceil(len(Extracted['daily']) / 4)) ShopImage = Image.new("RGBA", (2550, ((545 * rows) + 365))) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize(self, background, ShopImage.width, ShopImage.height) ShopImage.paste( background, ImageUtil.CenterX(self, background.width, ShopImage.width)) except FileNotFoundError: log.warning("Failed to open background.png") for num, unity in enumerate(Extracted.items()): if len(unity[1]) > 1: Unity = ShopBot.GenerateUnity(self, unity[1], namefont, categoryfont) if Unity is not None: canvas = ImageDraw.Draw(ShopImage) font = ImageUtil.OpenFont(self, 48, namefont) ShopImage.paste(Unity, ((num * 1200) + ((num + 1) * 50), 315), Unity) if unity[0] != "special": canvas.text( (50 + (num * 1250), 260), text_override.get(unity[0], unity[0].capitalize()), font=font) else: canvas.text((50 + (num * 1250), 260), specialoffer, font=font) else: log.debug(f"{unity[0]} is None") else: ShopImage = Image.new("RGBA", (2550, 365)) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize(self, background, ShopImage.width, ShopImage.height) ShopImage.paste( background, ImageUtil.CenterX(self, background.width, ShopImage.width)) except FileNotFoundError: log.warning("Failed to open background.png") canvas = ImageDraw.Draw(ShopImage) font = ImageUtil.OpenFont(self, 48, namefont) canvas.text((50, 260), text_override.get("featured", "Featured"), font=font) canvas.text((1300, 260), text_override.get("daily", "Daily"), font=font) log.info("Shop is None") try: logo = ImageUtil.Open(self, "logo.png").convert("RGBA") logo = ImageUtil.RatioResize(self, logo, 0, 210) ShopImage.paste( logo, ImageUtil.CenterX(self, logo.width, ShopImage.width), logo) except FileNotFoundError: log.warning("Failed to open logo.png") font = ImageUtil.OpenFont(self, 40, namefont) canvas.text((5, 5), date, font=font) ShopImage.save("itemshop.png") return True except Exception as e: log.error(self, f"Failed to generate image, {e}") return False
def GenerateImage(self, date: str, itemShop: dict): """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ if itemShop["featured"] != None: featured = itemShop["featured"]["entries"] else: featured = [] if itemShop["daily"] != None: daily = itemShop["daily"]["entries"] else: daily = [] if itemShop["specialFeatured"] != None: specialFeatured = itemShop["specialFeatured"]["entries"] else: specialFeatured = [] if itemShop["specialDaily"] != None: specialDaily = itemShop["specialDaily"]["entries"] else: specialDaily = [] # Determine the max amount of rows required for the current # Item Shop when there are 3 columns for both Featured and Daily. # This allows us to determine the image height. rows = max(ceil((len(featured) + len(specialFeatured)) / 3), ceil((len(daily) + len(specialDaily)) / 3)) shopImage = Image.new("RGB", (1920, ((545 * rows) + 340))) try: background = ImageUtil.Open(self, "background.png") background = ImageUtil.RatioResize(self, background, shopImage.width, shopImage.height) shopImage.paste( background, ImageUtil.CenterX(self, background.width, shopImage.width)) except FileNotFoundError: log.warn("Failed to open background.png, defaulting to dark gray") shopImage.paste((18, 18, 18), [0, 0, shopImage.size[0], shopImage.size[1]]) logo = ImageUtil.Open(self, "logo.png") logo = ImageUtil.RatioResize(self, logo, 0, 210) shopImage.paste( logo, ImageUtil.CenterX(self, logo.width, shopImage.width, 20), logo) canvas = ImageDraw.Draw(shopImage) font = ImageUtil.Font(self, 48) textWidth, _ = font.getsize(date) canvas.text( ImageUtil.CenterX(self, textWidth, shopImage.width, 255), date, (255, 255, 255), font=font, ) featureds = itemShop["featured"]["name"] dailys = itemShop["daily"]["name"] canvas.text((20, 255), f"{featureds}", (255, 255, 255), font=font) textWidth, _ = font.getsize(f"{dailys}") canvas.text( (shopImage.width - (textWidth + 20), 255), f"{dailys}", (255, 255, 255), font=font, ) # Track grid position i = 0 for item in specialFeatured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (20 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 for item in featured: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (20 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 # Reset grid position i = 0 for item in specialDaily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (990 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 for item in daily: card = Athena.GenerateCard(self, item) if card is not None: shopImage.paste( card, ( (990 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 try: shopImage.save("itemshop.png") log.info("Generated Item Shop image") return True except Exception as e: log.critical(f"Failed to save Item Shop image, {e}")