Beispiel #1
0
 def testQuality(self):
     img1 = scaleImage(CMYK, 84, 103)[0]
     img2 = scaleImage(CMYK, 84, 103, quality=50)[0]
     img3 = scaleImage(CMYK, 84, 103, quality=20)[0]
     self.assertNotEqual(img1, img2)
     self.assertNotEqual(img1, img3)
     self.failUnless(len(img1) > len(img2) > len(img3))
Beispiel #2
0
 def testQuality(self):
     img1 = scaleImage(CMYK, 84, 103)[0]
     img2 = scaleImage(CMYK, 84, 103, quality=50)[0]
     img3 = scaleImage(CMYK, 84, 103, quality=20)[0]
     self.assertNotEqual(img1, img2)
     self.assertNotEqual(img1, img3)
     self.failUnless(len(img1) > len(img2) > len(img3))
Beispiel #3
0
 def icon(self, uid):
     try:
         portrait = getattr(self.mdata.portraits, uid)
     except AttributeError:
         default = getattr(self.context, 'defaultUser.png')
         self.request.response.setHeader('Content-type', default.content_type)
         return scaleImage(default._data, width=64)[0]
     self.request.response.setHeader('Content-type', portrait.content_type)
     return scaleImage(portrait.data, width=64)[0]
Beispiel #4
0
 def create(self, fieldname, direction="thumbnail", height=None, width=None, **parameters):
     """ factory for image scales, see `IImageScaleStorage.scale` """
     orig_value = self.context.data.get(fieldname)
     if orig_value is None:
         return
     if height is None and width is None:
         _, format = orig_value.contentType.split("/", 1)
         return None, format, (orig_value._width, orig_value._height)
     if hasattr(aq_base(orig_value), "open"):
         orig_data = orig_value.open()
     else:
         orig_data = getattr(aq_base(orig_value), "data", orig_value)
     if not orig_data:
         return
     try:
         result = scaleImage(orig_data, direction=direction, height=height, width=width, **parameters)
         # Disable Plone 5 implicit CSRF to allow scaling on GET
         if HAS_PLONE_PROTECT:
             alsoProvides(self.request, IDisableCSRFProtection)
     except (ConflictError, KeyboardInterrupt):
         raise
     except Exception:
         exception('could not scale "%r" of %r', orig_value, self.context.context.absolute_url())
         return
     if result is not None:
         data, format, dimensions = result
         mimetype = "image/%s" % format.lower()
         value = orig_value.__class__(data, contentType=mimetype, filename=orig_value.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #5
0
 def icon(self, uid):
     try:
         portrait = getattr(self.mdata.portraits, uid)
     except AttributeError:
         return None
     self.request.response.setHeader('Content-type', portrait.content_type)
     return scaleImage(portrait.data, width=32)[0]
Beispiel #6
0
 def get_thumb(self, scale, key="image", direction="thumb"):
     """ Return data from plone scale or None"""
     #Make cache optional
     cachekey = (self.context.uid, scale, key)
     cached = thumb_cache.get(cachekey)
     if cached:
         return cached
     scales = get_image_scales()
     maxwidth, maxheight = scales[scale]
     blobs = IBlobs(self.context)
     if key in blobs:
         registry = get_current_registry()
         if blobs[key].mimetype in registry.settings[
                 'supported_thumbnail_mimetypes']:
             with blobs[key].blob.open() as f:
                 try:
                     thumb_data, image_type, size = scaleImage(
                         f,
                         width=maxwidth,
                         height=maxheight,
                         direction=direction)
                 except IOError:
                     #FIXME: Logging?
                     return
             thumb = Thumbnail(thumb_data, image_type=image_type, size=size)
             thumb_cache.put(cachekey, thumb)
             return thumb
Beispiel #7
0
 def create(self, context, **parameters):
     value = self.field.get(context)
     data = getattr(aq_base(value), 'data', value)
     if isinstance(data, Pdata):
         data = str(data)
     if data:
         return scaleImage(data, **parameters)
Beispiel #8
0
 def create(self, fieldname, direction='thumbnail', height=None, width=None, **parameters):
     """ factory for image scales, see `IImageScaleStorage.scale` """
     orig_value = getattr(self.context, fieldname)
     if orig_value is None:
         return
     if height is None and width is None:
         _, format = orig_value.contentType.split('/', 1)
         return None, format, (orig_value._width, orig_value._height)
     if hasattr(aq_base(orig_value), 'open'):
         orig_data = orig_value.open()
     else:
         orig_data = getattr(aq_base(orig_value), 'data', orig_value)
     if not orig_data:
         return
     try:
         result = scaleImage(orig_data, direction=direction, height=height, width=width, **parameters)
     except (ConflictError, KeyboardInterrupt):
         raise
     except Exception:
         exception('could not scale "%r" of %r',
             orig_value, self.context.absolute_url())
         return
     if result is not None:
         data, format, dimensions = result
         mimetype = 'image/%s' % format.lower()
         value = orig_value.__class__(data, contentType=mimetype, filename=orig_value.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #9
0
 def get_thumb(self, scale, key = None, direction = "thumbnail"):
     """ Return data from plone scale or None"""
     #Make cache optional
     if key is None:
         key = getattr(self.context, 'blob_key', 'image')
     cachekey = (self.context.uid, scale, key, direction)
     cached = self.thumb_cache.get(cachekey)
     if cached:
         return cached
     if direction not in _ALLOWED_SCALE_DIRECTIONS:
         return
     scales = get_image_scales()
     maxwidth, maxheight = scales[scale]
     blobs = IBlobs(self.context)
     if key in blobs:
         registry = get_current_registry()
         if blobs[key].mimetype in registry.settings['supported_thumbnail_mimetypes']:
             with blobs[key].blob.open() as f:
                 try:
                     thumb_data, image_type, size = scaleImage(
                         f, width = maxwidth, height = maxheight, direction = direction
                     )
                 except IOError:
                     #FIXME: Logging?
                     return
             thumb = Thumbnail(thumb_data, image_type = image_type, size = size)
             self.thumb_cache.put(cachekey, thumb)
             return thumb
Beispiel #10
0
 def create(self, fieldname, direction='thumbnail',
            height=None, width=None, **parameters):
     """ factory for image scales, see `IImageScaleStorage.scale` """
     orig_value = self.context.data.get(fieldname)
     if orig_value is None:
         return
     if height is None and width is None:
         _, format = orig_value.contentType.split('/', 1)
         return None, format, (orig_value._width, orig_value._height)
     if hasattr(aq_base(orig_value), 'open'):
         orig_data = orig_value.open()
     else:
         orig_data = getattr(aq_base(orig_value), 'data', orig_value)
     if not orig_data:
         return
     try:
         result = scaleImage(orig_data, direction=direction,
                             height=height, width=width, **parameters)
     except (ConflictError, KeyboardInterrupt):
         raise
     except Exception:
         exception('could not scale "%r" of %r',
                   orig_value, self.context.context.absolute_url())
         return
     if result is not None:
         data, format, dimensions = result
         mimetype = 'image/%s' % format.lower()
         value = orig_value.__class__(data, contentType=mimetype,
                                      filename=orig_value.filename)
         value.fieldname = fieldname
         return value, format, dimensions
 def crop_factory(fieldname, direction='keep', **parameters):
     blob = Blob()
     result = blob.open('w')
     _, image_format, dimensions = scaleImage(
         data['data'], result=result, **parameters)
     result.close()
     return blob, image_format, dimensions
Beispiel #12
0
    def create(self,
               fieldname,
               direction='thumbnail',
               height=None,
               width=None,
               **parameters):
        """ factory for image scales, see `IImageScaleStorage.scale` """
        orig_value = getattr(self.context, fieldname)
        
        # BfS extension:
        if callable(orig_value):
            orig_value = orig_value()

        if orig_value is None:
            return

        if height is None and width is None:
            _, format = orig_value.contentType.split('/', 1)
            return None, format, (orig_value._width, orig_value._height)
        if hasattr(aq_base(orig_value), 'open'):
            orig_data = orig_value.open()
        else:
            orig_data = getattr(aq_base(orig_value), 'data', orig_value)
        if not orig_data:
            return

        # Handle cases where large image data is stored in FileChunks instead
        # of plain string
        if isinstance(orig_data, FileChunk):
            # Convert data to 8-bit string
            # (FileChunk does not provide read() access)
            orig_data = str(orig_data)

        # If quality wasn't in the parameters, try the site's default scaling
        # quality if it exists.
        if 'quality' not in parameters:
            quality = self.getQuality()
            if quality:
                parameters['quality'] = quality

        try:
            result = scaleImage(orig_data,
                                direction=direction,
                                height=height,
                                width=width,
                                **parameters)
        except (ConflictError, KeyboardInterrupt):
            raise
        except Exception:
            exception('could not scale "%r" of %r',
                      orig_value, self.context.absolute_url())
            return
        if result is not None:
            data, format, dimensions = result
            mimetype = 'image/%s' % format.lower()
            value = orig_value.__class__(
                data, contentType=mimetype, filename=orig_value.filename)
            value.fieldname = fieldname
            return value, format, dimensions
Beispiel #13
0
    def image(self, subpath=None):
        """Return the image in a specific scale, either inline
        (default) or as attachment.

        :param subpath: [<image_scale>]/download] (optional).
                        When 'download' is the last element in subpath,
                        the image is served with a 'Content-Disposition:
                        attachment' header.  <image_scale> has to be one of the
                        predefined image_scales - either from the defaults in
                        this module or one set with a
                        kotti.image_scales.<scale_name> in your app config ini
                        file.
        :type subpath: str

        :result: complete response object
        :rtype: pyramid.response.Response
        """

        if subpath is None:
            subpath = self.request.subpath

        width, height = (None, None)
        subpath = list(subpath)

        if (len(subpath) > 0) and (subpath[-1] == "download"):
            disposition = "attachment"
            subpath.pop()
        else:
            disposition = "inline"

        if len(subpath) == 1:
            scale = subpath[0]
            if scale in image_scales:
                # /path/to/image/scale/thumb
                width, height = image_scales[scale]

        if not (width and height):
            return self.request.uploaded_file_response(
                self.context.data, disposition)

        image, format, size = scaleImage(self.context.data.file.read(),
                                         width=width,
                                         height=height,
                                         direction="thumb")
        res = Response(
            headerlist=[
                ('Content-Disposition', '{0};filename="{1}"'.format(
                    disposition,
                    self.context.filename.encode('ascii', 'ignore'))),
                ('Content-Length', str(len(image))),
                ('Content-Type', str(self.context.mimetype)),
            ],
            body=image,
        )
        res.content_disposition = rfc6266.build_header(
            self.context.filename, disposition=disposition,
            filename_compat=unidecode(self.context.filename))

        return res
Beispiel #14
0
 def create_scale(self, data, direction, height, width, **parameters):
     return scaleImage(
         data,
         direction=direction,
         height=height,
         width=width,
         **parameters
     )
Beispiel #15
0
 def testAlphaForcesPNG(self):
     # first image without alpha
     src = PIL.Image.new("RGBA", (256, 256), (255, 255, 255, 255))
     for y in range(0, 256):
         for x in range(0, 256):
             src.putpixel((x, y), (x, y, 0, 255))
     result = StringIO()
     src.save(result, "TIFF")
     self.assertEqual(scaleImage(result, 84, 103, "down")[1], "JPEG")
     # now with alpha
     src = PIL.Image.new("RGBA", (256, 256), (255, 255, 255, 128))
     result = StringIO()
     for y in range(0, 256):
         for x in range(0, 256):
             src.putpixel((x, y), (x, y, 0, x))
     src.save(result, "TIFF")
     self.assertEqual(scaleImage(result, 84, 103, "down")[1], "PNG")
Beispiel #16
0
 def crop_factory(fieldname, direction='keep', **parameters):
     blob = Blob()
     result = blob.open('w')
     _, image_format, dimensions = scaleImage(data['data'],
                                              result=result,
                                              **parameters)
     result.close()
     return blob, image_format, dimensions
Beispiel #17
0
 def testAlphaForcesPNG(self):
     # first image without alpha
     src = PIL.Image.new("RGBA", (256, 256), (255, 255, 255, 255))
     for y in range(0, 256):
         for x in range(0, 256):
             src.putpixel((x, y), (x, y, 0, 255))
     result = StringIO()
     src.save(result, "TIFF")
     self.assertEqual(scaleImage(result, 84, 103, "down")[1], "JPEG")
     # now with alpha
     src = PIL.Image.new("RGBA", (256, 256), (255, 255, 255, 128))
     result = StringIO()
     for y in range(0, 256):
         for x in range(0, 256):
             src.putpixel((x, y), (x, y, 0, x))
     src.save(result, "TIFF")
     self.assertEqual(scaleImage(result, 84, 103, "down")[1], "PNG")
Beispiel #18
0
 def create_scale(self, data, direction, height, width, **parameters):
     return scaleImage(
         data,
         direction=direction,
         height=height,
         width=width,
         **parameters
     )
Beispiel #19
0
    def create(self,
               fieldname,
               direction='thumbnail',
               height=None,
               width=None,
               **parameters):
        #         import pdb
        #         pdb.set_trace()
        """ factory for image scales, see `IImageScaleStorage.scale` """
        orig_value = getattr(self.context, fieldname)
        if orig_value is None:
            return

        if height is None and width is None:
            _, format = orig_value.contentType.split('/', 1)
            return None, format, (orig_value._width, orig_value._height)
        if hasattr(aq_base(orig_value), 'open'):
            orig_data = orig_value.open()
        else:
            orig_data = getattr(aq_base(orig_value), 'data', orig_value)
        if not orig_data:
            return

        # Handle cases where large image data is stored in FileChunks instead
        # of plain string
        if isinstance(orig_data, FileChunk):
            # Convert data to 8-bit string
            # (FileChunk does not provide read() access)
            orig_data = str(orig_data)

        # If quality wasn't in the parameters, try the site's default scaling
        # quality if it exists.
        if 'quality' not in parameters:
            quality = self.getQuality()
            if quality:
                parameters['quality'] = quality

        try:
            result = scaleImage(orig_data,
                                direction=direction,
                                height=height,
                                width=width,
                                **parameters)
        except (ConflictError, KeyboardInterrupt):
            raise
        except Exception:
            exception('could not scale "%r" of %r', orig_value,
                      self.context.absolute_url())
            return
        if result is not None:
            data, format, dimensions = result
            mimetype = 'image/%s' % format.lower()
            value = orig_value.__class__(data,
                                         contentType=mimetype,
                                         filename=orig_value.filename)
            value.fieldname = fieldname
            return value, format, dimensions
Beispiel #20
0
 def create(self, context, **parameters):
     value = self.field.get(context)
     data = getattr(aq_base(value), 'data', value)
     if isinstance(data, Pdata):
         data = str(data)
     if data:
         if 'quality' not in parameters and self.quality:
             parameters['quality'] = self.quality
         return scaleImage(data, **parameters)
Beispiel #21
0
 def create(self, context, **parameters):
     value = self.field.get(context)
     data = getattr(aq_base(value), 'data', value)
     if isinstance(data, Pdata):
         data = str(data)
     if data:
         if 'quality' not in parameters and self.quality:
             parameters['quality'] = self.quality
         return scaleImage(data, **parameters)
Beispiel #22
0
 def create(self, context, **parameters):
     wrapper = self.field.get(context)
     if wrapper:
         blob = Blob()
         result = blob.open('w')
         _, format, dimensions = scaleImage(wrapper.getBlob().open('r'),
                                            result=result, **parameters)
         result.close()
         return blob, format, dimensions
Beispiel #23
0
    def image(self, subpath=None):
        """Return the image in a specific scale, either inline
        (default) or as attachment.

        :param subpath: [<image_scale>]/download] (optional).
                        When 'download' is the last element in subpath,
                        the image is served with a 'Content-Disposition:
                        attachment' header.  <image_scale> has to be one of the
                        predefined image_scales - either from the defaults in
                        this module or one set with a
                        kotti.image_scales.<scale_name> in your app config ini
                        file.
        :type subpath: str

        :result: complete response object
        :rtype: pyramid.response.Response
        """

        if subpath is None:
            subpath = self.request.subpath

        width, height = (None, None)
        subpath = list(subpath)

        if (len(subpath) > 0) and (subpath[-1] == "download"):
            disposition = "attachment"
            subpath.pop()
        else:
            disposition = "inline"

        if len(subpath) == 1:
            scale = subpath[0]
            if scale in image_scales:
                # /path/to/image/scale/thumb
                width, height = image_scales[scale]

        if not (width and height):
            return UploadedFileResponse(self.context.data, self.request,
                                        disposition)

        image, format, size = scaleImage(self.context.data.file.read(),
                                         width=width,
                                         height=height,
                                         direction="thumb")
        res = Response(
            headerlist=[
                ('Content-Disposition', '{0};filename="{1}"'.format(
                    disposition,
                    self.context.filename.encode('ascii', 'ignore'))),
                ('Content-Length', str(len(image))),
                ('Content-Type', str(self.context.mimetype)),
            ],
            body=image,
        )

        return res
Beispiel #24
0
 def crop_factory(fieldname, **parameters):
     result = scaleImage(image_file.read(), **parameters)
     if result is not None:
         data, format, dimensions = result
         mimetype = 'image/%s' % format.lower()
         value = field.__class__(data,
                                 contentType=mimetype,
                                 filename=field.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #25
0
 def create(self, context, **parameters):
     wrapper = self.field.get(context)
     if wrapper:
         blob = Blob()
         result = blob.open('w')
         _, format, dimensions = scaleImage(wrapper.getBlob().open('r'),
                                            result=result,
                                            **parameters)
         result.close()
         return blob, format, dimensions
Beispiel #26
0
    def handle_save_action(self, action, data):
        if form.applyChanges(self.context, self.form_fields, data,
                             self.adapters):
            zope.event.notify(
                zope.lifecycleevent.ObjectModifiedEvent(self.context))
            zope.event.notify(ploneformbase.EditSavedEvent(self.context))
            IStatusMessage(self.request).addStatusMessage(_("Changes saved."),
                                                          type="info")
        else:
            zope.event.notify(ploneformbase.EditCancelledEvent(self.context))
            IStatusMessage(self.request).addStatusMessage(
                _("No changes made."), type="info")

        self.settings = PageSliderSettings(self.context)
        slides = self.settings.slides
        index = data.get('index', -1)

        image = data.get('image')
        image_type = None
        if image != None:
            scale_width = getUtility(IRegistry)[
                'tx.slider.configlet.ISliderControlPanel.image_scale_width']
            (image, image_type, image_size) = scaleImage(image,
                                                         width=scale_width)
        else:
            if index != -1:
                image = slides[index].get('image')
                image_type = slides[index].get('image_type')

        # create new uuid on each save
        uuid = uuid4().hex

        value = {
            'configuration': data.get('configuration'),
            'heading': data.get('heading'),
            'html': data.get('slide'),
            'image': image,
            'image_type': image_type,
            'link_reference': data.get('link_reference'),
            'url': data.get('url'),
            'uuid': uuid
        }

        if index == -1:
            slides.append(value)
            index = len(slides) - 1
        else:
            slides[index] = value

        self.settings.slides = slides

        url = getMultiAdapter((self.context, self.request),
                              name='absolute_url')() + "/@@tx-slider-settings"
        self.request.response.redirect(url)
Beispiel #27
0
 def testAutomaticGreyscale(self):
     src = PIL.Image.new("RGB", (256, 256), (255, 255, 255))
     draw = PIL.ImageDraw.Draw(src)
     for i in range(0, 256):
         draw.line(((0, i), (256, i)), fill=(i, i, i))
     result = StringIO()
     src.save(result, "JPEG")
     (imagedata, format, size) = scaleImage(result, 200, None, "down")
     image = PIL.Image.open(StringIO(imagedata))
     self.assertEqual(max(image.size), 200)
     self.assertEqual(image.mode, 'L')
     self.assertEqual(image.format, 'JPEG')
Beispiel #28
0
 def testAutomaticGreyscale(self):
     src = PIL.Image.new("RGB", (256, 256), (255, 255, 255))
     draw = PIL.ImageDraw.Draw(src)
     for i in range(0, 256):
         draw.line(((0, i), (256, i)), fill=(i, i, i))
     result = StringIO()
     src.save(result, "JPEG")
     (imagedata, format, size) = scaleImage(result, 200, None, "down")
     image = PIL.Image.open(StringIO(imagedata))
     self.assertEqual(max(image.size), 200)
     self.assertEqual(image.mode, 'L')
     self.assertEqual(image.format, 'JPEG')
 def crop_factory(fieldname, **parameters):
     result = scaleImage(image_file.read(), **parameters)
     if result is not None:
         data, format, dimensions = result
         mimetype = 'image/%s' % format.lower()
         value = field.__class__(
             data,
             contentType=mimetype,
             filename=field.filename
         )
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #30
0
    def image(self):
        """return the image in a specific scale, either inline (default) or as attachment"""

        subpath = list(self.request.subpath)

        if (len(subpath) > 0) and (subpath[-1] == "download"):
            disposition = "attachment"
            subpath.pop()
        else:
            disposition = "inline"

        if len(subpath) == 1:
            scale = subpath[0]
            if scale in image_scales:
                # /path/to/image/scale/thumb
                width, height = image_scales[scale]
            else:
                # /path/to/image/scale/160x120
                try:
                    width, height = [int(v) for v in scale.split("x")]
                except ValueError:
                    width, height = (None, None)

        elif len(subpath) == 2:
            # /path/to/image/scale/160/120
            try:
                width, height = [int(v) for v in subpath]
            except ValueError:
                width, height = (None, None)

        else:
            # don't scale at all
            width, height = (None, None)

        if width and height:
            image, format, size = scaleImage(self.context.data, width=width, height=height, direction="thumb")
        else:
            image = self.context.data

        res = Response(
            headerlist=[
                (
                    "Content-Disposition",
                    '%s;filename="%s"' % (disposition, self.context.filename.encode("ascii", "ignore")),
                ),
                ("Content-Length", str(len(image))),
                ("Content-Type", str(self.context.mimetype)),
            ],
            app_iter=image,
        )

        return res
Beispiel #31
0
    def __call__(self, fieldname='image'):
        image_view = self.context.unrestrictedTraverse('@@imgview')
        image = getattr(image_view, 'img', None)
        url = self.context.absolute_url()
        if not image:
            logger.error("Error while recreating scale for %s" % url)
            raise AttributeError(fieldname)

        info = None
        if getattr(image, 'portal_type', '') == 'Image':
            field = image.getField(fieldname)
            if not field:
                raise AttributeError(fieldname)
            try:
                field.removeScales(image)
                field.createScales(image)
                logger.info("Succesfully scaled %s" % url)
            except Exception:
                logger.error("Error while recreating scale for %s" % url)
        else:
            # use plone.app.blob store scale
            for name, size in image.sizes.items():
                image_data = image_view(name)
                if not image_data:
                    continue

                width, height = size
                scale_result = scaleImage(image_data, width=width, height=height)
                if scale_result is not None:
                    id = fieldname + "_" + name
                    data, format_, dimensions = scale_result
                    info = dict(
                        data=data,
                        id = id,
                        content_type='image/{0}'.format(format_.lower()),
                        filename='',
                    )
                    fields = getattr(aq_base(self.context), blobScalesAttr, {})
                    scales = fields.setdefault(fieldname, {})
                    info['blob'] = Blob()
                    blob = info['blob'].open('w')
                    blob.write(info['data'])
                    blob.close()
                    del info['data']
                    scales[name] = info
                    setattr(self.context, blobScalesAttr, fields)
                    self.context._p_changed = True
            logger.info("Succesfully scaled %s " % url)
        return "Done"
Beispiel #32
0
    async def __call__(self):
        registry = await get_registry()
        settings = registry.for_interface(IImagingSettings)
        scale_name = self.request.matchdict["scale"]
        allowed_sizes = settings["allowed_sizes"]
        if scale_name not in allowed_sizes:
            raise HTTPNotFound(
                content={"reason": f"{scale_name} is not supported"})
        file = self.field.get(self.field.context or self.context)
        if file is None:
            raise HTTPNotFound(
                content={
                    "message": "File or custom filename required to download"
                })

        adapter = get_multi_adapter((self.context, self.request, self.field),
                                    IFileManager)
        data = b""
        async for chunk in adapter.iter_data():
            data += chunk

        width, _, height = allowed_sizes[scale_name].partition(":")

        result, format_, size = scaleImage(
            data,
            int(width),
            int(height),
            quality=settings["quality"],
            direction="thumbnail",
        )

        cors_renderer = app_settings["cors_renderer"](self.request)
        headers = await cors_renderer.get_headers()
        headers.update({
            "CONTENT-DISPOSITION":
            'attachment; filename="{}"'.format(file.filename)
        })

        download_resp = Response(
            status=200,
            headers=headers,
            content_type=f"image/{format_}",
            content_length=len(result),
        )
        await download_resp.prepare(self.request)

        await download_resp.write(result)
        await download_resp.write(eof=True)
        return download_resp
Beispiel #33
0
 def crop_factory(fieldname, **parameters):
     # LMU patch: remove the scale parameter
     _parameters = {
         key: value
         for key, value in parameters.iteritems() if key != 'scale'
     }
     result = scaleImage(image_file.read(), **_parameters)
     if result is not None:
         data, format, dimensions = result
         mimetype = 'image/{0:s}'.format(format.lower())
         field = self.get_image_field(fieldname)
         value = field.__class__(data,
                                 contentType=mimetype,
                                 filename=field.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #34
0
 def create(self,
            fieldname,
            direction='thumbnail',
            height=None,
            width=None,
            **parameters):
     """ factory for image scales, see `IImageScaleStorage.scale` """
     if not IPersistentCoverTile.providedBy(self.context):
         base_scales = queryMultiAdapter((self.context, self.request),
                                         name='images',
                                         default=None)
         return base_scales and base_scales.create(
             fieldname, direction, height, width, **parameters)
     orig_value = self.context.data.get(fieldname)
     if orig_value is None:
         return
     if height is None and width is None:
         _, format = orig_value.contentType.split('/', 1)
         return None, format, (orig_value._width, orig_value._height)
     if hasattr(aq_base(orig_value), 'open'):
         orig_data = orig_value.open()
     else:
         orig_data = getattr(aq_base(orig_value), 'data', orig_value)
     if not orig_data:
         return
     try:
         result = scaleImage(orig_data,
                             direction=direction,
                             height=height,
                             width=width,
                             **parameters)
     except (ConflictError, KeyboardInterrupt):
         raise
     except Exception:
         logging.exception(
             'could not scale "%r" of %r', orig_value,
             self.context.context.absolute_url())  # FIXME: PEP 3101
         return
     if result is not None:
         data, format, dimensions = result
         # FIXME: PEP 3101; how to avoid confusion among method and variable name?
         mimetype = 'image/%s' % format.lower()
         value = orig_value.__class__(data,
                                      contentType=mimetype,
                                      filename=orig_value.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #35
0
    async def __call__(self):
        settings = self.request.container_settings.for_interface(
            IImagingSettings)
        scale_name = self.request.matchdict['scale']
        allowed_sizes = settings['allowed_sizes']
        if scale_name not in allowed_sizes:
            raise HTTPNotFound(
                content={'reason': f'{scale_name} is not supported'})
        file = self.field.get(self.field.context or self.context)
        if file is None:
            raise HTTPNotFound(
                content={
                    'message': 'File or custom filename required to download'
                })

        adapter = get_multi_adapter((self.context, self.request, self.field),
                                    IFileManager)
        data = b''
        async for chunk in adapter.iter_data():
            data += chunk

        width, _, height = allowed_sizes[scale_name].partition(':')

        result, format_, size = scaleImage(data,
                                           int(width),
                                           int(height),
                                           quality=settings['quality'],
                                           direction='thumbnail')

        cors_renderer = app_settings['cors_renderer'](self.request)
        headers = await cors_renderer.get_headers()
        headers.update({
            'CONTENT-DISPOSITION':
            'attachment; filename="{}"'.format(file.filename)
        })

        download_resp = StreamResponse(headers=headers)
        download_resp.content_type = f'image/{format_}'
        if file.size:
            download_resp.content_length = len(result)

        await download_resp.prepare(self.request)
        await download_resp.write(result)
        await download_resp.drain()
        await download_resp.write_eof()
        return download_resp
Beispiel #36
0
 def _get_scaled_img(self, item, image_field, size):
     request = getRequest()
     if (
         ICatalogBrain.providedBy(item) or
         IContentListingObject.providedBy(item)
     ):
         obj = item.getObject()
     else:
         obj = item
     info = {}
     if hasattr(obj, image_field):
         scales = getMultiAdapter((obj, request), name='images')
         if size == 'lgip':
             stored_image = getattr(obj, image_field)
             scale = image_scale.scaleImage(
                 stored_image.data,
                 width=stored_image.getImageSize()[0],
                 height=stored_image.getImageSize()[1],
                 direction='keep',
                 quality=10
             )
         if size == 'small':
             scale = scales.scale(image_field, width=300, height=300)
         if size == 'medium':
             scale = scales.scale(image_field, width=600, height=600)
         if size == 'large':
             scale = scales.scale(image_field, width=900, height=900)
         else:
             scale = scales.scale(image_field, width=1200, height=1200)
         if scale is not None:
             info['url'] = scale.url
             info['width'] = scale.width
             info['height'] = scale.height
         else:
             info['url'] = IMG
             info['width'] = '1px'
             info['height'] = '1px'
     else:
         info['url'] = IMG
         info['width'] = '1px'
         info['height'] = '1px'
     return info
Beispiel #37
0
    def image(self, subpath=None):
        """Return the image in a specific scale, either inline
        (default) or as attachment."""

        if subpath is None:
            subpath = self.request.subpath

        width, height = (None, None)
        subpath = list(subpath)

        if (len(subpath) > 0) and (subpath[-1] == "download"):
            disposition = "attachment"
            subpath.pop()
        else:
            disposition = "inline"

        if len(subpath) == 1:
            scale = subpath[0]
            if scale in image_scales:
                # /path/to/image/scale/thumb
                width, height = image_scales[scale]

        if width and height:
            image, format, size = scaleImage(self.context.data,
                                             width=width,
                                             height=height,
                                             direction="thumb")
        else:
            image = self.context.data

        res = Response(
            headerlist=[
                ('Content-Disposition', '%s;filename="%s"' %
                 (disposition, self.context.filename.encode('ascii',
                                                            'ignore'))),
                ('Content-Length', str(len(image))),
                ('Content-Type', str(self.context.mimetype)),
            ],
            body=image,
        )

        return res
Beispiel #38
0
 def testAutomaticPalette(self):
     # get a JPEG with more than 256 colors
     jpeg = PIL.Image.open(StringIO(PROFILE))
     self.assertEqual(jpeg.mode, 'RGB')
     self.assertEqual(jpeg.format, 'JPEG')
     self.assertIsNone(jpeg.getcolors(maxcolors=256))
     # convert to PNG
     dst = StringIO()
     jpeg.save(dst, "PNG")
     dst.seek(0)
     png = PIL.Image.open(dst)
     self.assertEqual(png.mode, 'RGB')
     self.assertEqual(png.format, 'PNG')
     self.assertIsNone(png.getcolors(maxcolors=256))
     # scale it to a size where we get less than 256 colors
     (imagedata, format, size) = scaleImage(dst.getvalue(), 24, None, "down")
     image = PIL.Image.open(StringIO(imagedata))
     # we should now have an image in palette mode
     self.assertEqual(image.mode, 'P')
     self.assertEqual(image.format, 'PNG')
Beispiel #39
0
 def create(self, fieldname, direction='thumbnail',
            height=None, width=None, **parameters):
     """ factory for image scales, see `IImageScaleStorage.scale` """
     if not IPersistentCoverTile.providedBy(self.context):
         base_scales = queryMultiAdapter((self.context, self.request),
                                         name='images', default=None)
         return base_scales and base_scales.create(fieldname,
                                                   direction,
                                                   height,
                                                   width,
                                                   **parameters)
     orig_value = self.context.data.get(fieldname)
     if orig_value is None:
         return
     if height is None and width is None:
         _, format = orig_value.contentType.split('/', 1)
         return None, format, (orig_value._width, orig_value._height)
     if hasattr(aq_base(orig_value), 'open'):
         orig_data = orig_value.open()
     else:
         orig_data = getattr(aq_base(orig_value), 'data', orig_value)
     if not orig_data:
         return
     try:
         result = scaleImage(orig_data, direction=direction,
                             height=height, width=width, **parameters)
     except (ConflictError, KeyboardInterrupt):
         raise
     except Exception:
         logging.exception(
             'could not scale "%r" of %r',
             orig_value, self.context.context.absolute_url())  # FIXME: PEP 3101
         return
     if result is not None:
         data, format, dimensions = result
         # FIXME: PEP 3101; how to avoid confusion among method and variable name?
         mimetype = 'image/%s' % format.lower()
         value = orig_value.__class__(data, contentType=mimetype,
                                      filename=orig_value.filename)
         value.fieldname = fieldname
         return value, format, dimensions
Beispiel #40
0
    def image(self, subpath=None):
        """Return the image in a specific scale, either inline
        (default) or as attachment."""

        if subpath is None:
            subpath = self.request.subpath

        width, height = (None, None)
        subpath = list(subpath)

        if (len(subpath) > 0) and (subpath[-1] == "download"):
            disposition = "attachment"
            subpath.pop()
        else:
            disposition = "inline"

        if len(subpath) == 1:
            scale = subpath[0]
            if scale in image_scales:
                # /path/to/image/scale/thumb
                width, height = image_scales[scale]

        if width and height:
            image, format, size = scaleImage(self.context.data,
                                             width=width,
                                             height=height,
                                             direction="thumb")
        else:
            image = self.context.data

        res = Response(
            headerlist=[('Content-Disposition', '%s;filename="%s"' % (
                disposition,
                self.context.filename.encode('ascii', 'ignore'))),
                ('Content-Length', str(len(image))),
                ('Content-Type', str(self.context.mimetype)),
            ],
            body=image,
            )

        return res
Beispiel #41
0
 def testAutomaticPalette(self):
     # get a JPEG with more than 256 colors
     jpeg = PIL.Image.open(StringIO(PROFILE))
     self.assertEqual(jpeg.mode, 'RGB')
     self.assertEqual(jpeg.format, 'JPEG')
     self.assertIsNone(jpeg.getcolors(maxcolors=256))
     # convert to PNG
     dst = StringIO()
     jpeg.save(dst, "PNG")
     dst.seek(0)
     png = PIL.Image.open(dst)
     self.assertEqual(png.mode, 'RGB')
     self.assertEqual(png.format, 'PNG')
     self.assertIsNone(png.getcolors(maxcolors=256))
     # scale it to a size where we get less than 256 colors
     (imagedata, format, size) = scaleImage(
         dst.getvalue(), 24, None, "down"
     )
     image = PIL.Image.open(StringIO(imagedata))
     # we should now have an image in palette mode
     self.assertEqual(image.mode, 'P')
     self.assertEqual(image.format, 'PNG')
Beispiel #42
0
 def get_thumb(self, scale, key = "image", direction = "thumb"):
     """ Return data from plone scale or None"""
     #Make cache optional
     cachekey = (self.context.uid, scale, key)
     cached = thumb_cache.get(cachekey)
     if cached:
         return cached
     scales = get_image_scales()
     maxwidth, maxheight = scales[scale]
     blobs = IBlobs(self.context)
     if key in blobs:
         registry = get_current_registry()
         if blobs[key].mimetype in registry.settings['supported_thumbnail_mimetypes']:
             with blobs[key].blob.open() as f:
                 try:
                     thumb_data, image_type, size = scaleImage(f, width = maxwidth, height = maxheight, direction = direction)
                 except IOError:
                     #FIXME: Logging?
                     return
             thumb = Thumbnail(thumb_data, image_type = image_type, size = size)
             thumb_cache.put(cachekey, thumb)
             return thumb
Beispiel #43
0
 def testRestrictHeightOnlyUpScaleZero(self):
     self.assertEqual(scaleImage(PNG, 0, 51, "up")[2], (42, 51))
Beispiel #44
0
 def testNoStretchingUpScale(self):
     self.assertEqual(scaleImage(PNG, 200, 103, "up")[2], (84, 103))
Beispiel #45
0
 def testSameSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 84, 103, "up")[2], (84, 103))
Beispiel #46
0
 def testDoubleSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 168, 206, "up")[2], (168, 206))
Beispiel #47
0
 def testHalfSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 42, 51, "up")[2], (42, 51))
Beispiel #48
0
 def testNoStretchingUpScale(self):
     self.assertEqual(scaleImage(PNG, 200, 103, "up")[2], (84, 103))
Beispiel #49
0
 def testRestrictWidthOnlyUpScaleZero(self):
     self.assertEqual(scaleImage(PNG, 42, 0, "up")[2], (42, 52))
Beispiel #50
0
 def testRestrictWidthOnlyUpScale(self):
     self.assertEqual(scaleImage(PNG, 42, None, "up")[2], (42, 52))
Beispiel #51
0
 def testKeepAspectRatioBBB(self):
     self.assertEqual(scaleImage(PNG, 80, 80, "keep")[2], (65, 80))
Beispiel #52
0
 def testResultBuffer(self):
     img1 = scaleImage(PNG, 84, 103)[0]
     result = BytesIO()
     img2 = scaleImage(PNG, 84, 103, result=result)[0]
     self.assertEqual(result, img2)      # the return value _is_ the buffer
     self.assertEqual(result.getvalue(), img1)   # but with the same value
Beispiel #53
0
 def testRestrictHeightOnlyUpScale(self):
     self.assertEqual(scaleImage(PNG, None, 51, "up")[2], (42, 51))
Beispiel #54
0
 def testKeepAspectRatio(self):
     self.assertEqual(scaleImage(PNG, 80, 80, "keep")[2], (65, 80))
Beispiel #55
0
 def testDoubleSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 168, 206, "up")[2], (168, 206))
Beispiel #56
0
 def testSameSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 84, 103, "up")[2], (84, 103))
Beispiel #57
0
 def testKeepAspectRatio(self):
     self.assertEqual(scaleImage(PNG, 80, 80, "thumbnail")[2], (65, 80))
Beispiel #58
0
 def testHalfSizeUpScale(self):
     self.assertEqual(scaleImage(PNG, 42, 51, "up")[2], (42, 51))