HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
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