PEP8-ing and whitespacing.

This commit is contained in:
Bryan Veloso 2011-10-31 23:12:03 +09:00
parent a45f3af2a5
commit 06c1c678b6
7 changed files with 113 additions and 100 deletions

View file

@ -3,8 +3,8 @@ from django.template.loader import render_to_string
class AdminThumbnail(object):
"""A convenience utility for adding thumbnails to the Django admin change
list.
"""
A convenience utility for adding thumbnails to Django's admin change list.
"""
short_description = _('Thumbnail')
@ -12,8 +12,8 @@ class AdminThumbnail(object):
def __init__(self, image_field, template=None):
"""
:param image_field: The name of the ImageField or ImageSpec on the model
to use for the thumbnail.
:param image_field: The name of the ImageField or ImageSpec on the
model to use for the thumbnail.
:param template: The template with which to render the thumbnail
"""
@ -25,7 +25,7 @@ class AdminThumbnail(object):
if not thumbnail:
raise Exception('The property {0} is not defined on {1}.'.format(
obj, self.image_field))
obj, self.image_field))
original_image = getattr(thumbnail, 'source_file', None) or thumbnail
template = self.template or 'imagekit/admin/thumbnail.html'

View file

@ -1 +0,0 @@

View file

@ -1,7 +1,7 @@
"""Flushes the cached ImageKit images.
"""
Flushes and re-caches all images under ImageKit.
"""
from django.db.models.loading import cache
from django.core.management.base import BaseCommand

View file

@ -29,11 +29,11 @@ class _ImageSpecMixin(object):
class ImageSpec(_ImageSpecMixin):
"""The heart and soul of the ImageKit library, ImageSpec allows you to add
"""
The heart and soul of the ImageKit library, ImageSpec allows you to add
variants of uploaded images to your models.
"""
_upload_to_attr = 'cache_to'
def __init__(self, processors=None, quality=70, format=None,
@ -41,31 +41,31 @@ class ImageSpec(_ImageSpecMixin):
"""
:param processors: A list of processors to run on the original image.
:param quality: The quality of the output image. This option is only
used for the JPEG format.
:param format: The format of the output file. If not provided, ImageSpec
will try to guess the appropriate format based on the extension
of the filename and the format of the input image.
used for the JPEG format.
:param format: The format of the output file. If not provided,
ImageSpec will try to guess the appropriate format based on the
extension of the filename and the format of the input image.
:param image_field: The name of the model property that contains the
original image.
:param pre_cache: A boolean that specifies whether the image should be
generated immediately (True) or on demand (False).
original image.
:param pre_cache: A boolean that specifies whether the image should
be generated immediately (True) or on demand (False).
:param storage: A Django storage system to use to save the generated
image.
image.
:param cache_to: Specifies the filename to use when saving the image
cache file. This is modeled after ImageField's ``upload_to`` and
can be either a string (that specifies a directory) or a
callable (that returns a filepath). Callable values should
accept the following arguments:
cache file. This is modeled after ImageField's ``upload_to`` and
can be either a string (that specifies a directory) or a
callable (that returns a filepath). Callable values should
accept the following arguments:
- instance -- The model instance this spec belongs to
- path -- The path of the original image
- specname -- the property name that the spec is bound to on
the model instance
- extension -- A recommended extension. If the format of the
spec is set explicitly, this suggestion will be
based on that format. if not, the extension of the
original file will be passed. You do not have to use
this extension, it's only a recommendation.
- instance -- The model instance this spec belongs to
- path -- The path of the original image
- specname -- the property name that the spec is bound to on
the model instance
- extension -- A recommended extension. If the format of the
spec is set explicitly, this suggestion will be
based on that format. if not, the extension of the
original file will be passed. You do not have to use
this extension, it's only a recommendation.
"""
@ -97,7 +97,7 @@ class ImageSpec(_ImageSpecMixin):
def _get_suggested_extension(name, format):
if format:
# Try to look up an extension by the format
# Try to look up an extension by the format.
extensions = [k for k, v in Image.EXTENSION.iteritems() \
if v == format.upper()]
else:
@ -112,7 +112,6 @@ def _get_suggested_extension(name, format):
class _ImageSpecFileMixin(object):
def _process_content(self, filename, content):
img = open_image(content)
original_format = img.format
@ -161,18 +160,20 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
return super(ImageFieldFile, self).url
def _create(self, lazy=False):
"""Creates a new image by running the processors on the source file.
"""
Creates a new image by running the processors on the source file.
Keyword Arguments:
lazy -- True if an already-existing image should be returned; False if
a new image should be created and the existing one overwritten.
lazy -- True if an already-existing image should be returned;
False if a new image should be created and the existing
one overwritten.
"""
if lazy and (getattr(self, '_file', None) or self.storage.exists(self.name)):
return
if self.source_file: # TODO: Should we error here or something if the source_file doesn't exist?
# Process the original image file
# Process the original image file.
try:
fp = self.source_file.storage.open(self.source_file.name)
except IOError:
@ -184,7 +185,8 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
self.storage.save(self.name, content)
def delete(self, save=False):
"""Pulled almost verbatim from ``ImageFieldFile.delete()`` and
"""
Pulled almost verbatim from ``ImageFieldFile.delete()`` and
``FieldFile.delete()`` but with the attempts to reset the instance
property removed.
@ -194,7 +196,7 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
del self._dimensions_cache
# Only close the file if it's already open, which we know by the
# presence of self._file
# presence of self._file.
if hasattr(self, '_file'):
self.close()
del self.file
@ -204,7 +206,7 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
except (NotImplementedError, IOError):
pass
# Delete the filesize cache
# Delete the filesize cache.
if hasattr(self, '_size'):
del self._size
self._committed = False
@ -217,9 +219,10 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
return _get_suggested_extension(self.source_file.name, self.field.format)
def _default_cache_to(self, instance, path, specname, extension):
"""Determines the filename to use for the transformed image. Can be
overridden on a per-spec basis by setting the cache_to property on the
spec.
"""
Determines the filename to use for the transformed image. Can be
overridden on a per-spec basis by setting the cache_to property on
the spec.
"""
filepath, basename = os.path.split(path)
@ -253,10 +256,10 @@ class ImageSpecFile(_ImageSpecFileMixin, ImageFieldFile):
@name.setter
def name(self, value):
# TODO: Figure out a better way to handle this. We really don't want to
# allow anybody to set the name, but ``File.__init__`` (which is called
# by ``ImageSpecFile.__init__``) does, so we have to allow it at least
# that one time.
# TODO: Figure out a better way to handle this. We really don't want
# to allow anybody to set the name, but ``File.__init__`` (which is
# called by ``ImageSpecFile.__init__``) does, so we have to allow it
# at least that one time.
pass
@ -322,7 +325,8 @@ class ProcessedImageFieldFile(ImageFieldFile, _ImageSpecFileMixin):
class ProcessedImageField(models.ImageField, _ImageSpecMixin):
"""ProcessedImageField is an ImageField that runs processors on the uploaded
"""
ProcessedImageField is an ImageField that runs processors on the uploaded
image *before* saving it to storage. This is in contrast to specs, which
maintain the original. Useful for coercing fileformats or keeping images
within a reasonable size.
@ -336,12 +340,11 @@ class ProcessedImageField(models.ImageField, _ImageSpecMixin):
**kwargs):
"""
The ProcessedImageField constructor accepts all of the arguments that
the :class:`django.db.models.ImageField` constructor accepts, as well as
the ``processors``, ``format``, and ``quality`` arguments of
the :class:`django.db.models.ImageField` constructor accepts, as well
as the ``processors``, ``format``, and ``quality`` arguments of
:class:`imagekit.models.ImageSpec`.
"""
_ImageSpecMixin.__init__(self, processors, quality=quality,
format=format)
models.ImageField.__init__(self, verbose_name, name, width_field,

View file

@ -1,4 +1,5 @@
"""Imagekit image processors.
"""
Imagekit image processors.
A processor accepts an image, does some stuff, and returns the result.
Processors can do anything with the image you want, but their responsibilities
@ -6,12 +7,13 @@ should be limited to image manipulations--they should be completely decoupled
from both the filesystem and the ORM.
"""
from imagekit.lib import *
from imagekit.lib import Image, ImageColor, ImageEnhance
from imagekit.processors import resize
class ProcessorPipeline(list):
"""A :class:`list` of other processors. This class allows any object that
"""
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::
@ -25,27 +27,28 @@ class ProcessorPipeline(list):
class Adjust(object):
"""Performs color, brightness, contrast, and sharpness enhancements on the
"""
Performs color, brightness, contrast, and sharpness enhancements on the
image. See :mod:`PIL.ImageEnhance` for more imformation.
"""
def __init__(self, color=1.0, brightness=1.0, contrast=1.0, sharpness=1.0):
"""
: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 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`
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`
blurred image; 1 corresponds to the original sharpness; 2
results in a sharpened image. See
:class:`PIL.ImageEnhance.Sharpness`
"""
self.color = color
self.brightness = brightness
@ -65,25 +68,26 @@ class Adjust(object):
class Reflection(object):
"""Creates an image with a reflection.
"""
Creates an image with a reflection.
"""
background_color = '#FFFFFF'
size = 0.0
opacity = 0.6
def process(self, img):
# convert bgcolor string to rgb value
# Convert bgcolor string to RGB value.
background_color = ImageColor.getrgb(self.background_color)
# handle palleted images
# Handle palleted images.
img = img.convert('RGB')
# copy orignial image and flip the orientation
# Copy orignial image and flip the orientation.
reflection = img.copy().transpose(Image.FLIP_TOP_BOTTOM)
# create a new image filled with the bgcolor the same size
# Create a new image filled with the bgcolor the same size.
background = Image.new("RGB", img.size, background_color)
# calculate our alpha mask
start = int(255 - (255 * self.opacity)) # The start of our gradient
steps = int(255 * self.size) # the number of intermedite values
# Calculate our alpha mask.
start = int(255 - (255 * self.opacity)) # The start of our gradient.
steps = int(255 * self.size) # The number of intermedite values.
increment = (255 - start) / float(steps)
mask = Image.new('L', (1, 255))
for y in range(255):
@ -93,22 +97,24 @@ class Reflection(object):
val = 255
mask.putpixel((0, y), val)
alpha_mask = mask.resize(img.size)
# merge the reflection onto our background color using the alpha mask
# Merge the reflection onto our background color using the alpha mask.
reflection = Image.composite(background, reflection, alpha_mask)
# crop the reflection
# Crop the reflection.
reflection_height = int(img.size[1] * self.size)
reflection = reflection.crop((0, 0, img.size[0], reflection_height))
# create new image sized to hold both the original image and the reflection
composite = Image.new("RGB", (img.size[0], img.size[1]+reflection_height), background_color)
# paste the orignal image and the reflection into the composite image
# Create new image sized to hold both the original image and
# the reflection.
composite = Image.new("RGB", (img.size[0], img.size[1] + reflection_height), background_color)
# Paste the orignal image and the reflection into the composite image.
composite.paste(img, (0, 0))
composite.paste(reflection, (0, img.size[1]))
# return the image complete with reflection effect
# Return the image complete with reflection effect.
return composite
class Transpose(object):
""" Rotates or flips the image
"""
Rotates or flips the image.
"""
AUTO = 'auto'
@ -133,18 +139,18 @@ class Transpose(object):
def __init__(self, *args):
"""
Possible arguments:
- Transpose.AUTO
- 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.
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
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.
"""

View file

@ -2,7 +2,6 @@ from imagekit.lib import Image
class _Resize(object):
width = None
height = None
@ -17,10 +16,10 @@ class _Resize(object):
class Crop(_Resize):
"""Resizes an image , cropping it to the specified width and height.
"""
Resizes an image , cropping it to the specified width and height.
"""
TOP_LEFT = 'tl'
TOP = 't'
TOP_RIGHT = 'tr'
@ -47,8 +46,8 @@ class Crop(_Resize):
"""
:param width: The target width, in pixels.
:param height: The target height, in pixels.
:param anchor: Specifies which part of the image should be retained when
cropping. Valid values are:
:param anchor: Specifies which part of the image should be retained
when cropping. Valid values are:
- Crop.TOP_LEFT
- Crop.TOP
@ -68,7 +67,7 @@ class Crop(_Resize):
cur_width, cur_height = img.size
horizontal_anchor, vertical_anchor = Crop._ANCHOR_PTS[self.anchor or \
Crop.CENTER]
ratio = max(float(self.width) / cur_width, float(self.height)/cur_height)
ratio = max(float(self.width) / cur_width, float(self.height) / cur_height)
resize_x, resize_y = ((cur_width * ratio), (cur_height * ratio))
crop_x, crop_y = (abs(self.width - resize_x), abs(self.height - resize_y))
x_diff, y_diff = (int(crop_x / 2), int(crop_y / 2))
@ -88,17 +87,17 @@ class Crop(_Resize):
class Fit(_Resize):
"""Resizes an image to fit within the specified dimensions.
"""
Resizes an image to fit within the specified dimensions.
"""
def __init__(self, width=None, height=None, upscale=None):
"""
:param width: The maximum width of the desired image.
:param height: The maximum height of the desired image.
:param upscale: A boolean value specifying whether the image should be
enlarged if its dimensions are smaller than the target
dimensions.
:param upscale: A boolean value specifying whether the image should
be enlarged if its dimensions are smaller than the target
dimensions.
"""
super(Fit, self).__init__(width, height)

View file

@ -5,24 +5,30 @@ from imagekit.specs import ImageSpec
class ResizeToWidth(processors.Resize):
width = 100
class ResizeToHeight(processors.Resize):
height = 100
class ResizeToFit(processors.Resize):
width = 100
height = 100
class ResizeCropped(ResizeToFit):
crop = ('center', 'center')
class TestResizeToWidth(ImageSpec):
access_as = 'to_width'
processors = [ResizeToWidth]
class TestResizeToHeight(ImageSpec):
access_as = 'to_height'
processors = [ResizeToHeight]
class TestResizeCropped(ImageSpec):
access_as = 'cropped'
processors = [ResizeCropped]