83 |
83 |
84 class LargeImageError(Error): |
84 class LargeImageError(Error): |
85 """The image data given is too large to process.""" |
85 """The image data given is too large to process.""" |
86 |
86 |
87 |
87 |
|
88 class InvalidBlobKeyError(Error): |
|
89 """The provided blob key was invalid.""" |
|
90 |
|
91 |
88 class Image(object): |
92 class Image(object): |
89 """Image object to manipulate.""" |
93 """Image object to manipulate.""" |
90 |
94 |
91 def __init__(self, image_data): |
95 def __init__(self, image_data=None, blob_key=None): |
92 """Constructor. |
96 """Constructor. |
93 |
97 |
94 Args: |
98 Args: |
95 image_data: str, image data in string form. |
99 image_data: str, image data in string form. |
|
100 blob_key: str, image data as a blobstore blob key. |
96 |
101 |
97 Raises: |
102 Raises: |
98 NotImageError if the given data is empty. |
103 NotImageError if the given data is empty. |
99 """ |
104 """ |
100 if not image_data: |
105 if not image_data and not blob_key: |
101 raise NotImageError("Empty image data.") |
106 raise NotImageError("Empty image data.") |
|
107 if image_data and blob_key: |
|
108 raise NotImageError("Can only take one image or blob key.") |
102 |
109 |
103 self._image_data = image_data |
110 self._image_data = image_data |
|
111 self._blob_key = blob_key |
104 self._transforms = [] |
112 self._transforms = [] |
105 self._width = None |
113 self._width = None |
106 self._height = None |
114 self._height = None |
107 |
115 |
108 def _check_transform_limits(self): |
116 def _check_transform_limits(self): |
121 |
129 |
122 Raises: |
130 Raises: |
123 NotImageError if the image data is not an image. |
131 NotImageError if the image data is not an image. |
124 BadImageError if the image data is corrupt. |
132 BadImageError if the image data is corrupt. |
125 """ |
133 """ |
|
134 if not self._image_data: |
|
135 raise NotImageError("Dimensions unavailable for blob key input") |
126 size = len(self._image_data) |
136 size = len(self._image_data) |
127 if size >= 6 and self._image_data.startswith("GIF"): |
137 if size >= 6 and self._image_data.startswith("GIF"): |
128 self._update_gif_dimensions() |
138 self._update_gif_dimensions() |
129 elif size >= 8 and self._image_data.startswith("\x89PNG\x0D\x0A\x1A\x0A"): |
139 elif size >= 8 and self._image_data.startswith("\x89PNG\x0D\x0A\x1A\x0A"): |
130 self._update_png_dimensions() |
140 self._update_png_dimensions() |
446 transform = images_service_pb.Transform() |
456 transform = images_service_pb.Transform() |
447 transform.set_autolevels(True) |
457 transform.set_autolevels(True) |
448 |
458 |
449 self._transforms.append(transform) |
459 self._transforms.append(transform) |
450 |
460 |
|
461 def _set_imagedata(self, imagedata): |
|
462 """Fills in an ImageData PB from this Image instance. |
|
463 |
|
464 Args: |
|
465 imagedata: An ImageData PB instance |
|
466 """ |
|
467 if self._blob_key: |
|
468 imagedata.set_content("") |
|
469 imagedata.set_blob_key(self._blob_key) |
|
470 else: |
|
471 imagedata.set_content(self._image_data) |
|
472 |
451 def execute_transforms(self, output_encoding=PNG): |
473 def execute_transforms(self, output_encoding=PNG): |
452 """Perform transformations on given image. |
474 """Perform transformations on given image. |
453 |
475 |
454 Args: |
476 Args: |
455 output_encoding: A value from OUTPUT_ENCODING_TYPES. |
477 output_encoding: A value from OUTPUT_ENCODING_TYPES. |
461 BadRequestError when there is something wrong with the request |
483 BadRequestError when there is something wrong with the request |
462 specifications. |
484 specifications. |
463 NotImageError when the image data given is not an image. |
485 NotImageError when the image data given is not an image. |
464 BadImageError when the image data given is corrupt. |
486 BadImageError when the image data given is corrupt. |
465 LargeImageError when the image data given is too large to process. |
487 LargeImageError when the image data given is too large to process. |
|
488 InvalidBlobKeyError when the blob key provided is invalid. |
466 TransformtionError when something errors during image manipulation. |
489 TransformtionError when something errors during image manipulation. |
467 Error when something unknown, but bad, happens. |
490 Error when something unknown, but bad, happens. |
468 """ |
491 """ |
469 if output_encoding not in OUTPUT_ENCODING_TYPES: |
492 if output_encoding not in OUTPUT_ENCODING_TYPES: |
470 raise BadRequestError("Output encoding type not in recognized set " |
493 raise BadRequestError("Output encoding type not in recognized set " |
474 raise BadRequestError("Must specify at least one transformation.") |
497 raise BadRequestError("Must specify at least one transformation.") |
475 |
498 |
476 request = images_service_pb.ImagesTransformRequest() |
499 request = images_service_pb.ImagesTransformRequest() |
477 response = images_service_pb.ImagesTransformResponse() |
500 response = images_service_pb.ImagesTransformResponse() |
478 |
501 |
479 request.mutable_image().set_content(self._image_data) |
502 self._set_imagedata(request.mutable_image()) |
480 |
503 |
481 for transform in self._transforms: |
504 for transform in self._transforms: |
482 request.add_transform().CopyFrom(transform) |
505 request.add_transform().CopyFrom(transform) |
483 |
506 |
484 request.mutable_output().set_mime_type(output_encoding) |
507 request.mutable_output().set_mime_type(output_encoding) |
500 raise BadImageError() |
523 raise BadImageError() |
501 elif (e.application_error == |
524 elif (e.application_error == |
502 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
525 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
503 raise LargeImageError() |
526 raise LargeImageError() |
504 elif (e.application_error == |
527 elif (e.application_error == |
|
528 images_service_pb.ImagesServiceError.INVALID_BLOB_KEY): |
|
529 raise InvalidBlobKeyError() |
|
530 elif (e.application_error == |
505 images_service_pb.ImagesServiceError.UNSPECIFIED_ERROR): |
531 images_service_pb.ImagesServiceError.UNSPECIFIED_ERROR): |
506 raise TransformationError() |
532 raise TransformationError() |
507 else: |
533 else: |
508 raise Error() |
534 raise Error() |
509 |
535 |
510 self._image_data = response.image().content() |
536 self._image_data = response.image().content() |
|
537 self._blob_key = None |
511 self._transforms = [] |
538 self._transforms = [] |
512 self._width = None |
539 self._width = None |
513 self._height = None |
540 self._height = None |
514 return self._image_data |
541 return self._image_data |
515 |
542 |
543 Error when something unknown, but bad, happens. |
570 Error when something unknown, but bad, happens. |
544 """ |
571 """ |
545 request = images_service_pb.ImagesHistogramRequest() |
572 request = images_service_pb.ImagesHistogramRequest() |
546 response = images_service_pb.ImagesHistogramResponse() |
573 response = images_service_pb.ImagesHistogramResponse() |
547 |
574 |
548 request.mutable_image().set_content(self._image_data) |
575 self._set_imagedata(request.mutable_image()) |
|
576 |
549 try: |
577 try: |
550 apiproxy_stub_map.MakeSyncCall("images", |
578 apiproxy_stub_map.MakeSyncCall("images", |
551 "Histogram", |
579 "Histogram", |
552 request, |
580 request, |
553 response) |
581 response) |
559 images_service_pb.ImagesServiceError.BAD_IMAGE_DATA): |
587 images_service_pb.ImagesServiceError.BAD_IMAGE_DATA): |
560 raise BadImageError() |
588 raise BadImageError() |
561 elif (e.application_error == |
589 elif (e.application_error == |
562 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
590 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
563 raise LargeImageError() |
591 raise LargeImageError() |
|
592 elif (e.application_error == |
|
593 images_service_pb.ImagesServiceError.INVALID_BLOB_KEY): |
|
594 raise InvalidBlobKeyError() |
564 else: |
595 else: |
565 raise Error() |
596 raise Error() |
566 histogram = response.histogram() |
597 histogram = response.histogram() |
567 return [histogram.red_list(), |
598 return [histogram.red_list(), |
568 histogram.green_list(), |
599 histogram.green_list(), |
766 if anchor not in ANCHOR_TYPES: |
797 if anchor not in ANCHOR_TYPES: |
767 raise BadRequestError("Anchor type '%s' not in recognized set %s" % |
798 raise BadRequestError("Anchor type '%s' not in recognized set %s" % |
768 (anchor, ANCHOR_TYPES)) |
799 (anchor, ANCHOR_TYPES)) |
769 if image not in image_map: |
800 if image not in image_map: |
770 image_map[image] = request.image_size() |
801 image_map[image] = request.image_size() |
771 request.add_image().set_content(image) |
802 |
|
803 if isinstance(image, Image): |
|
804 image._set_imagedata(request.add_image()) |
|
805 else: |
|
806 request.add_image().set_content(image) |
772 |
807 |
773 option = request.add_options() |
808 option = request.add_options() |
774 option.set_x_offset(x) |
809 option.set_x_offset(x) |
775 option.set_y_offset(y) |
810 option.set_y_offset(y) |
776 option.set_opacity(opacity) |
811 option.set_opacity(opacity) |
799 raise BadImageError() |
834 raise BadImageError() |
800 elif (e.application_error == |
835 elif (e.application_error == |
801 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
836 images_service_pb.ImagesServiceError.IMAGE_TOO_LARGE): |
802 raise LargeImageError() |
837 raise LargeImageError() |
803 elif (e.application_error == |
838 elif (e.application_error == |
|
839 images_service_pb.ImagesServiceError.INVALID_BLOB_KEY): |
|
840 raise InvalidBlobKeyError() |
|
841 elif (e.application_error == |
804 images_service_pb.ImagesServiceError.UNSPECIFIED_ERROR): |
842 images_service_pb.ImagesServiceError.UNSPECIFIED_ERROR): |
805 raise TransformationError() |
843 raise TransformationError() |
806 else: |
844 else: |
807 raise Error() |
845 raise Error() |
808 |
846 |