Exemple #1
0
 def test_margin(self):
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     self.assertEqual(margin(im, '1000x1000'), '250px 250px 250px 250px')
     self.assertEqual(margin(im, '800x1000'), '250px 150px 250px 150px')
     self.assertEqual(margin(im, '500x500'), '0px 0px 0px 0px')
     self.assertEqual(margin(im, '500x501'), '0px 0px 1px 0px')
     self.assertEqual(margin(im, '503x500'), '0px 2px 0px 1px')
     self.assertEqual(margin(im, '300x300'), '-100px -100px -100px -100px')
Exemple #2
0
 def test_storage_serialize(self):
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     self.assertEqual(im.serialize_storage(),
                      'tests.thumbnail_tests.storage.TestStorage')
     self.assertEqual(
         ImageFile('http://www.image.jpg').serialize_storage(),
         'sorl.thumbnail.images.UrlStorage',
     )
     self.assertEqual(
         ImageFile('http://www.image.jpg',
                   default.storage).serialize_storage(),
         'tests.thumbnail_tests.storage.TestStorage',
     )
     self.assertEqual(
         ImageFile('getit', default_storage).serialize_storage(),
         'tests.thumbnail_tests.storage.TestStorage',
     )
Exemple #3
0
 def test_new_tag_style(self):
     item = Item.objects.get(image='500x500.jpg')
     image = ImageFile(item.image.path)
     val = render_to_string('thumbnail20a.html', {
         'image': image,
     }).strip()
     im = self.backend.get_thumbnail(image, '32x32', crop='center')
     self.assertEqual('<img src="%s">' % im.url, val)
 def test_quality(self):
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     th = self.BACKEND.get_thumbnail(im, '100x100', quality=50)
     p1 = Popen(['identify', '-verbose', th.storage.path(th.name)], stdout=PIPE)
     p2 = Popen(['grep', '-c', 'Quality: 50'], stdin=p1.stdout, stdout=PIPE)
     p1.stdout.close()
     output = p2.communicate()[0].strip()
     self.assertEqual(output.decode('utf-8'), '1')
Exemple #5
0
def create_thumbnail(file_, geometry_string, options, name, force=False):
    if file_:
        source = ImageFile(file_)
    else:
        return

    thumbnail = ImageFile(name, default.storage)

    # We have to check exists() because the Storage backend does not
    # overwrite in some implementations.
    if settings.THUMBNAIL_FORCE_OVERWRITE or not thumbnail.exists() or force:
        try:
            source_image = default.engine.get_image(source)
        except IOError as e:
            logger.exception(e)
            # if S3Storage says file doesn't exist remotely, don't try to
            # create it and exit early.
            # Will return working empty image type; 404'd image
            logger.warn(
                "Remote file [{}}] at [{}}] does not exist".format(file_, geometry_string)
            )
            return

        # We might as well set the size since we have the image in memory
        try:
            image_info = default.engine.get_image_info(source_image)
            options['image_info'] = image_info
        except AttributeError:
            options['image_info'] = {}
        size = default.engine.get_image_size(source_image)
        source.set_size(size)

        try:
            default.backend._create_thumbnail(
                source_image, geometry_string, options, thumbnail)
            default.backend._create_alternative_resolutions(
                source_image, geometry_string, options, thumbnail.name)
        finally:
            default.engine.cleanup(source_image)

    # If the thumbnail exists we don't create it, the other option is
    # to delete and write but this could lead to race conditions so I
    # will just leave that out for now.
    default.kvstore.get_or_set(source)
    default.kvstore.set(thumbnail, source)
Exemple #6
0
 def save(self, name, *args, **kwargs):
     if self.exists(name):
         self.delete(name)
         delete_sorl_thumbnail(
             ImageFile(Path(name).as_posix(), storage=self),
             # Should not delete the source file, as this has already been done by `self.delete()` above
             delete_file=False,
         )
     return super().save(name, *args, **kwargs)
Exemple #7
0
 def delete(self, file_, delete_file=True):
     """
     Deletes file_ references in Key Value store and optionally the file_
     it self.
     """
     image_file = ImageFile(file_)
     if delete_file:
         image_file.delete()
     default.kvstore.delete(image_file)
    def get_thumbnail(self, file_, geometry_string, **options):
        source = ImageFile(file_)
        for key, value in self.default_options.items():
            options.setdefault(key, value)
        name = self._get_thumbnail_filename(source, geometry_string, options)
        thumbnail = ImageFile(name, default.storage)
        cached = default.kvstore.get(thumbnail)
        if cached:
            return cached
        # We don't check if thumbnail exists as sorl-thumbnail does. It becomes
        # very costly for remote storages.
        # Furthermore, I have added following code to reduce/prevent duplicate
        # tasks in celery. It's hacky.

        # Finally, if there is no thumbnail, we create one.
        from .tasks import create_thumbnail
        job = create_thumbnail.delay(source.name, geometry_string, **options)
        # Sometimes thumbnail generation takes quite some time, just return
        # the original image then.
        if job:
            geometry = parse_geometry(geometry_string)
            # We can't add a source row to the kvstore without the size
            # information being looked up, so add dummy information here
            # We'll need to correct this information when we generate the thumbnail
            source.set_size(geometry)
            default.kvstore.get_or_set(source)

            # We don't want to do any file access in this thread, so we tell sorlery
            # to proceed as normal and cheekily update the name and storage after
            # the hash has been calculated.
            thumbnail.set_size(geometry)
            default.kvstore.set(thumbnail, source)

            # Now we go back and manually update the thumbnail to point at the source image
            # Hopefully someone can suggest a better way to do this ... but the sorl internals
            # don't make it easy to.
            rawvalue = default.kvstore._get_raw(add_prefix(thumbnail.key))
            rawvaluearr = deserialize(rawvalue)
            rawvaluearr['name'] = file_.name
            default.kvstore._set_raw(add_prefix(thumbnail.key),
                                     serialize(rawvaluearr))

        thumbnail.name = file_.name
        return thumbnail
Exemple #9
0
def is_portrait(file_):
    """
    A very handy filter to determine if an image is portrait or landscape.
    """
    if sorl_settings.THUMBNAIL_DUMMY:
        return sorl_settings.THUMBNAIL_DUMMY_RATIO < 1
    if not file_:
        return False
    image_file = default.kvstore.get_or_set(ImageFile(file_))
    return image_file.is_portrait()
 def test_field1(self):
     self.KVSTORE.clear()
     item = Item.objects.get(image='100x100.jpg')
     im = ImageFile(item.image)
     self.assertEqual(None, self.KVSTORE.get(im))
     self.BACKEND.get_thumbnail(im, '27x27')
     self.BACKEND.get_thumbnail(im, '81x81')
     self.assertNotEqual(None, self.KVSTORE.get(im))
     self.assertEqual(3, len(list(self.KVSTORE._find_keys(identity='image'))))
     self.assertEqual(1, len(list(self.KVSTORE._find_keys(identity='thumbnails'))))
Exemple #11
0
def create_thumbnail(image_file, geometry_string, **options):
    # Note that thumbnail options must be same for a type of thumbnail.
    # Otherwise, different thumbnails are created.
    source = ImageFile(image_file)
    for key, value in default.backend.default_options.items():
        options.setdefault(key, value)
    name = default.backend._get_thumbnail_filename(source, geometry_string,
                                                   options)
    thumbnail = ImageFile(name, default.storage)
    source_image = default.engine.get_image(source)
    default.backend._create_thumbnail(source_image, geometry_string, options,
                                      thumbnail)

    # Need to set size to store in kvstore.
    size = default.engine.get_image_size(source_image)
    source.set_size(size)

    default.kvstore.get_or_set(source)
    default.kvstore.set(thumbnail, source)
Exemple #12
0
 def test_kvstore(self):
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     self.KVSTORE.delete_thumbnails(im)
     th1 = self.BACKEND.get_thumbnail(im, '50')
     th2 = self.BACKEND.get_thumbnail(im, 'x50')
     th3 = self.BACKEND.get_thumbnail(im, '20x20')
     self.assertEqual(set([th1.key, th2.key, th3.key]),
                      set(self.KVSTORE._get(im.key, identity='thumbnails')))
     self.KVSTORE.delete_thumbnails(im)
     self.assertEqual(None, self.KVSTORE._get(im.key,
                                              identity='thumbnails'))
Exemple #13
0
    def test_image_with_orientation(self):
        name = 'data/aspect_test.jpg'
        item, _ = Item.objects.get_or_create(image=name)

        im = ImageFile(item.image)
        th = self.BACKEND.get_thumbnail(im, '50x50')

        # this is a 100x200 image with orientation 6 (90 degrees CW rotate)
        # the thumbnail should end up 25x50
        self.assertEqual(th.x, 25)
        self.assertEqual(th.y, 50)
Exemple #14
0
    def setUp(self):
        os.makedirs(settings.MEDIA_ROOT)
        fn = pjoin(settings.MEDIA_ROOT, self.name)
        Image.new('L', (100, 100)).save(fn)
        self.im = ImageFile(self.name)

        logger = logging.getLogger('slog')
        logger.setLevel(logging.DEBUG)
        handler = MockLoggingHandler(level=logging.DEBUG)
        logger.addHandler(handler)
        self.log = handler.messages['debug']
Exemple #15
0
    def test_delete(self):
        im1 = Item.objects.get(image='100x100.jpg').image
        im2 = Item.objects.get(image='500x500.jpg').image
        default.kvstore.get_or_set(ImageFile(im1))
        # exists in kvstore and in storage 
        self.assertTrue(bool(default.kvstore.get(ImageFile(im1))))
        self.assertTrue(ImageFile(im1).exists())
        # delete
        delete(im1)
        self.assertFalse(bool(default.kvstore.get(ImageFile(im1))))
        self.assertFalse(ImageFile(im1).exists())

        default.kvstore.get_or_set(ImageFile(im2))
        # exists in kvstore and in storage 
        self.assertTrue(bool(default.kvstore.get(ImageFile(im2))))
        self.assertTrue(ImageFile(im2).exists())
        # delete
        delete(im2, delete_file=False)
        self.assertFalse(bool(default.kvstore.get(ImageFile(im2))))
        self.assertTrue(ImageFile(im2).exists())
    def setUp(self):
        super(CropTestCase, self).setUp()

        # portrait
        name = 'portrait.jpg'
        fn = os.path.join(settings.MEDIA_ROOT, name)
        im = Image.new('L', (100, 200))
        im.paste(255, (0, 0, 100, 100))
        im.save(fn)
        self.portrait = ImageFile(Item.objects.get_or_create(image=name)[0].image)
        self.KVSTORE.delete(self.portrait)

        # landscape
        name = 'landscape.jpg'
        fn = os.path.join(settings.MEDIA_ROOT, name)
        im = Image.new('L', (200, 100))
        im.paste(255, (0, 0, 100, 100))
        im.save(fn)
        self.landscape = ImageFile(Item.objects.get_or_create(image=name)[0].image)
        self.KVSTORE.delete(self.landscape)
Exemple #17
0
 def test_write(self):
     with same_open_fd_count(self):
         with self.assertRaises(Exception):
             self.engine.write(
                 image=self.engine.get_image(StringIO(b'xxx')),
                 options={
                     'format': 'JPEG',
                     'quality': 90,
                     'image_info': {}
                 },
                 thumbnail=ImageFile('whatever_thumb.jpg', default.storage))
Exemple #18
0
    def get_thumbnail(self, file_, geometry_string, **options):
        """
        Returns thumbnail as an ImageFile instance for file with geometry and
        options given. First it will try to get it from the key value store,
        secondly it will create it.
        """
        source = ImageFile(file_)

        #preserve image filetype
        if settings.THUMBNAIL_PRESERVE_FORMAT:
            self.default_options['format'] = self._get_format(file_)

        for key, value in self.default_options.iteritems():
            options.setdefault(key, value)
        # For the future I think it is better to add options only if they
        # differ from the default settings as below. This will ensure the same
        # filenames beeing generated for new options at default.
        for key, attr in self.extra_options:
            value = getattr(settings, attr)
            if value != getattr(default_settings, attr):
                options.setdefault(key, value)
        name = self._get_thumbnail_filename(source, geometry_string, options)
        thumbnail = ImageFile(name, default.storage)
        cached = default.kvstore.get(thumbnail)
        if cached:
            return cached
        if not thumbnail.exists():
            # We have to check exists() because the Storage backend does not
            # overwrite in some implementations.
            source_image = default.engine.get_image(source)
            # We might as well set the size since we have the image in memory
            size = default.engine.get_image_size(source_image)
            source.set_size(size)
            self._create_thumbnail(source_image, geometry_string, options,
                                   thumbnail)
        # If the thumbnail exists we don't create it, the other option is
        # to delete and write but this could lead to race conditions so I
        # will just leave that out for now.
        default.kvstore.get_or_set(source)
        default.kvstore.set(thumbnail, source)
        return thumbnail
Exemple #19
0
 def test_clear_doesnt_regenerate(self):
     self.KVSTORE.clear()
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     th = self.BACKEND.get_thumbnail(im, '27x27')
     th_name_orig = self.KVSTORE.get(th).name
     self.KVSTORE.clear()
     th = self.BACKEND.get_thumbnail(im, '27x27')
     th_name_new = self.KVSTORE.get(th).name
     self.assertEqual(
         th_name_orig,
         th_name_new,
     )
Exemple #20
0
    def test_crop_image_with_icc_profile(self):
        name = 'data/icc_profile_test.jpg'
        item, _ = Item.objects.get_or_create(image=name)

        im = ImageFile(item.image)
        th = self.BACKEND.get_thumbnail(im, '100x100')

        engine = PILEngine()

        self.assertEqual(
            engine.get_image(im).info.get('icc_profile'),
            engine.get_image(th).info.get('icc_profile'))
Exemple #21
0
 def test_cleanup1(self):
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     self.KVSTORE.delete_thumbnails(im)
     th = self.BACKEND.get_thumbnail(im, '3x3')
     self.assertEqual(th.exists(), True)
     th.delete()
     self.assertEqual(th.exists(), False)
     self.assertEqual(self.KVSTORE.get(th).x, 3)
     self.assertEqual(self.KVSTORE.get(th).y, 3)
     self.KVSTORE.cleanup()
     self.assertEqual(self.KVSTORE.get(th), None)
     self.KVSTORE.delete(im)
Exemple #22
0
 def make_thumbnail(self,
                    file_name,
                    thumb_name,
                    thumb_options,
                    geometry,
                    force=False):
     """
     Generate separate thumbnail.
     Generate new thumbnail if `force` is True.
     """
     try:
         if force:
             source = ImageFile(file_name, sorl_storage)
             full_options = get_thumbnail_options(source, thumb_options)
             thumb_name = sorl_backend._get_thumbnail_filename(
                 source, geometry, full_options)
             thumb = ImageFile(thumb_name, sorl_storage)
             sorl_kvstore._delete(thumb.key)
         get_thumbnail(file_name, geometry, **thumb_options)
     except Exception:
         if THUMBNAIL_MAKER_DEBUG:
             raise
Exemple #23
0
    def setUp(self):
        self.backend = get_module_class(settings.THUMBNAIL_BACKEND)()
        self.engine = get_module_class(settings.THUMBNAIL_ENGINE)()
        self.kvstore = get_module_class(settings.THUMBNAIL_KVSTORE)()
        if not os.path.exists(settings.MEDIA_ROOT):
            os.makedirs(settings.MEDIA_ROOT)
        # portrait
        name = 'portrait.jpg'
        fn = pjoin(settings.MEDIA_ROOT, name)
        im = Image.new('L', (100, 200))
        im.paste(255, (0, 0, 100, 100))
        im.save(fn)
        self.portrait = ImageFile(Item.objects.get_or_create(image=name)[0].image)
        self.kvstore.delete(self.portrait)

        # landscape
        name = 'landscape.jpg'
        fn = pjoin(settings.MEDIA_ROOT, name)
        im = Image.new('L', (200, 100))
        im.paste(255, (0, 0, 100, 100))
        im.save(fn)
        self.landscape = ImageFile(Item.objects.get_or_create(image=name)[0].image)
        self.kvstore.delete(self.landscape)
    def _clean_image(self):
        from sorl.thumbnail.engines.pil_engine import Engine
        from sorl.thumbnail.images import ImageFile

        e = Engine()
        f = ImageFile(self.image.file)
        tmp_image = e.get_image(f)
        tmp_image = e._orientation(tmp_image)
        tmp_image = tmp_image.convert('RGB')
        new_file = BytesIO()

        tmp_image.save(new_file, 'jpeg')
        file_content = ContentFile(new_file.getvalue())
        self.image.save(self.image.name, file_content, save=False)
Exemple #25
0
def background_margin(file_, geometry_string):
    """
    Returns the calculated margin for a background image and geometry
    """
    if not file_ or settings.THUMBNAIL_DUMMY:
        return 'auto'
    margin = [0, 0]
    image_file = default.kvstore.get_or_set(ImageFile(file_))
    x, y = parse_geometry(geometry_string, image_file.ratio)
    ex = x - image_file.x
    margin[0] = ex / 2
    ey = y - image_file.y
    margin[1] = ey / 2
    return ' '.join(['%spx' % n for n in margin])
Exemple #26
0
def create_thumbnail(field_name, pk, app_label, model_name, geometry_string,
                     **options):
    # Note that thumbnail options must be same for a type of thumbnail.
    # Otherwise, different thumbnails are created.
    model_type = ContentType.objects.get(app_label=app_label, model=model_name)
    obj = model_type.get_object_for_this_type(pk=pk)
    image = getattr(obj, field_name)
    source = ImageFile(image)

    for key, value in default.backend.default_options.items():
        options.setdefault(key, value)
    name = default.backend._get_thumbnail_filename(source, geometry_string,
                                                   options)
    thumbnail = ImageFile(name, default.storage)
    source_image = default.engine.get_image(source)
    default.backend._create_thumbnail(source_image, geometry_string, options,
                                      thumbnail)

    # Need to set size to store in kvstore.
    size = default.engine.get_image_size(source_image)
    source.set_size(size)

    default.kvstore.get_or_set(source)
    default.kvstore.set(thumbnail, source)
    def twitter_card(self, instance):

        source = ImageFile(instance.twitter_card_image)
        path = thumb_storage.backend._get_thumbnail_filename(source, "300x200", {'format': 'PNG'})

        full_path = os.path.join(settings.MEDIA_ROOT, path)
        if os.path.exists(full_path):
            os.unlink(full_path)

        thumbnail = get_thumbnail(instance.twitter_card_image, "300x200", format="PNG")
        settings.THUMBNAIL_FORCE_OVERWRITE = False
        html = """<a href="{url}" target="_blank"><img src="{img}"></a>""".format(
            url=instance.twitter_card_image.url,
            img=thumbnail.url
        )
        return mark_safe(html)
Exemple #28
0
    def test_image_from_hash(self):
        storage = S3Boto3Storage(bucket=self.bucket)
        s3_file = S3Boto3StorageFile(name=self.s3_image_key,
                                     mode='r',
                                     storage=storage)

        # Mock model Image field
        # S3Boto3StorageFile store storage information in ._storage wich is not checked by
        # ImageFile during storage identification
        s3_file.storage = storage

        image_s3 = ImageFile(s3_file)

        # Test local part
        options = {}
        thumbnail = get_thumbnail(s3_file, self.geometry_string, **options)
        print('Generated thumbnail url: {}'.format(thumbnail.url))
        print('Thumbnail cache key: {}'.format(thumbnail.name))

        # Now, test shrinkmeister server (should be up and running)
        resp = requests.get(thumbnail.url)
        image = Image(blob=resp.content)
        self.assertEqual(image.width, 50)
        self.assertEqual(image.height, 38)

        thumbnail_from_cache = self.cache.get(thumbnail.name)
        self.assertNotEqual(thumbnail_from_cache,
                            None,
                            msg="No image in cache detected :(")
        image = Image(blob=resp.content)
        self.assertEqual(image.width, 50)
        self.assertEqual(image.height, 38)

        resp = requests.get(thumbnail_from_cache.url)

        url, ext = thumbnail_from_cache.url.rsplit('.', 1)
        x2_url = '{}@2x.{}'.format(url, ext)
        print('x2 url {}'.format(x2_url))
        resp = requests.get(x2_url)
        image = Image(blob=resp.content)
        self.assertEqual(image.width, 100)
        self.assertEqual(image.height, 75)
Exemple #29
0
 def test_cleanup2(self):
     self.kvstore.clear()
     im = ImageFile(Item.objects.get(image='500x500.jpg').image)
     th3 = self.backend.get_thumbnail(im, '27x27')
     th4 = self.backend.get_thumbnail(im, '81x81')
     def keys_test(x, y, z):
         self.assertEqual(x, len(list(self.kvstore._find_keys(identity='image'))))
         self.assertEqual(y, len(list(self.kvstore._find_keys(identity='thumbnails'))))
         self.assertEqual(z, len(self.kvstore._get(im.key, identity='thumbnails') or []))
     keys_test(3, 1, 2)
     th3.delete()
     keys_test(3, 1, 2)
     self.kvstore.cleanup()
     keys_test(2, 1, 1)
     th4.delete()
     keys_test(2, 1, 1)
     self.kvstore.cleanup()
     keys_test(1, 0, 0)
     self.kvstore.clear()
     keys_test(0, 0, 0)
def margin(file_, geometry_string):
    """
    Returns the calculated margin for an image and geometry
    """
    if not file_ or settings.THUMBNAIL_DUMMY:
        return 'auto'
    margin = [0, 0, 0, 0]
    image_file = default.kvstore.get_or_set(ImageFile(file_))
    x, y = parse_geometry(geometry_string, image_file.ratio)
    ex = x - image_file.x
    margin[3] = ex // 2
    margin[1] = ex // 2
    if ex % 2:
        margin[1] += 1
    ey = y - image_file.y
    margin[0] = ey // 2
    margin[2] = ey // 2
    if ey % 2:
        margin[2] += 1
    return ' '.join(['%spx' % n for n in margin])