Image of photoshop shadow customization
I would like to be able to customize all of the properties of the shadow like shown from this Photoshop screenshot.
Please double check if my assumptions are right:
from PIL import Image, ImageDraw, ImageFont
from typing import Optional, Dict, Tuple, Union
class Text:
def __init__(self, image: Image):
self._draw = ImageDraw.Draw(image)
self._image = image
def text(self, position: Tuple[int, int], text: str, font: ImageFont, color: Tuple[int, int, int, int], drop_shadow: Optional[Dict[str, Union[int, Tuple[int, int, int]]]] = None):
if drop_shadow is not None:
self._add_drop_shadow(position, text, font, drop_shadow)
self._draw.text(position, text, font=font, fill=color)
def _add_drop_shadow(self, original_position: Tuple[int, int], text: str, font: ImageFont, drop_shadow: Dict[str, Union[int, Tuple[int, int, int]]]):
# Not sure. How do I gaussian blur just some text and then put it onto the image? This class represents an entire image, where I will put multiple drop shadowed text or normal text
# Also, how do I make everything match the Photoshop image I linked? Like the percent and px and stuff.
pass
if __name__ == "__main__":
args = {
"opacity": 65,
"angle" : 30,
"distance": 15,
"spread": 29,
"size": 15,
"color": (0, 0, 0)
}
img = Image.new("RGB", (1920, 1080), (255, 255, 255))
text = Text(image=img)
font = ImageFont.truetype("./assets/Hiragino.ttf", 200)
text.text((200, 400), "ダミーテキスト", font, (0, 153, 255, 255), args)
img.show()
Also, I'm trying out Python typing but it seems very tedious. If there's anything unidiomatic about my code please tell me also.
Image of photoshop shadow customization
I would like to be able to customize all of the properties of the shadow like shown from this Photoshop screenshot.
Please double check if my assumptions are right:
from PIL import Image, ImageDraw, ImageFont
from typing import Optional, Dict, Tuple, Union
class Text:
def __init__(self, image: Image):
self._draw = ImageDraw.Draw(image)
self._image = image
def text(self, position: Tuple[int, int], text: str, font: ImageFont, color: Tuple[int, int, int, int], drop_shadow: Optional[Dict[str, Union[int, Tuple[int, int, int]]]] = None):
if drop_shadow is not None:
self._add_drop_shadow(position, text, font, drop_shadow)
self._draw.text(position, text, font=font, fill=color)
def _add_drop_shadow(self, original_position: Tuple[int, int], text: str, font: ImageFont, drop_shadow: Dict[str, Union[int, Tuple[int, int, int]]]):
# Not sure. How do I gaussian blur just some text and then put it onto the image? This class represents an entire image, where I will put multiple drop shadowed text or normal text
# Also, how do I make everything match the Photoshop image I linked? Like the percent and px and stuff.
pass
if __name__ == "__main__":
args = {
"opacity": 65,
"angle" : 30,
"distance": 15,
"spread": 29,
"size": 15,
"color": (0, 0, 0)
}
img = Image.new("RGB", (1920, 1080), (255, 255, 255))
text = Text(image=img)
font = ImageFont.truetype("./assets/Hiragino.ttf", 200)
text.text((200, 400), "ダミーテキスト", font, (0, 153, 255, 255), args)
img.show()
Also, I'm trying out Python typing but it seems very tedious. If there's anything unidiomatic about my code please tell me also.
Done, final result that scales properly:
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from typing import Optional, Dict, Tuple, Union
import math
class Text:
def __init__(self, image: Image):
self._draw = ImageDraw.Draw(image)
self._image = image
def add_text(self, position: Tuple[int, int], text: str, font_path: str, font_size: int, color: Tuple[int, int, int, int], drop_shadow: Optional[Dict[str, Union[int, Tuple[int, int, int], Tuple[int, int]]]] = None):
if drop_shadow is not None:
self._add_drop_shadow(position, text, font_path, font_size, drop_shadow)
font = ImageFont.truetype(font_path, font_size)
self._draw.text(position, text, font=font, fill=color)
def _add_drop_shadow(self, original_position: Tuple[int, int], text: str, font_path: str, original_font_size: int, drop_shadow: Dict[str, Union[int, Tuple[int, int, int], Tuple[int, int]]]):
shadow = Image.new("RGBA", self._image.size)
draw = ImageDraw.Draw(shadow)
r, g, b = drop_shadow["color"]
a = drop_shadow["opacity"]
offset_scale_x, offset_scale_y = drop_shadow["offset_scale_font"]
offset_x = offset_scale_x * original_font_size
offset_y = offset_scale_y * original_font_size
blur_scale = drop_shadow["blur_scale_font"]
blur = blur_scale * original_font_size
shadow_font = ImageFont.truetype(font_path, original_font_size * drop_shadow["size_scale"])
draw.text((original_position[0] + offset_x, original_position[1] + offset_y), text, font=shadow_font, fill=(r, g, b, a))
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=blur))
self._image.paste(shadow, mask=shadow.getchannel("A"))
if __name__ == "__main__":
# args = {
# "opacity": 255,
# "angle" : 30,
# "distance": 15,
# "spread": 29,
# "size": 15,
# "color": (128, 128, 128)
# }
args = {
"opacity": 255,
"offset_scale_font": (0.015, 0.01),
"blur_scale_font": 0.02,
"size_scale": 1.01,
"color": (128, 128, 128)
}
img = Image.new("RGB", (1920, 1080), (255, 255, 255))
text = Text(image=img)
text.add_text((200, 400), "ダミーテキスト", "assets/Hiragino.ttf", 200, (0, 153, 255, 255), args)
text.add_text((200, 600), "ダミーテキスト", "assets/Hiragino.ttf", 100, (255, 0, 0, 255), args)
img.show()
(However, I'm still not sure if the "size" works the same as in Photoshop. I might be confused about size and spread. In Photoshop, size seems to make it bigger AND blurrier, while spread changes blurriness. Mine just makes it bigger).