"""
Django Jcrop form
Author: Markus Thielen, mt@thiguten.de
= Description =
Implements a Django form that integrates image uploading plus cropping using
the awesome Jcrop plugin (http://deepliquid.com/content/Jcrop.html).
It does not create or use any models, so to use it, simply copy it to
your project tree and import it as appropriate.
= License =
MIT
= Limitations =
Many, probably ;-) It does basically work but lacks proper error handling.
If you upload something that is not an image, no error is dispayed.
I hope I find the time to fix this. If you have a hint, I'd be grateful if you
dropped me a note.
= Usage =
In your views.py, import JcropForm.
The view function that displays the form has three parts (or control flows):
* if request is POSTed but contains no uploaded files, crop coordinates
were submitted. Use JcropForm's crop/resize/save methods to apply.
* if request was posted with file data, the user just uploaded a new
image. Use JcropForm's static method prepare_uploaded_img to scale the
image to a reasonable size (that does not break your layout) and save it
* for normal GET requests just display the form with the current image.
Example view function:
@login_required # the view func expects a logged on user
def img_edit_view(request):
# get the profile (i.e. the model containing the image to edit);
# In this example, the model in question is the user profile model,
# so we can use Django's get_profile() method.
profile = request.user.get_profile()
# define a fixed aspect ratio for the user image
aspect = 105.0 / 75.0
# the final size of the user image
final_size = (105, 75)
if request.method == "POST" and len(request.FILES) == 0:
# user submitted form with crop coordinates
form = JcropForm(request.POST)
if form.is_valid():
# apply cropping
form.crop()
form.resize(final_size)
form.save()
# redirect to profile display page
return HttpResponseRedirect("/myprofile/")
elif request.method == "POST" and len(request.FILES):
# user uploaded a new image; save it and make sure it is not too large
# for our layout
img_fn = JcropForm.prepare_uploaded_img(request.FILES, image_upload_to,
profile, (370, 500))
if img_fn:
# store new image in the member instance
profile.avatar = img_fn # 'avatar' is an ImageField
profile.save()
# redisplay the form with the new image; this is the same as for
# GET requests -> fall through to GET
elif request.method != "GET":
# only POST and GET, please
return HttpResponse(status=400)
# for GET requests, just display the form with current image
form = JcropForm(initial = { "imagefile": profile.avatar },
jcrop_options = {
"aspectRatio":aspect,
"setSelect": "[100, 100, 50, 50]",
}
)
return render_to_response("profile/img_edit.html",
{
"form": form,
},
RequestContext(request))
The template is the same as for normal Django forms, nothing special there.
This code is somehow inspired by https://github.com/azizmb/django-ip-form,
although the original code did not work for me.
"""
from django import forms
from django.conf import settings
from django.utils.safestring import mark_safe
from django.utils.datastructures import MultiValueDictKeyError
import Image as pil
UPLOAD_IMG_ID="new-img-file"
class JcropWidget(forms.Widget):
class Media:
# form media, i.e. CSS and JavaScript needed for Jcrop.
# You'll have to adopt these to your project's paths.
css = {
'all': (settings.MEDIA_URL + "css/jquery.Jcrop.css",)
}
js = (
settings.MEDIA_URL + "js/lib/jquery.Jcrop.min.js",
)
# fixed Jcrop options; to pass options to Jcrop, use the jcrop_options
# argument passed to the JcropForm constructor. See example above.
jcrop_options = {
"onSelect": "storeCoords",
"onChange": "storeCoords",
}
# HTML template for the widget.
#
# The widget is constructed from the following parts:
#
# * HTML - the actual image used for displaying and cropping
# * HTML