Python 2.7 has reached end of supportand will bedeprecatedon January 31, 2026. After deprecation, you won't be able to deploy Python 2.7applications, even if your organization previously used an organization policy tore-enable deployments of legacy runtimes. Your existing Python2.7 applications will continue to run and receive traffic after theirdeprecation date. We recommend thatyoumigrate to the latest supported version of Python.

Images API for legacy bundled services

App Engine provides the ability to manipulate image data using a dedicatedImages service. The Images service can manipulate images, composite multipleimages into a single image, convert image formats, provide image metadata suchas format, width, height, and a histogram of color values.

This API is supported for first-generation runtimes and can be used whenupgrading to corresponding second-generation runtimes. If you are updating to the App Engine Python 3 runtime, refer to themigration guide to learn about your migration options for legacy bundled services.

The Images service can accept image data directly from the app, or it can use aCloud Storage value. (The Images service can also use aCloud Blobstorevalue, but we recommend the use of Cloud Storage.)

Images stored in Cloud Storage and Cloud Blobstore can be up to the maximumallowed value for the respective service. The transformed image is returneddirectly to the app, and must be less than 32 megabytes.

Cloud Storage bucketsmust use fine-grainedAccess Control Lists for the Images API to work. For buckets that have been configured for uniform bucket-level access, the Images API will not be able to fetch images in that bucket and throws the error messageTransformationError. If your bucket is configured in this manner, you candisable uniform bucket-level access.

Transforming images in Python 2

The following example loads image data from Cloud Datastore, then uses theImages service to resize it and return it to the browser as a JPEG image.

fromgoogle.appengine.apiimportimagesfromgoogle.appengine.extimportndbimportwebapp2classPhoto(ndb.Model):title=ndb.StringProperty()full_size_image=ndb.BlobProperty()classThumbnailer(webapp2.RequestHandler):defget(self):ifself.request.get("id"):photo=Photo.get_by_id(int(self.request.get("id")))ifphoto: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 inthe Python Imaging Library (PIL) in your Python 2.7 app. You simply declare thelibrary in thelibraries section oftheapp.yaml file. However, if you wish to use PIL in your local environment(using the development server) you must alsodownload and installPIL orpillow locally.

Available image transformations

The Images service can resize, rotate, flip, and crop images, and enhancephotographs. It can also composite multiple images into a single image.

Resize

You can resize the image while maintaining the same aspect ratio. Neither thewidth nor the height of the resized image can exceed 4000 pixels.

Rotate

You can rotate the image in 90 degree increments.

Flip horizontally

You can flip the image horizontally.

Flip vertically

You can flip the image vertically.

Crop

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 imageand adjusts both color and optimizes contrast.

Image formats

The service accepts image data in the JPEG, PNG, WEBP, GIF (including animatedGIF), 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 convertsthe input data to the output format before performing the transformation.

Note: The Images service does not support multilayer TIFF images.

Transforming images

The Images service can use a value fromGoogle CloudStorageorBlobstore as the imagesource for a transformation. You have two ways to transform images:

  1. Using theImage() class allows you to perform simple image transformations, such as crop, flip, and rotate.
  2. Usingget_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 afteryou 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 imagesize is smaller than the maximum allowed by Cloud Storage or Blobstore. Notethat the result of the transformation is returned directly to the app, and mustnot exceed the API response limit of 32 megabytes.

To transform an image from Cloud Storage or Blobstore in Python 2, instead of setting theimage_data argument of theImage constructor with the image data, set theblob_key argument to the Blobstore key whose value is the image. The rest of the API behaves as expected. Theexecute_transforms() method returns the result of the transforms, or throws anLargeImageError if the result is larger than the maximum size of 32 megabytes.

fromgoogle.appengine.apiimportimagesfromgoogle.appengine.extimportblobstoreimportwebapp2classThumbnailer(webapp2.RequestHandler):defget(self):blob_key=self.request.get("blob_key")ifblob_key:blob_info=blobstore.get(blob_key)ifblob_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 thePython Imaging Library (PIL) in your Python 2.7 app. To do this, declare thelibrary in thelibrariessection of theapp.yaml file.

To use PIL in the development server,download and install PIL orpillow locally.

Theget_serving_url()method allows you to generate a fixed, dedicated URL for an image that is storedin 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 isseparate from your application. As the image is served independently from yourapp, it does not generate load and can be highly cost effective. The URLreturned by this method is always publicly accessible but not guessable.

If you wish to stop serving the URL, delete it using thedelete_serving_url() function.

The method returns a URL encoded with the specified size and crop arguments. Ifyou do not specify any arguments, the method returns the default URL for theimage, for example:

http://lhx.ggpht.com/randomStringImageId

You can resize and crop the image dynamically by specifying the arguments in theURL. The available arguments are:

  • =sxx wherexx is an integer from 0–2560 representing the length, inpixels, of the image's longest side. For example, adding=s32 resizes theimage so its longest dimension is 32 pixels.
  • =sxx-c wherexx is an integer from 0–2560 representing the croppedimage size in pixels, and-c tells the system to crop the image.
Important: Only the resize and crop arguments listed above are supported. Usingany other arguments might result in breaking failures.
# Resize the image to 32 pixels (aspect-ratio preserved)http://lhx.ggpht.com/randomStringImageId=s32# Crop the image to 32 pixelshttp://lhx.ggpht.com/randomStringImageId=s32-c

Images and the development server

The development server uses your local machine to perform the capabilities ofthe Images service.

The Python development server uses the Python Imaging Library (PIL) to simulatethe Image service. This library is not included with the Python standard libraryor the SDK, andmust be installedseparately. Thepillow fork also works. The WEBP image formatis 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 callthedelete_serving_url()function.

You should avoid directly deleting images in Cloud Storage or Blobstore as doingso can leave them accessible through the serving URL.

Serving URLs will stop working if the application that created them is disabledor deleted, even if the underlying image remains available.

Quotas, limits, and pricing

There is currently no additional charge incurred by using the Images API. Seethe App Enginepricing page.

Each Images API request counts toward theImage Manipulation API Callsquota. An app can perform multiple transformations of an image in a single APIcall.

Data sent to the Images service counts toward theData Sent to (Images) APIquota. Data received from the Images service counts toward theData Receivedfrom (Images) API quota.

Each transformation of an image counts toward theTransformations Executedquota.

For more information, seeQuotas. You can see thecurrent quota usage of your app by visiting theGoogle Cloud console QuotaDetails tab.

In addition to quotas, the following limits apply to the use of the Imagesservice:

LimitAmount
maximum data size of image sent to service32 megabytes
maximum data size of image received from service32 megabytes
maximum size of image sent or received from service50 megapixels

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.