How add watermark diagonally limiting height and width according to background image specifications without losing logo quality?

Question:

Question summary: My expected result is to be able to frame the watermark diagonally and regardless of the width and height of the background image, it always fits within the limits and with dimensions that maintain the quality of the logo.


In order not to lose the quality of the image that I use as a watermark, I had to readjust its size from the width of the image where I am going to paste it, but as you can see in the image that I will publish below the code, when the image has a too small height, the watermark exceeds the limits of the image.

If I need to adjust the watermark according to the width of the other image to maintain the quality, how should I go about adjusting both the height and width so that the watermark fits perfectly inside the other image regardless of its height or width?

from PIL import Image

def watermark_with_transparency(input_image_path,
                                output_image_path,
                                watermark_image_path):
    
    TRANSPARENCY = 20
    angle = 30

    base_image = Image.open(input_image_path)
    w_img, h_img = base_image.size
    
    basewidth = w_img
    watermark = Image.open(watermark_image_path)
    wpercent = (basewidth/float(watermark.size[0]))
    hsize = int((float(watermark.size[1])*float(wpercent)))
    watermark = watermark.resize((basewidth,hsize), Image.ANTIALIAS)
    watermark = watermark.rotate( angle, expand=1 )
    w_logo, h_logo = watermark.size

    center_y = int(h_img / 2)
    center_x = int(w_img / 2)
    top_y = center_y - int(h_logo / 2)
    left_x = center_x - int(w_logo / 2)

    if watermark.mode!='RGBA':
        alpha = Image.new('L', (w_img, h_img), 255)
        watermark.putalpha(alpha)

    paste_mask = watermark.split()[3].point(lambda i: i * TRANSPARENCY / 100.)
    base_image.paste(watermark, (left_x,top_y), mask=paste_mask)
    base_image.show()
    base_image.save(output_image_path)

if __name__ == '__main__':
    watermark_with_transparency(
        'jogos_de_hoje_na_tv.png',
        'watermark_create.png',
        'logo_com_transparencia.png'
        )

Current result:

enter image description here




I tried add doing it for the width like this:

    basehight = h_img
    hpercent = (basehight/float(watermark.size[0]))
    wsize = int((float(watermark.size[0])*float(hpercent)))

    watermark = watermark.resize((wsize,hsize), Image.ANTIALIAS)

But the result was a watermark with a lot of height and without any quality in the size adjustment.

Asked By: Digital Farmer

||

Answers:

I change your code like this:

def watermark_with_transparency(input_image_path,
                                output_image_path,
                                watermark_image_path):
    TRANSPARENCY = 20
    angle = 30
    base_image = Image.open(input_image_path)
    base_image.show()
    w_img, h_img = base_image.size
    basewidth = w_img
    watermark = Image.open(watermark_image_path)
    watermark = watermark.rotate(angle, expand=True)
    wpercent = (basewidth / float(watermark.size[0]))
    hpercent = h_img / float(watermark.size[1])
    if wpercent < hpercent:
        hsize = int((float(watermark.size[1]) * float(wpercent)))
        watermark = watermark.resize((basewidth, hsize), Image.ANTIALIAS)
    else:
        wsize = int((float(watermark.size[0]) * float(hpercent)))
        watermark = watermark.resize((wsize, h_img), Image.ANTIALIAS)
    w_logo, h_logo = watermark.size
    center_y = int(h_img / 2)
    center_x = int(w_img / 2)
    top_y = center_y - int(h_logo / 2)
    left_x = center_x - int(w_logo / 2)
    if watermark.mode != 'RGBA':
        alpha = Image.new('L', (w_img, h_img), 255)
        watermark.putalpha(alpha)
    paste_mask = watermark.split()[3].point(lambda i: i * TRANSPARENCY / 100.)
    base_image.paste(watermark, (left_x, top_y), mask=paste_mask)
    base_image.show()
    base_image.save(output_image_path)

The idea is that when your resize your watermark you have to check which factor (height or width) is the smallest and you want to take it. Otherwise, in your first version of the code the resizing did not take into account that the new height could be larger than the input image height.

Answered By: T.Lucas
from PIL import Image
import math

def add_watermark(source, source_output_path, watermark):
    source_image = Image.open( source )
    watermark_image = Image.open(watermark)

    source_image_width, source_image_height = source_image.size
    watermark_image_width = math.ceil( (source_image_width * 70 ) / 100 ) 
    # float(watermark_image.size[0]))
    watermark_image_height = math.ceil( ( source_image_height * 70 ) / 100 ) # float(watermark_image.size[1])

    watermark_x_axis = math.ceil( (source_image_width * 15 ) / 100 )
    watermark_y_axis = math.ceil( ( source_image_height * 15 ) / 100 )

    watermark_image = watermark_image.resize((watermark_image_width, watermark_image_height), Image.Resampling.LANCZOS )

    # Calculate the position to place the watermark (bottom-right corner)
    watermark_position = (watermark_x_axis, watermark_y_axis)

    # Create a copy of the input image
    source_with_watermark = source_image.copy()

    # Paste the watermark image onto the input image
    watermark_image_paste_mask = watermark_image.split()[3].point(lambda i: i * 50 / 100 )
    source_with_watermark.paste(watermark_image, watermark_position, mask=watermark_image_paste_mask)

    # Save the image with the watermark
    source_with_watermark.save( source_output_path )

add_watermark("source-image-path/m.png", "source-output-image-path/m.png", "watermark-image-path/m.png")

try this one #m

Answered By: vijin selvaraj