mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-16 21:30:23 +00:00
123 lines
3.8 KiB
Python
123 lines
3.8 KiB
Python
from imagekit.lib import Image
|
|
|
|
|
|
class _Resize(object):
|
|
width = None
|
|
height = None
|
|
|
|
def __init__(self, width=None, height=None):
|
|
if width is not None:
|
|
self.width = width
|
|
if height is not None:
|
|
self.height = height
|
|
|
|
def process(self, img):
|
|
raise NotImplementedError('process must be overridden by subclasses.')
|
|
|
|
|
|
class Crop(_Resize):
|
|
"""
|
|
Resizes an image , cropping it to the specified width and height.
|
|
|
|
"""
|
|
TOP_LEFT = 'tl'
|
|
TOP = 't'
|
|
TOP_RIGHT = 'tr'
|
|
BOTTOM_LEFT = 'bl'
|
|
BOTTOM = 'b'
|
|
BOTTOM_RIGHT = 'br'
|
|
CENTER = 'c'
|
|
LEFT = 'l'
|
|
RIGHT = 'r'
|
|
|
|
_ANCHOR_PTS = {
|
|
TOP_LEFT: (0, 0),
|
|
TOP: (0.5, 0),
|
|
TOP_RIGHT: (1, 0),
|
|
LEFT: (0, 0.5),
|
|
CENTER: (0.5, 0.5),
|
|
RIGHT: (1, 0.5),
|
|
BOTTOM_LEFT: (0, 1),
|
|
BOTTOM: (0.5, 1),
|
|
BOTTOM_RIGHT: (1, 1),
|
|
}
|
|
|
|
def __init__(self, width=None, height=None, anchor=None):
|
|
"""
|
|
: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:
|
|
|
|
- Crop.TOP_LEFT
|
|
- Crop.TOP
|
|
- Crop.TOP_RIGHT
|
|
- Crop.LEFT
|
|
- Crop.CENTER
|
|
- Crop.RIGHT
|
|
- Crop.BOTTOM_LEFT
|
|
- Crop.BOTTOM
|
|
- Crop.BOTTOM_RIGHT
|
|
|
|
"""
|
|
super(Crop, self).__init__(width, height)
|
|
self.anchor = anchor
|
|
|
|
def process(self, img):
|
|
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)
|
|
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))
|
|
box_left, box_right = {
|
|
0: (0, self.width),
|
|
0.5: (int(x_diff), int(x_diff + self.width)),
|
|
1: (int(crop_x), int(resize_x)),
|
|
}[horizontal_anchor]
|
|
box_upper, box_lower = {
|
|
0: (0, self.height),
|
|
0.5: (int(y_diff), int(y_diff + self.height)),
|
|
1: (int(crop_y), int(resize_y)),
|
|
}[vertical_anchor]
|
|
box = (box_left, box_upper, box_right, box_lower)
|
|
img = img.resize((int(resize_x), int(resize_y)), Image.ANTIALIAS).crop(box)
|
|
return img
|
|
|
|
|
|
class Fit(_Resize):
|
|
"""
|
|
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.
|
|
|
|
"""
|
|
super(Fit, self).__init__(width, height)
|
|
self.upscale = upscale
|
|
|
|
def process(self, img):
|
|
cur_width, cur_height = img.size
|
|
if not self.width is None and not self.height is None:
|
|
ratio = min(float(self.width) / cur_width,
|
|
float(self.height) / cur_height)
|
|
else:
|
|
if self.width is None:
|
|
ratio = float(self.height) / cur_height
|
|
else:
|
|
ratio = float(self.width) / cur_width
|
|
new_dimensions = (int(round(cur_width * ratio)),
|
|
int(round(cur_height * ratio)))
|
|
if new_dimensions[0] > cur_width or \
|
|
new_dimensions[1] > cur_height:
|
|
if not self.upscale:
|
|
return img
|
|
img = img.resize(new_dimensions, Image.ANTIALIAS)
|
|
return img
|