Created
April 7, 2014 14:24
-
-
Save vapask/10021258 to your computer and use it in GitHub Desktop.
Image Free Crop Field for image cropping
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from image_cropping.fields import ImageRatioField | |
class ImageFreeCropField(ImageRatioField): | |
def __init__(self, *args, **kwargs): | |
self.keep_ratio = kwargs.pop("keep_ratio", False) | |
super(ImageFreeCropField, self).__init__(*args, **kwargs) | |
def formfield(self, *args, **kwargs): | |
kwargs['widget'] = forms.TextInput(attrs={ | |
'data-width': int(self.width), | |
'data-height': int(self.height), | |
'data-image-field': self.image_field, | |
'data-my-name': self.name, | |
'data-adapt-rotation': str(self.adapt_rotation).lower(), | |
'data-allow-fullsize': str(self.allow_fullsize).lower(), | |
'data-size-warning': str(self.size_warning).lower(), | |
'data-keep-ratio': str(self.keep_ratio).lower(), | |
'class': 'image-ratio', | |
}) | |
return super(ImageRatioField, self).formfield(*args, **kwargs) | |
def south_field_triple(self): | |
""" | |
Return a suitable description of this field for South. | |
""" | |
# We'll just introspect ourselves, since we inherit. | |
from south.modelsinspector import introspector | |
field_class = "django.db.models.fields.CharField" | |
args, kwargs = introspector(self) | |
return (field_class, args, kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var image_cropping = { | |
$: jQuery.noConflict(), | |
init: function() { | |
// set styles for size-warning | |
var style_img_warning = 'div.jcrop-image.size-warning .jcrop-vline{border:1px solid red; background: none;}' + | |
'div.jcrop-image.size-warning .jcrop-hline{border:1px solid red; background: none;}'; | |
image_cropping.$("<style type='text/css'>" + style_img_warning + "</style>").appendTo('head'); | |
image_cropping.$('input.image-ratio').each(function() { | |
var $this = image_cropping.$(this), | |
// find the image field corresponding to this cropping value | |
// by stripping the last part of our id and appending the image field name | |
field = $this.attr('name').replace($this.data('my-name'), $this.data('image-field')), | |
// there should only be one file field we're referencing but in special cases | |
// there can be several. Deal with it gracefully. | |
$image_input = image_cropping.$('input.crop-thumb[data-field-name=' + field + ']:first'); | |
// skip this image if it's empty and hide the whole field, within admin and by itself | |
if (!$image_input.length || $image_input.data('thumbnail-url') == undefined) { | |
$this.hide().parents('div.form-row:first').hide(); | |
return; | |
} | |
// check if the image field should be hidden | |
if ($image_input.data('hide-field')) { | |
$image_input.hide().parents('div.form-row:first').hide(); | |
} | |
var image_id = $this.attr('id') + '-image', | |
org_width = $image_input.data('org-width'), | |
org_height = $image_input.data('org-height'), | |
min_width = $this.data('width'), | |
min_height = $this.data('height'), | |
dont_keep_ratio = ($this.data('keep-ratio') == false) ? true: false; | |
var is_image_portrait = (org_height > org_width); | |
var is_select_portrait = (min_height > min_width); | |
if ($this.data('adapt-rotation') == true) { | |
if (is_image_portrait != is_select_portrait) { | |
// cropping height/width need to be switched, picture is in portrait mode | |
var x = min_width; | |
min_width = min_height; | |
min_height = x; | |
} | |
} | |
var $image = image_cropping.$('<img>', { | |
'id': image_id, | |
'src': $image_input.data('thumbnail-url') | |
}); | |
var options = { | |
// aspectRatio: min_width/min_height, | |
minSize: [5, 5], | |
trueSize: [org_width, org_height], | |
onSelect: image_cropping.update_selection($this), | |
addClass: ($this.data('size-warning') && ((org_width < min_width) || (org_height < min_height))) ? 'size-warning jcrop-image': 'jcrop-image' | |
} | |
if (dont_keep_ratio){ | |
options.minSize = [min_width, min_height]; | |
} else { | |
options.aspectRatio = min_width/min_height; | |
} | |
var cropping_disabled = false; | |
if($this.val()[0] == "-"){ | |
cropping_disabled = true; | |
$this.val($this.val().substr(1)); | |
} | |
// is the image bigger than the minimal cropping values? | |
// otherwise lock cropping area on full image | |
var initial; | |
if ($this.val()) { | |
initial = image_cropping.initial_cropping($this.val()); | |
} else { | |
var initial_min_width = min_width || min_height; | |
var initial_min_height = min_height || min_width; | |
initial = image_cropping.max_cropping(initial_min_width, initial_min_height, org_width, org_height); | |
// set cropfield to initial value | |
$this.val(initial.join(',')); | |
} | |
image_cropping.$.extend(options, {setSelect: initial}); | |
// hide the input field, show image to crop instead | |
$this.hide().after($image); | |
var jcrop = {}; | |
image_cropping.$('#' + image_id).Jcrop(options, function(){jcrop[image_id]=this;}); | |
if ($this.data('allow-fullsize') == true) { | |
if(cropping_disabled){ | |
jcrop[image_id].release(); | |
$this.val('-'+$this.val()); | |
} | |
var label = 'allow-fullsize-'+image_id; | |
var checked = cropping_disabled ? '' : ' checked="checked"'; | |
image_cropping.$('<div class="field-box allow-fullsize">' + | |
'<input type="checkbox" id="'+label+'" name="'+label+'"'+checked+'></div>').appendTo($this.parent()); | |
image_cropping.$('<style type="text/css">div.allow-fullsize{padding: 5px 0 0 10px;}</style>').appendTo('head'); | |
image_cropping.$('#'+label).click(function(){ | |
if (cropping_disabled==true){ | |
$this.val($this.val().substr(1)); | |
jcrop[image_id].setSelect($this.val().split(',')); | |
cropping_disabled = false; | |
} else { | |
$this.val('-'+$this.val()); | |
jcrop[image_id].release(); | |
cropping_disabled = true; | |
} | |
}); | |
$this.parent().find('.jcrop-tracker').mousedown(function(){ | |
if (cropping_disabled){ | |
image_cropping.$('#'+label).attr('checked','checked') | |
cropping_disabled = false; | |
} | |
}); | |
} | |
}); | |
if (image_cropping.$('body').hasClass('change-form')) { | |
// if we're in the Django admin, the holder needs to be floated | |
// so it clears the label | |
image_cropping.$("<style type='text/css'>div.jcrop-holder{float:left;}</style>").appendTo('head'); | |
} | |
}, | |
max_cropping: function(width, height, image_width, image_height) { | |
var ratio = width/height; | |
var offset; | |
if (image_width < image_height * ratio) { | |
// width fits fully, height needs to be cropped | |
offset = Math.round((image_height-(image_width/ratio))/2); | |
return [0, offset, image_width, image_height - offset]; | |
} | |
// height fits fully, width needs to be cropped | |
offset = Math.round((image_width-(image_height * ratio))/2); | |
return [offset, 0, image_width - offset, image_height]; | |
}, | |
initial_cropping: function(val) { | |
if (val == '') { return; } | |
var s = val.split(','); | |
return [ | |
parseInt(s[0], 10), | |
parseInt(s[1], 10), | |
parseInt(s[2], 10), | |
parseInt(s[3], 10) | |
]; | |
}, | |
_update_selection: function(sel, $crop_field) { | |
if ($crop_field.data('size-warning')) { | |
image_cropping.crop_indication(sel, $crop_field); | |
} | |
$crop_field.val(new Array( | |
Math.floor(sel.x), | |
Math.floor(sel.y), | |
Math.floor(sel.x2), | |
Math.floor(sel.y2) | |
).join(',')); | |
}, | |
update_selection: function($crop_field) { | |
return function(sel) { image_cropping._update_selection(sel, $crop_field); }; | |
}, | |
crop_indication: function(sel, $crop_field) { | |
// indicate if cropped area gets smaller than the specified minimal cropping | |
var $jcrop_holder = $crop_field.siblings('.jcrop-holder'); | |
var min_width = $crop_field.data("width"); | |
var min_height = $crop_field.data("height"); | |
if ((sel.w < min_width) || (sel.h < min_height)) { | |
$jcrop_holder.addClass('size-warning'); | |
} else { | |
$jcrop_holder.removeClass('size-warning'); | |
} | |
} | |
}; | |
image_cropping.$(function() {image_cropping.init();}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
image_cropping.js should be available by URL /static/image_cropping/image_cropping.js