class UserFloat(UserMember): instantiable = True groups_order = UserMember.groups_order member_class = schema.Float member_min = schema.Float(listed_by_default=False, member_group="constraints") member_max = schema.Float(min=member_min, listed_by_default=False, member_group="constraints")
class Sharpness(ImageEffect): instantiable = True level = schema.Float(required=True) def apply(self, image): return ImageEnhance.Sharpness(image).enhance(self.level)
class Contrast(ImageEffect): instantiable = True level = schema.Float(required=True) def apply(self, image): return ImageEnhance.Contrast(image).enhance(self.level)
class ReducedOpacity(ImageEffect): """An image effect that reduces the opacity of the given image.""" instantiable = True level = schema.Float(required=True, default=0.5, min=0.0, max=1.0) def apply(self, image): return reduce_opacity(image, self.level)
class Watermark(ImageEffect): instantiable = True mark = schema.Reference(type=File, required=True, related_end=schema.Collection()) opacity = schema.Float(required=True, min=0.0, max=1.0, default=1.0) placement = schema.String(required=True, default="middle", enumeration=["middle", "scale", "tile"]) def apply(self, image): mark_image = Image.open(self.mark.file_path) if self.opacity < 1: mark_image = reduce_opacity(mark_image, opacity) if image.mode != 'RGBA': image = image.convert('RGBA') # Create a transparent layer the size of the image and draw the # watermark in that layer. layer = Image.new('RGBA', image.size, (0, 0, 0, 0)) if self.placement == 'tile': for y in range(0, image.size[1], mark_image.size[1]): for x in range(0, image.size[0], mark_image.size[0]): layer.paste(mark_image, (x, y), mark_image) elif self.placement == 'scale': # scale, but preserve the aspect ratio ratio = min( float(image.size[0]) / mark_image.size[0], float(image.size[1]) / mark_image.size[1]) w = int(mark_image.size[0] * ratio) h = int(mark_image.size[1] * ratio) mark_image = mark_image.resize((w, h)) layer.paste(mark_image, ((image.size[0] - w) / 2, (image.size[1] - h) / 2), mark_image) elif self.placement == 'middle': layer.paste(mark_image, ((image.size[0] - mark_image.size[0]) / 2, (image.size[1] - mark_image.size[1]) / 2), mark_image) else: raise ValueError( "Must specify position parameter [tile,scale,middle].") # composite the watermark with the layer return Image.composite(layer, image, layer)
class PDFRenderer(Renderer): """A content renderer that handles pdf files.""" instantiable = True command = schema.String(required=True) timeout = schema.Integer(required=True, default=20) timeout_size_factor = schema.Float(default=10.0) def can_render(self, item, **parameters): return (self.command and isinstance(item, File) and item.resource_type == "document" and item.file_name.split(".")[-1].lower() == "pdf") def render(self, item, page=1, **parameters): timeout = self.timeout # Increase the timeout for bigger files if self.timeout_size_factor: size = item.file_size if size: timeout += size / (self.timeout_size_factor * 1024 * 1024) RESOLUTION = 0.25 temp_path = mkdtemp() try: temp_image_file = os.path.join(temp_path, "thumbnail.png") command = self.command % { "source": item.file_path, "dest": temp_image_file, "page": page } p = Popen(command, shell=True, stdout=PIPE) start = time() while p.poll() is None: if time() - start > timeout: p.terminate() raise IOError("PDF rendering timeout: '%s' took more than " "%.2f seconds" % (command, timeout)) sleep(RESOLUTION) return Image.open(temp_image_file) finally: rmtree(temp_path)
class AudioEncoder(Item): instantiable = True visible_from_root = False resolution = 0.25 members_order = [ "identifier", "mime_type", "extension", "command", "timeout", "timeout_size_factor" ] identifier = schema.String(required=True, unique=True, indexed=True, normalized_index=False, descriptive=True) mime_type = schema.String(required=True) extension = schema.String(required=True) command = schema.String(required=True) timeout = schema.Integer(required=True, default=60) timeout_size_factor = schema.Float(default=10.0) def encode(self, file, dest): # Most encoders expect PCM wave files as input, so we start by finding # an appropiate decoder for the given file. mime_type = file.mime_type if mime_type == "audio/mp3": mime_type = "audio/mpeg" decoder = AudioDecoder.require_instance(mime_type=mime_type) # Next, we produce the command line instructions for the decoding / # encoding procedure, using a shell pipe. decode_command = decoder.command % file.file_path encode_command = self.command % dest command = decode_command + " | " + encode_command # Calculate the timeout, based on a base value incremented according to # a file size factor timeout = self.timeout if self.timeout_size_factor: size = file.file_size if size: timeout += size / (self.timeout_size_factor * 1024 * 1024) # Encode the file and save it to the indicated location proc = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) start = time() while proc.poll() is None: if time() - start > timeout: proc.terminate() raise AudioEncodingTimeoutError( "The following audio encoding command exceeded its " "timeout of %d seconds: %s" % (timeout, command)) sleep(self.resolution) if proc.returncode: raise AudioEncodingCommandError( "The following audio encoding command reported an error: " "%s\n%s" % (command, proc.stderr.read().strip()))