Decoding base64 from POST to use in PIL - python

I'm making a simple API in Flask that accepts an image encoded in base64, then decodes it for further processing using Pillow.
I've looked at some examples (1, 2, 3), and I think I get the gist of the process, but I keep getting an error where Pillow can't read the string I gave it.
Here's what I've got so far:
import cStringIO
from PIL import Image
import base64
data = request.form
image_string = cStringIO.StringIO(base64.b64decode(data['img']))
image = Image.open(image_string)
which gives the error:
IOError: cannot identify image file <cStringIO.StringIO object at 0x10f84c7a0>

You should try something like:
from PIL import Image
from io import BytesIO
import base64
data['img'] = '''R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLl
N48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw=='''
im = Image.open(BytesIO(base64.b64decode(data['img'])))
Your data['img'] string should not include the HTML tags or the parameters data:image/jpeg;base64 that are in the example JSFiddle.
I've changed the image string for an example I took from Google, just for readability purposes.

There is a metadata prefix of data:image/jpeg;base64, being included in the img field. Normally this metadata is used in a CSS or HTML data URI when embedding image data into the document or stylesheet. It is there to provide the MIME type and encoding of the embedded data to the rendering browser.
You can strip off the prefix before the base64 decode and this should result in valid image data that PIL can load (see below), but you really need to question how the metadata is being submitted to your server as normally it should not.
import re
import cStringIO
from PIL import Image
image_data = re.sub('^data:image/.+;base64,', '', data['img']).decode('base64')
image = Image.open(cStringIO.StringIO(image_data))

Sorry for necromancy, but none of the answers worked completely for me. Here is code working on Python 3.6 and Flask 0.13.
Server:
from flask import Flask, jsonify, request
from io import BytesIO
from web import app
import base64
import re
import json
from PIL import Image
#app.route('/process_image', methods=['post'])
def process_image():
image_data = re.sub('^data:image/.+;base64,', '', request.form['data'])
im = Image.open(BytesIO(base64.b64decode(image_data)))
return json.dumps({'result': 'success'}), 200, {'ContentType': 'application/json'}
Client JS:
// file comes from file input
var reader = new FileReader();
reader.onloadend = function () {
var fileName = file.name;
$.post('/process_image', { data: reader.result, name: fileName });
};
reader.readAsDataURL(file);

Related

Read and use image requested from url in Python

I'm currently trying to work with Google's python vision library. But I'm currently stuck on how to read images from the web. So far I've got this here down below. My issue is that the contents always seem to be empty and when I check using PyCharm, it says that it only contains b''.
How can I open this image so I can use it for Google's library?
from google.cloud import vision
from google.cloud.vision import types
from urllib import request
import io
client = vision.ImageAnnotatorClient.from_service_account_json('cred.json')
url = "https://cdn.getyourguide.com/img/location_img-59-1969619245-148.jpg"
img = request.urlopen(url)
with io.open('location_img-59-1969619245-148.jpg', 'rb') as fhand:
content = fhand.read()
image = types.Image(content=content)
response = client.label_detection(image=image)
labels = response.label_annotations
print('Labels:')
for label in labels:
print(label.description)
Do you try get image via requests library?
import requests
r = requests.get("https://cdn.getyourguide.com/img/location_img-59-1969619245-148.jpg")
o = open("location_img.jpg", "wb")
o.write(r.content)
o.close()

Flask to Numpy Image Conversion

I have been trying to send an image over javascript to a Flask server to draw bounding boxes on coordinates I received from my own API. How might I convert this to a numpy array?
I was thinking of using the cv2.imdecode feature, but I don't want to download that huge file on my server. Here is an example of the input string src i am sending to flask:
data:image/jpeg;base64,IMGDATA HERE
I believe that this string is base64 encoded, but I am not sure how to make this conversion in python.
I have done something similar to this. If you have your url, then you first have to decode the IMGDATA part of the src string, which is base64 encoded. So first you need to separate IMGDATA from the inputstring. This can be done using:
import base64
imgdata = imgsrcstring.split(',')[1]
decoded = base64.b64decode(imgdata)
Then you can use the PIL Libarary to convert the Bytes representation of the string to an image, which can then be converted to a numpy array:
from PIL import Image
from io import BytesIO
img = np.array(Image.open(BytesIO(decoded)))
def upload_file():
if request.method == 'POST':
f = request.files['file'].read()
# print(f)
npimg = np.fromstring(f,np.uint8)
img = cv2.imdecode(npimg,cv2.IMREAD_COLOR)
img = Image.fromarray(img.astype("uint8"))
#do anything with image here
rawBytes = io.BytesIO()
img.save(rawBytes, "JPEG")
rawBytes.seek(0)
img_base64 = base64.b64encode(rawBytes.getvalue()).decode('ascii')
mime = "image/jpeg"
uri = "data:%s;base64,%s"%(mime, img_base64)
return render_template("./template/output.html",image=uri)
this will read image from the javascript code and after you have performed operations will return image which can be passed in HTML page given you assign placeholder for the image on the page.

A clean way to read a multi-band tiff file from URL?

I have a web service from which I want to load a multi-band image in-memory inside a Python script (ultimately I'll be converting the image into a numpy array). As far as I know packages such as PIL and imageio don't support this.
What is the preferred way of doing this? I want to avoid saving and reading images to disk.
If I save the file to disk and then load as a multi-band tiff with tifffile package things work fine (see code below); but, as I said, I want to avoid reading/writing from/to disk.
import requests
import tifffile as tiff
TMP = 'tmp.tiff'
def save_img(url, outfilename):
resp = requests.get(url)
with open(outfilename, 'wb') as f:
f.write(resp.content)
def read_img(url):
save_img(url, TMP)
return tiff.imread(TMP)
The following snippet does the trick. (Note that one should do some additional error checking on response object.)
import requests
import tifffile as tiff
import io
def read_image_from_url(url):
resp = requests.get(url)
# Check that request succeeded
return tiff.imread(io.BytesIO(resp.content))
I'm not sure about multi-band images -- if Pillow (née PIL) supports them, fine -- but this is the basic method to load images from URLs in-memory using Requests and Pillow:
import requests
from PIL import Image
from io import BytesIO
resp = requests.get('https://i.imgur.com/ZPXIw.jpg')
resp.raise_for_status()
sio = BytesIO(resp.content) # Create an in-memory stream of the content
img = Image.open(sio) # And load it
print(img)
outputs
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=605x532>

Broken image when decoding base64 string

I'm trying to send a user image from my iOS app to a Python script through Firebase by creating a base64 string from the image and then posting that string to Firebase and decoding it in Python. However, a corrupted image is produced. How do I fix this? Here is my Swift code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
var byteArray = NSData()
if let file = info[UIImagePickerControllerOriginalImage] as? UIImage {
byteArray = UIImageJPEGRepresentation(file, 1.0)!
}
let b64 = byteArray.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
FIRDatabase.database().reference().child("dataUploaded").setValue(b64)
uploaded = true
dismissViewControllerAnimated(true, completion: nil)
}
And then the Python code:
from firebase import firebase
import os
from PIL import Image
import numpy as np
import io
fb = firebase.FirebaseApplication("https://xxxxxx.firebaseio.com/", None)
a = fb.get('/dataUploaded', None)
filename = 'image.png'
with open(filename, 'wb') as f:
f.write(a)

Python image processing of picture directly from the web

I am writing python code to take an image from the web and calculate the standard deviation, ... and do other image processing with it. I have the following code:
from scipy import ndimage
from urllib2 import urlopen
from urllib import urlretrieve
import urllib2
import Image
import ImageFilter
def imagesd(imagelist):
for imageurl in imagelist:
opener1 = urllib2.build_opener()
page1 = opener1.open(imageurl)
im = page1.read()
#localfile = urlretrieve(
#img = Image.fromstring("RGBA", (1,1), page1.read())
#img = list(im.getdata())
# page1.read()
print img
#standard_deviation(p
Now I keep going back and forth because I am not sure how to take the image directly from the web, without saving it to disk, and passing it to the standard deviation function.
Any hints/help would be greatly appreciated.
Thanks.
PIL (Python Imaging Library) methods "fromstring" and "frombuffer" expect the image data in a raw, uncompacted, format.
When you do page1.read() you get the binary file data. In order to have PIL understanding it, you have to make this data mimick a file, and pass it to the "Image.open" method, which understands the file format as it is read from the web (i.e., the .jpg, gif, or .png data instead of raw pixel values)
Try something like this:
from cStringIO import StringIO
(...)
data = StringIO(page1.read())
img = Image.open(data)

Categories