KineticJS toDataURL() gives incorrect padding error in Python - python

I have a base64 string that I've acquired from KineticJS toDataURL(). It's a valid base64 string. This fiddle shows that it is: http://jsfiddle.net/FakRe/
My Problem: I'm sending this dataURI up to my server, decoding using python, and saving on the server. However, I'm getting a padding error. Here's my code:
def base64_to_file(self, image_data, image_name):
extension = re.search('data\:image\/(\w+)\;', image_data)
if extension:
ext = extension.group(1)
image_name = '{0}.{1}'.format(image_name, ext)
else:
# it's not in a format we understand
return None
image_data = image_data + '=' #fix incorrect padding
image_path = os.path.join('/my/image/path/', image_name)
image_file = open(image_path, 'w+')
image_file.write(image_data.decode('base64'))
image_file.close()
return image_file
I can get around this padding error by doing this at the top of my function:
image_data = image_data + '=' #fixes incorrect padding
After I add the arbitrary padding, it decodes successfully and writes to the filesystem. However, whenever I try and view the image, it doesn't render, and gives me the 'broken image' icon. No 404, just a broken image. What gives? Any help would be greatly appreciated. I've already spent way too much time on this as it is.
Steps to recreate (May be pedantic but I'll try and help)
Grab the base64 string from the JSFiddle
Save it to a text file
Open up the file in python, read in the data, save to variable
Change '/path/to/my/image' in the function to anywhere on your machine
Pass in your encoded text variable into the function with an name
See the output
Again, any help would be awesome. Thanks.

If you need to add padding, you have the wrong string. Do make sure you are parsing the data URI correctly; the data:image/png;base64, section is metadata about the encoded value, only the part after the comma is the actual Base64 value.
The actual data portion is 223548 characters long:
>>> len(image_data)
223548
>>> import hashlib
>>> hashlib.md5(image_data).hexdigest()
'03918c3508fef1286af8784dc65f23ff'
If your URI still includes the data: prefix, do parse that out:
from urllib import unquote
if image_data.startswith('data:'):
params, data = image_data.split(',', 1)
params = params[5:] or 'text/plain;charset=US-ASCII'
params = params.split(';')
if not '=' in params[0] and '/' in params[0]:
mimetype = params.pop(0)
else:
mimetype = 'text/plain'
if 'base64' in params:
# handle base64 parameters first
data = data.decode('base64')
for param in params:
if param.startswith('charset='):
# handle characterset parameter
data = unquote(data).decode(param.split('=', 1)[-1])
This then lets you make some more informed decisions about what extension to use for image URLs, for example, as you now have the mimetype parsed out as well.

Related

decoding base64 encoded image in Flask

My Flask app is receives base64 encoded images like so
`b'"{\\"image\\": \\"/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyU...opHNf//Z\\", \\"id\\": \\"e3ad9809-b84c-57f1-bd03-a54e25c59bcc\\"}"'
I have tried a number of ways but I cannot seem to get the image bytes for decoding. If I json.loads this it becomes a string. If I treat it as a bytes dictionary it doesn't take the key and asks it to be an integer which will not work of course. I have tried many things, this is just one other which doesn't work. Any help is appreciated, Thanks.
def main():
try:
p = randint(100, 200)
image = request.data
jsonResponse = json.loads(image.decode('utf-8'))
im = base64.decode(jsonResponse)
print(im)
with open(f'Image{p}.jpg', 'wb') as f:
f.write(im)
If you use request context (from flask import request), then you can access the sended data as a python dictionary using the request.json attribute instead of the request.data.
To get the dictionary as you wish from the example you provided, a double call to json.loads solved the problem:
import json
data = b'"{\\"image\\": \\"/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyU...opHNf//Z\\", \\"id\\": \\"e3ad9809-b84c-57f1-bd03-a54e25c59bcc\\"}"'
data_as_dictionary = json.loads(json.loads(data))
It seems like because your data has the leading " and the trailing ", json.loads is parsing it as a string (which is a valid json) and that's why you don't get the dictionary you want in the first call to json.loads.
import json
import base64
from codecs import encode
request = b'"{\\"image\\": \\"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\\", \\"id\\": \\"e3ad9809-b84c-57f1-bd03-a54e25c59bcc\\"}"'
data_as_dictionary = json.loads(json.loads(request.decode('utf-8')))
base64_img = data_as_dictionary['image']
bytes_img = encode(base64_img, 'utf-8')
binary_img = base64.decodebytes(bytes_img)
with open("imageToSave.jpg", "wb") as fh:
fh.write(binary_img)
you need several steps. first of all, you should transform request data into a python dictionary then take the image as base64 then encode it in bytes array then as binary, and last save it.
The above code works well.

How to build an image from an str containing the binary data?

I have a byte string, and trying to convert it into a file but I keep getting an error:
OS Error cannot identify image file <_io.BytesIO object at 0x03BBD330>
The code that I've implemented is below:
def test_view(request):
with open("test_json.json") as imageFile:
b=bytearray(json.load(imageFile)["IMAGE_DATA"], 'utf8')
print(b)
image = Image.open(io.BytesIO(b))
response = HttpResponse(content_type="image/jpeg")
image.save(response, "JPEG")
return response
The byte string is read from a json file, it looks like this, but it is much longer, I've just copied some characters.
"b'\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\x00\\x01\\x01\\x01\\x00`\\x00`\\x00\\x00\\xff\\xdb\\x00C\\x00\\x05\\x04\\x04\\x04\\x04\\x03\\x05\\x04\\x04\\x04\\x06\\x05\\x05\\x06\\x08\\r\\x08\\x08\\x07\\x07\\x08\\x10\\x0b\\x0c\\t\\r\\x13\\x10\\x14\\x13\\x12\\x10\\x12\\x12\\x14\\x17\\x1d\\x19\\x14\\x16\\x1c\\x16\\x12\\x12\\x1a#\\x1a\\x1c\\x1e\\x1f!!!\\x14\\x19$\\'$ &\\x1d ! \\xff\\xdb\\x00C\\x01\\x05\\x06\\x06\\x08\\x07\\x08\\x0f\\x08\\x08\\x0f \\x15\\x12\\x15 \\xff\\xc0\\x00\\x11\\x08\\x01&\\x02q\\x03\\x01\"\\x00\\x02\\x11\\x01\\x03\\x11\\x01\\xff\\xc4\\x00\\x1f\\x00\\x00\\x01\\x05\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\xff\\xc4\\x00\\xb5\\x10\\x00\\x02\\x01\\x03\\x03\\x02\\x04\\x03\\x05\\x05\\x04\\x04\\x00\\x00\\x01}\\x01\\x02\\x03\\x00\\x04\\x11\\x05\\x12!1A\\x06\\x13Qa\\x07\"q\\x142\\x81\\x91\\xa1\\x08#B\\xb1\\xc1\\x15R\\xd1\\xf0$3br\\x82\\t\\n\\x16\\x17\\x18\\x19\\x1a%&\\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xff\\xc4\\x00\\x1f\\x01\\x00\\x03\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\xff\\xc4\\x00\\xb5\\x11\\x00\\x02\\x01\\x02\\x04\\x04\\x03\\x04\\x07\\x05\\x04\\x04\\x00\\x01\\x02w\\x00\\x01\\x02\\x03\\x11\\x04\\x05!1\\x06\\x12AQ\\x07aq\\x13\"2\\x81\\x08\\x14B\\x91\\xa1\\xb1\\xc1\\t#3R\\xf0\\x15br\\xd1\\n\\x16$4\\xe1%\\xf1\\x17\\x18\\x19\\x1a&\\'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99'"
I am not entirely sure what exactly is the best solution to this issue because the problem you're running into is that json.load(imageFile)["IMAGE_DATA"] is going to return "b'bytes'", which when it converts to bytearray, you're doing bytearray("b\'bytes\'"), which is wrong.
Also this behavior is specific between JSON parsers, and different JSON parsers might interpret differently
Either strip the b'' that's wrapping your bytestring, or do an ast.literal_eval()
def test_view(request):
with open("test_json.json") as imageFile:
b = bytearray(
ast.literal_eval(
json.load(imageFile)["IMAGE_DATA"], 'utf8')
print(b)
image = Image.open(io.BytesIO(b))
response = HttpResponse(content_type="image/jpeg")
image.save(response, "JPEG")
return response

Decode Base64 after it has been saved as a string object?

I am fairly new to Python and am attempting to compile a text (.txt) document that acts as a save file and can be loaded later.
I would like it to be a standalone document that holds all attributes the user is working with (including some images that I would like to be saved in the file as encoded base64 binary strings).
I have written the program and it saves everything to the text file correctly (although I did have to pass the encoded values through a str()) but I am unable to access the images later for decoding. Here is an example of my creation of the text information:
if os.path.isfile("example.png"): #if the user has created this type of image..
with open("example.png", "rb") as image_file:
image_data_base64_encoded_string = base64.b64encode(image_file.read())
f = open("example_save.txt",'a+')
f.write("str(image_data_base64_encoded_string)+"\n")
f.close() #save its information to the text doc
And here is an example of one of my many attempts to re-access this information.
master.filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = ((".txt files","*.txt"),("all files","*.*")))
with open(master.filename) as f:
image_import = ((f.readlines()[3]))#pulling the specific line the data string is in
image_imported = tk.PhotoImage(data=image_import)
This is only my most recent attempt of many - and still returns an error. I tried decoding the encoded information before passing to the tkinter PhotoImage function but I think that Python may be seeing the encoded information as a string (since I made it one when I saved the information) but I do not know how to change it back without altering the information.
Any help would be appreciated.
I would recommend using Pillow module for working with images but if you insist on your current way try this code below:
from tkinter import *
import base64
import os
if os.path.isfile("example.png"): #if the user has created this type of image..
with open("example.png", "rb") as image_file:
image_data_base64_encoded_string = base64.b64encode(image_file.read())
f = open("example_save.txt",'a+')
f.write(image_data_base64_encoded_string.decode("utf-8")+"\n")
f.close()
filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = ((".txt files","*.txt"),("all files","*.*")))
with open(filename) as f:
image_import = f.readlines()[3].strip()
image_imported = PhotoImage(data=image_import)
You see your string needs to be utf-8 and that trailing newline character is also preventing PhotoImage() from interpreting your image data as image.
When you write out the value as such:
str(image_data_base64_encoded_string)
That's writing it as follows:
b'...blah...'
Look at the file you're writing, you'll find that line is surrounded by b' '.
You want to decode the binary into the appropriate encoding for your file, for example:
f.write(image_data_base64_encoded_string.decode('utf-8') + "\n")

Load image from base64 encoded image in Gtk3+

The main problem is that, from what I could find, there is no easy/documented way to load an image from base64 encoded image. I use the following code to encode the image to base64 (so that I wouldn't need to include all the images with the source, nor should I create temp files and delete them at exit). The image format I use is .png which is supported in Gtk3+. (from GdkPixbuf.Pixbuf.get_formats() i have ['png'] in the results. I am really confused on how to use Gtk3+ for this purpose.
import base64
image_name = 'image.png'
image_loc = 'd:\\Home\\' + image_name
with open(image_loc, 'rb') as image_file:
encoded_string = base64.b64encode(image_file.read())
print(encoded_string)
I want to use the output for example:
base64_data="""
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABsklEQVRYhe2XIVMCQRSAv2AwGAgEAuFmJBiMFmcMBH8AgUAgXHDMFww2gtFA
IBicsRgNBgLBcS7yE4gEIsFgIBDO8Pa8x7FwB7cnxTfzyr637327b+/dLiTSBIbAHIgydAGMgAscyUOOpDZdAu2iyZsq4BcwAHpb9NE1xFAl
P8s558klRFzzwQ5zejgsRxygVxBgbwiXAHtBuAaIIa7KBAgyACJgBlTKAqgBH8A0pWmIXKXYB2CbdFRM/xAA3qEBKipm8A9wCIAa8q/oUOJn
6FTKAqgA10gZWkD9rwAugRfWm1IEfCKlKQ2ghdwrstp0vwyAuiX5HGnRMwtE1zVAfLPS6hubZ7HNgaorgFPkppxOEvcBG0AE3LoCuGZ1Zb7R
hrGfqLGJ8h24ArhTcaYZvqHyDV0BtFWcGbLlHrJygCM1Nla+r5Cc0OcCAA3sNfaN3dtgDwDeSO5xzQIQthvRNoAlcA7yGFmowTFSmzz6jmwv
rL6wYp0Yv7HFttKMusC3xSmP3qs4/ZxzJiTn41c85N032mEHQqQBHacWs+mFvTSQa8ldSxW4Qb7zEDntAabmWn4A0clKl9nNvDwAAAAASUVO
RK5CYII
"""
And render the image from base64.
As a side note, on tkinter this was easily done with:
tkinter.PhotoImage(data=base64_data)
And then display the image where you needed it.
Getting back to Gtk3+, I didn't find a method of loading the image from base64. Even with GdkPixbuf.Pixbuf.new_from_data, I get a broken image. I have also tried with Gio.MemoryInputStream.new_from_bytes, but it says that the format of the image isn't supported.
Your data is base64 encoded, in order for Gtk3+ to use it, you must first decode it:
import base64
raw_data = base64.b64decode(data)
Then you were right with GdkPixbuf.Pixbuf.new_from_data:
(I cannot test, but I think this may work)
import base64
raw_data = base64.b64decode(data)
image = GdkPixbuf.Pixbuf.new_from_data(raw_data)
image_show_2.set_from_pixbuf(image)
Else you can do as you showed:
import base64
raw_data = base64.b64decode(data)
byting = GLib.Bytes(raw_data)
inputing = Gio.MemoryInputStream.new_from_bytes(byting)
image = GdkPixbuf.Pixbuf.new_from_data(inputing)
image_show_2.set_from_pixbuf(image)

How to get image file size in python when fetching from URL (before deciding to save)

import urllib.request,io
url = 'http://www.image.com/image.jpg'
path = io.BytesIO(urllib.request.urlopen(url).read())
I'd like to check the file size of the URL image in the filestream path before saving, how can i do this?
Also, I don't want to rely on Content-Length headers, I'd like to fetch it into a filestream, check the size and then save
You can get the size of the io.BytesIO() object the same way you can get it for any file object: by seeking to the end and asking for the file position:
path = io.BytesIO(urllib.request.urlopen(url).read())
path.seek(0, 2) # 0 bytes from the end
size = path.tell()
However, you could just as easily have just taken the len() of the bytestring you just read, before inserting it into an in-memory file object:
data = urllib.request.urlopen(url).read()
size = len(data)
path = io.BytesIO(data)
Note that this means your image has already been loaded into memory. You cannot use this to prevent loading too large an image object. For that using the Content-Length header is the only option.
If the server uses a chunked transfer encoding to facilitate streaming (so no content length has been set up front), you can use a loop limit how much data is read.
Try importing urllib.request
import urllib.request, io
url = 'http://www.elsecarrailway.co.uk/images/Events/TeddyBear-3.jpg'
path = urllib.request.urlopen(url)
meta = path.info()
>>>meta.get(name="Content-Length")
'269898' # ie 269kb
You could ask the server for the content-length information. Using urllib2 (which I hope is available in your python):
req = urllib2.urlopen(url)
meta = req,info()
length_text = meta.getparam("Content-Length")
try:
length = int(length_text)
except:
# length unknown, you may need to read
length = -1

Categories

Resources