示例#1
0
    def _transform_image(self, blob_key, options):
        """Construct and execute a transform request using the images stub.

    Args:
      blob_key: A str containing the blob_key of the image to transform.
      options: A str containing the resize and crop options to apply to the
          image.

    Returns:
      A str containing the tranformed (if necessary) image.
    """
        resize, crop = self._parse_options(options)
        image_data = images_service_pb.ImageData()
        image_data.set_blob_key(blob_key)
        image = _get_images_stub()._OpenImageData(image_data)
        original_mime_type = image.format
        width, height = image.size

        # Crop to square if necessary
        if crop:
            crop_xform = None
            if width > height:
                # landscape: slice the sides
                crop_xform = images_service_pb.Transform()
                delta = (width - height) / (width * 2.0)
                crop_xform.set_crop_left_x(delta)
                crop_xform.set_crop_right_x(1.0 - delta)
            elif width < height:
                # portrait: slice the top and bottom with bias
                crop_xform = images_service_pb.Transform()
                delta = (height - width) / (height * 2.0)
                top_delta = max(0.0, delta - 0.25)
                bottom_delta = 1.0 - (2.0 * delta) + top_delta
                crop_xform.set_crop_top_y(top_delta)
                crop_xform.set_crop_bottom_y(bottom_delta)
            if crop_xform:
                image = _get_images_stub()._Crop(image, crop_xform)

        # Resize
        if resize is None:
            if width > _DEFAULT_SERVING_SIZE or height > _DEFAULT_SERVING_SIZE:
                resize = _DEFAULT_SERVING_SIZE

        # resize value of 0 is valid and translates to 'serve at original size'.
        if resize:
            # Note that resize transform maintains the image aspect ratio.
            resize_xform = images_service_pb.Transform()
            resize_xform.set_width(resize)
            resize_xform.set_height(resize)
            image = _get_images_stub()._Resize(image, resize_xform)

        output_settings = images_service_pb.OutputSettings()
        # EncodeImage only saves out to JPEG or PNG. All image formats other than
        # GIF or PNG, will be served as a JPEG.
        output_mime_type = images_service_pb.OutputSettings.JPEG
        if original_mime_type in ['PNG', 'GIF']:
            output_mime_type = images_service_pb.OutputSettings.PNG
        output_settings.set_mime_type(output_mime_type)
        return (_get_images_stub()._EncodeImage(image, output_settings),
                _MIME_TYPE_MAP[output_mime_type])
示例#2
0
        def _TransformImage(self, blob_key, options):
            """Construct and execute transform request to the images stub.

      Args:
        blob_key: blob_key to the image to transform.
        options: resize and crop option string to apply to the image.

      Returns:
        The tranformed (if necessary) image bytes.
      """
            resize, crop = self._ParseOptions(options)

            image_data = images_service_pb.ImageData()
            image_data.set_blob_key(blob_key)
            image = self._images_stub._OpenImageData(image_data)
            original_mime_type = image.format
            width, height = image.size

            if crop:
                crop_xform = None
                if width > height:

                    crop_xform = images_service_pb.Transform()
                    delta = (width - height) / (width * 2.0)
                    crop_xform.set_crop_left_x(delta)
                    crop_xform.set_crop_right_x(1.0 - delta)
                elif width < height:

                    crop_xform = images_service_pb.Transform()
                    delta = (height - width) / (height * 2.0)
                    top_delta = max(0.0, delta - 0.25)
                    bottom_delta = 1.0 - (2.0 * delta) + top_delta
                    crop_xform.set_crop_top_y(top_delta)
                    crop_xform.set_crop_bottom_y(bottom_delta)
                if crop_xform:
                    image = self._images_stub._Crop(image, crop_xform)

            if resize is None:
                if width > DEFAULT_SERVING_SIZE or height > DEFAULT_SERVING_SIZE:
                    resize = DEFAULT_SERVING_SIZE

            if resize:

                resize_xform = images_service_pb.Transform()
                resize_xform.set_width(resize)
                resize_xform.set_height(resize)
                image = self._images_stub._Resize(image, resize_xform)

            output_settings = images_service_pb.OutputSettings()

            output_mime_type = images_service_pb.OutputSettings.JPEG
            if original_mime_type in ['PNG', 'GIF']:
                output_mime_type = images_service_pb.OutputSettings.PNG
            output_settings.set_mime_type(output_mime_type)
            return (self._images_stub._EncodeImage(image, output_settings),
                    self._mime_type_map[output_mime_type])
示例#3
0
  def rotate(self, degrees):
    """Rotate an image a given number of degrees clockwise.

    Args:
      degrees: int, must be a multiple of 90.

    Raises:
      TypeError when degrees is not either 'int' or 'long' types.
      BadRequestError when there is something wrong with the given degrees or
      if MAX_TRANSFORMS_PER_REQUEST transforms have already been requested.
    """
    if not isinstance(degrees, (int, long)):
      raise TypeError("Degrees must be integers.")

    if degrees % 90 != 0:
      raise BadRequestError("degrees argument must be multiple of 90.")


    degrees = degrees % 360




    self._check_transform_limits()

    transform = images_service_pb.Transform()
    transform.set_rotate(degrees)

    self._transforms.append(transform)
示例#4
0
  def resize(self, width=0, height=0, crop_to_fit=False,
             crop_offset_x=0.5, crop_offset_y=0.5):
    """Resize the image maintaining the aspect ratio.

    If both width and height are specified, the more restricting of the two
    values will be used when resizing the image. The maximum dimension allowed
    for both width and height is 4000 pixels.
    If both width and height are specified and crop_to_fit is True, the less
    restricting of the two values will be used when resizing and the image will
    be cropped to fit the specified size. In this case the center of cropping
    can be adjusted  by crop_offset_x and crop_offset_y.

    Args:
      width: int, width (in pixels) to change the image width to.
      height: int, height (in pixels) to change the image height to.
      crop_to_fit: If True and both width and height are specified, the image is
        cropped after resize to fit the specified dimensions.
      crop_offset_x: float value between 0.0 and 1.0, 0 is left and 1 is right,
        default is 0.5, the center of image.
      crop_offset_y: float value between 0.0 and 1.0, 0 is top and 1 is bottom,
        default is 0.5, the center of image.

    Raises:
      TypeError when width or height is not either 'int' or 'long' types.
      BadRequestError when there is something wrong with the given height or
        width or if MAX_TRANSFORMS_PER_REQUEST transforms have already been
        requested on this image.
    """
    if (not isinstance(width, (int, long)) or
        not isinstance(height, (int, long))):
      raise TypeError("Width and height must be integers.")
    if width < 0 or height < 0:
      raise BadRequestError("Width and height must be >= 0.")

    if not width and not height:
      raise BadRequestError("At least one of width or height must be > 0.")

    if width > 4000 or height > 4000:
      raise BadRequestError("Both width and height must be <= 4000.")

    if not isinstance(crop_to_fit, bool):
      raise TypeError("crop_to_fit must be boolean.")

    if crop_to_fit and not (width and height):
      raise BadRequestError("Both width and height must be > 0 when "
                            "crop_to_fit is specified")

    self._validate_crop_arg(crop_offset_x, "crop_offset_x")
    self._validate_crop_arg(crop_offset_y, "crop_offset_y")

    self._check_transform_limits()

    transform = images_service_pb.Transform()
    transform.set_width(width)
    transform.set_height(height)
    transform.set_crop_to_fit(crop_to_fit)
    transform.set_crop_offset_x(crop_offset_x)
    transform.set_crop_offset_y(crop_offset_y)

    self._transforms.append(transform)
示例#5
0
 def expect_resize(self, resize):
   """Setup a mox expectation to images_stub._Resize."""
   resize_xform = images_service_pb.Transform()
   resize_xform.set_width(resize)
   resize_xform.set_height(resize)
   self._images_stub._Resize(mox.IsA(MockImage),
                             resize_xform).AndReturn(self._image)
示例#6
0
 def expect_crop(self,
                 left_x=None,
                 right_x=None,
                 top_y=None,
                 bottom_y=None):
     """Setup a mox expectation to images_stub._Crop."""
     crop_xform = images_service_pb.Transform()
     if left_x is not None:
         if not isinstance(left_x, float):
             raise self.failureException('Crop argument must be a float.')
         crop_xform.set_crop_left_x(left_x)
     if right_x is not None:
         if not isinstance(right_x, float):
             raise self.failureException('Crop argument must be a float.')
         crop_xform.set_crop_right_x(right_x)
     if top_y is not None:
         if not isinstance(top_y, float):
             raise self.failureException('Crop argument must be a float.')
         crop_xform.set_crop_top_y(top_y)
     if bottom_y is not None:
         if not isinstance(bottom_y, float):
             raise self.failureException('Crop argument must be a float.')
         crop_xform.set_crop_bottom_y(bottom_y)
     self._images_stub._Crop(mox.IsA(MockImage),
                             crop_xform).AndReturn(self._image)
示例#7
0
  def vertical_flip(self):
    """Flip the image vertically.

    Raises:
      BadRequestError if MAX_TRANSFORMS_PER_REQUEST transforms have already been
      requested on the image.
    """
    self._check_transform_limits()
    transform = images_service_pb.Transform()
    transform.set_vertical_flip(True)

    self._transforms.append(transform)
示例#8
0
  def im_feeling_lucky(self):
    """Automatically adjust image contrast and color levels.

    This is similar to the "I'm Feeling Lucky" button in Picasa.

    Raises:
      BadRequestError if MAX_TRANSFORMS_PER_REQUEST transforms have already
        been requested for this image.
    """
    self._check_transform_limits()
    transform = images_service_pb.Transform()
    transform.set_autolevels(True)

    self._transforms.append(transform)
示例#9
0
  def crop(self, left_x, top_y, right_x, bottom_y):
    """Crop the image.

    The four arguments are the scaling numbers to describe the bounding box
    which will crop the image.  The upper left point of the bounding box will
    be at (left_x*image_width, top_y*image_height) the lower right point will
    be at (right_x*image_width, bottom_y*image_height).

    Args:
      left_x: float value between 0.0 and 1.0 (inclusive).
      top_y: float value between 0.0 and 1.0 (inclusive).
      right_x: float value between 0.0 and 1.0 (inclusive).
      bottom_y: float value between 0.0 and 1.0 (inclusive).

    Raises:
      TypeError if the args are not of type 'float'.
      BadRequestError when there is something wrong with the given bounding box
        or if MAX_TRANSFORMS_PER_REQUEST transforms have already been requested
        for this image.
    """
    self._validate_crop_arg(left_x, "left_x")
    self._validate_crop_arg(top_y, "top_y")
    self._validate_crop_arg(right_x, "right_x")
    self._validate_crop_arg(bottom_y, "bottom_y")

    if left_x >= right_x:
      raise BadRequestError("left_x must be less than right_x")
    if top_y >= bottom_y:
      raise BadRequestError("top_y must be less than bottom_y")

    self._check_transform_limits()

    transform = images_service_pb.Transform()
    transform.set_crop_left_x(left_x)
    transform.set_crop_top_y(top_y)
    transform.set_crop_right_x(right_x)
    transform.set_crop_bottom_y(bottom_y)

    self._transforms.append(transform)
示例#10
0
    def resize(self, width=0, height=0):
        """Resize the image maintaining the aspect ratio.

    If both width and height are specified, the more restricting of the two
    values will be used when resizing the photo.  The maximum dimension allowed
    for both width and height is 4000 pixels.

    Args:
      width: int, width (in pixels) to change the image width to.
      height: int, height (in pixels) to change the image height to.

    Raises:
      TypeError when width or height is not either 'int' or 'long' types.
      BadRequestError when there is something wrong with the given height or
        width or if MAX_TRANSFORMS_PER_REQUEST transforms have already been
        requested on this image.
    """
        if (not isinstance(width, (int, long))
                or not isinstance(height, (int, long))):
            raise TypeError("Width and height must be integers.")
        if width < 0 or height < 0:
            raise BadRequestError("Width and height must be >= 0.")

        if not width and not height:
            raise BadRequestError(
                "At least one of width or height must be > 0.")

        if width > 4000 or height > 4000:
            raise BadRequestError("Both width and height must be <= 4000.")

        self._check_transform_limits()

        transform = images_service_pb.Transform()
        transform.set_width(width)
        transform.set_height(height)

        self._transforms.append(transform)