Ejemplo n.º 1
0
def images(request):
  """
  request sample
  for thumbnail: 
  ?url=<filebasename>_T[width,height].<extension>
  for cropping (http://docs.wand-py.org/en/0.4.1/wand/image.html)
  ?url=<filebasename>_c[300,300,310,310].<extension>
  or
  ?url=<filebasename>_c[300,300].<extension>
  """
  #if not request.user.is_authenticated:
  #  raise NotAuthenticated()
  #_c[10,20,50,100]
  # before the last point.
  if not 'url' in request.GET:
    return Response({"error": "missing url param"},  status=status.HTTP_422_UNPROCESSABLE_ENTITY)

  # search for something like ?url=/media/image/2162934893_b053386d3f_o_c[100,20,500,200].jpg
  # where the original image is this part: /media/image/2162934893_b053386d3f_o.jpg
  ms = re.search(r'\/media\/(?P<path>[a-zA-Z_\/\d\-]+)_(?P<funcs>[a-zA-Z\[\]\-\d\!\^%,]+)\.(?P<ext>jpg|gif|jpeg|jpe)$', request.GET['url'])

  if ms is None:
    return Response({"error": "invalid url param", "url": request.GET['url']},  status=status.HTTP_422_UNPROCESSABLE_ENTITY)

  # get the groups from our regex
  basepath  = os.path.normpath(ms.group('path'))
  ext       = ms.group('ext')
  functions = ms.group('funcs')

  # input filename (original) and output filename (modified)
  filename    = os.path.join(settings.MEDIA_ROOT, '%s.%s'% (basepath,ext))
  filenameout = os.path.join(settings.MEDIA_ROOT, '%s_%s.%s'% (basepath,functions,ext))
  
  if not os.path.exists(filename):
    return Response({"error": "requested image was not found"}, status=status.HTTP_404_NOT_FOUND)

  #if os.path.exists(filenameout):
  #  return streamHttpResponse(filenameout)

  # get distinct wand methods
  funcs = re.findall(r'(?P<func>[a-zA-Z])\[?(?P<args>[\d\-%x,]+)\]?',functions)

  if not funcs:
    return Response({"error": "invalid url param - url does not contain any valid resize function.", "url": request.GET['url']},  status=status.HTTP_422_UNPROCESSABLE_ENTITY)

  available_funcs = {
    'c': 'crop',
    't': 'transform', # crop and resize
    'T': 'thumbnail',
    'r': 'resize',
    'F': 'fit'
  }

  with Image(filename=filename, resolution=settings.MILLER_CROPPING_RESOLUTION) as img:
    for a,b in funcs:
      if a == 'T':
        args = map(lambda x: int(x) if x.isnumeric() else x,b.split(','))
        generate_snapshot(filename, filenameout, width=args[0], height=args[-1], crop=True)
        return streamHttpResponse(filenameout)
      else:
        args = map(lambda x: int(x) if x.isnumeric() else x, b.split(','))
      if a == 'F':
        generate_snapshot(filename, filenameout, width=args[0])
        return streamHttpResponse(filenameout)
      try:
        getattr(img,available_funcs[a])(*args)
        # transform resize image automatically based on settings
        if settings.MILLER_CROPPING_AUTO_RESIZE and (img.width > settings.MILLER_CROPPING_MAX_SIZE or img.height > settings.MILLER_CROPPING_MAX_SIZE):
          # calculate ratio 
          ratio = 1.0*img.width/img.height
          # dummy var init
          width = height = 0
          if img.width > img.height:
            width = settings.MILLER_CROPPING_MAX_SIZE
            height = width / ratio
          elif img.width < img.height:
            height = settings.MILLER_CROPPING_MAX_SIZE
            width = ratio * height
          else: 
            #squared image
            height = width = max_size
          img.transform(resize='%sx%s'% (width, height))
          img.resolution = (settings.MILLER_CROPPING_RESOLUTION, settings.MILLER_CROPPING_RESOLUTION)
          img.compression_quality = settings.MILLER_CROPPING_COMPRESSION_QUALITY
        img.save(filename=filenameout)
      except TypeError as e:
        return Response({"exception": '%s' % e, 'type': 'TypeError'},  status=status.HTTP_400_BAD_REQUEST)
      except KeyError as e:
        return Response({"exception": '%s' % e, 'type': 'KeyError'},  status=status.HTTP_400_BAD_REQUEST)
      except ValueError as e:
        return Response({"exception": '%s' % e, 'type': 'ValueError'},  status=status.HTTP_400_BAD_REQUEST)
      except ModuleError as e:
        print e
        return Response({"exception": '%s' % e, 'type': 'ModuleError'},  status=status.HTTP_400_BAD_REQUEST)
      except NameError as e:
        return Response({"exception": '%s' % e, 'type': 'NameError'}, status=status.HTTP_400_BAD_REQUEST)
      else:
        return streamHttpResponse(filenameout)
Ejemplo n.º 2
0
    def create_snapshot(self):
        logger.debug('document {pk:%s, mimetype:%s, type:%s} init snapshot' %
                     (self.pk, self.mimetype, self.type))

        if not self.attachment or not getattr(self.attachment, 'path', None):
            logger.debug('document {pk:%s} snapshot cannot be generated.' %
                         self.pk)
            return

        if not os.path.exists(self.attachment.path):
            logger.debug(
                'document {pk:%s} snapshot cannot be generated, attached file does not exist.'
                % self.pk)
            return

        # reconsider mimetype
        mimetype, encoding = mimetypes.guess_type(self.attachment.path,
                                                  strict=True)
        if mimetype:
            self.mimetype = mimetype

        logger.debug(
            'document {pk:%s, mimetype:%s, type:%s} snapshot can be generated'
            % (self.pk, self.mimetype, self.type))

        filename = '%s.snapshot.png' % self.short_url
        outfile = os.path.join(settings.MEDIA_ROOT,
                               snapshot_attachment_file_name(self, filename))

        # generate dir if there is none
        try:
            os.makedirs(os.path.dirname(outfile))
        except OSError:
            logger.debug(
                'document {pk:%s, mimetype:%s, type:%s} creating folder for snapshot'
                % (self.pk, self.mimetype, self.type))
            pass

        # generate thumbnail
        if self.mimetype.split(
                '/'
        )[0] == 'image' or self.type == Document.IMAGE or self.type == Document.PHOTO:
            logger.debug(
                'document {pk:%s, mimetype:%s, type:%s} generating IMAGE thumbnail...'
                % (self.pk, self.mimetype, self.type))

            # generate snapshot
            d = helpers.generate_snapshot(
                filename=self.attachment.path,
                output=outfile,
                width=settings.MILLER_SNAPSHOT_WIDTH,
                height=settings.MILLER_SNAPSHOT_HEIGHT)
            if d:
                self.data.update(d)

            self.snapshot = snapshot_attachment_file_name(
                self, filename
            )  #outfile# .save(os.path.basename(outfile), files.images.ImageFile(f), save=False)
            self._dirty = True
            logger.debug(
                'document {pk:%s, mimetype:%s, type:%s} IMAGE thumbnail done.'
                % (self.pk, self.mimetype, self.type))
            # remove tempfile

        # print mimetype
        elif self.mimetype == 'application/pdf':
            logger.debug(
                'document {pk:%s, mimetype:%s, type:%s} generating PDF snapshot...'
                % (self.pk, self.mimetype, self.type))

            pdffile = self.attachment.path
            pdf_im = PyPDF2.PdfFileReader(pdffile)

            # get page
            page = 0
            try:
                metadata = json.loads(self.contents)
                page = int(metadata['thumbnail_page']
                           ) if 'thumbnail_page' in metadata else 0
            except Exception as e:
                logger.exception(e)

            try:
                # Converting first page into JPG
                with Image(filename='%s[%s]' % (pdffile, page),
                           resolution=150) as img:
                    img.format = 'png'
                    img.background_color = Color(
                        'white')  # Set white background.
                    img.alpha_channel = 'remove'
                    img.save(filename=outfile)

                self.snapshot = snapshot_attachment_file_name(
                    self, filename
                )  #outfile# .save(os.path.basename(outfile), files.images.ImageFile(f), save=False)
                self._dirty = True

                # with open(self.attachment.path + '.png') as f:
                #   self.snapshot.save(os.path.basename(self.attachment.path)[:100] + '.png', files.images.ImageFile(f), save=False)
                #   self._dirty = True
                #   logger.debug('document {pk:%s, type:%s} PDF snapshot done.' % (self.pk,self.type))

            except Exception as e:
                logger.exception(e)
                print 'could not save snapshot of the required resource', self.pk
            else:
                logger.debug(
                    'snapshot generated for document {pk:%s}, page %s' %
                    (self.pk, page))
Ejemplo n.º 3
0
  def optimise(self, pk=None, override=False, **options):
    """
    Create an optimised version for documents typed IMAGE attachents.
    Add or update data.resolution.full for the documents, so it needs resolution field to be in place.
    """
    docs = Document.objects.exclude(Q(attachment='') | Q(attachment__exact=None)).filter(type=Document.IMAGE)

    logger.debug('settings.MILLER_ATTACHMENT_MAX_SIZE: {0}'.format(settings.MILLER_ATTACHMENT_MAX_SIZE))
    if pk:
      docs = docs.filter(pk=pk) if pk.isdigit() else docs.filter(slug=pk)

    for doc in docs.iterator():


      if not override and 'resolutions' in doc.data and 'full' in doc.data['resolutions']:
        if pk:
          logger.debug('data field of the selected document already contains "full" resolutions. add --override!')
        continue

      print doc.pk, doc.slug
      print '    type       :', doc.type
      print '    short_url  :', doc.short_url
      print '    orig. path :', doc.attachment.name
      print '    orig. size :', os.stat(doc.attachment.path).st_size, '(', convert_bytes(os.stat(doc.attachment.path).st_size) , ')'


      _, file_extension = os.path.splitext(doc.attachment.name)
      print '    orig. ext  :', file_extension

      filename = Document.snapshot_attachment_file_name(
        instance=doc,
        filename='{pk}.full{ext}'.format(pk=doc.short_url, ext=file_extension)
      )

      print '    new path   :', filename
      newfile = os.path.join(settings.MEDIA_ROOT, filename)

      snapshot = helpers.generate_snapshot(
        filename    = doc.attachment.path,
        output      = newfile,
        width       = None,
        height      = None,
        resolution  = settings.MILLER_ATTACHMENT_RESOLUTION,
        max_size    = settings.MILLER_ATTACHMENT_MAX_SIZE,
        compression_quality    = settings.MILLER_ATTACHMENT_COMPRESSION_QUALITY,
      )

      if not snapshot:
        raise Exception('no snapshot created!')

      print '    new size   :', os.stat(newfile).st_size, '(', convert_bytes(os.stat(newfile).st_size) , ')'

      from PIL import Image, ImageFile

      with Image.open(newfile) as img_file:
        img_file.save(newfile, optimize=True, progressive=True)

      print '    comp. size :', os.stat(newfile).st_size, '(', convert_bytes(os.stat(newfile).st_size) , ')'


      #doc.attachment.name = row['attachment']
      #
      if not 'resolutions' in doc.data:
        doc.data['resolutions'] = {}

      doc.data['resolutions']['full'] = {
        'url': '{host}{file}'.format(host=settings.MILLER_HOST, file=os.path.join(settings.MEDIA_URL, filename)),
        'width': snapshot['thumbnail_width'],
        'height': snapshot['thumbnail_height']
      }

      print '    new width  :', doc.data['resolutions']['full']['width']
      print '    new height :', doc.data['resolutions']['full']['height']

      # doc.attachment.name = filename
      # print doc.data['resolutions']
      doc.save()
Ejemplo n.º 4
0
    def create_snapshots(self,
                         resolutions=None,
                         override=True,
                         custom_logger=None):
        """
    Create multisize snapshots and add relaive width and height to <Document instance>.data
    It follows settings.MILLER_RESOLUTIONS
    param boolean override: if True, default behavior, this allows file overriding.
    """
        if not custom_logger:
            custom_logger = logger
        if not resolutions:
            resolutions = settings.MILLER_RESOLUTIONS

        # document doesn't have an attachment / snapshots
        if (not self.attachment or not getattr(self.attachment, 'path', None)
            ) and (not self.snapshot
                   or not getattr(self.snapshot, 'path', None)):
            custom_logger.error(
                u'pk={pk} snapshot cannot be generated, empty attachment or empty snapshot field.'
                .format(pk=self.pk))
            return

        # generate dir if there is none. Check logger exception for results.
        if not self.create_snapshots_folder():
            custom_logger.error(
                u'pk={pk} snapshot cannot be generated, couldn\'t create snapshot folder!'
                .format(pk=self.pk))
            return

        # generate the mimetype based on the attachment.
        if not self.mimetype:
            mimetype, encoding = mimetypes.guess_type(self.attachment.path,
                                                      strict=True)
            if mimetype:
                custom_logger.debug(
                    u'pk={pk} get mimetype, found: {mimetype}'.format(
                        pk=self.pk, mimetype=mimetype))

                self.mimetype = mimetype

        custom_logger.debug(
            u'pk={pk} using mimetype, found: {mimetype}'.format(
                pk=self.pk, mimetype=self.mimetype))

        # get filepath according to mimetype.
        # Since Pdf files are often given as attachments, filepath for the multisize snapshots is stored in ... doc.snapshot FileField.
        if self.mimetype.split('/')[0] == 'image':
            filepath = self.attachment.path
        elif self.mimetype == 'application/pdf':
            pdfsnapshot = self.create_snapshot_from_attachment(
                override=override)
            if not pdfsnapshot:
                custom_logger.error(
                    u'pk={pk} snapshot cannot be generated, probably this is due to PDF error.'
                    .format(pk=self.pk))
                return
            filepath = os.path.join(settings.MEDIA_ROOT, pdfsnapshot)
            self.snapshot = pdfsnapshot
        elif self.mimetype == 'video/mp4':
            if not self.snapshot:
                custom_logger.error(
                    u'pk={pk} snapshot cannot be generated, no valid snapshot found'
                    .format(pk=self.pk))
                return
            filepath = self.snapshot.path
        else:
            custom_logger.error(
                u'pk={pk} snapshot cannot be generated: not a compatible type choiche (mimetype: {mimetype}).'
                .format(pk=self.pk, mimetype=self.mimetype))
            return

        # special warning: cannot find attachment.
        if not os.path.exists(filepath):
            custom_logger.error(
                u'pk={pk} snapshot cannot be generated, attached file {path} does not exist.'
                .format(pk=self.pk, path=filepath))
            return

        #print filepath, settings.MILLER_HOST
        # log file metadata.
        custom_logger.debug(
            u'pk={pk} generating snapshot with slug={slug}, type={type} and mimetype={mimetype} ...'
            .format(pk=self.pk,
                    type=self.type,
                    mimetype=self.mimetype,
                    slug=self.slug))

        _d = {'original': {}}

        for field, resolution, width, height, max_size in resolutions:

            filename = Document.snapshot_attachment_file_name(
                instance=self,
                filename='{pk}.{field}.jpg'.format(pk=self.short_url,
                                                   field=field))
            # print filename, self.short_url
            # print outfile, doc.attachment.path
            _d[field] = {
                'url':
                '{host}{file}'.format(host=settings.MILLER_HOST,
                                      file=os.path.join(
                                          settings.MEDIA_URL, filename))
            }

            try:
                snapshot = helpers.generate_snapshot(filename=filepath,
                                                     output=os.path.join(
                                                         settings.MEDIA_ROOT,
                                                         filename),
                                                     width=width,
                                                     height=height,
                                                     resolution=resolution,
                                                     max_size=max_size)
            except Exception as e:
                custom_logger.exception(e)
                return

            snapshot_width = int(snapshot['snapshot_width'])
            snapshot_height = int(snapshot['snapshot_height'])

            # save first width.
            if 'width' not in _d['original']:
                _dim = {
                    'width': int(snapshot['width']),
                    'height': int(snapshot['height'])
                }
                _d['original'].update(_dim)
                self.data.update(_dim)

            custom_logger.debug(
                'pk={pk} snapshot generated, field={field}, resolution={resolution}, max_size={max_size}, size={width}x{height}!'
                .format(pk=self.pk,
                        field=field,
                        resolution=resolution,
                        max_size=max_size,
                        width=snapshot_width,
                        height=snapshot_height))

            _d[field].update({
                'width': snapshot_width,
                'height': snapshot_height
            })

            if field == 'thumbnail':
                # save thumbnail along with its width and height
                self.data.update({
                    'thumbnail_width': snapshot_width,
                    'thumbnail_height': snapshot_height
                })

        self.data['resolutions'] = _d

        # force save when in save() pipeline
        self._dirty = True
Ejemplo n.º 5
0
def images(request):
    """
  request sample
  for thumbnail: 
  ?url=<filebasename>_T[width,height].<extension>
  for cropping (http://docs.wand-py.org/en/0.4.1/wand/image.html)
  ?url=<filebasename>_c[300,300,310,310].<extension>
  or
  ?url=<filebasename>_c[300,300].<extension>
  """
    if not request.user.is_authenticated:
        raise NotAuthenticated()
    #_c[10,20,50,100]
    # before the last point.
    if not 'url' in request.GET:
        return Response({"error": "missing url param"},
                        status=status.HTTP_422_UNPROCESSABLE_ENTITY)

    # search for something like ?url=/media/image/2162934893_b053386d3f_o_c[100,20,500,200].jpg
    # where the original image is this part: /media/image/2162934893_b053386d3f_o.jpg
    ms = re.search(
        r'\/media\/(?P<path>[a-zA-Z_\/\d\-]+)_(?P<funcs>[a-zA-Z\[\]\-\d\!\^%]+)\.(?P<ext>jpg|gif|jpeg|jpe)$',
        request.GET['url'])

    if ms is None:
        return Response(
            {
                "error": "invalid url param",
                "url": request.GET['url']
            },
            status=status.HTTP_422_UNPROCESSABLE_ENTITY)

    # get the groups from our regex
    basepath = os.path.normpath(ms.group('path'))
    ext = ms.group('ext')
    functions = ms.group('funcs')

    # input filename (original) and output filename (modified)
    filename = os.path.join(settings.MEDIA_ROOT, '%s.%s' % (basepath, ext))
    filenameout = os.path.join(settings.MEDIA_ROOT,
                               '%s_%s.%s' % (basepath, functions, ext))

    if not os.path.exists(filename):
        return Response({"error": "requested image was not found"},
                        status=status.HTTP_404_NOT_FOUND)

    if os.path.exists(filenameout):
        return streamHttpResponse(filenameout)

    # get distinct wand methods
    funcs = re.findall(r'(?P<func>[a-zA-Z])\[?(?P<args>[\d\-%x]+)\]?',
                       functions)

    if not funcs:
        return Response(
            {
                "error":
                "invalid url param - url does not contain any valid resize function.",
                "url": request.GET['url']
            },
            status=status.HTTP_422_UNPROCESSABLE_ENTITY)

    available_funcs = {
        'c': 'crop',
        't': 'transform',  # crop and resize
        'T': 'thumbnail',
        'r': 'resize'
    }

    with Image(filename=filename) as img:
        for a, b in funcs:
            args = map(lambda x: int(x) if x.isnumeric() else x, b.split('-'))
            if a == 'T':
                generate_snapshot(filename,
                                  filenameout,
                                  width=args[0],
                                  height=args[-1],
                                  crop=True)
                return streamHttpResponse(filenameout)
            try:
                getattr(img, available_funcs[a])(*args)
                img.save(filename=filenameout)
            except TypeError as e:
                return Response({
                    "exception": '%s' % e,
                    'type': 'TypeError'
                },
                                status=status.HTTP_400_BAD_REQUEST)
            except KeyError as e:
                return Response({
                    "exception": '%s' % e,
                    'type': 'KeyError'
                },
                                status=status.HTTP_400_BAD_REQUEST)
            except ValueError as e:
                return Response({
                    "exception": '%s' % e,
                    'type': 'ValueError'
                },
                                status=status.HTTP_400_BAD_REQUEST)
            else:
                return streamHttpResponse(filenameout)