django-imagekit/imagekit/processors/__init__.py

166 lines
5.9 KiB
Python
Raw Normal View History

"""Imagekit image processors.
2009-01-04 17:38:06 +00:00
A processor accepts an image, does some stuff, and returns the result.
Processors can do anything with the image you want, but their responsibilities
should be limited to image manipulations--they should be completely decoupled
from both the filesystem and the ORM.
2009-01-04 17:38:06 +00:00
"""
2009-01-08 21:11:15 +00:00
from imagekit.lib import *
2009-01-04 17:38:06 +00:00
class ProcessorPipeline(list):
2011-09-26 00:38:43 +00:00
"""A :class:`list` of other processors. This class allows any object that
knows how to deal with a single processor to deal with a list of them.
For example::
processed_image = ProcessorPipeline([ProcessorA(), ProcessorB()]).process(image)
"""
def process(self, img):
for proc in self:
img = proc.process(img)
return img
class Adjust(object):
2011-09-26 00:38:43 +00:00
"""Performs color, brightness, contrast, and sharpness enhancements on the
image. See :mod:`PIL.ImageEnhance` for more imformation.
"""
2011-09-08 13:15:08 +00:00
def __init__(self, color=1.0, brightness=1.0, contrast=1.0, sharpness=1.0):
2011-09-26 00:38:43 +00:00
"""
:param color: A number between 0 and 1 that specifies the saturation of
the image. 0 corresponds to a completely desaturated image
(black and white) and 1 to the original color.
See :class:`PIL.ImageEnhance.Color`
:param brightness: A number representing the brightness; 0 results in a
completely black image whereas 1 corresponds to the brightness
of the original. See :class:`PIL.ImageEnhance.Brightness`
:param contrast: A number representing the contrast; 0 results in a
completely gray image whereas 1 corresponds to the contrast of
the original. See :class:`PIL.ImageEnhance.Contrast`
:param sharpness: A number representing the sharpness; 0 results in a
blurred image; 1 corresponds to the original sharpness; 2
results in a sharpened image. See
:class:`PIL.ImageEnhance.Sharpness`
"""
2011-09-08 13:15:08 +00:00
self.color = color
self.brightness = brightness
self.contrast = contrast
self.sharpness = sharpness
2009-01-09 14:07:10 +00:00
def process(self, img):
2009-06-04 15:06:11 +00:00
img = img.convert('RGB')
2009-01-09 14:07:10 +00:00
for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
2011-09-08 13:15:08 +00:00
factor = getattr(self, name.lower())
2009-01-09 14:07:10 +00:00
if factor != 1.0:
2009-06-04 15:06:11 +00:00
try:
img = getattr(ImageEnhance, name)(img).enhance(factor)
except ValueError:
pass
return img
2009-01-09 14:07:10 +00:00
class Reflection(object):
2011-09-26 00:38:43 +00:00
"""Creates an image with a reflection.
"""
2009-01-09 14:07:10 +00:00
background_color = '#FFFFFF'
size = 0.0
opacity = 0.6
2009-12-19 16:01:54 +00:00
def process(self, img):
2009-01-09 14:07:10 +00:00
# convert bgcolor string to rgb value
2011-09-08 13:15:08 +00:00
background_color = ImageColor.getrgb(self.background_color)
2009-06-04 15:06:11 +00:00
# handle palleted images
img = img.convert('RGB')
2009-01-09 14:07:10 +00:00
# copy orignial image and flip the orientation
2009-06-04 15:06:11 +00:00
reflection = img.copy().transpose(Image.FLIP_TOP_BOTTOM)
2009-01-09 14:07:10 +00:00
# create a new image filled with the bgcolor the same size
2009-06-04 15:06:11 +00:00
background = Image.new("RGB", img.size, background_color)
2009-01-09 14:07:10 +00:00
# calculate our alpha mask
2011-09-08 13:15:08 +00:00
start = int(255 - (255 * self.opacity)) # The start of our gradient
steps = int(255 * self.size) # the number of intermedite values
2009-01-09 14:07:10 +00:00
increment = (255 - start) / float(steps)
mask = Image.new('L', (1, 255))
for y in range(255):
if y < steps:
val = int(y * increment + start)
else:
val = 255
mask.putpixel((0, y), val)
2009-06-04 15:06:11 +00:00
alpha_mask = mask.resize(img.size)
2009-01-09 14:07:10 +00:00
# merge the reflection onto our background color using the alpha mask
reflection = Image.composite(background, reflection, alpha_mask)
# crop the reflection
2011-09-08 13:15:08 +00:00
reflection_height = int(img.size[1] * self.size)
2009-06-04 15:06:11 +00:00
reflection = reflection.crop((0, 0, img.size[0], reflection_height))
2009-01-09 14:07:10 +00:00
# create new image sized to hold both the original image and the reflection
2009-06-04 15:06:11 +00:00
composite = Image.new("RGB", (img.size[0], img.size[1]+reflection_height), background_color)
2009-01-09 14:07:10 +00:00
# paste the orignal image and the reflection into the composite image
2009-06-04 15:06:11 +00:00
composite.paste(img, (0, 0))
composite.paste(reflection, (0, img.size[1]))
2009-01-09 14:07:10 +00:00
# return the image complete with reflection effect
return composite
2009-01-09 14:07:10 +00:00
class Transpose(object):
2009-01-04 17:38:06 +00:00
""" Rotates or flips the image
2009-12-19 16:01:54 +00:00
2009-01-04 17:38:06 +00:00
"""
AUTO = 'auto'
FLIP_HORIZONTAL = Image.FLIP_LEFT_RIGHT
FLIP_VERTICAL = Image.FLIP_TOP_BOTTOM
ROTATE_90 = Image.ROTATE_90
ROTATE_180 = Image.ROTATE_180
ROTATE_270 = Image.ROTATE_270
methods = [AUTO]
_EXIF_ORIENTATION_STEPS = {
1: [],
2: [FLIP_HORIZONTAL],
3: [ROTATE_180],
4: [FLIP_VERTICAL],
5: [ROTATE_270, FLIP_HORIZONTAL],
6: [ROTATE_270],
7: [ROTATE_90, FLIP_HORIZONTAL],
8: [ROTATE_90],
}
2009-12-19 16:01:54 +00:00
def __init__(self, *args):
2011-09-26 00:38:43 +00:00
"""
Possible arguments:
- Transpose.AUTO
- Transpose.FLIP_HORIZONTAL
- Transpose.FLIP_VERTICAL
- Transpose.ROTATE_90
- Transpose.ROTATE_180
- Transpose.ROTATE_270
The order of the arguments dictates the order in which the Transposition
steps are taken.
If Transpose.AUTO is present, all other arguments are ignored, and the
processor will attempt to rotate the image according to the
EXIF Orientation data.
"""
super(Transpose, self).__init__()
if args:
self.methods = args
2009-12-19 16:01:54 +00:00
def process(self, img):
if self.AUTO in self.methods:
try:
orientation = img._getexif()[0x0112]
ops = self._EXIF_ORIENTATION_STEPS[orientation]
except AttributeError:
ops = []
else:
ops = self.methods
for method in ops:
img = img.transpose(method)
return img