Skip to content

Commit

Permalink
Add full-fit-in feature
Browse files Browse the repository at this point in the history
Similiar to `fit-in`, while scaling the image to exactly fill a given box to the full without cropping
  • Loading branch information
gockxml committed Jan 14, 2014
1 parent 9ccfb48 commit b607114
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 10 deletions.
2 changes: 2 additions & 0 deletions integration_tests/urls_helpers.py
Expand Up @@ -36,6 +36,8 @@
'',
'fit-in',
'adaptive-fit-in',
'full-fit-in',
'adaptive-full-fit-in'
]

sizes = [
Expand Down
2 changes: 2 additions & 0 deletions thumbor/context.py
Expand Up @@ -84,6 +84,7 @@ def __init__(self,
crop_bottom=None,
crop=None,
adaptive=False,
full = False,
fit_in=False,
width=0,
height=0,
Expand Down Expand Up @@ -129,6 +130,7 @@ def __init__(self,
self.crop['bottom'] > 0

self.adaptive = bool(adaptive)
self.full = bool(full)
self.fit_in = bool(fit_in)

self.width = width == "orig" and "orig" or self.int_or_0(width)
Expand Down
2 changes: 2 additions & 0 deletions thumbor/crypto.py
Expand Up @@ -26,6 +26,7 @@ def encrypt(self,
height,
smart,
adaptive,
full,
fit_in,
flip_horizontal,
flip_vertical,
Expand All @@ -45,6 +46,7 @@ def encrypt(self,
smart=smart,
meta=False,
adaptive=adaptive,
full=full,
fit_in=fit_in,
horizontal_flip=flip_horizontal,
vertical_flip=flip_vertical,
Expand Down
10 changes: 7 additions & 3 deletions thumbor/transformer.py
Expand Up @@ -310,10 +310,14 @@ def fit_in_resize(self):
self.target_width = self.target_height
self.target_height = tmp

if self.target_width >= source_width and self.target_height >= source_height:
return
sign = 1
if self.context.request.full:
sign = -1

if source_width / self.target_width >= source_height / self.target_height:
if sign == 1 and self.target_width >= source_width and self.target_height >= source_height:
return

if source_width / self.target_width * sign >= source_height / self.target_height * sign:
resize_height = round(source_height * self.target_width / source_width)
resize_width = self.target_width
else:
Expand Down
13 changes: 9 additions & 4 deletions thumbor/url.py
Expand Up @@ -19,7 +19,7 @@ class Url(object):
meta = '(?:(?P<meta>meta)/)?'
trim = '(?:(?P<trim>trim(?::(?:top-left|bottom-right))?(?::\d+)?)/)?'
crop = '(?:(?P<crop_left>\d+)x(?P<crop_top>\d+):(?P<crop_right>\d+)x(?P<crop_bottom>\d+)/)?'
fit_in = '(?:(?P<adaptive>adaptive-)?(?P<fit_in>fit-in)/)?'
fit_in = '(?:(?P<adaptive>adaptive-)?(?P<full>full-)?(?P<fit_in>fit-in)/)?'
dimensions = '(?:(?P<horizontal_flip>-)?(?P<width>(?:\d+|orig))?x(?P<vertical_flip>-)?(?P<height>(?:\d+|orig))?/)?'
halign = r'(?:(?P<halign>left|right|center)/)?'
valign = r'(?:(?P<valign>top|bottom|middle)/)?'
Expand Down Expand Up @@ -75,6 +75,7 @@ def parse_decrypted(cls, url):
'bottom': int_or_0(result['crop_bottom'])
},
'adaptive': result['adaptive'] == 'adaptive',
'full': result['full'] == 'full',
'fit_in': result['fit_in'] == 'fit-in',
'width': result['width'] == 'orig' and 'orig' or int_or_0(result['width']),
'height': result['height'] == 'orig' and 'orig' or int_or_0(result['height']),
Expand All @@ -98,6 +99,7 @@ def generate_options(cls,
meta=False,
trim=None,
adaptive=False,
full=False,
fit_in=False,
horizontal_flip=False,
vertical_flip=False,
Expand Down Expand Up @@ -133,10 +135,13 @@ def generate_options(cls,
))

if fit_in:
fit_ops = []
if adaptive:
url.append('adaptive-fit-in')
else:
url.append('fit-in')
fit_ops.append('adaptive')
if full:
fit_ops.append('full')
fit_ops.append('fit-in');
url.append('-'.join(fit_ops))

if horizontal_flip:
width = '-%s' % width
Expand Down
3 changes: 3 additions & 0 deletions thumbor/url_composer.py
Expand Up @@ -31,6 +31,7 @@ def main(arguments=None):
parser.add_option('-n', '--fitin', dest='fitin', action='store_true', default=False, help='Indicates that fit-in resizing should be performed.')
parser.add_option('-m', '--meta', dest='meta', action='store_true', default=False, help='Indicates that meta information should be retrieved.')
parser.add_option('', '--adaptive', action='store_true', dest='adaptive', default=False, help='Indicates that adaptive fit-in cropping should be used.')
parser.add_option('', '--full', action='store_true', dest='full', default=False, help='Indicates that fit-full cropping should be used.')
parser.add_option('-s', '--smart', action='store_true', dest='smart', default=False, help='Indicates that smart cropping should be used.')
parser.add_option('-t', '--trim', action='store_true', default=False, help='Indicate that surrounding whitespace should be trimmed.')
parser.add_option('-f', '--horizontal-flip', action='store_true', dest='horizontal_flip', default=False, help='Indicates that the image should be horizontally flipped.')
Expand Down Expand Up @@ -80,6 +81,7 @@ def main(arguments=None):
parsed_options.height,
parsed_options.smart,
parsed_options.adaptive,
parsed_options.full,
parsed_options.fitin,
parsed_options.horizontal_flip,
parsed_options.vertical_flip,
Expand All @@ -103,6 +105,7 @@ def main(arguments=None):
smart=parsed_options.smart,
meta=parsed_options.meta,
adaptive=parsed_options.adaptive,
full=parsed_options.full,
fit_in=parsed_options.fitin,
horizontal_flip=parsed_options.horizontal_flip,
vertical_flip=parsed_options.vertical_flip,
Expand Down
4 changes: 4 additions & 0 deletions vows/crypto_vows.py
Expand Up @@ -43,6 +43,7 @@ def topic(self, crypto):
height=300,
smart=True,
adaptive=False,
full=False,
fit_in=False,
flip_horizontal=True,
flip_vertical=True,
Expand Down Expand Up @@ -157,6 +158,7 @@ def should_equal_encrypted_string(self, test_data):
'height': 0,
'smart': False,
'adaptive': False,
'full': False,
'fit_in': False,
'flip_horizontal': False,
'flip_vertical': False,
Expand Down Expand Up @@ -196,6 +198,7 @@ def should_equal_encrypted_string(self, test_data):
'filters': '',
'debug': False,
'adaptive': False,
'full' : False,
'trim': None
}
},
Expand Down Expand Up @@ -224,6 +227,7 @@ def should_equal_encrypted_string(self, test_data):
'filters': 'quality(20):brightness(10)',
'debug': False,
'adaptive': False,
'full' : False,
'trim': None
}
}
Expand Down
33 changes: 31 additions & 2 deletions vows/transformer_test_data.py
Expand Up @@ -76,7 +76,7 @@ def __init__(
target_width, target_height,
halign, valign, focal_points,
crop_left, crop_top, crop_right, crop_bottom,
fit_in=False, adaptive=False, meta=False):
fit_in=False, adaptive=False,full=False, meta=False):

self.source_width = source_width
self.source_height = source_height
Expand All @@ -91,6 +91,7 @@ def __init__(
self.crop_bottom = crop_bottom
self.fit_in = fit_in
self.adaptive = adaptive
self.full = full
self.meta = meta

def __repr__(self):
Expand Down Expand Up @@ -140,6 +141,7 @@ def to_context(self, detectors=[], ignore_detector_error=False):
'bottom': self.crop_bottom
},
adaptive=self.adaptive,
full = self.full,
fit_in=self.fit_in,
horizontal_flip=flip_horizontally,
vertical_flip=flip_vertically,
Expand Down Expand Up @@ -948,5 +950,32 @@ def has_cropped_properly(self):
focal_points=[],
crop_left=None, crop_top=None, crop_right=None, crop_bottom=None,
fit_in=True, adaptive=True
), (200, 100, 1))
), (200, 100, 1)),

(TestData(
source_width=800, source_height=400,
target_width=400, target_height=100,
halign="middle", valign="middle",
focal_points=[],
crop_left=None, crop_top=None, crop_right=None, crop_bottom=None,
fit_in=True, full=True
), (400, 200, 1)),

(TestData(
source_width=200, source_height=250,
target_width=500, target_height=400,
halign="middle", valign="middle",
focal_points=[],
crop_left=None, crop_top=None, crop_right=None, crop_bottom=None,
fit_in=True, full=True
), (500, 625, 1)),

(TestData(
source_width=800, source_height=400,
target_width=100, target_height=400,
halign="middle", valign="middle",
focal_points=[],
crop_left=None, crop_top=None, crop_right=None, crop_bottom=None,
fit_in=True, adaptive=True, full=True
), (400, 200, 1))
]
7 changes: 6 additions & 1 deletion vows/url_vows.py
Expand Up @@ -81,6 +81,11 @@ class Adaptive(ctx(fit_in=True, adaptive=True)):
def should_return_proper_url(self, topic):
expect(topic).to_equal('adaptive-fit-in')

class Full(ctx(fit_in=True, full=True)):

def should_return_proper_url(self, topic):
expect(topic).to_equal('full-fit-in')

class Complete(ctx(
width=300, height=200, smart=True, fit_in=True, meta=True, horizontal_flip=True,
vertical_flip=True, crop_left=10, crop_top=11, crop_right=12, crop_bottom=13,
Expand All @@ -103,7 +108,7 @@ def should_contain_crop(self, topic):
expect(topic).to_include('(?:(?P<crop_left>\d+)x(?P<crop_top>\d+):(?P<crop_right>\d+)x(?P<crop_bottom>\d+)/)?')

def should_contain_fit_in(self, topic):
expect(topic).to_include('(?:(?P<adaptive>adaptive-)?(?P<fit_in>fit-in)/)?')
expect(topic).to_include('(?:(?P<adaptive>adaptive-)?(?P<full>full-)?(?P<fit_in>fit-in)/)?')

def should_contain_dimensions(self, topic):
expect(topic).to_include(
Expand Down

0 comments on commit b607114

Please sign in to comment.