I need to take an uploaded JPG from request.FILES, convert it to a GIF thumbnail and then POST it to a 3rd party web service.
import StringIO
import Image
import requests
img_file = request.FILES['files[]'] if request.FILES else None
#create the thumbnail
import StringIO
thumb_buffer = StringIO.StringIO()
im = Image.open(img_file)
im.thumbnail(settings.THUMBNAIL_SIZE)
im.save(thumb_buffer, "GIF")
thumb_buffer.seek(0)
thumb_contents = thumb_buffer.getvalue()
thumb_buffer.close()
#send file via POST request
thumb_upload_dict = {
'upload_file': (filename + '.gif', thumb_contents)}
print thumb_upload_dict
thumb_payload = {
'func': 'upload_file',
'base_id': new_asset.base_id,
'type': 'GIF',
'username': 'remote_admin',
'password': 'we1398fj'
}
r = requests.post(url, params=thumb_payload, files=thumb_upload_dict)
Unfortunately this doesn't work. When I try to view the image I get The image “http://theurl.com/gif_filename.gif” cannot be displayed because it contains errors.
I should note that if I just POST img_file without converting it, it works fine. I'm guessing the problem has to do with thumb_contents but I'm not totally sure.
Related
I am uploading an image to a wordpress site. How can I get the url of the image? The library is at this link. I am sharing the codes. https://python-wordpress-xmlrpc.readthedocs.io/en/latest/ref/methods.html#wordpress_xmlrpc.methods.demo.SayHello
filename = 'C:\\Users\\Image_1.jpg'
prepare metadata
data = {
'name': 'Image_1.jpg',
'type': 'image/jpeg', # mimetype
}
read the binary file and let the XMLRPC library encode it into base64
with open(filename, 'rb') as img:
data['bits'] = xmlrpc_client.Binary(img.read())
response = client.call(media.UploadFile(data))
attachment_id = response['id']
Have a look at the docs you linked: https://python-wordpress-xmlrpc.readthedocs.io/en/latest/ref/methods.html#wordpress_xmlrpc.methods.media.UploadFile
it says that the media.UploadFile method:
Returns: dict with keys id, file (filename), url (public URL), and type (MIME-type).
so you should be able to get the url of uploaded image in response["url"]
For my CS exam I have written a python code to download images from a user account using Graph APIs but I have faced a problem I am not able to fix:
When I open the pic in the browser to download it it is located at the following URL:
https://scontent.fbzo1-2.fna.fbcdn.net/v/t39.30808-6/276154675_133885455881794_6427257905137797718_n.jpg?_nc_cat=108&ccb=1-5&_nc_sid=9267fe&_nc_ohc=YLBzlwDAyFMAX-xSuA2&_nc_ht=scontent.fbzo1-2.fna&oh=00_AT8Id6JhclEoVKJSWjxj2QPFxJJV4AiyuLQRfaEP02-81A&oe=625D705A
but when I open it from a python application it tries to download the pic from a different URL:
https://scontent.fbzo1-2.fna.fbcdn.net/v/t39.30808-6/276154675_133885455881794_6427257905137797718_n.jpg?stp=dst-jpg_s720x720&_nc_cat=108&ccb=1-5&_nc_sid=2d5d41&_nc_ohc=YLBzlwDAyFMAX-xSuA2&_nc_ht=scontent.fbzo1-2.fna&edm=AJfPMC4EAAAA&oh=00_AT8deCIWQLP87HEgyDOa1GIAcGBb9L7bElubSoHzidxvvQ&oe=625D705A
and it has a different resolution from the original!
I will post here some code, if you need the full code, I can add it.
this is the downloading function:
# retrieve the post id to download the image from fb posst
# download and save image from permalink url
def download_and_save_img(img_url, img_name):
# retrieve only the img name / the file extention seams to generate an error -> setting it manualy
last_slash = img_name.rfind('/')
file_ext = img_name.rfind('.')
img_name = img_name[last_slash+1:file_ext]
# download the image with a GET request and write it to an img file
# print(img_url)
img_response = requests.get(img_url)
image = open("fl-tw-fb/" + img_name + '.jpg', "wb")
image.write(img_response.content)
image.close()
And here is the call
response = get_img_link_from_fb_postID(post_id['post_id'])
response_json = json.loads(response)
print(response_json)
img_url = response_json['attachments']['data'][0]['media']['image']['src']
# finaly download the img from fb and save it
download_and_save_img(img_url, line)
when printing the response_json I get:
{
"attachments":{
"data":[
{
"media":{
"image":{
"height":405,
"src":"https://scontent.fbzo1-1.fna.fbcdn.net/v/t39.30808-6/278102009_133887052548301_9150026685369816171_n.jpg?stp=dst-jpg_s720x720&_nc_cat=100&ccb=1-5&_nc_sid=2d5d41&_nc_ohc=WF5mnEaaoKcAX9GxsvH&_nc_ht=scontent.fbzo1-1.fna&edm=AJfPMC4EAAAA&oh=00_AT9T6TUvuRni6TEcLz7oteYsH8E_6yko2FRSEXTH9MPppQ&oe=625BDBB7",
"width":720
}
}
}
]
},
"id":"102956292308044_133887055881634"
}
Any idea?
Edit: adding code for #WizKid:
# retrieve the image link present in a given post_id
def get_img_link_from_fb_postID(post_id):
# (extended) access token
at = 'xxx' # removed
# build the url
url = 'https://graph.facebook.com/v13.0/' + post_id + '?fields=attachments%7Bmedia%7D&access_token=' + at
try:
response = requests.get(url)
except Exception as e:
print(f"Error in get img link from post_id: {e}")
return response.content
def upload_image(request):
if request.is_ajax and request.POST:
image = request.POST.get('image')
image_name = request.POST.get('image_name')
imgdata = base64.b64decode(image + '==')
extension = image_name.split('.')[1].lower()
image_name = '{}_{}_profile_image.{}'.format(request.user.first_name, request.user.last_name, extension)
with open(image_name, "wb") as image_file:
image_file.write(imgdata)
upload = ProfileImage(
file=image_file,
user = request.user.username
)
upload.save()
data = {
}
return JsonResponse(data)
I am trying to crop images in Django using Croppie.js. The images are then uploaded to an S3 bucket.
I have the cropping working and it is returning the image cropped as a base64 string. I decoded it and write it to a new image file so that it could be then saved in the database.
When it it gets to upload.save() I am getting the error.
AttributeError: '_io.BufferedWriter' object has no attribute '_committed'
I'm not sure what the problem is. This is my first time working with base64 images and im not sure if im missing something when i'm converting back to a file or what is going on.
I was able to find a solution by using ContentFile
from django.core.files.base import ContentFile
def upload_image(request):
if request.is_ajax and request.POST:
image = request.POST.get('image')
image_name = request.POST.get('image_name')
extension = image_name.split('.')[1].lower()
image_name = '{}_{}_profile_image.{}'.format(request.user.first_name, request.user.last_name, extension)
imgStr = image.split(';base64')
data = ContentFile(base64.b64decode(imgStr[1]), name=image_name)
upload = Upload(
file=data,
user = request.user.username
)
# Saves upload to S3 bucket
upload.save()
data = {
}
return JsonResponse(data)
It converts the base64 string to a file that is readable by django.
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);
My images are stored in a MongoDB, and I'd like to return them to the client, here is how the code is like:
#app.route("/images/<int:pid>.jpg")
def getImage(pid):
# get image binary from MongoDB, which is bson.Binary type
return image_binary
However, it seems that I can't return binary directly in Flask? My idea so far:
Return the base64 of the image binary. The problem is that IE<8 doesn't support this.
Create a temporary file then return it with send_file.
Are there better solutions?
Create a response object with the data and then set the content type header. Set the content disposition header to attachment if you want the browser to save the file instead of displaying it.
#app.route('/images/<int:pid>.jpg')
def get_image(pid):
image_binary = read_image(pid)
response = make_response(image_binary)
response.headers.set('Content-Type', 'image/jpeg')
response.headers.set(
'Content-Disposition', 'attachment', filename='%s.jpg' % pid)
return response
Relevant: werkzeug.Headers and flask.Response
You can pass a file-like object and the header arguments to send_file to let it set up the complete response. Use io.BytesIO for binary data:
return send_file(
io.BytesIO(image_binary),
mimetype='image/jpeg',
as_attachment=True,
download_name='%s.jpg' % pid)
Prior to Flask 2.0, download_name was called attachment_filename.
Just wanted to confirm that dav1d's second suggestion is correct - I tested this (where obj.logo is a mongoengine ImageField), works fine for me:
import io
from flask import current_app as app
from flask import send_file
from myproject import Obj
#app.route('/logo.png')
def logo():
"""Serves the logo image."""
obj = Obj.objects.get(title='Logo')
return send_file(
io.BytesIO(obj.logo.read()),
download_name='logo.png',
mimetype='image/png'
)
Easier than manually creating a Response object and settings its headers.
Prior to Flask 2.0, download_name was called attachment_filename.
Suppose i have the stored image path with me. The below code helps to send image through.
from flask import send_file
#app.route('/get_image')
def get_image():
filename = 'uploads\\123.jpg'
return send_file(filename, mimetype='image/jpg')
uploads is my folder name where my image with 123.jpg is present.
[PS: The uploads folder should be in the current directory as of the your script file]
Hope it helps.
The following worked for me (for Python 3.7.3):
import io
import base64
# import flask
from PIL import Image
def get_encoded_img(image_path):
img = Image.open(image_path, mode='r')
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format='PNG')
my_encoded_img = base64.encodebytes(img_byte_arr.getvalue()).decode('ascii')
return my_encoded_img
...
# your api code
...
img_path = 'assets/test.png'
img = get_encoded_img(img_path)
# prepare the response: data
response_data = {"key1": value1, "key2": value2, "image": img}
# return flask.jsonify(response_data )