7
votes

I'm currently working on a project running flask on the Appengine standard environment, and I'm attempting to serve an image that has been uploaded onto Google Cloud Storage on my project's default Appengine storage bucket.

This is the routing code I currently have:

# main.py

from google.appengine.api import images
from flask import Flask, send_file

app = Flask(__name__)

...

@app.route("/sample_route")
def sample_handler():
    myphoto = images.Image(filename="/gs/myappname.appspot.com/mysamplefolder/photo.jpg")
    return send_file(myphoto)
...

However, I am getting an AttributeError: 'Image' object has no attribute 'read' error.

The question is, how do I serve an image sourced from google cloud storage using an arbitrary route using python and flask?

EDIT:

I am actually trying to serve an image that I have uploaded to the default Cloud Storage Bucket in my app engine project.

I've also tried to serve the image using the following code without success:

# main.py

from google.appengine.api import images
from flask import Flask, send_file

app = Flask(__name__)

...

@app.route("/sample_route")
def sample_handler():
    import cloudstorage as gcs
    gcs_file = gcs.open("/mybucketname/mysamplefolder/photo.jpg")
    img = gcs_file.read()
    gcs_file.close()

    return send_file(img, mimetype='image/jpeg')
...
3
Are you trying to send it as bytes?GAEfan
Hi. What I want to do is, when the user loads the url in his browser or if the url is included in a page, the browser should display the image.B B
I have photos in google cloud storage that I want the user to be able to load. The image from url_to_image should load when the user goes to http://example.com/sample_route.B B

3 Answers

6
votes

I've used the GoogleAppEngineCloudStorageClient Python library and loaded images with code similar to the following example:

from google.appengine.api import app_identity
import cloudstorage
from flask import Flask, send_file
import io, os

app = Flask(__name__)

# ...

@app.route('/imagetest')
def test_image():

  # Use BUCKET_NAME or the project default bucket.
  BUCKET_NAME = '/' + os.environ.get('MY_BUCKET_NAME',
                                     app_identity.get_default_gcs_bucket_name())
  filename = 'mytestimage.jpg'
  file = os.path.join(BUCKET_NAME, filename)

  gcs_file = cloudstorage.open(file)
  contents = gcs_file.read()
  gcs_file.close()

  return send_file(io.BytesIO(contents),
                   mimetype='image/jpeg')
5
votes

Using google-cloud-storage==1.6.0

from flask import current_app as app, send_file, abort
from google.cloud import storage
import tempfile

@app.route('/blobproxy/<filename>', methods=['GET'])
def get(filename):
    if filename:
        client = storage.Client()
        bucket = client.get_bucket('yourbucketname')
        blob = bucket.blob(filename)
        with tempfile.NamedTemporaryFile() as temp:
            blob.download_to_filename(temp.name)
            return send_file(temp.name, attachment_filename=filename)
    else:
        abort(400)

I recommend looking at the docs for the path or string converters for your route, and NamedTemporaryFile defaults to delete=True so no residue. flask also figures out the mimetype if you give it a file name, as is the case here.

3
votes

Are you trying to accomplish something like this:

@app.route("/sample_route")
def sample_handler():
    import urllib2
    import StringIO

    request = urllib2.Request("{image url}")

    img = StringIO.StringIO(urllib2.urlopen(request).read())
    return send_file(img, mimetype='image/jpeg') # display in browser

or

    return send_file(img) # download file

The image url is needed, not a relative path. You could just do a redirect to the image url, but they would get a 301.