I'm trying to upload an image to the Face.com API. It either takes a url to an image, or images can be uploaded directly. Their website says:
A requests that uploads a photo must be formed as a MIME multi-part
message sent using POST data. Each argument, including the raw image
data, should be specified as a separate chunk of form data.
Problem is, I don't know exactly what that means. Right now my code looks like this:
import urllib
import json
apikey = "[redacted]"
secret = "[redacted]"
img = raw_input("Enter the URL of an image: ");
url = "http://api.face.com/faces/detect.json?api_key=" + apikey + "&api_secret=" + secret + "&urls=" + urllib.quote(img) + "&attributes=all"
data = json.loads(urllib.urlopen(url).read())
How can I convert this to work with a locally stored image?
The easiest way to upload photo in Python to face.com API is just using the Python Client Library that can be downloaded form http://developers.face.com/download/.
You got 2 there. Both support uploading by passing filename to the detected method (as a different param than the urls).
Related
I want to upload images from the mobile application to my Firestore using a Flask API.
The app is uploading a list of int that represents the image. The length of the list is really long, over a thousand I believe.
I'm sending this list of ints in the request json.
How can I upload this list of ints to Firebase storage using the Firebase module for Flask.
Is using a list of ints to upload the image even the correct way?
If not, how can I upload the image using the Flask API?
This the code I have so far, and it's a mess :) :
def post(self):
request_data = request.get_json()
baqala_id = request_data["userID"]
imageBytes = request_data["imageBytes"]
# imageFile = request_data["imageFile"]
bucket = storage.bucket("bucket_name.appspot.com")
blob = bucket.blob(f"{baqala_id}/{imageBytes}")
# blob = bucket.blob(f"{baqala_id}/{imageFile}")
upload = blob.upload_from_string(imageBytes)
# upload = blob.upload_from_file(imageFile)
return {"message": "upload succesfull"}, 200
Note: I can't using the Firebase plugin for Flutter because it's too slow and cannot be used in a separate Isolate.
I'm trying to create a simple serverless function in AWS with a Gateway API that allows uploading an image to the server, it should then save the image in a S3 bucket.
This is my code:
def lambda_handler(event, context):
operation = event['httpMethod']
if operation != 'PUT':
return respond(ValueError('Unsupported method "{}"'.format(operation)))
try:
queryParameters = event['queryStringParameters']
username = queryParameters['username']
picturename = username + "_image"
print("picture name: " + picturename)
fileContent = event['body']
print("body size: " + str(len(fileContent)))
object = s3.Object('zoneuserimagesbucket', picturename)
object.put(Body=fileContent)
return respond(None, "OK")
The image being save is twice as big as the original and not the same as the original.. What I'm missing?
Looks like you have a base64 encoded data in event.body.
There are two ways to overcome this situation.
Option 1 (easy)
Check event.isBase64Encoded - if it's set to true, base64.decode event.content to get a bytes object to write to S3.
Option 2 (needs config and time)
API Gateway could decode the data for you, if asked.
This has the benefit your lambda function will need less memory and time to run, which is great in the long term
Steps:
1 - Decide how you want API Gateway to encode binary data for you (base64, raw) etc. If you receive the data as you want, your lambda will need less memory and time to run.
2 - Decide the 'field' in the request where you want your data to come (instead of just ´event.body´).
3 - Verify you have in API Gateway a media encoding defined for the field you want. For images: image/jpeg, image/png, image/gif, etc.
3 - Check that you have the correct mediaHandling in the responseTemplate:
CONVERT_TO_BINARY: Transcode it binary data if it's in base64.
CONVERT_TO_TEXT: Transcode the data as base64.
Related documentation:
See the [announce in the AWS blog post (https://aws.amazon.com/es/blogs/compute/binary-support-for-api-integrations-with-amazon-api-gateway/)
and AWS API Gateway Payload Encodings.
I'm trying to create a blobstore entry from an image data-uri object, but am getting stuck.
Basically, I'm posting via ajax the data-uri as text, an example of the payload:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPA...
I'm trying to receive this payload with the following handler. I'm assuming I need to convert the data-uri back into an image before storing? So am using the PIL library.
My python handler is as follows:
import os
import urllib
import webapp2
from google.appengine.ext.webapp import template
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.api import images
class ImageItem(db.Model):
section = db.StringProperty(required=False)
description = db.StringProperty(required=False)
img_url = db.StringProperty()
blob_info = blobstore.BlobReferenceProperty()
when = db.DateTimeProperty(auto_now_add=True)
#Paste upload handler
class PasteUpload(webapp2.RequestHandler):
def post(self):
from PIL import Image
import io
import base64
data = self.request.body
#file_name = data['file_name']
img_data = data.split('data:image/png;base64,')[1]
#Convert base64 to jpeg bytes
f = Image.open(io.BytesIO(base64.b64decode(img_data)))
img = ImageItem(description=self.request.get('description'), section=self.request.get('section') )
img.blob_info = f.key()
img.img_url = images.get_serving_url( f.key() )
img.put()
This is likely all kinds of wrong. I get the following error when posting:
img.blob_info = f.key()
AttributeError: 'PngImageFile' object has no attribute 'key'
What am I doing wrong here? Is there an easier way to do this? I'm guessing I don't need to convert the data-uri into an image to store as a blob?
I also want this Handler to return the URL of the image created in the blobstore.
There are a couple of ways to view your question and the sample code you posted, and it's a little confusing what you need because you are mixing strategies and technologies.
POST base64 to _ah/upload/...
Your service uses create_upload_url() to make a one-time upload URL/session for your client. Your client makes a POST to that URL and the data never touches your service (no HTTP-request-size restrictions, no CPU-time spent handling the POST). An App Engine internal "blob service" receives that POST and saves the body as a Blob in the Blobstore. App Engine then hands control back to your service in the BlobstoreUploadHandler class you write and then you can determine how you want to respond to the successful POST. In the case of the example/tutorial, PhotoUploadHandler redirects the client to the photo that was just uploaded.
That POST from your client must be encoded as multipart/mixed and use the fields shown in the example HTML <form>.
The multipart form can take the optional parameter, Content-Transfer-Encoding, and the App Engine internal handler will properly decode base64 data. From blob_upload.py:
base64_encoding = (form_item.headers.get('Content-Transfer-Encoding') ==
'base64')
...
if base64_encoding:
blob_file = cStringIO.StringIO(base64.urlsafe_b64decode(blob_file.read()))
...
Here's a complete multipart form I tested with cURL, based on the fields used in the example. I found out how to do this over at Is there a way to pass the content of a file to curl?:
myconfig.txt:
header = "Content-length: 435"
header = "Content-type: multipart/mixed; boundary=XX
data-binary = "#myrequestbody.txt"
myrequestbody.txt:
--XX
Content-Disposition: form-data; name="file"; filename="test.gif"
Content-Type: image/gif
Content-Transfer-Encoding: base64
R0lGODdhDwAPAIEAAAAAzMzM/////wAAACwAAAAADwAPAAAIcQABCBxIsODAAAACAAgAIACAAAAiSgwAIACAAAACAAgAoGPHACBDigwAoKTJkyhTqlwpQACAlwIEAJhJc6YAAQByChAAoKfPn0CDCh1KtKhRAAEAKF0KIACApwACBAAQIACAqwECAAgQAIDXr2DDAggIADs=
--XX
Content-Disposition: form-data; name="submit"
Submit
--XX--
and then run like:
curl --config myconfig.txt "http://127.0.0.1:8080/_ah/upload/..."
You'll need to create/mock-up the multipart form in your client.
Also, as an alternative to Blobstore, you can use Cloud Storage if you want to save a little on storage costs or have some need to share the data without your API. Follow the documentation for Setting Up Google Cloud Storage, and then modify your service to create the upload URL for your bucket of choice:
create_upload_url(gs_bucket_name=...)
It's a little more complicated than just that, but reading the section Using the Blobstore API with Google Cloud Storage in the Blobstore document will get you pointed in the right direction.
POST base64 directly to your service/handler
Kind of like you coded in the original post, your service receives the POST from your client and you then decide if you need to manipulate the image and where you want to store it (Datastore, Blobstore, Cloud Storage).
If you need to manipulate the image, then using PIL is good:
from io import BytesIO
from PIL import Image
from StringIO import StringIO
data = self.request.body
#file_name = data['file_name']
img_data = data.split('data:image/png;base64,')[1]
# Decode base64 and open as Image
img = Image.open(BytesIO(base64.b64decode(img_data)))
# Create thumbnail
img.thumbnail((128, 128))
# Save img output as blob-able string
output = StringIO()
img.save(output, format=img.format)
img_blob = output.getvalue()
# now you choose how to save img_blob
If you don't need to manipulate the image, just stop at b64decode():
img_blob = base64.b64decode(img_data)
An image object (https://cloud.google.com/appengine/docs/standard/python/refdocs/google.appengine.api.images) isn't a Datastore entity, so it has no key. You need to actually save the image to blobstore[2] or Google Cloud Storage[1] then get a serving url for your image.
[1] https://cloud.google.com/appengine/docs/standard/python/googlecloudstorageclient/setting-up-cloud-storage
[2] https://cloud.google.com/appengine/docs/standard/python/blobstore/
Goal: Take/attach pictures in a PhoneGap application and send a public URL for each picture to a Google Cloud SQL database.
Question 1: Is there a way to create a Google Cloud Storage object from a base64 encoded image (in Python), then upload that object to a bucket and return a public link?
I'm looking to use PhoneGap to send images to a Python Google App Engine application, then have that application send the images to a Google Cloud Storage bucket I have set up, then return a public link back to the PhoneGap app. These images can either be taken directly from the app, or attached from existing photo's on the user's device.
I use PhoneGap's FileTransfer plugin to upload the images to GAE, which are sent as base64 encoded images (this isn't something I can control).
Based on what I've found in Google Docs, I can upload the images to Blobstore; however, it requires <input type='file'> elements in a form. I don't have 'file' input elements; I just take the image URI returned from PhoneGap's camera object and display a thumbnail of the picture that was taken (or attached).
Question 2: Is it possible to have an <input type='file'> element and control it's value? As in, is it possible to set it's value based on whether the user chooses a file, or takes a picture?
Thanks in advance!
Here's a solution for others who might face this problem. Turns out it's incredibly simple!
Once you have a bucket setup for your GAE project, you can use this Python code to send an image to the bucket:
import cloudstorage as gcs
import webapp2
import cgi
import MySQLdb
import os
import logging
import time
from google.appengine.api import mail
from google.appengine.api import images
from google.appengine.ext import blobstore
class UploadImageHandler(webapp2.RequestHandler):
def post(self):
self.response.headers.add_header(ACCESS_CONTROL, '*')
f = self.request.POST['image']
fname = '/your-bucket-name/%s' % f.filename;
gcs_file = gcs.open(fname, 'w', content_type="image/jpeg")
gcs_file.write(self.request.get('image'))
gcs_file.close()
And the code used to upload the file from a PhoneGap application:
// Uploads images in "imageURIs" to the web service specified in "server".
function uploadImages(imageURIs, server) {
var success = function(data) {
alert("Successfully uploaded image!");
};
var fail = function(error) {
alert("Failed to upload image: "+error);
};
var options = new FileUploadOptions();
options.fileKey = "image";
options.mimeType = "image/jpeg";
var ft = new FileTransfer();
for (var i = 0; i < imageURIs.length; i++) {
alert("Uploading"+i);
options.fileName = imageURIs[i].substr(imageURIs[i].lastIndexOf('/') + 1);
ft.upload(imageURIs[i], encodeURI(server), success, fail, options);
}
}
I hope it helps someone else. :)
Yes, that is a fine use for GAE and GCS. You do not need an <input type=file>, per se. You can just set up POST parameters in your call to your GAE url. Make sure you send a hidden key as well, and work from SSL-secured urls, to prevent spammers from posting to your app.
I'm currently working on an augmented reality app using Django and the Vuforia SDK.
Vuforia provides an API to manage target images on the Vuforia Clouddatabase.
I stumbled across a python script to communicate with Vuforias Rest-API: https://github.com/dadoeyad/python-vuforia
The functions fetch data from the Database work nicely.
But I can't figure out how to use the function to add data to the Database.
import augmented.vuforia
upload = vuforia.Vuforia()
data = '{"name":"tarmac","width":"265.0","image":"/9j/4AAQSkZJR..."}'
upload.add_target(data)
This gives me an error: Bad Http Request
Is someone smart out there who gets how the data should be formatted?
The docs also seem to have typos:
https://developer.vuforia.com/resources/dev-guide/adding-target-cloud-database-api
In the library there is an example of how to add a target.
v = Vuforia(server_access, server_secret)
image_file = open('PATH_TO_IMAGE_FILE')
image = base64.b64encode(image_file.read())
meta = "this is the metadata"
metadata = base64.b64encode(meta)
print v.add_target({"name": "zxczxc", "width": "550", "image": image, "application_metadata": metadata, "active_flag": 1})