def get_image(url, file_dir): try: data = urllib2.urlopen(url, timeout=gk7.HTTP_TIME_OUT).read() # 文件路径 file_path = '%s/%s' % (file_dir, url[url.rfind('/') + 1:]) with open(file_path, 'w') as f_data: f_data.write(data) # 压缩 ImageUtil.compress(file_path, gk7.PIC_MAX_WIDTH) except Exception as e: ## 延迟20s后重试 DownloadTask.get_image.retry(countdown=20, exc=e) return file_path
def get_image(url, file_dir): try: data = urllib2.urlopen(url, timeout=gk7.HTTP_TIME_OUT).read() # 文件路径 file_path = '%s/%s' %(file_dir, url[url.rfind('/')+1:]) with open(file_path, 'w') as f_data: f_data.write(data) # 压缩 ImageUtil.compress(file_path, gk7.PIC_MAX_WIDTH) except Exception as e: ## 延迟20s后重试 DownloadTask.get_image.retry(countdown=20, exc=e) return file_path
def get_image(url, file_dir): try: data = urllib2.urlopen(url).read() # 文件路径 file_path = '%s/%s' %(file_dir, url[url.rfind('/')+1:]) with open(file_path, 'w') as f_data: f_data.write(data) # 压缩 ImageUtil.compress(file_path, gk7.PIC_MAX_WIDTH) except Exception as e: logger.error(u'下载文件失败,url:%s,文件目录:%s,原因:%s' %(url, file_dir, str(e))) ## 延迟20s后重试 DownloadTask.get_image.retry(countdown=20, exc=e) return file_path
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 downLoadImg(source_url, content_html): # 处理图片 selector = Selector(text=content_html) # 解析文档中的所有图片url,然后替换成标识 image_urls = [] imgs = selector.xpath(u'descendant::img') for img in imgs: # 图片可能放在src 或者data-src image_url_base = img.xpath(u'@src').extract_first('') if not image_url_base: continue if image_url_base.startswith(u'//'): image_url = u'http:' + image_url_base elif image_url_base.startswith(u'/'): image_url = getNetLoc(source_url) + image_url_base elif image_url_base.startswith(u'./'): # 得到当前url结尾的最后一个 /之前的字符串 base_url = source_url[0:source_url.rindex(u'/')] + u'/' image_url = image_url_base.replace(u'./', base_url) elif image_url_base.startswith(u'../../'): image_url = image_url_base.replace(u'../../', getNetLoc(source_url) + u'/') elif image_url_base.startswith(u'http'): image_url = image_url_base else: base_url = source_url[0:source_url.rindex(u'/')] + u'/' image_url = base_url + image_url_base if image_url and image_url.startswith(u'http'): print(u'得到图片:' + image_url) image_urls.append({ u'url': image_url, }) content_html = content_html.replace(image_url_base, image_url) # TODO..先不下载 image_urls = [] result_image_urls = ImageUtil.downLoadImage(image_urls) for item in result_image_urls: url = item.get(u'url', u'') image_url = item.get(u'image_url', u'') content_html = content_html.replace(u'&', u'&').replace(url, image_url) return content_html
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 generate_card(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"] # Select bundle image and name if item["bundle"] is not None: name = item["bundle"]["name"] icon = item["bundle"]["image"] except Exception as error: log.error(f"Failed to parse item, {error}") return # Should be outdated if rarity == "frozen": blend_color = (148, 223, 255) elif rarity == "lava": blend_color = (234, 141, 35) elif rarity == "legendary": blend_color = (211, 120, 65) elif rarity == "dark": blend_color = (251, 34, 223) elif rarity == "starwars": blend_color = (231, 196, 19) elif rarity == "marvel": blend_color = (197, 51, 52) elif rarity == "dc": blend_color = (84, 117, 199) elif rarity == "icon": blend_color = (54, 183, 183) elif rarity == "shadow": blend_color = (113, 113, 113) elif rarity == "epic": blend_color = (177, 91, 226) elif rarity == "rare": blend_color = (73, 172, 242) elif rarity == "uncommon": blend_color = (96, 170, 58) elif rarity == "common": blend_color = (190, 190, 190) else: blend_color = (255, 255, 255) card = Image.new("RGBA", (300, 545)) try: layer = ImageUtil().open_image(self.style + f"/card_top_{rarity}.png") except FileNotFoundError: log.warning( f"Failed to open card_top_{rarity}.png, defaulted to Common") layer = ImageUtil().open_image(f"{self.style}/card_top_common.png") card.paste(layer) icon = ImageUtil().download_image(icon).convert("RGBA") if category in ["outfit", "emote"]: icon = ImageUtil().resize_ratio(icon, 285, 365) elif category == "wrap": icon = ImageUtil().resize_ratio(icon, 230, 310) else: icon = ImageUtil().resize_ratio(icon, 310, 390) if category in ["outfit", "emote"]: card.paste(icon, ImageUtil().align_center(card.width, icon.width), icon) else: card.paste(icon, ImageUtil().align_center(card.width, icon.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: extra_rarity = extra["rarity"]['value'] extra_icon = extra["images"]["smallIcon"] except Exception as error: log.error(f"Failed to parse item {name}, {error}") return try: layer = ImageUtil().open_image( self.style + f"/box_bottom_{extra_rarity}.png") except FileNotFoundError: log.warning( f"Failed to open box_bottom_{extra_rarity}.png, defaulted to Common" ) layer = ImageUtil().open_image( f"{self.style}/box_bottom_common.png") card.paste( layer, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * layer.height)), ), ) extra_icon = ImageUtil().download_image(extra_icon) extra_icon = ImageUtil().resize_ratio(extra_icon, 75, 75) card.paste( extra_icon, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * extra_icon.height)), ), extra_icon, ) try: layer = ImageUtil().open_image( self.style + f"/box_faceplate_{extra_rarity}.png") except FileNotFoundError: log.warning( f"Failed to open box_faceplate_{extra_rarity}.png, defaulted to Common" ) layer = ImageUtil().open_image( f"{self.style}/box_faceplate_common.png") card.paste( layer, ( (card.width - (layer.width + 9)), (9 + ((i // 1) * layer.height)), ), layer, ) i += 1 if self.style == 'old': try: layer = ImageUtil().open_image(self.style + f"/card_faceplate_{rarity}.png") except FileNotFoundError: log.warning( f"Failed to open card_faceplate_{rarity}.png, defaulted to Common" ) layer = ImageUtil().open_image( f"{self.style}/card_faceplate_common.png") card.paste(layer, layer) try: layer = ImageUtil().open_image(self.style + f"/card_bottom_{rarity}.png") except FileNotFoundError: log.warning( f"Failed to open card_bottom_{rarity}.png, defaulted to Common" ) layer = ImageUtil().open_image( f"{self.style}/card_bottom_common.png") card.paste(layer, layer) canvas = ImageDraw.Draw(card) if self.style == 'old': font = ImageUtil().get_font(30) text_width, _ = font.getsize( f"{rarity.capitalize()} {category.capitalize()}") canvas.text( ImageUtil().align_center(card.width, text_width, 385), f"{rarity.capitalize()} {category.capitalize()}", blend_color, font=font, ) vbucks = ImageUtil().open_image("vbucks.png") vbucks = ImageUtil().resize_ratio(vbucks, 25, 25) price = str(f"{price:,}") text_width, _ = font.getsize(price) canvas.text( ImageUtil().align_center(card.width, (text_width - vbucks.width), 495), price, blend_color, font=font, ) card.paste( vbucks, ImageUtil().align_center(card.width, (vbucks.width + (text_width + 5)), 495), vbucks, ) font = ImageUtil().get_font(56) text_width, _ = font.getsize(name) change = 0 if text_width >= 270: # Ensure that the item name does not overflow font, text_width, change = ImageUtil().fit_text(name, 56, 260) canvas.text( ImageUtil().align_center(card.width, text_width, (425 + (change // 2))), name, (255, 255, 255), font=font, ) elif self.style == 'new': font = ImageUtil().get_font(33) vbucks = ImageUtil().open_image("vbucks_card.png") vbucks = ImageUtil().resize_ratio(vbucks, 49, 49) price = str(f"{price:,}") text_width, _ = font.getsize(price) canvas.text( ImageUtil().align_center(card.width, ((text_width + 15) - vbucks.width), 450), price, blend_color, font=font, ) card.paste( vbucks, ImageUtil().align_center(card.width, (vbucks.width + (text_width - 290)), 436), vbucks, ) font = ImageUtil().get_font(56) text_width, _ = font.getsize(name) change = 0 if text_width >= 270: # Ensure that the item name does not overflow font, text_width, change = ImageUtil().fit_text(name, 56, 260) canvas.text( ImageUtil().align_center(card.width, text_width, (380 + (change // 2))), name, (255, 255, 255), font=font, ) return card
def generate_image(self, date: str, item_shop: dict) -> bool: """ Generate the Item Shop image using the provided Item Shop. Return True if image sucessfully saved. """ if item_shop["featured"] is not None: featured = item_shop["featured"]["entries"] else: featured = [] if item_shop["daily"] is not None: daily = item_shop["daily"]["entries"] else: daily = [] # 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)) shop_image = Image.new("RGBA", (1920, ((545 * rows) + 340))) try: background = ImageUtil().open_image("background.png") background = ImageUtil().resize_ratio(background, shop_image.width, shop_image.height) shop_image.paste( background, ImageUtil().align_center(shop_image.width, background.width)) except FileNotFoundError: log.warning( "Failed to open background.png, defaulting to dark gray") shop_image.paste((18, 18, 18), [0, 0, shop_image.size[0], shop_image.size[1]]) logo = ImageUtil().open_image("logo.png") logo = ImageUtil().resize_ratio(logo, 0, 210) shop_image.paste( logo, ImageUtil().align_center(shop_image.width, logo.width, 20), logo) canvas = ImageDraw.Draw(shop_image) font = ImageUtil().get_font(48) text_width, _ = font.getsize(date) canvas.text( ImageUtil().align_center(shop_image.width, text_width, 255), date, (255, 255, 255), font=font, ) featured_title = Translator().translate("Featured", str='en', dest=self.language).text daily_title = Translator().translate("Daily", str='en', dest=self.language).text canvas.text((20, 255), featured_title, (255, 255, 255), font=font) text_width, _ = font.getsize(daily_title) canvas.text( (shop_image.width - (text_width + 20), 255), daily_title, (255, 255, 255), font=font, ) # Track grid position i = 0 for item in featured: card = self.generate_card(item) if card is not None: shop_image.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 = self.generate_card(item) if card is not None: shop_image.paste( card, ( (990 + ((i % 3) * (card.width + 5))), (315 + ((i // 3) * (card.height + 5))), ), card, ) i += 1 try: shop_image.save("itemshop.png") log.info("Generated Item Shop image") return True except Exception as error: log.critical(f"Failed to save Item Shop image, {error}") return False
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"]["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 generate_panel( panel: dict, colors: dict, session: Optional[requests.Session] = requests.Session() ) -> Image.Image: image = Image.new('RGB', get_size(panel)) canvas = ImageDraw.Draw(image) image2 = Image.new('RGBA', (image.width * 2, image.height * 2)) canvas2 = ImageDraw.Draw(image2) size = get_size(panel) background = ImageUtil.ratio_resize( ImageUtil.get_image(panel['displayAssets'][0]['background'], session).convert('RGBA'), *size) image.paste(background, ImageUtil.center_x(background.width, image.width, 0), background) display_asset = ImageUtil.ratio_resize( ImageUtil.get_image(panel['displayAssets'][0]['url'], session).convert('RGBA'), *size) image.paste(display_asset, ImageUtil.center_x(display_asset.width, image.width, 0), display_asset) canvas.polygon( ((0, size[1] - PRICE_HEIGHT), (size[0], size[1] - PRICE_HEIGHT), (size[0], size[1]), (0, size[1])), fill=(14, 14, 14)) vbucks = ImageUtil.ratio_resize( ImageUtil.open('vbucks.png').point(lambda x: x * 0.8).convert( 'RGBA').rotate(-15), 40, 40) pos = size[0] - vbucks.width - 5 image.paste(vbucks, (pos, size[1] - vbucks.height + 10), vbucks) text = f"{panel['price']['finalPrice']:,}" fonts = name_fonts.fonts_size(15, 15, 15) x, y = fonts.text_size(text) pos = pos - x - 3 fonts.write_text(canvas, text, (pos, size[1] - y - 4), fill=(160, 175, 185)) if panel['price']['finalPrice'] != panel['price']['regularPrice']: text = f"{panel['price']['regularPrice']:,}" fonts = name_fonts.fonts_size(15, 15, 15) x, y = fonts.text_size(text) pos = pos - x - 6 fonts.write_text(canvas, text, (pos, size[1] - y - 4), fill=(100, 100, 100)) canvas2.line((((pos - 2) * 2, (size[1] - y - 4 + 10) * 2), ((pos + x + 3) * 2, (size[1] - y - 4 + 6) * 2)), fill=(100, 110, 110), width=3 * 2) canvas2.polygon( ((0, (size[1] - PRICE_HEIGHT - NAME_HEIGHT - RARITY_HEIGHT) * 2), (size[0] * 2, (size[1] - PRICE_HEIGHT - NAME_HEIGHT - RARITY_HEIGHT - SLOPE) * 2), (size[0] * 2, (size[1] - PRICE_HEIGHT - NAME_HEIGHT - SLOPE) * 2), (0, (size[1] - PRICE_HEIGHT - NAME_HEIGHT) * 2)), fill=colors[panel['series']['id'] if panel['series'] is not None else panel['rarity']['id']]) canvas2.polygon( ((0, (size[1] - PRICE_HEIGHT - NAME_HEIGHT) * 2), (size[0] * 2, (size[1] - PRICE_HEIGHT - NAME_HEIGHT - SLOPE) * 2), (size[0] * 2, (size[1] - PRICE_HEIGHT) * 2), (0, (size[1] - PRICE_HEIGHT) * 2)), fill=(30, 30, 30)) image2.thumbnail(image.size, Image.LANCZOS) image.paste(image2, (0, 0), image2) fonts = name_fonts.fonts_size(20, 20, 20) x, y = fonts.text_size(panel['displayName']) fonts.write_text(canvas, panel['displayName'], ImageUtil.center_x(x, image.width, size[1] - PRICE_HEIGHT - y - 10), fill=(255, 255, 255)) icons = [ ImageUtil.ratio_resize( ImageUtil.open(filename).convert('RGBA'), 30, 30) for filename in set( itertools.chain(*[ get_user_facing_flag_images(item) for item in panel['granted'] ])) ] x = size[0] - 10 for icon in icons: x -= icon.width image.paste(icon, (x, size[1] - PRICE_HEIGHT - NAME_HEIGHT - RARITY_HEIGHT - 15 - icon.height), icon) x -= 10 return image
def generate_section( section: dict, colors: dict, now: datetime.datetime, session: Optional[requests.Session] = requests.Session() ) -> Image.Image: if len(section['panels'] ) == 1 and section['panels'][0]['tileSize'] == 'Small': image = Image.new('RGBA', (MARGIN_LEFT + get_section_width(section) + MARGIN_RIGHT, Y_MARGIN + SMALL_SIZE[1])) else: image = Image.new('RGBA', (MARGIN_LEFT + get_section_width(section) + MARGIN_RIGHT, Y_MARGIN + NORMAL_SIZE[1])) canvas = ImageDraw.Draw(image) x = MARGIN_LEFT size = 50 if section['name']: fonts = name_fonts.fonts_size(size, size, size) x = 50 final_x, _ = fonts.write_text(canvas, section['name'].upper(), (x, Y_MARGIN // 2 - 25)) x += final_x if section['until'] is not None: timer = ImageUtil.ratio_resize( ImageUtil.open('shop_timer.png').convert('RGBA'), size, size) x += 12 image.paste(timer, (x, Y_MARGIN // 2 - 15 - 4), timer) end = section['until'] - now m, s = divmod(end.seconds, 60) h, m = divmod(m, 60) timer_text = ("{}:{:0>2}:{:0>2}".format(h, m, s) if end > datetime.timedelta(hours=1) else "{}:{:0>2}".format(m, s)) x += timer.width + 6 fonts = name_fonts.fonts_size(size // 2, size // 2, size // 2) _, y = fonts.text_size(timer_text) fonts.write_text(canvas, timer_text, (x, Y_MARGIN // 2 - 15 + y // 2), fill=(115, 200, 235)) with ThreadPoolExecutor() as executor: futures = [ executor.submit(generate_panel, panel, colors, session) for panel in section['panels'] ] x = MARGIN_LEFT small_count = 0 for num, future in enumerate(futures): try: panel_image = future.result() except Exception: print('Failed to generate panel', file=sys.stderr) traceback.print_exc() else: panel = section['panels'][num] size = get_size(panel) if panel['tileSize'] == 'Small': small_count += 1 if small_count % 2 == 1: pos = (x, Y_MARGIN) x += size[0] + X_MARGIN else: pos = (x - size[0] - X_MARGIN, Y_MARGIN + (NORMAL_SIZE[1] - size[1] * 2) + size[1]) else: pos = (x, Y_MARGIN) x += size[0] + X_MARGIN image.paste(panel_image, pos) if panel['banner'] is not None: font_size, minus = name_fonts.fit_fonts_size( image.width - 25, 16, panel['banner']['name']) fonts = name_fonts.fonts_size(font_size, font_size, font_size) text_width = fonts.text_size(panel['banner']['name'])[0] banner_height = 32 color = 'red' if panel['banner'][ 'intensity'] == 'Low' else 'yellow' banner_rear = ImageUtil.ratio_resize( ImageUtil.open(f'{color}_banner_rear.png').convert('RGBA'), 0, banner_height, resample=Image.BICUBIC) banner_middle = ImageUtil.open( f'{color}_banner_middle.png').convert('RGBA').resize( (text_width, banner_height)) banner_front = ImageUtil.ratio_resize(ImageUtil.open( f'{color}_banner_front.png').convert('RGBA'), 0, banner_height, resample=Image.BICUBIC) image.paste(banner_rear, (pos[0] - 15, pos[1] - 15), banner_rear) image.paste(banner_middle, (pos[0] - 15 + banner_rear.width, pos[1] - 15), banner_middle) image.paste(banner_front, (pos[0] - 15 + banner_rear.width + banner_middle.width, pos[1] - 15), banner_front) fonts.write_text( canvas, panel['banner']['name'], (pos[0] - 15 + banner_rear.width, pos[1] - 15 + 5), fill=(255, 255, 255) if panel['banner']['intensity'] == 'Low' else (0, 0, 0)) return image
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 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. """ 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}")
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