I am working on a project where I have a web application frontend = React JS and backend = Django (python). Now I have the task of generating QR codes that will contain JSON with information about the product.
I used the "qrcode" library in python, modified the data appropriately, and saved it using the library's functions in the QR code. When I tried to save the QR to the server and load it, everything works as it should.
Now I need to transfer the QR to the frontend. I would like to try this without saving the QR image on the server, just transferring the data which is then rendered on the frontend.
here is the code I tried BACKEND
:
class generateQR(APIView):
permission_classes = (IsAuthenticated, )
def get(self, request, software_id):
user = request.user
try:
software = Software.objects.get(id=software_id)
location= software.location.all()
namelocation=[l.namefor l in location] # get location.nameatribut from object location
qr_data={
"kcm":software.kcm,
"name":software.name,
"admin":software.admin.name,
"location":name,
}
#print("QR data:",qr_data)
qr=qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data(qr_data)
qr.make(fit=True)
img=qr.make_image(fill_color="black", back_color="white")
img_data=BytesIO()
img_data.seek(0)
#img.save("testQR.png") # save localy to server, I want to avoid it
img.save(img_data) # save to "img_data" the created "img" if I tried "img.save(img_data, format="PNG")" - it failed here
img_data.seek(0) # set BytesIO pointer to the begining
img_binary=img_data.getvalue()
print("img binray: ",str(img_binary))
return Response({"qr": str(img_binary) }, status=status.HTTP_200_OK)
except :
..........code continues ............
and I have this part on the frontend:
{/* .... some code above ....*/}
const generateQRCode=async()=>{
//Call backend endpoint for generate QR code
console.log("sending with id:",id);
try{
const response = await axios.get(API_SOFTWARE+id+"/genQR"); //,{ responseType: 'arraybuffer' }
console.log("resp: ",response.data);
//const dataconverted = new Uint8Array(response.data);
//console.log("converted data: ", dataconverted);
const blob = new Blob([response.data.qr]); //transfer binary to blob , { type: 'image/png' }
console.log("blob: ",blob);
const url = URL.createObjectURL(blob); //create url for show QR
console.log("url: ",url);
setQRCode(url);
}catch (err){
console.log("Error in generating QR code", err);
}
};
{/* ..... code continues ....*/}
{/* Show QR code if it exists */}
{/* ..... in return some code above ....*/}
{QRCode && <img src={QRCode} alt="QR" />}
<Button variant="secondary" onClick={generateQRCode}>
Generate QR
</Button>
{/* ..... code continues ....*/}
When I tried to debug where the problem is I found that I get the same data as generated from the backend in the response.
These data are:
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\xea\x00\x00\x01\xea\x01\x00\x00\x00\x00\xe3\x160\x97\x00\x00\x03\x18IDATx\x9c\xed\xdaIn\xc4 \x10@Q$\x1f\xc0G\xea\xab\xfbH>\x80\xa5JCMx\x88\x94\x86^d\xf1Y$\x1exxS\x02\xaa\xe8"3m+p8\x1c\x0e\x87\xc3\xe1\xf0\xff\xc4\x8b\xb5E\xf2V\xb6\xf5x\xbf\xdd\xebU\xbd\x7f\xd5\xabz\xab\xed\x05\x87O\xf2v#\xfb"\xfe\xb8\xa1z\xbb\xdb@\xef\xabv\xeb_\x80\xc3\xa7\xf9^\xbc\x83\xbc\xbb\x96\xb5F\xee\xda\xdeE\xe4j\x0c/\xd2\x82\x1b\x0e\xff\x1e\x7f\xf7j\x8f-@}\xfa<b\xaa\x84\xc3\xbf\xce\xdf\xa1z\xc4@\x87\xce\x97\xddh/8\xfc{\xbc\xfdK.\xf6\xc7\x17\xedz%>n\n8|\x82G2\xd2\xc5\xe6\xf3\x9f\xc7d\x04\x0e\xff\x9cg\xb3\xf0\xd5\xbd\xa1m\x10=\xf1]\xe4\xda\xe0\xf0q\xde\xbaj\xce\x11]-,3-\x89\xa0\xd5\r"\x1c>\xc7m\xe3\xd7.\x1b_Ero\x98\xa3i\xe4n\xb7\xa9\x12\x0e\xff\x9ck\x87\x12\x89\x87\xf5?\xb4\x97\xff9J\xff\x198|\x8e\xb7yPk.\x12\xa1j\x19\xb1\xf8m|\xe6>U\xc2\xe1\xa3\\\xbc\x7f\xae\xc3\xfd,\xb9\x06\x97K\n\x0c\x87\x0f\xf0\x8cC\x9d k\x13\xd1\xb9\xd1\xd7\xeb\xb6s\xdc<\x86\xf5\xa3p\xf8\x04/YP^s\x8c\xa5C\xfd\xa6\xb1\xb6\x17\x1c>\xc7\xed\x18\xc3\x831\xa5_I\xa4 G\x047\x1c>\xc5m\xaa\xdc\xb3\xc3\xe5,\xad\xd8mL\x9f\xf6U8|\x98\xdb\xe3K\xe2\x11\xcb\xf2y\xbf\xe8\xe1\x0b\x87\xcf\xf1\xcd\x17h{\xbc&\xcf\x99\xb3\xff\x0c\x1c>\xcb\xef\xe8\xe8\xc6\xb5\x12L\xb1,\xf9)\x97\x81\xc3\x07\xb8\x16^|\n\xcc\xea\x9fN\x8b]}\xaf\x14\xab\xd2\xc0\xe1s<\x9f\xe8\xb60r\x93\x8c\xe6\x13\xbf\xad\xefp\xf8\x00\x97\xb6\x0e\xd7\xb6\xdahY\x8c)VZ\xceqs48|\x94[\xa6\xe1E>[\x82#\xf1\xed\xf6\x8b:s\xe6-\x1c>\xcc\xb5\xdc\x12\x99\xee%\x05\x891\xc4\xaa/\xd7\xa0\x85\xc3?\xe7\xa7J\x9f\xef\x12\xbb\x9asd\xbfY\x07\x84\xc3g\xb9\xae\xb9\xf1\x93\x81\x97\xbe\xcbe\xb9\xbd]t\x0c\x9fW\xe1\xf0)n\xc5\xe3\xd5\xc2\xb2\xb5\xb6\x18[\x1e\x9c\xc5\xc0\xbd<\x96\xfb\xe0\xf0\x01.Q}\x119\x97\xf6|\xaal\x19q\\Y\xac\xc3\xe1\xc3\\gI[\x87E\xb3_\x8b\\\x8fW\x1f\xf7)h\xe1\xf0\x01n\xfb@\xef\xaf\xc9\xb0v\x88\xa0\xd5\x05Z\x0f9J\x81\xc3g\xb9\x15Y"hM\x1e\xbaJ\xe7\xf2\xdd\r\t\x87OrKA\xda\xb9\x99\x87\xaf\xe7\xc1mp\xdb\x11Z\xbc^\x8f6\xe0\xf0\x01\x9e\xad\xe81\x86\x97\x91O\x85?\xff\x05U7\x91\xc2\xe1\xc3\xdc\xc3q\xf1<D\xa4\xeb\xdf\xad\xcdy\xaa!p\xf8$\xefz\xf9\x95\xa7\xbb\x0f\x81\\n3-\x1c>\xc0u\x81\x8e\x15Y[\xfex\xa0\xb6U\xfa+8\xfck\xbc\xbd\x96<\xc1\x88\x99\xf3\x94\x9b\xc438\xfc\x0b\\$N\xd0\xf2,C\xba\x17V\x07\xfc-\xe6\xe1\xf0\xbf\xf3\xf6o\xb7\x9c\xc3\x02\xb4\xcbC\xc4\xd3b\xb1b\xe0%h\xe1\xf0\xcf\xb9\xb5S\xba\xb1\xe5\xb3v\x9b\xcb\xf2\xed<\x0e\x0e\xff\x9c\x8f68\x1c\x0e\x87\xc3\xe1p\xf8\x7f\xe1?v\xf5\xeb\xd7Ta4\xa8\x00\x00\x00\x00IEND\xaeB`\x82'
I'm not sure, but this data looks suspicious and I was unable to convert it to an image using online tools.
According to the submitted code above, I think:
I think there is a bug somewhere in storing the data in binary form.
I would be very grateful for any advice or help. Maybe even a different solution than what I have thought of here. Thank you in advance
EDIT:
I tried to reconstruct the binary data into an image:
image=Image.open(BytesIO(img_binary))
image.save("reconstructedQR.png","PNG")
And the reconstructed picture is working so the problem is not in data.
Now I will try to findout if the problem is not in frontend in converting binary to picture.
EDIT 2:
I findout little mistake in received data in response:
There was on the start b'
and on the end '
which are from python binary type. So I deleted it and tried to use these binary daty.
I striped it with:
const binaryDataString=response.data.qr.substring(2, response.data.qr.length - 1);
This successfully works but the converted data in blob
are corupted.
Now I need to findout how to get the image from these data.
EDIT 3:
I chose a different approach for the transfer, namely base64:
img_binary=base64.b64encode(img_data.getvalue()).decode('utf-8')
Now I have to decode it and display on frontend:
console.log("resp: ",response.data.qr);
const binaryDataString=atob(response.data.qr);
const blob = new Blob([binaryDataString]);
const url = URL.createObjectURL(blob);
setQRCode(url);
When I try to decode data in cyberchef
which I console loged. The PNG file is good and it contains QR code which I want!
But the creation of blob and putting it to url is not working and saying that data are corupted.
EDIT 4:
I found out the problem. There is problem in frontend in converting base64 back to binary data. I saved these converted data and compare it with original send from backend and there are some differences in character for example:
‰PNG
--> PNG
&IDATxœíÚKr¬0
--> IDATxíMnë8
And more.... So I need to findout how to convert it without these differencies.
SOLUTION:
I found this Stackoverflow, where is solved creating png from base64 in JavaScript:
So I transformed my frontend code to :
const binaryDataString=atob(response.data.qr);
const byteNumbers = new Array(binaryDataString.length);
for (let i = 0; i < binaryDataString.length; i++) {
byteNumbers[i] = binaryDataString.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], {type: 'image/png'});
const url = URL.createObjectURL(blob);
setQRCode(url);
Just for having it in one place (answer) there is backend:
I prepared my data and saved them with library qrcode
to QR code.
I saved the created QR code (bytes) to variable img_data
then before sending them to the frontend I coded them to base64
.
img_data=BytesIO()
img_data.seek(0)
img.save(img_data)
img_data.seek(0) # set BytesIO pointer to the begining
img_binary=base64.b64encode(img_data.getvalue()).decode('utf-8')
return Response({"qr": (img_binary) }, status=status.HTTP_200_OK)
This is working solution for my project.