diff --git a/CHANGELOG.md b/CHANGELOG.md index 17bf827..b450308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,4 +43,13 @@ - Addition of `test_sandbox_card3` in Tester class to test sandbox. - Addition of more examples in Examples Folder. +
+ +## 0.6.0 + +- Custom Canvas in Sandbox mode. +- README.md documentation updated. +- Addition of `test_sandbox_custom_canvas` in Tester class to test sandbox. +- Addition of more examples in Examples Folder. +
\ No newline at end of file diff --git a/DiscordLevelingCard/sandbox.py b/DiscordLevelingCard/sandbox.py index 4d7ea32..a1eff2f 100644 --- a/DiscordLevelingCard/sandbox.py +++ b/DiscordLevelingCard/sandbox.py @@ -1,5 +1,5 @@ from io import BytesIO -from typing import Optional, Union +from typing import Optional, Union, List from aiohttp import ClientSession from PIL import Image, ImageDraw, ImageFont, ImageColor @@ -51,6 +51,8 @@ class Sandbox: ------- - `custom_card1` Creates a rank card with the first design + - `custom_canvas` + A blank canvas to make whatever you want! Raises ------ @@ -212,15 +214,17 @@ async def custom_card1( return image - async def custom_card3( + async def custom_canvas( self, - resize:int = 100, - senstivity:int = 200, - card_colour: str = "black", + has_background: bool = True, + background_colour: str = "black", + + canvas_size: tuple = (1000, 333), + + resize:int = 100, - border_width: int = 25, - border_height: int = 25, + overlay: Union[None, List] = [[(1000-50, 333-50),(25, 25), "black", 200]], avatar_frame: str = "curvedborder", avatar_size: int = 260, @@ -236,31 +240,40 @@ async def custom_card3( exp_position: tuple = (775,130), exp_font_size: int = 50, + bar_exp: Union[None, int] = None, + + exp_bar_width: int = 619, + exp_bar_height: int = 50, + exp_bar_background_colour: Union[str, tuple] = "white", + exp_bar_position:tuple = (330, 235), + exp_bar_curve: int = 30, + extra_text: Union[List, None] = None + + )-> Union[None, bytes]: """ Sandbox for third type of card which returns "BytesIO" Parameters ---------- + has_background: :class:`bool` + Whether to use a background image or not. Default is True + + background_colour: :class:`str` + The colour of the background, only used if has_background is set to False. Default is black. + + canvas_size: :class:`tuple` + The size of the canvas. Default is (1000, 333) + resize: :class:`int` The percentage to resize the image to. Default is 100 - - senstivity: :class:`int` - Change the transparency of the black box over the background image. - Default is 200.range - [0,255] + + overlay: :class:`list` + A list of overlays to be placed on the background. Default is [[(1000-50, 333-50),(25, 25), "black", 200]]. - border_width: :class:`int` - width of the border. default is 25 - - border_height: :class:`int` - height of the border. default is 25 - avatar_frame: :class:`str` `circle` `square` `curvedborder` `hexagon` or path to a self created mask. - card_colour: :class:`str` - colour of the translucent overlay. Default is black. - text_font: :class:`str` Default is `levelfont.otf` or path to a custom otf or ttf file type font. @@ -287,15 +300,37 @@ async def custom_card3( exp_font_size: :class:`int` font size of the exp. Default is 50. + + exp_bar_width: :class:`int` + width of the exp bar. Default is 619. + + exp_bar_height: :class:`int` + height of the exp bar. Default is 50. + + exp_bar_background_colour: :class:`str` + colour of the exp bar. Default is white. + + exp_bar_position: :class:`tuple` + pixel position of the exp bar to be placed at. Default is (330, 235) + exp_bar_curve: :class:`int` + curve of the exp bar. Default is 30. + + extra_text: :class:`list` + list of tuples containing text and position of the text to be placed on the card. Default is None. eg ["string", (x-position, y-position), font-size, "colour"] + + exp_bar: :class:`int` + The calculated exp of the user. Default is None. + + Attributes ---------- + - `has_background` + - `background_colour` + - `canvas_size` - `resize` - - `senstivity` - - `border_width` - - `border_height` + - `overlay` - `avatar_frame` - - `card_colour` - `text_font` - `avatar_size` - `avatar_position` @@ -305,6 +340,13 @@ async def custom_card3( - `level_font_size` - `exp_position` - `exp_font_size` + - `exp_bar_width` + - `exp_bar_height` + - `exp_bar_background_colour` + - `exp_bar_position` + - `exp_bar_curve` + - `extra_text` + - `exp_bar` """ path = str(Path(__file__).parent) @@ -317,9 +359,14 @@ async def custom_card3( else: raise TypeError(f"avatar must be a url, not {type(self.avatar)}") - background = self.background.resize((1000, 333)) - cut = Image.new("RGBA", (1000-(border_width*2), 333-(border_height*2)) , ImageColor.getcolor(card_colour, "RGB")+(senstivity,)) - background.paste(cut, (border_width, border_height) ,cut) + if has_background: + background = self.background.resize(canvas_size) + else: + background = Image.new("RGBA", canvas_size, ImageColor.getcolor(background_colour, "RGB")) + if overlay is not None: + for x in overlay: + cut = Image.new("RGBA", x[0] , ImageColor.getcolor(x[2], "RGB")+(x[3],)) + background.paste(cut, x[1] ,cut) avatar = self.avatar.resize((avatar_size, avatar_size)) @@ -360,20 +407,30 @@ async def custom_card3( draw.text(level_position, combined,font=ImageFont.truetype(fontname,level_font_size), fill=self.text_color,stroke_width=1,stroke_fill=(0, 0, 0)) draw.text(username_position, self.username,font=ImageFont.truetype(fontname,username_font_size), fill=self.text_color,stroke_width=1,stroke_fill=(0, 0, 0)) + if extra_text is not None and type(extra_text) == list: + for x in extra_text: + draw.text(x[1], x[0],font=ImageFont.truetype(fontname,x[2]), fill=(ImageColor.getcolor(x[3], "RGBA") if type(x[3]) != tuple else extra_text),stroke_width=1,stroke_fill=(0, 0, 0)) + exp = f"{self._convert_number(self.current_exp)}/{self._convert_number(self.max_exp)}" draw.text(exp_position, exp,font=ImageFont.truetype(fontname,exp_font_size), fill=self.text_color,stroke_width=1,stroke_fill=(0, 0, 0)) - bar_exp = (self.current_exp/self.max_exp)*619 + if bar_exp == None: + bar_exp = (self.current_exp/self.max_exp)*exp_bar_width + exp_bar_curve_custom = exp_bar_curve + else: + bar_exp = bar_exp*exp_bar_width + if bar_exp <= 50: - bar_exp = 50 + bar_exp = 50 + exp_bar_curve_custom = exp_bar_curve//2 - im = Image.new("RGBA", (620, 51)) + im = Image.new("RGBA", (exp_bar_width+1, exp_bar_height+1)) draw = ImageDraw.Draw(im, "RGBA") - draw.rounded_rectangle((0, 0, 619, 50), 30, fill=(255,255,255,225)) + draw.rounded_rectangle((0, 0, exp_bar_width, exp_bar_height), exp_bar_curve, fill=(exp_bar_background_colour if type(exp_bar_background_colour) == tuple else ImageColor.getcolor(exp_bar_background_colour, "RGBA"))) if self.current_exp != 0: - draw.rounded_rectangle((0, 0, bar_exp, 50), 30, fill=self.bar_color) - - background.paste(im, (330, 235), im.convert("RGBA")) + draw.rounded_rectangle((0, 0, bar_exp, exp_bar_height), exp_bar_curve_custom, fill=self.bar_color) + + background.paste(im, exp_bar_position, im.convert("RGBA")) image = BytesIO() if resize != 100: diff --git a/DiscordLevelingCard/tester.py b/DiscordLevelingCard/tester.py index 6f7674d..dd6cdfc 100644 --- a/DiscordLevelingCard/tester.py +++ b/DiscordLevelingCard/tester.py @@ -1,10 +1,6 @@ -from io import BytesIO -from typing import Optional, Union +from typing import Optional, Union, List -from aiohttp import ClientSession -from PIL import Image, ImageDraw, ImageFont -from .error import InvalidImageUrl -from pathlib import Path +from PIL import Image from .card_settings import Settings from . import RankCard, Sandbox @@ -229,15 +225,17 @@ async def test_sandbox_card1( Image.open(card).save(f"{self.path}.png", "PNG") return - async def test_sandbox_card3( + async def test_sandbox_custom_canvas( self, - resize:int = 100, - senstivity:int = 200, - card_colour: str = "black", + has_background: bool = True, + background_colour: str = "black", + + canvas_size: tuple = (1000, 333), - border_width: int = 25, - border_height: int = 25, + resize:int = 100, + + overlay: Union[None, List] = [[(1000-50, 333-50),(25, 25), "black", 200]], avatar_frame: str = "curvedborder", avatar_size: int = 260, @@ -252,32 +250,39 @@ async def test_sandbox_card3( level_font_size: int = 50, exp_position: tuple = (775,130), - exp_font_size: int = 50 + exp_font_size: int = 50, + bar_exp: Union[None, int] = None, + + exp_bar_width: int = 619, + exp_bar_height: int = 50, + exp_bar_background_colour: Union[str, tuple] = "white", + exp_bar_position:tuple = (330, 235), + exp_bar_curve: int = 30, + extra_text: Union[List, None] = None )->None: """test card3 of Sandbox with this method Parameters ---------- + has_background: :class:`bool` + Whether to use a background image or not. Default is True + + background_colour: :class:`str` + The colour of the background, only used if has_background is set to False. Default is black. + + canvas_size: :class:`tuple` + The size of the canvas. Default is (1000, 333) + resize: :class:`int` The percentage to resize the image to. Default is 100 - - senstivity: :class:`int` - Change the transparency of the black box over the background image. - Default is 200.range - [0,255] - - border_width: :class:`int` - width of the border. default is 25 - - border_height: :class:`int` - height of the border. default is 25 + + overlay: :class:`list` + A list of overlays to be placed on the background. Default is [[(1000-50, 333-50),(25, 25), "black", 200]]. avatar_frame: :class:`str` `circle` `square` `curvedborder` `hexagon` or path to a self created mask. - card_colour: :class:`str` - colour of the translucent overlay. Default is black. - text_font: :class:`str` Default is `levelfont.otf` or path to a custom otf or ttf file type font. @@ -304,15 +309,37 @@ async def test_sandbox_card3( exp_font_size: :class:`int` font size of the exp. Default is 50. + + exp_bar_width: :class:`int` + width of the exp bar. Default is 619. + + exp_bar_height: :class:`int` + height of the exp bar. Default is 50. + + exp_bar_background_colour: :class:`str` + colour of the exp bar. Default is white. + + exp_bar_position: :class:`tuple` + pixel position of the exp bar to be placed at. Default is (330, 235) + exp_bar_curve: :class:`int` + curve of the exp bar. Default is 30. + + extra_text: :class:`list` + list of tuples containing text and position of the text to be placed on the card. Default is None. eg ["string", (x-position, y-position), font-size, "colour"] + + exp_bar: :class:`int` + The calculated exp of the user. Default is None. + + Attributes ---------- + - `has_background` + - `background_colour` + - `canvas_size` - `resize` - - `senstivity` - - `border_width` - - `border_height` + - `overlay` - `avatar_frame` - - `card_colour` - `text_font` - `avatar_size` - `avatar_position` @@ -322,6 +349,13 @@ async def test_sandbox_card3( - `level_font_size` - `exp_position` - `exp_font_size` + - `exp_bar_width` + - `exp_bar_height` + - `exp_bar_background_colour` + - `exp_bar_position` + - `exp_bar_curve` + - `extra_text` + - `exp_bar` Returns ------- @@ -338,12 +372,12 @@ async def test_sandbox_card3( rank=self.rank, cacheing=self.cacheing ) - card = await card.custom_card3( + card = await card.custom_canvas( + has_background=has_background, + background_colour=background_colour, + canvas_size=canvas_size, resize=resize, - card_colour=card_colour, - senstivity=senstivity, - border_width=border_width, - border_height=border_height, + overlay=overlay, avatar_frame=avatar_frame, avatar_size=avatar_size, avatar_position=avatar_position, @@ -353,7 +387,15 @@ async def test_sandbox_card3( level_position=level_position, level_font_size=level_font_size, exp_position=exp_position, - exp_font_size=exp_font_size + exp_font_size=exp_font_size, + exp_bar_width=exp_bar_width, + exp_bar_height=exp_bar_height, + exp_bar_background_colour=exp_bar_background_colour, + exp_bar_position=exp_bar_position, + exp_bar_curve=exp_bar_curve, + extra_text=extra_text, + exp_bar=bar_exp + ) Image.open(card).save(f"{self.path}.png", "PNG") return \ No newline at end of file diff --git a/Examples/custom card examples/extra canvas example.png b/Examples/custom card examples/extra canvas example.png new file mode 100644 index 0000000..5e13268 Binary files /dev/null and b/Examples/custom card examples/extra canvas example.png differ diff --git a/README.md b/README.md index a334fc3..ec467ff 100644 --- a/README.md +++ b/README.md @@ -304,11 +304,11 @@ Sandbox.custom_card1(card_colour:str = "black", resize: int = 100)
- custom_card3 method + custom_canvas method ```py -Sandbox.custom_card3( +Sandbox.custom_canvas( resize:int = 100, senstivity:int = 200, @@ -336,21 +336,29 @@ Sandbox.custom_card3( ``` ## attribute -- `resize` : resize the final image. (default is 100, treat it as a percentage.) -- `senstivity` : senstivity of the avatar frame. (default is 200) -- `card_colour` : color of the card. (default is black) -- `border_width` : width of the border. (default is 25) -- `border_height` : height of the border. (default is 25) -- `avatar_frame` : avatar frame. (default is "curvedborder") -- `avatar_size` : size of the avatar. (default is 260) -- `avatar_position` : position of the avatar. (default is (53, 36)) -- `text_font` : font of the text. (default is "levelfont.otf") -- `username_position` : position of the username. (default is (330,130)) -- `username_font_size` : font size of the username. (default is 50) -- `level_position` : position of the level. (default is (500,40)) -- `level_font_size` : font size of the level. (default is 50) -- `exp_position` : position of the exp. (default is (775,130)) -- `exp_font_size` : font size of the exp. (default is 50) + - `has_background` : if set to `True` then it will add a background to the image. (default is `True`) + - `background_colour` : color of the background. (default is `black`) + - `canvas_size` : size of the canvas. (default is `(1000, 333)`) + - `resize` : resize the final image. (default is 100, treat it as a percentage.) + - `overlay` : A list of overlays to be placed on the background. (Default is `[[(1000-50, 333-50),(25, 25), "black", 200]]`.) + - `avatar_frame` : `circle` `square` `curvedborder` `hexagon` or path to a self created mask. (Default is `curvedborder`.) + - `text_font` : Default is `levelfont.otf` or path to a custom otf or ttf file type font. + - `avatar_size` : size of the avatar. (default is `260`) + - `avatar_position` : position of the avatar. (default is `(53, 36)`) + - `username_position` : position of the username. (default is `(330,130)`) + - `username_font_size` : font size of the username. (default is `50`) + - `level_position` : position of the level. (default is `(500,40)`) + - `level_font_size` : font size of the level. (default is `50`) + - `exp_position` : position of the exp. (default is `(775,130)`) + - `exp_font_size` : font size of the exp. (default is `50`) + - `exp_bar_width` : width of the exp bar. (default is `619`) + - `exp_bar_height` : height of the exp bar. (default is `50`) + - `exp_bar_background_colour` : color of the exp bar background. (default is `white`) + - `exp_bar_position` : position of the exp bar. (default is `(330, 235)`) + - `exp_bar_curve` : curve of the exp bar. (default is `30`) + - `extra_text` : A list of extra text to be placed on the image. (Default is `None`.) + - `exp_bar` : The calculated exp of the user. (Default is `None`.) + ## returns - `bytes` which can directly be used within `discord.File` class. @@ -358,9 +366,68 @@ Sandbox.custom_card3( ## examples -![custom_card3](https://raw.githubusercontent.com/krishsharma0413/DiscordLevelingCard/main/Examples/custom%20card%20examples/custom%20card3%20example-1.png) +![custom_canvas](https://raw.githubusercontent.com/krishsharma0413/DiscordLevelingCard/main/Examples/custom%20card%20examples/custom%20card3%20example-1.png) + +![custom_canvas](https://raw.githubusercontent.com/krishsharma0413/DiscordLevelingCard/main/Examples/custom%20card%20examples/custom%20card3%20unholy%20example-2.png) + + +An Example that i really loved was this one, here is the code for it as well. (you might have to tweak a lot to make it work for you though. ) + +```py +from DiscordLevelingCard import Sandbox, Settings +import asyncio +from PIL import Image + +setting = Settings( + background="./bg.jpg", + bar_color="green", + text_color="white") + +async def main(): + rank = Sandbox( + username="krishsharma0413", + level=1, + current_exp=10, + max_exp=400, + settings=setting, + avatar=Image.open("./avatarimg.png") + ) + result = await rank.custom_canvas( + avatar_frame="square", + avatar_size=233, + avatar_position=(50, 50), + exp_bar_background_colour = "black", + exp_bar_height=50, + exp_bar_width=560, + exp_bar_curve=0, + exp_bar_position=(70, 400), + username_position=(320, 50), + level_position=(320, 225), + exp_position=(70, 330), + canvas_size=(700, 500), + + overlay=[[(350, 233),(300, 50), "white", 100], + [(600, 170),(50, 300), "white", 100]], + + extra_text=[ + ["bio-", (320, 110), 25, "white"], + ["this can very well be a bio", (320, 140), 25, "white"], + ["even mutiple lines!", (320, 170), 25, "white"], + ["if we remove bio- even more!", (320, 200), 25, "white"], + ] + + ) + + # you don't need this line if you are using this in discord.py + Image.open(result).save("result.png", "PNG") + + +asyncio.run(main()) +``` + +and this is how it looks :D -![custom_card3](https://raw.githubusercontent.com/krishsharma0413/DiscordLevelingCard/main/Examples/custom%20card%20examples/custom%20card3%20unholy%20example-2.png) +![custom_canvas](https://raw.githubusercontent.com/krishsharma0413/DiscordLevelingCard/main/Examples/custom%20card%20examples/extra%20canvas%20example.png)
diff --git a/pyproject.toml b/pyproject.toml index 7fb747b..17338a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "discordlevelingcard" -version = "0.5.6" +version = "0.6.0" readme = "README.md" description = "A library with leveling cards for your discord bot." repository = "https://github.com/krishsharma0413/DiscordLevelingCard"