File: //home/arjun/projects/aigenerator/AI-LG-backend/Ai_logo_generation/utils/image_utils.py
import base64
from io import BytesIO
import requests
from PIL import Image, ImageDraw, ImageFont
from unidecode import unidecode
from .image_watermark_utils import create_watermark, get_watermark_svg
MAX_COMPANY_LINE_LENGTH = 25 # Adjust this as per your needs
MAX_SLOGAN_LINE_LENGTH = 40 # Adjust this as per your needs
def convert_url_bytes(url):
response = requests.get(url)
if response.status_code == 200:
return response.content
else:
return None
def convert_base64_bytes(base64_string):
return base64.b64decode(base64_string)
def convert_bytes_base64(buffer, encoding="utf-8"):
encode = base64.b64encode(buffer.getvalue())
return encode.decode(encoding)
def parse_resolution(resolution):
"""Convert resolution string(4000x3000) to a tuple of integers."""
try:
width, height = map(int, resolution.split("x"))
return width, height
except ValueError:
return 400, 300
def wrap_text(text, max_length):
words = text.split()
lines = []
current_line = ""
for word in words:
if len(current_line + word) + 1 > max_length:
lines.append(current_line)
current_line = word
else:
if current_line:
current_line += " " + word
else:
current_line = word
if current_line:
lines.append(current_line)
return [unidecode(current_line) for current_line in lines]
def is_text_within_bounds(draw, text, position, font, image_width, image_height):
text_bbox = draw.textbbox(position, text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
text_x, text_y = position
if (
text_x + text_width > image_width
or text_y + text_height >= image_height
or text_x < 0
or text_y < 0
):
return False
return True
def create_logo_image(
logo_bytes,
font_bytes,
company_name,
slogan,
company_name_color,
slogan_color,
background_width,
background_height,
):
company_name = company_name or ""
slogan = slogan or ""
company_name_color = company_name_color or "#3E0E1F"
slogan_color = slogan_color or "#D1284C"
# background_color = background_color or "#F6E1E1"
background_width = background_width or 4000
background_height = background_height or 3000
background = Image.new("RGBA", (background_width, background_height))
logo = Image.open(BytesIO(logo_bytes))
logo_width, logo_height = logo.size
# Scale the logo
logo_scale_factor = min(
background_width * 0.7 / logo_width, background_height * 0.5 / logo_height
)
new_logo_size = (
int(logo_width * logo_scale_factor),
int(logo_height * logo_scale_factor),
)
logo = logo.resize(new_logo_size)
# Position the logo
logo_x = (background_width - logo.width) // 2 # Center the logo horizontally
logo_y = (background_height - logo.height) // 3 # Center the logo Vertically
background.paste(logo, (logo_x, logo_y), logo)
# Calculate dynamic font sizes based on the background size
company_font_size = int(background_width * 0.05)
slogan_font_size = int(company_font_size * 0.75)
try:
font = ImageFont.truetype(BytesIO(font_bytes), company_font_size)
slogan_font = ImageFont.truetype(BytesIO(font_bytes), slogan_font_size)
except Exception as e:
font = ImageFont.load_default(company_font_size)
slogan_font = ImageFont.load_default(slogan_font_size)
# Create a draw object
draw = ImageDraw.Draw(background)
company_lines = wrap_text(company_name, MAX_COMPANY_LINE_LENGTH)
company_text_y = logo_y + logo.height + 10 # 10 pixels below the logo
for line in company_lines:
line_bbox = draw.textbbox((0, 0), line, font=font)
line_width = line_bbox[2] - line_bbox[0]
company_text_x = (background_width - line_width) // 2
line_position = (company_text_x, company_text_y)
if not is_text_within_bounds(
draw, line, line_position, font, background_width, background_height
):
break
draw.text(
(company_text_x, company_text_y),
line,
fill=company_name_color,
font=font,
stroke_width=4,
stroke_fill="white",
)
company_text_y += line_bbox[3] - line_bbox[1] + 10
slogan_lines = wrap_text(slogan, MAX_SLOGAN_LINE_LENGTH)
slogan_text_y = company_text_y + 10 # Slightly below company name
for line in slogan_lines:
line_bbox = draw.textbbox((0, 0), line, font=slogan_font)
line_width = line_bbox[2] - line_bbox[0]
slogan_text_x = (background_width - line_width) // 2
line_position = (slogan_text_x, slogan_text_y)
if not is_text_within_bounds(
draw, line, line_position, slogan_font, background_width, background_height
):
break
draw.text(
(slogan_text_x, slogan_text_y),
line,
fill=slogan_color,
font=slogan_font,
stroke_width=4,
stroke_fill="white",
)
slogan_text_y += line_bbox[3] - line_bbox[1] + 10
return convert_image_bytes(background)
def add_watermark(
original_image,
watermark_hexcolor=None,
):
watermark_hexcolor = watermark_hexcolor or "#000000"
original = Image.open(BytesIO(original_image)).convert("RGBA")
watermark_image = create_watermark(get_watermark_svg(watermark_hexcolor))
watermark = Image.open(BytesIO(watermark_image)).resize(
original.size, Image.Resampling.LANCZOS
)
watermark = watermark.convert("RGBA")
final_background = Image.alpha_composite(original, watermark)
return convert_image_bytes(final_background)
def resize_image(image, target_size):
image = Image.open(BytesIO(image))
original_size = image.size
ratio = min(target_size[0] / original_size[0], target_size[1] / original_size[1])
new_size = (int(original_size[0] * ratio), int(original_size[1] * ratio))
return image.resize(new_size, Image.Resampling.LANCZOS)
def convert_image_bytes(image):
buffered = BytesIO()
image.save(buffered, format="PNG")
buffered.seek(0)
value = buffered.getvalue()
buffered.close()
return value
def hex_to_rgb(hex_color):
hex_color = hex_color.lstrip("#")
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
def get_watermark_color(background_color):
r, g, b = hex_to_rgb(background_color)
luminance = 0.299 * r + 0.587 * g + 0.114 * b
if luminance > 128:
watermark_color = "#000000"
else:
watermark_color = "#FFFFFF"
return watermark_color
def create_solid_color_background(size, color):
img = Image.new("RGB", size, color)
return convert_image_bytes(img)
def convert_image_to_png(image):
with BytesIO(image) as input_stream:
with Image.open(input_stream) as img:
with BytesIO() as output:
img.save(output, format="PNG")
png_bytes = output.getvalue()
return png_bytes