Exemple #1
0
class FFmpegInput(BaseInput, AbstractOpus):
    def __init__(self,
                 source='-',
                 command='avconv',
                 streaming=False,
                 **kwargs):
        super(FFmpegInput, self).__init__(**kwargs)
        if source:
            self.source = source
        self.streaming = streaming
        self.command = command

        self._buffer = None
        self._proc = None

    def read(self, sz):
        if self.streaming:
            raise TypeError('Cannot read from a streaming FFmpegInput')

        # First read blocks until the subprocess finishes
        if not self._buffer:
            data, _ = self.proc.communicate()
            self._buffer = BufferedIO(data)

        # Subsequent reads can just do dis thang
        return self._buffer.read(sz)

    def fileobj(self):
        if self.streaming:
            return self.proc.stdout
        else:
            return self

    @property
    def proc(self):
        if not self._proc:
            if callable(self.source):
                self.source = self.source(self)

            if isinstance(self.source, (tuple, list)):
                self.source, self.metadata = self.source

            args = [
                self.command,
                '-i',
                str(self.source),
                '-f',
                's16le',
                '-ar',
                str(self.sampling_rate),
                '-ac',
                str(self.channels),
                '-loglevel',
                'warning',
                'pipe:1',
            ]
            self._proc = subprocess.Popen(args,
                                          stdin=None,
                                          stdout=subprocess.PIPE)
        return self._proc
Exemple #2
0
def pil_image(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:
        return
    source = BytesIO(source.read())

    image = Image.open(source)
    # Fully load the image now to catch any problems with the image contents.
    try:
        # An "Image file truncated" exception can occur for some images that
        # are still mostly valid -- we'll swallow the exception.
        image.load()
    except IOError:
        pass
    # Try a second time to catch any other potential exceptions.
    image.load()

    if exif_orientation:
        image = utils.exif_orientation(image)
    return image
def pil_image(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:
        return
    source = BytesIO(source.read())
    try:
        image = Image.open(source)
        # Fully load the image now to catch any problems with the image
        # contents.
        image.load()
    except Exception:
        return

    if exif_orientation:
        image = utils.exif_orientation(image)
    return image
Exemple #4
0
def pil_image(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:
        return
    source = BytesIO(source.read())

    image = Image.open(source)
    # Fully load the image now to catch any problems with the image
    # contents.
    image.load()

    if exif_orientation:
        image = utils.exif_orientation(image)
    return image
Exemple #5
0
def saveObscurement(image):
    """
    Return a 1-bit PNG byte string from the PIL image
    """
    output = StringIO()
    output.name = '__obscurement.png'
    image.save(output, optimize=True, transparency=TRANS, bits=1)
    output.seek(0)

    return output.read()
def saveObscurement(image):
    """
    Return a 1-bit PNG byte string from the PIL image
    """
    output = StringIO()
    output.name = '__obscurement.png'
    image.save(output, optimize=True, transparency=TRANS, bits=1)
    output.seek(0)

    return output.read()
    def create_image(self, storage, filename, size=(800, 600), image_mode="RGB", image_format="JPEG"):
        """
        Generate a test image, returning the filename that it was saved as.

        If ``storage`` is ``None``, the BytesIO containing the image data
        will be passed instead.
        """
        data = BytesIO()
        Image.new(image_mode, size).save(data, image_format)
        data.seek(0)
        if not storage:
            return data
        image_file = ContentFile(data.read())
        return storage.save(filename, image_file)
Exemple #8
0
    def create_image(self,
                     storage,
                     filename,
                     size=(800, 600),
                     image_mode='RGB',
                     image_format='JPEG'):
        """
        Generate a test image, returning the filename that it was saved as.

        If ``storage`` is ``None``, the BytesIO containing the image data
        will be passed instead.
        """
        data = BytesIO()
        Image.new(image_mode, size).save(data, image_format)
        data.seek(0)
        if not storage:
            return data
        image_file = ContentFile(data.read())
        return storage.save(filename, image_file)
Exemple #9
0
def iiif_image_api(request, identifier_param, region_param, size_param,
                   rotation_param, quality_param, format_param):
    """ Image repurposing endpoint for IIIF Image API 2.1 """
    ik_image, image = _get_image_or_404(identifier_param, load_image=True)

    is_transparent = et_utils.is_transparent(image)
    is_grayscale = image.mode in ('L', 'LA')

    # Map format names used for IIIF URL path extension to proper name
    format_mapping = {
        'jpg': 'jpeg',
        'tif': 'tiff',
    }

    try:
        # Parse region
        x, y, r_width, r_height = parse_region(region_param, image.width,
                                               image.height)

        # Parse size
        s_width, s_height = parse_size(size_param, r_width, r_height)

        # Parse rotation
        is_mirrored, rotation_degrees = \
            parse_rotation(rotation_param, s_width, s_height)

        # Parse quality
        quality = parse_quality(quality_param)

        # Parse format
        # TODO Add support for unsupported formats (see `parse_format`)
        image_format = os.path.splitext(ik_image.image.name)[1][1:].lower()
        output_format = parse_format(format_param, image_format)
        corrected_format = format_mapping.get(output_format, output_format)

        # Redirect to canonical URL if appropriate, per
        # http://iiif.io/api/image/2.1/#canonical-uri-syntax
        canonical_path = make_canonical_path(
            identifier_param,
            image.width,
            image.height,
            (x, y, r_width, r_height),  # Region
            (s_width, s_height),  # Size
            (is_mirrored, rotation_degrees),  # Rotation
            quality,
            output_format)
        if request.path != canonical_path:
            return HttpResponseRedirect(canonical_path)

        # Determine storage file name for item
        if iiif_storage:
            storage_path = build_iiif_file_storage_path(
                canonical_path, ik_image, iiif_storage)
        else:
            storage_path = None

        # Load pre-generated image from storage if one exists and is up-to-date
        # with the original image (per timestampt info embedded in the storage
        # path)
        # TODO The exists lookup is slow for S3 storage, cache metadata?
        # TODO Detect when original image would be unchanged & use it directly?
        if (storage_path and iiif_storage.exists(storage_path)):
            if is_remote_storage(iiif_storage, storage_path):
                return HttpResponseRedirect(iiif_storage.url(storage_path))
            else:
                return FileResponse(
                    iiif_storage.open(storage_path),
                    content_type='image/%s' % corrected_format,
                )

        ##################
        # Generate image #
        ##################

        # Apply region
        if x or y or r_width != image.width or r_height != image.height:
            box = (x, y, x + r_width, y + r_height)
            image = image.crop(box)

        # Apply size
        if s_width != r_width or s_height != r_height:
            size = (s_width, s_height)
            image = image.resize(size)

        # TODO Apply rotation

        # Apply quality
        # Much of this is cribbed from easythumbnails' `colorspace` processor
        # TODO Replace with glamkit-imagetools' sRGB colour space converter?
        if quality in ('default', 'color') and not is_grayscale:
            if is_transparent:
                new_mode = 'RGBA'
            else:
                new_mode = 'RGB'
        elif is_grayscale or quality == 'gray':
            if is_transparent:
                new_mode = 'LA'
            else:
                new_mode = 'L'
        if new_mode != image.mode:
            image = image.convert(new_mode)

        # Apply format and "save"
        result_image = BytesIO()
        image.save(result_image, format=corrected_format)

        # Save generated image to storage if possible
        if storage_path:
            iiif_storage.save(storage_path, result_image)

        if iiif_storage and is_remote_storage(iiif_storage, storage_path):
            return HttpResponseRedirect(iiif_storage.url(storage_path))
        else:
            result_image.seek(0)  # Reset image file in case it's just created
            return FileResponse(
                result_image.read(),
                content_type='image/%s' % corrected_format,
            )
    # Handle error conditions per iiif.io/api/image/2.1/#server-responses
    except ClientError, ex:
        return HttpResponseBadRequest(ex.message)  # 400 response