thirdparty/google_appengine/google/appengine/api/images/images_stub.py
changeset 2273 e4cb9c53db3e
parent 1278 a7766286a7be
child 2309 be1b94099f2d
equal deleted inserted replaced
2272:26491ee91e33 2273:e4cb9c53db3e
    46       service_name: Service name expected for all calls.
    46       service_name: Service name expected for all calls.
    47     """
    47     """
    48     super(ImagesServiceStub, self).__init__(service_name)
    48     super(ImagesServiceStub, self).__init__(service_name)
    49     Image.init()
    49     Image.init()
    50 
    50 
       
    51   def _Dynamic_Composite(self, request, response):
       
    52     """Implementation of ImagesService::Composite.
       
    53 
       
    54     Based off documentation of the PIL library at
       
    55     http://www.pythonware.com/library/pil/handbook/index.htm
       
    56 
       
    57     Args:
       
    58       request: ImagesCompositeRequest, contains image request info.
       
    59       response: ImagesCompositeResponse, contains transformed image.
       
    60     """
       
    61     width = request.canvas().width()
       
    62     height = request.canvas().height()
       
    63     color = request.canvas().color() % 0x100000000
       
    64     reordered_color = int((color & 0xff000000) | ((color >> 16) & 0xff) |
       
    65                           (color & 0xff00) | (color & 0xff) << 16)
       
    66     canvas = Image.new("RGBA", (width, height), reordered_color)
       
    67     sources = []
       
    68     if (not request.canvas().width() or request.canvas().width() > 4000 or
       
    69         not request.canvas().height() or request.canvas().height() > 4000):
       
    70       raise apiproxy_errors.ApplicationError(
       
    71           images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    72     if not request.image_size():
       
    73       raise apiproxy_errors.ApplicationError(
       
    74           images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    75     if not request.options_size():
       
    76       raise apiproxy_errors.ApplicationError(
       
    77           images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    78     if request.options_size() > images.MAX_COMPOSITES_PER_REQUEST:
       
    79       raise apiproxy_errors.ApplicationError(
       
    80           images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    81     for image in request.image_list():
       
    82       sources.append(self._OpenImage(image.content()))
       
    83 
       
    84     for options in request.options_list():
       
    85       if (options.anchor() < images.TOP_LEFT or
       
    86           options.anchor() > images.BOTTOM_RIGHT):
       
    87         raise apiproxy_errors.ApplicationError(
       
    88             images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    89       if options.source_index() >= len(sources) or options.source_index() < 0:
       
    90         raise apiproxy_errors.ApplicationError(
       
    91             images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    92       if options.opacity() < 0 or options.opacity() > 1:
       
    93         raise apiproxy_errors.ApplicationError(
       
    94             images_service_pb.ImagesServiceError.BAD_TRANSFORM_DATA)
       
    95       source = sources[options.source_index()]
       
    96       x_anchor = (options.anchor() % 3) * 0.5
       
    97       y_anchor = (options.anchor() / 3) * 0.5
       
    98       x_offset = int(options.x_offset() + x_anchor * (width - source.size[0]))
       
    99       y_offset = int(options.y_offset() + y_anchor * (height - source.size[1]))
       
   100       alpha = options.opacity() * 255
       
   101       mask = Image.new("L", source.size, alpha)
       
   102       canvas.paste(source, (x_offset, y_offset), mask)
       
   103     response_value = self._EncodeImage(canvas, request.canvas().output())
       
   104     response.mutable_image().set_content(response_value)
       
   105 
       
   106   def _Dynamic_Histogram(self, request, response):
       
   107     """Trivial implementation of ImagesService::Histogram.
       
   108 
       
   109     Based off documentation of the PIL library at
       
   110     http://www.pythonware.com/library/pil/handbook/index.htm
       
   111 
       
   112     Args:
       
   113       request: ImagesHistogramRequest, contains the image.
       
   114       response: ImagesHistogramResponse, contains histogram of the image.
       
   115     """
       
   116     image = self._OpenImage(request.image().content())
       
   117     img_format = image.format
       
   118     if img_format not in ("BMP", "GIF", "ICO", "JPEG", "PNG", "TIFF"):
       
   119       raise apiproxy_errors.ApplicationError(
       
   120           images_service_pb.ImagesServiceError.NOT_IMAGE)
       
   121     image = image.convert("RGBA")
       
   122     red = [0] * 256
       
   123     green = [0] * 256
       
   124     blue = [0] * 256
       
   125     for pixel in image.getdata():
       
   126       red[int((pixel[0] * pixel[3]) / 255)] += 1
       
   127       green[int((pixel[1] * pixel[3]) / 255)] += 1
       
   128       blue[int((pixel[2] * pixel[3]) / 255)] += 1
       
   129     histogram = response.mutable_histogram()
       
   130     for value in red:
       
   131       histogram.add_red(value)
       
   132     for value in green:
       
   133       histogram.add_green(value)
       
   134     for value in blue:
       
   135       histogram.add_blue(value)
       
   136 
    51   def _Dynamic_Transform(self, request, response):
   137   def _Dynamic_Transform(self, request, response):
    52     """Trivial implementation of ImagesService::Transform.
   138     """Trivial implementation of ImagesService::Transform.
    53 
   139 
    54     Based off documentation of the PIL library at
   140     Based off documentation of the PIL library at
    55     http://www.pythonware.com/library/pil/handbook/index.htm
   141     http://www.pythonware.com/library/pil/handbook/index.htm
    56 
   142 
    57     Args:
   143     Args:
    58       request: ImagesTransformRequest, contains image request info.
   144       request: ImagesTransformRequest, contains image request info.
    59       response: ImagesTransformResponse, contains transformed image.
   145       response: ImagesTransformResponse, contains transformed image.
    60     """
   146     """
    61     image = request.image().content()
   147     original_image = self._OpenImage(request.image().content())
       
   148 
       
   149     new_image = self._ProcessTransforms(original_image,
       
   150                                         request.transform_list())
       
   151 
       
   152     response_value = self._EncodeImage(new_image, request.output())
       
   153     response.mutable_image().set_content(response_value)
       
   154 
       
   155   def _EncodeImage(self, image, output_encoding):
       
   156     """Encode the given image and return it in string form.
       
   157 
       
   158     Args:
       
   159       image: PIL Image object, image to encode.
       
   160       output_encoding: ImagesTransformRequest.OutputSettings object.
       
   161 
       
   162     Returns:
       
   163       str with encoded image information in given encoding format.
       
   164     """
       
   165     image_string = StringIO.StringIO()
       
   166 
       
   167     image_encoding = "PNG"
       
   168 
       
   169     if (output_encoding.mime_type() == images_service_pb.OutputSettings.JPEG):
       
   170       image_encoding = "JPEG"
       
   171 
       
   172       image = image.convert("RGB")
       
   173 
       
   174     image.save(image_string, image_encoding)
       
   175 
       
   176     return image_string.getvalue()
       
   177 
       
   178   def _OpenImage(self, image):
       
   179     """Opens an image provided as a string.
       
   180 
       
   181     Args:
       
   182       image: image data to be opened
       
   183 
       
   184     Raises:
       
   185       apiproxy_errors.ApplicationError if the image cannot be opened or if it
       
   186       is an unsupported format.
       
   187 
       
   188     Returns:
       
   189       Image containing the image data passed in.
       
   190     """
    62     if not image:
   191     if not image:
    63       raise apiproxy_errors.ApplicationError(
   192       raise apiproxy_errors.ApplicationError(
    64           images_service_pb.ImagesServiceError.NOT_IMAGE)
   193           images_service_pb.ImagesServiceError.NOT_IMAGE)
    65 
   194 
    66     image = StringIO.StringIO(image)
   195     image = StringIO.StringIO(image)
    67     try:
   196     try:
    68       original_image = Image.open(image)
   197       image = Image.open(image)
    69     except IOError:
   198     except IOError:
    70       raise apiproxy_errors.ApplicationError(
   199       raise apiproxy_errors.ApplicationError(
    71           images_service_pb.ImagesServiceError.BAD_IMAGE_DATA)
   200           images_service_pb.ImagesServiceError.BAD_IMAGE_DATA)
    72 
   201 
    73     img_format = original_image.format
   202     img_format = image.format
    74     if img_format not in ("BMP", "GIF", "ICO", "JPEG", "PNG", "TIFF"):
   203     if img_format not in ("BMP", "GIF", "ICO", "JPEG", "PNG", "TIFF"):
    75       raise apiproxy_errors.ApplicationError(
   204       raise apiproxy_errors.ApplicationError(
    76           images_service_pb.ImagesServiceError.NOT_IMAGE)
   205           images_service_pb.ImagesServiceError.NOT_IMAGE)
    77 
   206     return image
    78     new_image = self._ProcessTransforms(original_image,
       
    79                                         request.transform_list())
       
    80 
       
    81     response_value = self._EncodeImage(new_image, request.output())
       
    82     response.mutable_image().set_content(response_value)
       
    83 
       
    84   def _EncodeImage(self, image, output_encoding):
       
    85     """Encode the given image and return it in string form.
       
    86 
       
    87     Args:
       
    88       image: PIL Image object, image to encode.
       
    89       output_encoding: ImagesTransformRequest.OutputSettings object.
       
    90 
       
    91     Returns:
       
    92       str with encoded image information in given encoding format.
       
    93     """
       
    94     image_string = StringIO.StringIO()
       
    95 
       
    96     image_encoding = "PNG"
       
    97 
       
    98     if (output_encoding.mime_type() == images_service_pb.OutputSettings.JPEG):
       
    99       image_encoding = "JPEG"
       
   100 
       
   101       image = image.convert("RGB")
       
   102 
       
   103     image.save(image_string, image_encoding)
       
   104 
       
   105     return image_string.getvalue()
       
   106 
   207 
   107   def _ValidateCropArg(self, arg):
   208   def _ValidateCropArg(self, arg):
   108     """Check an argument for the Crop transform.
   209     """Check an argument for the Crop transform.
   109 
   210 
   110     Args:
   211     Args: