how to draw text to bitmap in python? - python

I want to create text to bitmap. the text is considered long string text.
so please tell me how to create a bitmap from a text.
I tried this :
from PIL import Image, ImageFont
img = Image.new('L', (500, 500), color=0)
img_w, img_h = img.size
font = ImageFont.truetype('arial.ttf', 20)
mask = font.getmask('some text related location that is going to write here.'
'this is watermark text', mode='L')
mask_w, mask_h = mask.size
print(mask_w,mask_h)
print(type(mask))
d = Image.core.draw(img.im, 0)
# d = d.rotate(40)
d.draw_bitmap(((img_w - mask_w)/2, (img_h - mask_h)/2), mask, 255)
img = img.rotate(40)
img.show()
img.save('op.jpg')
But text is cut from both side.
here is what i get.

The text is cut from both sides because it was already cut by the horizontal boundary of the image before you rotate it. You should create an image with a width large enough to accommodate the entire text before you rotate it. That is to say, you should create an Image object with a width of mask_w after you obtain it.

Related

How to change the color of a pixel using PIL?

I was trying to change pixel of an image in python using this question. If mode is 0, it changes first pixel in top right corner of image to grey(#C8C8C8). But it doesn't change. There is not enough documentation about draw.point(). What is the problem with this code?
import random
from PIL import Image, ImageDraw
mode = 0
image = Image.open("dom.jpg")
draw = ImageDraw.Draw(image)
width = image.size[0]
height = image.size[1]
pix = image.load()
string = "kod"
n = 0
if (mode == 0):
draw.point((0, 0), (200, 200, 200))
if(mode == 1):
print(pix[0,0][0])
image.save("dom.jpg", "JPEG")
del draw
Is using PIL a must in your case? If not then consider using OpenCV (cv2) for altering particular pixels of image.
Code which alter (0,0) pixel to (200,200,200) looks following way in opencv:
import cv2
img = cv2.imread('yourimage.jpg')
height = img.shape[0]
width = img.shape[1]
img[0][0] = [200,200,200]
cv2.imwrite('newimage.bmp',img)
Note that this code saves image in .bmp format - cv2 can also write .jpg images, but as jpg is generally lossy format, some small details might be lost. Keep in mind that in cv2 [0][0] is left upper corner and first value is y-coordinate of pixel, while second is x-coordinate, additionally color are three values from 0 to 255 (inclusive) in BGR order rather than RGB.
For OpenCV tutorials, including installation see this.

how can I put multiple images and texts on a background image using Python PIL such that texts don't overlap with image?

I'm trying to put multiple images and texts on top of the background image. Making use of python PIL image library. The number of images and text printing won't need to be the same always. Text and image printing has to be separate. The text has to be printed outside anywhere image bounding box.
I'm using below code to make this happen
from PIL import Image
import os, random
with open('C:/Users/nike/Desktop/namelist.txt', "r") as word_list:
words = list(word_list)
k=[]
for i in words:
j = i.replace(' ','').replace('\n','')
k.append(j)
folder=r"C:/Users/nike/Desktop/imagefolder"
a=random.choice(os.listdir(folder))
file = folder+'//'+a
random_text=random.choice(k)
img = Image.open(file)
img_w, img_h = img.size
background = Image.open('C:/Users/nike/Desktop/backgroundimages/back.jpeg','r')
bg_w, bg_h = background.size
offset = ((bg_w - img_w) // 2, (bg_h - img_h) // 2)
draw = ImageDraw.Draw(background)
background.paste(img, offset)
font = ImageFont.truetype("C:/Users/nike/Desktop/open-sans/abc.ttf", 16)
draw.text((0, 0),random_text,(255,255,255),font=font)
background.save('out.png')
above code does printing of one image at the center of background image and text at the (0,0) coordinate of background image. How can I make multiple text and images to paste on background images such that text(x,y) do not print on image (x,y). Any suggestion will be helpful.
Example:
expected result
on the background image, I need to copy images and texts such that they won't overlap eachother.

How to draw text with image in background?

I want to make something like this python.
I have the image in background and write text with transparent fill, so that image shows up.
Here's one way I found to do it using the Image.composite() function which is documented here and here.
The approach used is described (very) tersely in this answer to the question Is it possible to mask an image in Python Imaging Library (PIL)? by #Mark Ransom…the following is just an illustration of applying it to accomplish what you want do.
from PIL import Image, ImageDraw, ImageFont
BACKGROUND_IMAGE_FILENAME = 'cookie_cutter_background_cropped.png'
RESULT_IMAGE_FILENAME = 'cookie_cutter_text_result.png'
THE_TEXT = 'LOADED'
FONT_NAME = 'arialbd.ttf' # Arial Bold
# Read the background image and convert to an RGB image with Alpha.
with open(BACKGROUND_IMAGE_FILENAME, 'rb') as file:
bgr_img = Image.open(file)
bgr_img = bgr_img.convert('RGBA') # Give iamge an alpha channel.
bgr_img_width, bgr_img_height = bgr_img.size
cx, cy = bgr_img_width//2, bgr_img_height//2 # Center of image.
# Create a transparent foreground to be result of non-text areas.
fgr_img = Image.new('RGBA', bgr_img.size, color=(0, 0, 0, 0))
font_size = bgr_img_width//len(THE_TEXT)
font = ImageFont.truetype(FONT_NAME, font_size)
txt_width, txt_height = font.getsize(THE_TEXT) # Size of text w/font if rendered.
tx, ty = cx - txt_width//2, cy - txt_height//2 # Center of text.
mask_img = Image.new('L', bgr_img.size, color=255)
mask_img_draw = ImageDraw.Draw(mask_img)
mask_img_draw.text((tx, ty), THE_TEXT, fill=0, font=font, align='center')
res_img = Image.composite(fgr_img, bgr_img, mask_img)
res_img.save(RESULT_IMAGE_FILENAME)
res_img.show()
Which, using the following BACKGROUND_IMAGE:
produced the image shown below, which is it being viewed in Photoshop so the transparent background it has would be discernible (not to scale):
Here's an enlargement, showing the smoothly rendered edges of the characters:

PIL how to scale image in relation to the text drawn on image

I am trying to dynamically increase image size with respect to font and text given to draw.text().
Orignal Problem is to create signature image based on name and the font user selects.
Here is my code
from PIL import (Image, ImageDraw, ImageFont,)
width=20
height=20
selected_font='simply_glomrous.ttf'
font_size=30
img = Image.new('RGBA', (width, height), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(selected_font, font_size)
draw.text((0,0), "Adil Malik", (0,0,0), font)
img.save('signature.png')
But i am still having same image size defined in width and height. Can we do dynamically resizing of image based on font and its size ?
Note: This question is opposite to this stackoverflow question
Unfortunately, No one able to answer my question.
Basically, You can't set fix width and height while setting the font size. Both are dependent on each other. So if one increase, second one also increases.
So I have come up with another solution. I am just setting the font size and then based on that font size, I am setting width and height.
from PIL import (Image, ImageDraw, ImageFont,)
name = 'Adil Malik'
selected_font='simply_glomrous.ttf'
font_size=30
font = ImageFont.truetype(selected_font, font_size)
font_size = font.getsize(name)
img = Image.new('RGBA', (font_size[0], font_size[0]), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(selected_font, font_size)
draw.text((0,0), name, (0,0,0), font)
img.save('signature.png')
The functionality you are looking for is the Draw.textsize method which takes a text string and drawing options as input and returns the width and height of the rendered text.
http://effbot.org/imagingbook/imagedraw.htm#tag-ImageDraw.Draw.textsize
You can use the Draw class with an image that has a width and height of zero and then call the method to determine the dimensions of the text you are looking to render. Once you know those dimensions, you can then resize the image accordingly. For example:
from PIL import ImageDraw, ImageFont, Image
# parameters
text = "My Name"
selected_font = "simply_glomrous.ttf"
font_size = 30
# get the size of the text
img = Image.new('RGBA', (0,0), (255, 255, 255, 0))
font = ImageFont.truetype(selected_font, font_size)
draw = ImageDraw.Draw(img)
text_size = draw.textsize(text, font)
# resize and draw
img = img.resize(text_size)
draw.text((0,0), text, (0,0,0), font)
img.save('signature.png')
If you can use openCV and numpy, you can
Check the text size using getTextSize
Create a white image using numpy.ones((height, width, 3), np.uint8)*255
Add text to the image using putText,
Save the image using imwrite.
See here and here for references.
First, you need to get your scales right: You are starting from a font size given in points, which defined to be 1/72 of an inch; those are "real world" scales. The image you are drawing on is defined in pixels. Pixels get a relation to inches/points only if you also define the pixels-per-inch ratio.
So the way you think about the problem is kind of backward: You need to start with the pixels you have (either from the source or the target image) and then compute the appropriate font size. If you want to have the user select a font size, you need to define (or ask for) a target DPI value in order to change between the units of scale involved.

PIL: Can't vertically align text accurately despite taking font into account

I want to create a simple Python script that let's me create an image file and place a word dead-center on that canvas. However, while I can get the word to align horizontally, I just can't get it to the center vertically. I am on MacOS btw. I have tried this so far:
import os
from PIL import Image, ImageDraw, ImageFont
font_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fonts')
font = ImageFont.truetype(os.path.join(font_path, "Verdana.ttf"), 80)
W, H = (1200,200)
msg = "hola"
im = Image.new("RGB",(W,H),(255,255,255))
draw = ImageDraw.Draw(im)
w, h = draw.textsize(msg, font)
draw.text(((W-w)/2,(H-h)/2), msg, font=font, fill="black")
im.save("output_script.png", "PNG")
I already considered the font in the textsize calculation. But the word still appears roughly 5-10% below the middle. Any ideas?
textsize seems to return the size of the actual text, not that of the line. So it's smaller for ooo than for XXX!
I think you should just use 80 — the size you gave PIL — for the height, although I can't guarantee that it's correct.
ImageFont.getmask(txt) returns the alpha mask bitmap with which text can be centered in the image.
import Image, ImageFont
img = Image.new('L', (32, 32), color=0)
img_w, img_h = img.size
font = ImageFont.truetype('/path/to/font.ttf', 16)
mask = font.getmask('hola') # your text here
mask_w, mask_h = mask.size
d = Image.core.draw(img.im, 0)
d.draw_bitmap(((img_w - mask_w)/2, (img_h - mask_h)/2), mask, 255) # last arg is pixel intensity of text
img.save('test.png')

Categories

Resources