kwork-poizonstore/store/utils.py

123 lines
4.0 KiB
Python

import os
import textwrap
from typing import Tuple
from PIL import Image, ImageDraw, ImageFont, UnidentifiedImageError
from poizonstore.settings import BASE_DIR
def create_preview(source_image: str, size=None, price_rub=None, title_lines=None):
# Create image
preview_width, preview_height = 800, 600
hor_padding = 15
vert_padding = 50
left_block_width = 270 # minimal width
canvas_img = Image.new('RGBA', (preview_width, preview_height), color='white')
draw = ImageDraw.Draw(canvas_img)
def get_font(font_size):
font_path = os.path.join(BASE_DIR, 'static', 'preview_image_font.ttf')
return ImageFont.truetype(font_path, size=font_size)
def draw_text(xy: Tuple[float, float], text: str, font: ImageFont, multiline_width: int = None, fill: str = None):
x, y = xy
block_width = 0
block_height = 0
if multiline_width is None:
text = [text]
else:
text = textwrap.wrap(text, width=multiline_width)
for line in text:
_, _, line_width, line_height = font.getbbox(line)
draw.text((x, y), line, font=font, fill=fill)
y += line_height
block_width = max(block_width, line_width)
block_height += line_height
return block_width, block_height
def resize_with_ar(image, size):
max_w, max_h = size
if image.height > image.width:
factor = max_h / image.height
else:
factor = max_w / image.width
return image.resize((int(image.width * factor), int(image.height * factor)))
if not os.path.isfile(source_image):
return None
# Draw top text
top_font = get_font(20)
text = 'Заказ в Poizon Store'
block_size = draw_text((hor_padding, vert_padding), text, font=top_font, fill='black')
left_block_width = max(left_block_width, block_size[0] + hor_padding)
# Draw title
title_x, title_y = hor_padding, vert_padding + 30
if title_lines:
title_font = get_font(40)
for title_line in title_lines:
width, height = draw_text((title_x, title_y), title_line, font=title_font, multiline_width=12, fill='black')
title_y += height
left_block_width = max(left_block_width, width + title_x)
# Draw size
if size:
size_text = str(size)
size_font = get_font(20)
rect_x, rect_y = hor_padding, title_y + 30
rect_width, rect_height = 40, 40
# size text is slightly inside a rect
size_x, size_y = rect_x + 7, rect_y + 7
draw.rectangle((rect_x, rect_y, rect_x + rect_width, rect_y + rect_height), fill='black', width=2)
block_size = draw_text((size_x, size_y), size_text, font=size_font, fill='white')
left_block_width = max(left_block_width, max(block_size[0], rect_width))
# Draw price
if price_rub:
price_text = f"{price_rub}"
price_font = get_font(50)
price_x, price_y = hor_padding + 15, preview_height - 100
block_size = draw_text((price_x, price_y), price_text, font=price_font, fill='black')
left_block_width = max(left_block_width, block_size[0] + price_x)
# Draw goods image
img2_box_w = preview_width - left_block_width - hor_padding * 2
img2_box_y = preview_height - vert_padding * 2
try:
with Image.open(source_image).convert("RGBA") as img2:
img2 = resize_with_ar(img2, (img2_box_w, img2_box_y))
img2_x = left_block_width + int(img2_box_w / 2) - int(img2.width / 2)
img2_y = 50 + int(img2_box_y / 2) - int(img2.height / 2)
canvas_img.paste(img2, (img2_x, img2_y), mask=img2)
# Debug only
# img2_box = (img2_x, img2_y, img2_x + img2.width, img2_y + img2.height)
# draw.rectangle(img2_box, outline='red', width=2)
return canvas_img.convert('RGB')
except UnidentifiedImageError:
return None
def concat_not_null_values(*values, separator=' '):
return separator.join([v for v in values if v is not None])