App Engine provides the ability to manipulate image data using a dedicated Images service. The Images service can manipulate images, composite multiple images into a single image, convert image formats, provide image metadata such as format, width, height, and a histogram of color values.
The Images service can accept image data directly from the app, or it can use a Google Cloud Storage value. (The Images service can also use a Cloud Blobstore value, but we recommend the use of Cloud Storage.)
Images stored in Cloud Storage and Cloud Blobstore can be up to the maximum allowed value for the respective service. The transformed image is returned directly to the app, and must be less than 32 megabytes.
Transforming images in Python
The following example loads image data from Cloud Datastore, then uses the Images service to resize it and return it to the browser as a JPEG image.
from google.appengine.api import images from google.appengine.ext import ndb import webapp2 class Photo(ndb.Model): title = ndb.StringProperty() full_size_image = ndb.BlobProperty() class Thumbnailer(webapp2.RequestHandler): def get(self): if self.request.get("id"): photo = Photo.get_by_id(int(self.request.get("id"))) if photo: img = images.Image(photo.full_size_image) img.resize(width=80, height=100) img.im_feeling_lucky() thumbnail = img.execute_transforms(output_encoding=images.JPEG) self.response.headers['Content-Type'] = 'image/jpeg' self.response.out.write(thumbnail) return # Either "id" wasn't provided, or there was no image with that ID # in the datastore. self.error(404)
In addition to the Images API, you can also use the transforms provided in
the Python Imaging Library (PIL) in your Python 2.7 app. You simply declare the
library in the
libraries section of
app.yaml file. However, if you wish to use PIL in your local environment
(using the development server) you must also download and install
Available image transformations
The Images service can resize, rotate, flip, and crop images, and enhance photographs. It can also composite multiple images into a single image.
You can resize the image while maintaining the same aspect ratio. Neither the width nor the height of the resized image can exceed 4000 pixels.
You can rotate the image in 90 degree increments.
You can flip the image horizontally.
You can flip the image vertically.
You can crop the image with a given bounding box.
I'm Feeling Lucky
The "I'm Feeling Lucky" transform enhances dark and bright colors in an image and adjusts both color and optimizes contrast.
The service accepts image data in the JPEG, PNG, WEBP, GIF (including animated GIF), BMP, TIFF and ICO formats. Transformed images can be returned in the JPEG, WEBP and PNG formats.
If the input format and the output format are different, the service converts the input data to the output format before performing the transformation.
- Using the Image() class allows you to perform simple image transformations, such as crop, flip, and rotate.
- Using get_serving_url() allows you to dynamically resize and crop images, so you don't need to store different image sizes on the server. This method returns a URL that serves the image, and transformations to the image are encoded in this URL. This function assumes that the image doesn't change; if it gets modified after you get the URL, you may get unexpected results from using the URL.
Using the Image() Class
You can transform images from Cloud Storage or Blobstore if the image size is smaller than the maximum allowed by Cloud Storage or Blobstore. Note that the result of the transformation is returned directly to the app, and must not exceed the API response limit of 32 megabytes.
To transform an image from Cloud Storage or Blobstore in Python, instead of setting the
image_data argument of the Image constructor with the image data, set the
blob_key argument to the Blobstore key whose value is the image. The rest of the API behaves as expected. The
execute_transforms() method returns the result of the transforms, or throws an
LargeImageError if the result is larger than the maximum size of 32 megabytes.
from google.appengine.api import images from google.appengine.ext import blobstore import webapp2 class Thumbnailer(webapp2.RequestHandler): def get(self): blob_key = self.request.get("blob_key") if blob_key: blob_info = blobstore.get(blob_key) if blob_info: img = images.Image(blob_key=blob_key) img.resize(width=80, height=100) img.im_feeling_lucky() thumbnail = img.execute_transforms(output_encoding=images.JPEG) self.response.headers['Content-Type'] = 'image/jpeg' self.response.out.write(thumbnail) return # Either "blob_key" wasn't provided, or there was no value with that ID # in the Blobstore. self.error(404)
Using get_serving_url()In addition to the Images API, you can also use the transforms provided in the Python Imaging Library (PIL) in your Python 2.7 app. To do this, declare the library in the libraries section of the
The get_serving_url() method allows you to generate a fixed, dedicated URL for an image that is stored in Cloud Storage or Blobstore. For example:
url = images.get_serving_url( blob_key, size=150, crop=True, secure_url=True)
The generated URL uses highly-optimized image serving infrastructure that is separate from your application. As the image is served independently from your app, it does not generate load and can be highly cost effective. The URL returned by this method is always publicly accessable but not guessable.
If you wish to stop serving the URL, delete it using the delete_serving_url() function.
The method returns a URL encoded with the specified size and crop arguments. If you do not specify any arguments, the method returns the default URL for the image, for example:
You can resize and crop the image dynamically by specifying the arguments in the URL. The available arguments are:
xxis an integer from 0–2560 representing the length, in pixels, of the image's longest side. For example, adding
=s32resizes the image so its longest dimension is 32 pixels.
=sxx-cwhere xx is an integer from 0–2560 representing the cropped image size in pixels, and
-ctells the system to crop the image.
# Resize the image to 32 pixels (aspect-ratio preserved) http://lhx.ggpht.com/randomStringImageId=s32 # Crop the image to 32 pixels http://lhx.ggpht.com/randomStringImageId=s32-c
Images and the development server
The development server uses your local machine to perform the capabilities of the Images service.
The Python development server uses the Python Imaging Library (PIL) to simulate the Image service. This library is not included with the Python standard library or the SDK, and must be installed separately. The pillow fork also works. The WEBP image format is only supported if a suitable PIL decoder plugin has been installed.
A note about deletion
To stop serving an image stored in Cloud Storage or Blobstore call the delete_serving_url() function.
You should avoid directly deleting images in Cloud Storage or Blobstore as doing so can leave them accessible through the serving URL.
Serving URLs will stop working if the application that created them is disabled or deleted, even if the underlying image remains available.
Quotas, limits, and pricing
There is currently no additional charge incurred by using the Images API. See the App Engine pricing page.
Each Images API request counts toward the Image Manipulation API Calls quota. An app can perform multiple transformations of an image in a single API call.
Data sent to the Images service counts toward the Data Sent to (Images) API quota. Data received from the Images service counts toward the Data Received from (Images) API quota.
Each transformation of an image counts toward the Transformations Executed quota.
In addition to quotas, the following limits apply to the use of the Images service:
|maximum data size of image sent to service||32 megabytes|
|maximum data size of image received from service||32 megabytes|
|maximum size of image sent or received from service||50 megapixels|