Python transparent watermark is not transparent - python

I have this issue, where whatever watermark I put, the background, which is transparent, appears as non-transparent.
Here is the code:
from PIL import Image
import glob
def watermark_with_transparency(input_image_path, output_image_path, watermark_image_path):
base_image = Image.open(input_image_path) # open base image
watermark = Image.open(watermark_image_path) # open water mark
width, height = base_image.size # getting size of image
width_of_watermark, height_of_watermark = watermark.size
position = [width / 2 - width_of_watermark / 2, height / 2 - height_of_watermark / 2]
position[0] = int(position[0])
position[1] = int(position[1])
water = watermark.copy()
water.convert('RGBA')
water.putalpha(70)
water.save('solid.png')
transparent = Image.new('RGBA', (width, height), (0, 0, 0, 0))
transparent.paste(base_image, (0, 0))
transparent.paste(water, position, mask=water)
transparent.show()
transparent.convert('RGB').save(output_image_path)
print('Image Done..!')
for inputImage in glob.glob('images/*.jpg'):
output = inputImage.replace('images\\', '')
outputImage = 'watermark images\\' + str(output)
watermark_with_transparency(inputImage, outputImage, 'watermark images/watermark.png')
Here you may see what the result is:

Related

How to better crop and paste an image in PIL

I am trying to crop an avatar and place it in a given location in another image using python pil.
Here is the output of what I have so far:
And here is the code:
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import textwrap
text = "Creating Twitter Cards dynamically with Python"
background_image = "data/obi-pvc.png" # this is the background
avatar = Image.open("data/avatar.png")
font = "data/fonts/AllertaStencil-Regular.ttf"
background = Image.open(background_image)
background_width, background_height = background.size
avatar.convert('RGBA')
## DO NOT change below this line!!
save_name = f"{text.lower().replace(' ', '_')}.png"
#textwrapped = textwrap.wrap(text, width=text_wrap_width)
# crop avatar
width, height = avatar.size
x = (width - height)//2
avatar_cropped = avatar.crop((x, 0, x+height, height))
width_cr, height_cr = avatar_cropped.size
# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', avatar_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = avatar_cropped.size
mask_draw.ellipse((0, 0, width, height), fill=255)
# add mask as alpha channel
avatar_cropped.putalpha(mask)
draw = ImageDraw.Draw(background)
font = ImageFont.truetype(font, font_size)
draw.text((offset,margin), '\n'.join(textwrapped), font=font, fill=color)
x, y = avatar_cropped.size
margin = 40
# left top
position_tl = (0 + margin, 0 + margin)
position_tr = (x - margin - width_cr, 0 + margin)
position_bl = (0 + margin, y - margin - height_cr)
position_br = (x - margin - width_cr, y - margin - height_cr)
background.paste(avatar_cropped, position)
background.save(f"data/output/{save_name}")
display(background)
The avatar should fit within the circle. I can't seem to really figure out how to apply the positioning. Thanks
Here is the avatar:

Making .png files with transparent pixels

I can make some .png files using PIL and tkinter:
import tkinter
from PIL import ImageGrab
canvas = tkinter.Canvas(width=100, height=100)
SomeInterestingPhotoImage = PhotoImage(file='Path/To/My/file.png')
canvas.create_image(0, 0, image=SomeInterestingPhotoImage, anchor='nw')
x0 = canvas.winfo_rootx()
y0 = canvas.winfo_rooty()
x1 = x0 + canvas.winfo_width()
y1 = y0 + canvas.winfo_height()
image = ImageGrab.grab((x0, y0, x1, y1))
image.save(name.png)
# I need to make some pixels transparent.
Here I can make an .png file, but all pixels have some colour. I need to make white pixels of canvas (not of image) transparent.
import glob
from PIL import Image
def transparent(myimage):
img = Image.open(myimage)
img = img.convert("RGBA")
pixdata = img.load()
width, height = img.size
for y in range(height):
for x in range(width):
if pixdata[x, y] == (0, 0, 0, 255):
pixdata[x, y] = (0, 0, 0, 0)
img.save(myimage, "PNG")
for image in glob.glob("*.png"):
transparent('mypic.png')
This code will basically change black (0, 0, 0, 255) to transparent (0, 0, 0, 0) pixels

How to move the circular image to the exact center position of the bigger image?

I want to move the circular image to the exact center position of the bigger image. How to do accomplish that task accurately?
from IPython.display import display
import numpy as np
from PIL import Image, ImageDraw, ImageFilter
def show_saved_image(str):
img = Image.open(str)
display(img)
im1 = Image.open('rocket.jpg')
im2 = Image.open('lena.jpg')
#height, width, channels = im1.shape
im1_width, im1_height = im1.size
im1_centreX, im1_centreY = int(im1_width/2), int(im1_height/2)
im2_width, im2_height = im2.size
im2_centreX, im2_centreY = int(im2_width/2), int(im2_height/2)
print(im1_width, im1_height)
print(im2_width, im2_height)
radius = int(min(im2_width/2, im2_height/2))
ulX, ulY = im2_centreX-radius, im2_centreY-radius
lrX, lrY = im2_centreX+radius, im2_centreY+radius
desired_pointX, desired_pointY = im1_centreX-radius, im1_centreY-radius
# ![rocket_pillow_paste_out](data/dst/rocket_pillow_paste_out.jpg)
mask_im = Image.new("L", im2.size, 0)
draw = ImageDraw.Draw(mask_im)
draw.ellipse((ulX, ulY, lrX, lrY), fill=255)
# mask_im_blur = mask_im.filter(ImageFilter.GaussianBlur(10))
# mask_im_blur.save('mask_circle_blur.jpg', quality=95)
back_im = im1.copy()
back_im.paste(im2, (desired_pointX, desired_pointY), mask_im)
#back_im.paste(im2, (desired_pointX, desired_pointY), mask_im_blur)
back_im.save('output.jpg', quality=95)
im = Image.open('output.jpg')
draw = ImageDraw.Draw(im)
draw.ellipse((im1_centreX-4, im1_centreY-4, im1_centreX+4, im1_centreY+4 ), fill=(0, 255, 0), outline=(0, 0, 0))
draw.ellipse((desired_pointX-4, desired_pointY-4, desired_pointX+4, desired_pointY+4 ), fill=(255, 0, 0), outline=(0, 0, 0))
im.save('imagedraw.jpg', quality=95)
show_saved_image("imagedraw.jpg")
Images:
rocket.jpg
lena.jpg
If there is another way, then please help me with that, too.
You just need to modify this line
desired_pointX, desired_pointY = im1_centreX - radius, im1_centreY - radius
to
desired_pointX, desired_pointY = im1_centreX - int(im2_width/2), im1_centreY - int(im2_height/2)
Your mask_im has shape im2.size, so you need to adapt to that, not just the radius of the circle. Since radius is int(im2_height/2), the vertical alignment is fine, but radius is smaller than int(im2_width/2), that's why the insufficient shift leftwards.

Image resizing function not running

I have a python method that is supposed to resize an image
def Reformat_Image(ImageFilePath,fileName,image):
print("inside Reformat_Image")
image_size = image.size
width = image_size[0]
print
height = image_size[1]
if(width != height):
bigside = width if width > height else height
background = Image.new('RGBA', (bigside, bigside), (255, 255, 255, 255))
offset = (int(round(((bigside - width) / 2), 0)), int(round(((bigside - height) / 2),0)))
background.paste(image, offset)
background.save(fileName+"Resized.jpg")
print("Image has been resized")
and when I call to use it
cwd = os.getcwd()
print("Resizing picture")
Reformat_Image(ImageFilePath =image_path,fileName=fileName,image=image)
The inside of the Reformat_Image() method never runs. I am able to successfully open the image a few lines before that code is ran so I think my file names/ locations should be working fine.
Command prompt output:
> Resizing picture
Expected output:
> Resizing picture
> inside Reformat_Image

Text within image in OpenCV

I was trying to get some text on an image using OpenCV. But the text is too long for one line and goes out of the image, instead of the next line. I could hardcode the spaces, but I was looking for a more dynamic solution. How do I work around this issue?
def get_text(img, text):
sh = img.shape
txt = np.ones(shape=sh)
fontface = cv2.FONT_HERSHEY_SIMPLEX
fontscale = 1
thickness = 2
color = (0, 0, 0)
orig = (10, 100)
linetype = cv2.LINE_AA
txt = cv2.putText(txt, text, orig, fontface, fontscale, color, thickness, linetype)
txt = txt.astype("uint8")
return txt
import textwrap
def get_text(img, text):
sh = img.shape
txt = np.ones(shape=sh)
fontface = cv2.FONT_HERSHEY_SIMPLEX
fontscale = 1
thickness = 2
color = (0, 0, 0)
orig = (10, 100)
linetype = cv2.LINE_AA
wrapped_text = textwrap.wrap(text, width=35)
x, y = 10, 40
font_size = 1
font_thickness = 2
i = 0
for line in wrapped_text:
textsize = cv2.getTextSize(line, font, font_size, font_thickness)[0]
gap = textsize[1] + 10
y = int((img.shape[0] + textsize[1]) / 2) + i * gap
x = int((img.shape[1] - textsize[0]) / 2)
cv2.putText(img, line, (x, y), font,
font_size,
(0,0,0),
font_thickness,
lineType = cv2.LINE_AA)
txt = txt.astype("uint8")
return txt
Try this, may require some adjustment, but the idea is to use textwrap.wrap(text, width=35).
in this code i simply split string into parts according image width.
# Python program to explain cv2.putText() method
import cv2
import math
import textwrap
path = r'YOUR PATH OF IMAGE'
image = cv2.imread(path)
window_name = 'Image'
font = cv2.FONT_HERSHEY_SIMPLEX
zero= 5
one =50
org = (zero, one)
fontScale = 1
color = (255, 0, 0)
thickness = 2
imageHeight = image.shape[0]
imageWidth = image.shape[1]
print(f"width:",imageWidth)
sizeofnumpix=min(imageWidth,imageHeight)/(25/fontScale)
stringputt = 'YOUR STRING'
i=len(stringputt)
print(i)
if i*sizeofnumpix > imageWidth*2:
n=math.ceil(i*sizeofnumpix/(imageWidth*2))
part_size = math.ceil(i/n)
txt = textwrap.wrap(stringputt, part_size)
for l in txt:
image = cv2.putText(image, l, org, font,fontScale, color, thickness, cv2.LINE_AA)
zero= 5
one = one+math.ceil(sizeofnumpix)
org = (zero, one)
else:
image = cv2.putText(image, stringputt, org, font,fontScale, color, thickness, cv2.LINE_AA)
# Displaying the image
cv2.imwrite('IMGWITHTXT.png',image)

Categories