Preview image:
* Title is rendered on separate lines, each 12 characters max * calculate width of block on the left, paste good's image with that info in mind
This commit is contained in:
parent
ea6bcf0a42
commit
dc22af6d4c
|
|
@ -3,6 +3,9 @@ from store.utils import create_preview
|
|||
|
||||
for i in range(1, 5):
|
||||
order_id = f'result{i}'
|
||||
image = create_preview(f'source{i}.jpeg', size=40, price_rub=100, title='Adidas Originals')
|
||||
image = create_preview(f'source{i}.jpeg',
|
||||
size=40,
|
||||
price_rub=100.5,
|
||||
title_lines=['New Balance', 'NB 9060'])
|
||||
|
||||
image.save(f'{order_id}.jpg')
|
||||
|
|
|
|||
|
|
@ -407,10 +407,6 @@ class Checklist(models.Model):
|
|||
|
||||
return self.images.filter(type=Image.DEFAULT)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return concat_not_null_values(self.brand, self.model)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.id}'
|
||||
|
||||
|
|
@ -419,11 +415,12 @@ class Checklist(models.Model):
|
|||
if not source_img:
|
||||
return
|
||||
|
||||
title_lines = [v for v in (self.brand, self.model) if v is not None]
|
||||
# Render preview image
|
||||
preview = create_preview(source_img.image.path,
|
||||
size=self.size,
|
||||
price_rub=self.full_price,
|
||||
title=self.title)
|
||||
title_lines=title_lines)
|
||||
|
||||
# Prepare bytes
|
||||
image_io = BytesIO()
|
||||
|
|
|
|||
|
|
@ -1,16 +1,48 @@
|
|||
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=None):
|
||||
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
|
||||
|
||||
|
|
@ -24,57 +56,63 @@ def create_preview(source_image: str, size=None, price_rub=None, title=None):
|
|||
if not os.path.isfile(source_image):
|
||||
return None
|
||||
|
||||
# Create image
|
||||
preview_width, preview_height = 800, 600
|
||||
hor_padding = 15
|
||||
vert_padding = 50
|
||||
|
||||
canvas_img = Image.new('RGBA', (preview_width, preview_height), color='white')
|
||||
draw = ImageDraw.Draw(canvas_img)
|
||||
|
||||
# Draw top text
|
||||
top_font = get_font(20)
|
||||
text = 'Заказ в Poizon Store'
|
||||
draw.text((hor_padding, vert_padding), text, font=top_font, fill='black')
|
||||
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
|
||||
if title:
|
||||
title_x, title_y = hor_padding, vert_padding + 30
|
||||
if title_lines:
|
||||
title_font = get_font(40)
|
||||
text = title
|
||||
wrapped_text = textwrap.wrap(text, width=10)
|
||||
|
||||
x, start_y = hor_padding, vert_padding + 30
|
||||
for line in wrapped_text:
|
||||
draw.text((x, start_y), line, font=title_font, fill='black')
|
||||
start_y += title_font.getbbox(line)[3]
|
||||
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)
|
||||
x1, y1 = hor_padding, vert_padding + 30 + 100
|
||||
x2, y2 = x1 + 40, y1 + 40
|
||||
draw.rectangle((x1, y1, x2, y2), fill='black', width=2)
|
||||
draw.text((x1 + 7, y1 + 7), size_text, font=size_font, fill='white')
|
||||
|
||||
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:.2f} ₽"
|
||||
price_font = get_font(50)
|
||||
draw.text((hor_padding + 15, preview_height - 100), price_text, font=price_font, fill='black')
|
||||
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 - 270 - hor_padding * 2
|
||||
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 = 270 + int(img2_box_w / 2) - int(img2.width / 2)
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user