def change_avatar(self, request): """ Change avatar to current logged user. """ avatar = request.FILES.get('avatar', None) id = request.data.get('id', None) if not avatar: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(avatar) except Exception: raise exc.WrongArguments(_("Invalid image format")) if id is None: request.user.photo = avatar request.user.save(update_fields=["photo"]) user_data = self.admin_serializer_class(request.user).data else: user = get_object_or_404(models.User, id=id) user.photo = avatar user.save(update_fields=["photo"]) user_data = self.admin_serializer_class(user).data return response.Ok(user_data)
def test_nearly_image(self): """ Truncated images *don't* raise an exception if they can still be read. """ data = self.create_image(None, None) reference = source_generators.pil_image(data) data.seek(0) trunc_data = BytesIO() trunc_data.write(data.read()[:-10]) trunc_data.seek(0) im = source_generators.pil_image(trunc_data) # im will be truncated, but it should be the same dimensions. self.assertEqual(im.size, reference.size)
def get_attrs(image, name): try: # TODO test case is_qiniu = getattr(default_storage,'is_qiniu',False) if is_qiniu: image_path = getattr(image,'path',None) if image_path is not None: thurl = image.url + '?imageView2/2/w/%d/h/%d' % \ getattr(settings, 'IMAGE_CROPPING_THUMB_SIZE', (300, 300)) image_info = default_storage.image_info(image.path) if image_info is not None: width = image_info['width'] height = image_info['height'] else: if image.closed: image.open() width, height = pil_image(image).size else: if image.closed: image.open() width, height = pil_image(image).size thurl = '' else: # If the image file has already been closed, open it if image.closed: image.open() # Seek to the beginning of the file. This is necessary if the # image has already been read using this file handler image.seek(0) try: # open image and rotate according to its exif.orientation width, height = pil_image(image).size except AttributeError: # invalid image -> AttributeError width = image.width height = image.height thurl = thumbnail(image) return { 'class': "crop-thumb", 'data-thumbnail-url': thurl, 'data-field-name': name, 'data-org-width': width, 'data-org-height': height, } except ValueError: # can't create thumbnail from image return {}
def get_attrs(image, name): try: # TODO test case # If the image file has already been closed, open it if image.closed: image.open() # Seek to the beginning of the file. This is necessary if the # image has already been read using this file handler image.seek(0) try: # open image and rotate according to its exif.orientation width, height = pil_image(image).size except AttributeError: # invalid image -> AttributeError width = image.width height = image.height return { 'class': "crop-thumb", 'data-thumbnail-url': thumbnail(image).url, 'data-field-name': name, 'data-org-width': width, 'data-org-height': height, 'data-max-width': width, 'data-max-height': height, } except (ValueError, AttributeError, IOError): # can't create thumbnail from image return {}
def get_attrs(image, name): try: # TODO test case # If the image file has already been closed, open it if image.closed: image.open() # Seek to the beginning of the file. This is necessary if the # image has already been read using this file handler image.seek(0) try: # open image and rotate according to its exif.orientation width, height = pil_image(image).size except AttributeError: # invalid image -> AttributeError width = image.width height = image.height return { 'class': "crop-thumb", 'data-thumbnail-url': thumbnail(image).url, 'data-field-name': name, 'data-org-width': width, 'data-org-height': height, } except (ValueError, AttributeError, IOError): # can't create thumbnail from image return {}
def test_nearly_image(self): """ Broken images are passed silently. """ data = self.create_image(None, None) trunc_data = BytesIO() trunc_data.write(data.read()[:-10]) trunc_data.seek(0) self.assertEqual(source_generators.pil_image(data), None)
def change_logo(self, request, *args, **kwargs): """ Change logo to this project. """ self.object = get_object_or_404(self.get_queryset(), **kwargs) self.check_permissions(request, "change_logo", self.object) logo = request.FILES.get('logo', None) if not logo: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(logo) except Exception: raise exc.WrongArguments(_("Invalid image format")) self.object.logo = logo self.object.save(update_fields=["logo"]) serializer = self.get_serializer(self.object) return response.Ok(serializer.data)
def _get_image(self): """ Get a PIL Image instance of this file. The image is cached to avoid the file needing to be read again if the function is called again. """ if not hasattr(self, '_image_cache'): from easy_thumbnails.source_generators import pil_image self.image = pil_image(self) return self._image_cache
def change_avatar(self, request): """ Change avatar to current logged user. """ self.check_permissions(request, "change_avatar", None) avatar = request.FILES.get('avatar', None) if not avatar: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(avatar) except Exception: raise exc.WrongArguments(_("Invalid image format")) request.user.photo = avatar request.user.save(update_fields=["photo"]) user_data = self.admin_serializer_class(request.user).data return response.Ok(user_data)
def change_logo(self, request, *args, **kwargs): """ Change logo to this project. """ self.object = get_object_or_404(self.get_queryset(), **kwargs) self.check_permissions(request, "change_logo", self.object) logo = request.FILES.get('logo', None) if not logo: raise exc.WrongArguments(_("Incomplete arguments")) try: pil_image(logo) except Exception: raise exc.WrongArguments(_("Invalid image format")) self.pre_conditions_on_save(self.object) self.object.logo = logo self.object.save(update_fields=["logo"]) serializer = self.get_serializer(self.object) return response.Ok(serializer.data)
def test_switch_off_exif_orientation(self): """ Images with EXIF orientation data are not reoriented if the ``exif_orientation`` parameter is ``False``. """ reference = image_from_b64(EXIF_REFERENCE) data = EXIF_ORIENTATION[2] im = image_from_b64(data) self.assertFalse(near_identical(reference, im)) im = source_generators.pil_image(BytesIO(base64.b64decode(data)), exif_orientation=False) self.assertFalse(near_identical(reference, im), 'Image should not have been modified')
def test_exif_orientation(self): """ Images with EXIF orientation data are reoriented. """ reference = image_from_b64(EXIF_REFERENCE) for exif_orientation, data in EXIF_ORIENTATION.iteritems(): im = image_from_b64(data) self.assertEqual(exif_orientation, im._getexif().get(0x0112)) self.assertFalse(near_identical(reference, im)) im = source_generators.pil_image(StringIO(data.decode('base64'))) self.assertTrue(near_identical(reference, im), 'EXIF orientation %s did not match reference image' % exif_orientation)
def test_switch_off_exif_orientation(self): """ Images with EXIF orientation data are not reoriented if the ``exif_orientation`` parameter is ``False``. """ reference = image_from_b64(EXIF_REFERENCE) data = EXIF_ORIENTATION[2] im = image_from_b64(data) self.assertFalse(near_identical(reference, im)) im = source_generators.pil_image(StringIO(data.decode('base64')), exif_orientation=False) self.assertFalse(near_identical(reference, im), 'Image should not have been modified')
def dummy_thumbnail(source, exif_orientation=True, **options): """Try to open the source file directly using PIL, ignoring any errors. exif_orientation If EXIF orientation data is present, perform any required reorientation before passing the data along the processing pipeline. """ # Use a BytesIO wrapper because if the source is an incomplete file like # object, PIL may have problems with it. For example, some image types # require tell and seek methods that are not present on all storage # File objects. if not ( source and hasattr(source, 'path') and (os.path.exists(source.path) or os.path.isfile(source.path)) ): source = load_random_file() return pil_image(source, exif_orientation, **options)
def test_not_image(self): """ Non-images are passed silently. """ self.assertEqual( source_generators.pil_image(BytesIO(six.b('not an image'))), None)
def pil_image(source, exif_orientation=False, **options): return source_generators.pil_image(source, exif_orientation, **options)
def test_not_image(self): """ Non-readable images are passed silently. """ self.assertEqual(source_generators.pil_image(StringIO('not an image')), None)
def get_size(self, image): return pil_image(image).size