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
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
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
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)
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)
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