I am trying to add some text next to and under a QR code
.
The problem is that I am struggling on how to edit the image into a QR Code + text
. The image below is what I would like to have as a result. The function signature can be changed too.
This is the code I have so far
"""
requirements.txt
qrcode==7.4.2
Pillow==8.1.0
opencv-python==4.7.0.68
"""
import os
from pathlib import Path
import cv2
import qrcode
from PIL import Image, ImageFont, ImageDraw, ImageOps
def create_qr_img() -> str:
QRcode = qrcode.QRCode(
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=5,
)
url = 'google.com'
QRcode.add_data(url)
QRcode.make()
# adding color to QR code
QRimg = QRcode.make_image(
fill_color='Black', back_color="white").convert('RGB')
# save the QR code generated
out_fp = f'temp_/QR.png'
QRimg.save(out_fp)
return out_fp
def add_str_to_img(img_path: str,
str1: str,
str2: str,
show:bool=False) -> str:
black_color_rgb = (0,0,0)
white_color_rgb = (255,255,255)
img = Image.open(img_path)
#failed attempt 1)
# expanding the border works only for writing on top or under the QR code
# but if the string is too long, it gets cut off
img = ImageOps.expand(img, border=30, fill=white_color_rgb)
# failed attempt 2)
# add empty space to the left of the QR code
# exp_cm = 3
# exp_px = int(exp_cm * 37.79527559055118)
# new_shape_pixels = (img.width+exp_px, img.height)
# img = ImageOps.fit(img, new_shape_pixels, method=Image.ANTIALIAS,
# #bleed=0.0, centering=(0.5, 0.5)
# )
# end failed attempt 2)
draw = ImageDraw.Draw(img)
font_path = os.path.join(cv2.__path__[0],'qt','fonts','DejaVuSans.ttf')
font = ImageFont.truetype(font_path, size=52)
# on top of the QR code
draw.text((62,0),str1,(0,0,0),font=font,
align='center'
)
# bottom
draw.text((0,470),str2,black_color_rgb,font=font,
align='center',
)
print('QR code TO BE generated!')
out_fp = f'temp_/QR_print.png'
Path(out_fp).unlink(missing_ok=True)
img.save(out_fp)
if show:
img.show()
print('QR code generated!')
return out_fp
if __name__ == '__main__':
img_path = create_qr_img()
add_str_to_img(img_path,
'ExampleAboveQr',
'This is some long string. It could be multi-line. 22222222',
show=True)
I think the solution should be something like with ImageOps.fit
but I could not get it work how I wanted (see attempt 2)
) in code.
Thanks to the comment from Paul-ET suggesting: Add Text on Image using PIL
I created a white image with create_background_image
and then pasted the QR
and the text later.
def cm_to_pixels(cm: float) -> int:
return int(cm * 37.79527559055118)
def create_background_image(cm_width: float,
cm_height: float,
) -> Image.Image:
w, h = cm_to_pixels(cm=cm_width), cm_to_pixels(cm=cm_height)
# creating new Image object
img = Image.new("RGB", (w, h), color='white')
return img
if __name__ == '__main__':
img_path = create_qr_img()
# resize it to make it constant
qr_img = Image.open(img_path)
qr_img = qr_img.resize((70, 70))
# start making the background image
background_img = create_background_image(cm_width=5, cm_height=2.9)
# paste qr
background_img.paste(qr_img, (2, 0), qr_img.convert('RGBA'))
d = ImageDraw.Draw(background_img)
widht_and_height_pixels=(5, 68)
font_path = os.path.join(cv2.__path__[0],'qt','fonts','DejaVuSans.ttf')
font = ImageFont.truetype(font_path, size=15)
d.text(widht_and_height_pixels,
"123123345345",fill='black',
font=font
)
background_img.show()