python qrcode decode getting output? - python

Hi there i have managed to create a qr code and then read it again. However on reading it i get lots of extra information that i do not want such as the width and hieght of the qr code image that was decoded. How do i just get the first part of the result?
My code :
from PIL import Image
from pyzbar.pyzbar import decode
import pyqrcode
qr = pyqrcode.create("example")
qr.png("test1.png", scale=6)
data = decode(Image.open('test1.png'))
print(data)
my output on running of the code :
[Decoded(data=b'example', type='QRCODE', rect=Rect(left=24, top=24, width=126, height=126), polygon=[Point(x=24, y=24), Point(x=24, y=150), Point(x=150, y=150), Point(x=150, y=24)])]

decode() returns a list of Decoded objects, so I would simply try this:
decoded_list = decode(Image.open('test1.png'))
print(decoded_list[0].data)
I renamed your "data" variable to avoid confusion with the data attribute of a Decoded object.

Related

Creating QR code containing both text and photo

It is possible to create a QR code which contains both some text and photo (which is small logo) in python?
I mean text, which is not part of the photo. But I will have separately text (string variable) and photo (e.g. *.png).
So far I saw only the examples where it was possible to create a QR code from text or photo. I couldn't find example with both used at the same time.
Basically when I scan my QR code, I would like for it to show my photo (logo) and text information.
Expanding on my comment. QR Codes are used to encode text. So you have to read in your image, convert to base64, append your string with some delimiter and then write out your QR code.
Because we took special steps to encode the data (the image and the string) before storing in a QR code, we must also have a special application to read the QR code, split the base64 string by our delimiter, and then decode the base64 pieces into their appropriate media (writing the binary to a file for the image and printing out the decoded string).
All in all this will look something like the following:
import base64
#open image and convert to b64 string
with open("small.png", "rb") as img_file:
my_string = base64.b64encode(img_file.read())
#append a message to b64 encoded image
my_string = my_string + b'\0' + base64.b64encode(b'some text')
#write out the qrcode
import qrcode
qr = qrcode.QRCode(
version=2,
error_correction=qrcode.constants.ERROR_CORRECT_M,
)
qr.add_data(my_string, optimize=0)
qr.make()
qr.make_image().save("qrcode.png")
#--------Now when reading the qr code:-------#
#open qr code and read in with cv2 (as an example), decode with pyzbar
from pyzbar.pyzbar import decode
import cv2 #importing opencv
img = cv2.imread('qrcode.png', 0)
barcodes = decode(img)
for barcode in barcodes:
barcodeData = barcode.data.decode("utf-8")
#split the b64 string by the null byte we wrote
data = barcodeData.split('\x00')
#save image to file after decoding b64
filename = 'some_image.jpg'
with open(filename, 'wb') as f:
f.write(base64.b64decode(data[0]))
#print out message after decoding
print(base64.b64decode(data[1]))
Obviously this is only going to work for a VERY small image and just a little bit of text. You quickly blow out the max size of a QR code, and even before you hit the limits for the standard, you'll hit the limits for qrcode and pyzbar modules.
With this, you can start with a tiny image like:
And after encoding and appending text, have a qr code like:
And end up with the exact same picture and your appended text
Ultimately this really isn't terribly useful though since you have to have a special application to decode your QR code. The more traditional method of creating a web page with the content you want to share along with a qr code containing a link to the page, is a more user-friendly and approachable method to solving this.
when I scan my QR code, I would like for it to show my photo (logo) and text information
You can put the picture and the text on a public web page, and then encode the URL of the web page in the QR code.

Generating and reading QR codes with special characters

I'm writing Python program that does the following:
Create a QR code > Save to a png file > Open the file > Read the QR code information
However, when the data on the code has special characters, I got some confusion output data. Here's my code:
import pyqrcode
from PIL import Image
from pyzbar.pyzbar import decode
data = 'Thomsôn Gonçalves Ámaral,325.432.123-21'
file_iso = 'QR_ISO.png'
file_utf = 'QR_Utf.png'
#creating QR codes
qr_iso = pyqrcode.create(data) #creates qr code using iso-8859-1 encoding
qr_utf = pyqrcode.create(data, encoding = 'utf-8') #creates qr code using utf-8 encoding
#saving png files
qr_iso.png(file_iso, scale = 8)
qr_utf.png(file_utf, scale = 8)
#Reading and Identifying QR codes
img_iso = Image.open(file_iso)
img_utf = Image.open(file_utf)
dec_iso = decode(img_iso)
dec_utf = decode(img_utf)
# Reading Results:
print(dec_iso[0].data)
print(dec_iso[0].data.decode('utf-8'))
print(dec_iso[0].data.decode('iso-8859-1'),'\n')
print(dec_utf[0].data)
print(dec_utf[0].data.decode('utf-8'))
print(dec_utf[0].data.decode('iso-8859-1'))
And here's the output:
b'Thoms\xee\x8c\x9e Gon\xe8\xbb\x8blves \xef\xbe\x81maral,325.432.123-21'
Thoms Gon軋lves チmaral,325.432.123-21
Thoms Gon軋lves ï¾maral,325.432.123-21
b'Thoms\xef\xbe\x83\xef\xbd\xb4n Gon\xef\xbe\x83\xef\xbd\xa7alves \xef\xbe\x83\xef\xbc\xbbaral,325.432.123-21'
Thomsテエn Gonテァalves テ[aral,325.432.123-21
Thomsテエn Gonテァalves テ[aral,325.432.123-21
For simple data it works just fine, but when data has characters like 'Á, ç ' and so on this happens.
Any ideas of what should I do to fix it?
Additional information:
I'm using python 3.8 and PyCharm IDE
When I scan the generated codes using an Android App, it reads both codes just fine.
I've read this topic: Unicode Encoding and decoding issues in QRCode but it didn't help much
Try to encode the UTF-8 decoded result with shift-jis and decode the result again with UTF-8.
dec_utf[0].data.decode('utf-8').encode('shift-jis').decode('utf-8')
This works at least with your example where the QR code uses UTF-8 as well.
See also https://github.com/NaturalHistoryMuseum/pyzbar/issues/14
Alright! Got some updates:
Short version:
The answer from #user14091216 seems to solve the problem. The line:
dec_utf[0].data.decode('utf-8').encode('shift-jis').decode('utf-8')
does a double-decoding, which fix the problem. I did lots of tests without any error. The new code is down bellow.
What I've tried and found out - Long version:
After talking to some colleagues they suggested that my data was somehow double-encoded. I still don't know why this happens, but for what I've read, it seems to be a problem with pyzbar lib, when it reads data with special characters.
The first thing I've tried was to use the BOM (byte order mark):
Based on my original code, used this lines:
data = '\xEF\xBB\xBF' + 'Thomsôn Gonçalves Ámaral,325.432.123-21'
qr_iso = pyqrcode.create(data) #creates qr code using iso-8859-1 encoding as standard
qr_iso.png(file_iso, scale = 8)
img_iso = Image.open(file_iso)
dec_iso = decode(img_iso)
print(dec_iso[0].data.decode('utf-8'))
And this was the output:
Thomsôn Gonçalves Ámaral,325.432.123-21
Note that even though I created the QR code using 'iso-8859-1' enconding, it only worked when decoded as 'utf-8'.
I also need to treat this data, removing the BOM. Which is easy, but it is an additional step. It worth mentioning that for simpler data (without the special characters), the output didn't have the '' with it.
The solution above works, but at least for me it didn't seem completely right. I was using because I didn't have a better one.
I even try to double decode the data:
Based on 'python double-decoding' searches, I've tried codes like this (and some variations):
dec_iso[0].data.decode('iso-8859-1').encode('raw_unicode_escape').decode('iso-8859-1')
dec_utf[0].data.decode('utf-8).encode('raw_unicode_escape').decode('utf-8)
but none of this worked.
The fix:
As suggested, I tried the following line:
dec_utf[0].data.decode('utf-8').encode('shift-jis').decode('utf-8')
And it worked perfectly. I've tested it with over 1800 data strings without getting a single error.
The QR code generation seems to be fine. This line of code only treats the output data from the pyzbar lib, when it reads the QR image (and it doesn't need to be a QR code created by pyqrcode lib specifically).
I haven't been able to decode QR codes generated with 'iso-8859-1' encoding using the same technique. I might be something related to pyzbar or I simply haven't found out which one is the right pattern for the decode-encode-decode process.
So here's a simple code for creating and reading a QR code, based on utf-8 encoding:
import pyqrcode
from PIL import Image
from pyzbar.pyzbar import decode
data = 'Thomsôn Gonçalves Ámaral,325.432.123-21'
file_utf = 'QR_Utf.png'
#creating QR codes
qr_utf = pyqrcode.create(data, encoding = 'utf-8') #creates qr code using utf-8 encoding
#saving png file
qr_utf.png(file_utf, scale = 8)
#Reading and Identifying QR code
img_utf = Image.open(file_utf)
dec_utf = decode(img_utf)
# Decoding Results:
print(dec_utf[0].data.decode('utf-8').encode('shift-jis').decode('utf-8'))
For more info, see also:
iOS: ZBar SDK unicode characters
https://sourceforge.net/p/zbar/support-requests/21/

what is the best way to save PIL image in json

I'm trying to send json dict that should contain Pillow image as one of his fields, to do that I have to convert the image to string.
I tried to use pillow function:
image.toString()
but still got it as bytes, so I tried to encode it:
buff = BytesIO()
image.save(buff, format="JPEG")
img_str = base64.b64encode(buff.getvalue())
but still got it as bytes.
How can I convert Pillow images to format that can be saved in json file?
In the comments, Mark Setchell suggests calling .decode('ascii') on the result of your b64encode call. I agree that this will work, but I think base64encoding to begin with is introducing an unnecessary extra step that complicates your code.*
Instead, I suggest directly decoding the bytes returned by image.tostring. The only complication is that the bytes object can contain values larger than 128, so you can't decode it with ascii. Try using an encoding that can handle values up to 256, such as latin1.
from PIL import Image
import json
#create sample file. You don't have to do this in your real code.
img = Image.new("RGB", (10,10), "red")
#decode.
s = img.tobytes().decode("latin1")
#serialize.
with open("outputfile.json", "w") as file:
json.dump(s, file)
(*but, to my surprise, the resulting json file is still smaller than one made with a latin1 encoding, at least for my sample file. Use your own judgement to determine whether file size or program clarity is more important.)
I use the following to exchange Pillow images via json.
import json
from PIL import Image
import numpy as np
filename = "filename.jpeg"
image = Image.open(filename)
json_data = json.dumps(np.array(image).tolist())
new_image = Image.fromarray(np.array(json.loads(json_data), dtype='uint8'))

I have a svg file containing data of a qr-code . How do i use it to print qr code on screen using python?

I have a SVG file containing data of a QR-code. How do I use it to print QR code on the screen using python?
what ever you want to create in the qr code just do
first download pyqrcode, pyzbar, pillow with pip like so
$ pip install PyQRCode pyzbar pillow
import the lib
import pyqrcode
from pyzbar.pyzbar import decode
from PIL import Image
then you instantiate the object with a passing data of what you want to encode in the create function
data = pyqrcode.create('hi')
#the data format is import
data.png('qrcode_img.png', scale=2)
#qr code image is created
decoded = decode(Image.open('qrcode_img.png'))
#your output console print contains a list of info encoded in your qrcode
print(decoded)
thanks #OriginalGoldman

how to convert datamatrix code from hubarcode to PILimage

I'm trying to encode a string into a DataMatrix using the hubarcode package. I would like to convert the en object to a PIL image so that I can use it further downstream.
If I read this function correctly, get_pilimage() is defined and I figured en.get_pilimage() should work, but of course doesn't. When I examine dir(en), get_pilimage is not defined (only get_imagedata and get_ascii). Is this because get_pilimage is not defined in __init__.py for DataMatrixRenderer?
This is the code I use
# pip install huBarcode
from hubarcode.datamatrix import DataMatrixEncoder
en = DataMatrixEncoder("M103")
en.get_imagedata() # result below
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00F\x00\x00\x00F\x08\x00\x00\x00\x00TE\xbdX\x00\x00\x00\x9aIDATx\x9c\xed\x98\xc1\n\xc00\x08Cu\xf4\xff\x7f\xb9\xbbM\x16t\xb3\xc3CV\xcc\xc9ayh\x10i\xa7S*t\x94P\x1a\xd3\x98O\x1a\x16\xaa\x88\xc8\\\x89\xca\xab\xd9\x12\xa3\xe6\x95^Q\xe8d\xe83WS\\\x98\x01\xdf\x9e\xa7\x90\xed)^\x13Zl\xfe=\x9b\xddS\x9c\x16Z\x0c\x82\xe5\x01Qy5[b\xdcE\xe1me\xb9G\x96\xad\xacfK\xcc\xcb\x14\x87\xea]\x9cV|\xa3\xc0\x83W\xc2;\xc7\xd5\x14\x17\xc6\xb5\x18\x94x\x00r5\xc5\x85\xc9,\x8a\x84\xf7\\Mqa\xb4\xffQ4\xe6\xf7\x98\x13\xd1\xa9\x1f\x8e\x11\x9b\xc5\x81\x00\x00\x00\x00IEND\xaeB`\x82'
en.get_pilimage() # doesn't work, but I imagine result would be an image
Alternatively, is there another way of converting the result of en.get_imagedata() to png?
I ended up grabbing the raw image string, converting it to BytesIO object and passing the stream to PIL.Image.
import io
import PIL
from hubarcode.datamatrix import DataMatrixEncoder
dm = DataMatrixEncoder("M103")
dm_in_bytes = io.BytesIO(dm.get_imagedata())
img = PIL.Image.open(dm_in_bytes)
img.show()

Categories