I'm working on an application in which I need to upload images to an S3 bucket. The images come from HTTP requests inside form datas. I upload the images directly to S3 as objects (https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.put_object), without saving them on my backend for security purposes.
But for other security purposes, is there a way to check if my image object is actually representing an image before uploading it to S3?
Given a bytes object, the following solution worked out for me:
def validate_image(bytes_object):
import io
from PIL import Image
try:
Image.open(io.BytesIO(bytes_array))
except OSError:
print('Not a valid image')
Related
I am trying to create an image thumbnail creation function using python, running in a google cloud platform's function. The image is sent as a base64 string to the cloud function, manipulated and made smaller with Python's Pillow package. It is then uploaded as an image, going from a Pillow Image object, to a BytesIO object, then saved to google cloud storage. This is all done successfully.
The problem here is very strange: Google Cloud Storage does not recognize the image until an access token is created manually. Otherwise, the image is left in an infinite loop, never loading, and never being able to be used.
I have reviewed this SO post, which has a very similar problem to mine (the image here shows exactly my problem: an uploaded file cannot be loaded properly), but it differs in two imporant categories: 1) They are manipulating the image array directly, while my code never touches it and 2) they are working in Node.js, where the Firebase SDK is different than in Python.
The code to generate the image is as follows:
def thumbnailCreator(request):
# Setting up the resourcse we are going to use
storage_client = storage.Client()
stor_bucket = storage_client.bucket(BUCKET_LINK)
# Retriving the Data
sent_data = request.get_json()['data']
name = sent_data['name']
userID = sent_data['userID']
# Process to go between base64 string to bytes, to a file object
imageString = stor_bucket.blob(PATH_TO_FULL_SIZE_IMAGE).download_as_string()
imageFile = BytesIO(imageString)
image = Image.open(imageFile)
# Resizing the image is the goal
image = image.resize(THUMBNAIL_SIZE)
# Go between pillow Image object to a file
imageFile = BytesIO()
image.save(imageFile, format='PNG')
imageBytes = imageFile.getvalue()
image64 = base64.b64encode(imageBytes)
imageFile.seek(0)
# Uploading the Data
other_blob = stor_bucket.blob(PATH_FOR_THUMBNAIL_IMAGE)
other_blob.upload_from_file(imageFile, content_type = 'image/png')
return {'data': {'response': 'ok', 'status': 200}}
Again, this works. I have a feeling there is something wrong with the MIME type. I am a novice when it comes to this type of programming/networking/image manipulation, so I'm always looking for a better way to do this. Anyway, thanks for any and all help.
It appears that the premise of this question - that a access token must be made manually for the image to work - is not accurate. After further testing, the error came from other parts of the code base I was working in. The above python script does work for image manipulation. An access token to the image can be generated via code, and be provided client-side.
Leaving this up in case someone stumbles upon it in the future when they need to work with Pillow/PIL in the Google Cloud Platform.
What I am trying to do is quite simple when dealing with a local file, but the problem comes when I try to do it with a remote URL.
Basically, I am trying to create a PIL image object from a file extracted from a URL. Of course, I could always fetch the URL and store it in a temporary file, then open it in an image object, but that seems very inefficient.
Here is what I have:
from PIL import Image
import requests
from io import BytesIO
response = requests.get(url)
img = Image.open(BytesIO(response.content))
So the Code is not returning the image if anyone knows.
I am writing a flask application that receives two image URLs as parameters. Traditionally, I would download this images on the server local disk and carry out my image processing operations. I am downloading them using following code.
urllib.request.urlretrieve(image1url, image_id + '.jpg')
After this I read the image using :
original_image = Image.open(image_id + '.jpg')
and carry out my Image Processing operations like crop and applying a few filters.
original_crop = original_image.crop((x, y, x + width / 3, y + height / 3))
Also, I use ImageFilter operations on this image. Now this code will be deployed on a server. If i continue this way I will keep downloading and saving images on the disk of the server. Of course, I understand that deleting the images after I am done with my Image Processing operations is one option. But if I get a few 100 calls per second, I might at some point of time use up a lot of space. The application is multi threaded using the call
app.run(threaded=true)
which works like a charm.
I want to know if there is a way to load an image without using disk storage of the server. Thus reducing the hard disk space requirements of my service.
if you don't want to store images in temporary files you can wrap URL content in stream and pass it to Image.open
import io
import urllib.request
from PIL import Image
# your avatar URL as example
url = ('https://www.gravatar.com/avatar/3341748e9b07c9854d50799e0e247fa3'
'?s=328&d=identicon&response=PG&f=1')
content = urllib.request.urlopen(url).read()
original_image = Image.open(io.BytesIO(content))
You could move them to a known remote location and fetch them back as needed. Using Amazon S3 or a hosted FTP service like BrickFTP are both easy. S3 is especially cheap since you only pay for what you use -- no monthly fee. Brick is a great service if you want to make access to the images as simple as possible for other applications and users but there is a minimum monthly fee.
Im working with Google App Engine Project and I want use facebook share like this.
http://i.stack.imgur.com/uz52n.png
Im already read this
How does Facebook Sharer select Images and other metadata when sharing my URL?
but GAE cant upload physical Image, all image store in blob property in database as base64 so facebook share cant get the image :(
anyone had another idea for this problem ??
Facebook reads the og:image meta to resolve the image from your webpage. og:image don't allow data-URI image (base64 encoded).
You have to provide an image url in og:image, but with that url, you can make a workaround to simulate the behaviour of a direct image resolution and get the image from your appengine database.
This is a solution in python using Django, but the concept works for everything. The name of the image is here "key.png" where key is the key of the object containing the base64 stored image.
First, add an url to the list of django urls for your image resolution:
(r'^image/(?P<key>[^\.^/]+)\.png$', 'yourapp.views.image'),
Then in your views, get the key from the url, retrieve your object, base64 decode and send it back with the correct mimetype:
import base64
def image(request, key):
# get your object from database
f = YourImageObject.get(key)
# f.pic is the base64 encoded image
pic = f.pic[len("data:image/png;base64,"):] # remove the header
# base64 decode and respond with correct mimetype
return HttpResponse(base64.b64decode(pic), mimetype="image/png")
Does anyone know how to convert a GAE Images API Image object into a "file like object"?
I'm trying to upload an image that I've transformed from the GAE Images API to Facebook. I'm using the execute_transforms function, which returns a "Image Representation" of the image.
I've tried to upload it using the following code, but I get a FB API Error "No Uploaded Image"
img = images.Image(ORIGINAL_IMAGE)
img.crop(0.0, 5.0/img.height, 713.0/img.width, 644.0/img.height)
output = img.execute_transforms(output_encoding=images.PNG)
graph = fb.GraphAPI(access_token)
graph.put_photo(output, 'Look at this cool photo!')
I think the issue is that output is not a "file like object" which is what put_photo requires, but the GAE docs doesn't have a function for casting into a "file like object". Tried creating temp files and writing to them, but GAE doesn't allow writing to filesystem. I've also tried to write to a StringIO object, but that didn't work.
Thanks
Use StringIO
enter code here
import StringIO
graph.put_photo(StringIO.StringIO(output), 'Look at this cool photo!')
Have a read of the docs at http://docs.python.org/library/stringio.html