How to Crop Image Before Upload in Django Website

In web applications, image manipulation is a common requirement. Cropping images before uploading can be especially useful when you want to allow users to focus on specific parts of an image. In this blog post, we’ll guide you through the process of implementing image cropping before upload in a Django web application. We’ll cover everything from setting up your project to integrating a client-side JavaScript library and handling image processing on the server side.

How to Crop Image Before Upload in Django Website

Step by Step Implementation

Lets dive into image cropping in django website using cropper.js plugin.

Step 1: Setting Up Your Django Project

Assuming you have an existing Django project, ensure your models, views, and templates are set up to handle image uploads. We have used from which we developed in our Django Basic Template Boilerplate Skeleton Project blog. For this tutorial, we have created a project with name myproject and app named myapp

Make Sure that you install Pillow Dependency to Handle Images Operations in Django

pip install Pillow

Add media and static path in settings.py and urls.py

# settings.py

STATIC_URL = 'static/'
STATICFILES_DIRS=[BASE_DIR/'static']

MEDIA_URL ='/media/'
MEDIA_ROOT = BASE_DIR /'media'
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls')),
]

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Step 2: Create Model

Create a Django model that stores image details.

from django.db import models

class CroppedImage(models.Model):
    file = models.ImageField(upload_to='images')
    uploaded = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return str(self.pk)

Migrate the model:

python manage.py makemigrations
python manage.py migrate

Step 3. Creating an Image Upload Form

Create a Django form that allows users to upload an image. Include an <input> element of type “file” for selecting the image file.

from django import forms
from .models import CroppedImage

class ImageUploadForm(forms.ModelForm):
    class Meta:
        model = CroppedImage
        fields = ('file',)

Step 4: Handling Image Upload and Cropping on the Server

In your Django view, process the uploaded image and apply the cropping coordinates as needed. You can use libraries like Pillow to manipulate images on the server side.

# myapp/views.py

from django.shortcuts import render
from .forms import ImageUploadForm
from django.http import JsonResponse
from django.http import HttpResponse


def upload_and_crop(request):
    form = ImageUploadForm(request.POST or None, request.FILES or None)
    if form.is_valid():
        form.save()
        return JsonResponse({'message': 'works'})
    context = {'form': form}
    return render(request, 'crop.html', context)

Create a urls.py in your app and reference it view

# myapp/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('hello/', views.hello_world, name='hello_world'),
    path('crop-image/', views.upload_and_crop, name='upload_and_crop'),
]

Step 5. Initializing and Handling Image Cropping

Create a templates named folder and in that create crop.html which we are using in views and add the following code

{% load static %}
<!doctype html>
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- favicon -->
  <link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}" />
  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">

  <!-- jquery -->
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

  <!-- cropper -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/cropper/4.1.0/cropper.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropper/4.1.0/cropper.min.css">

  <!-- custom js-->
  <script src={% static 'crop-image.js' %} defer></script>

  <style>
    .not-visible {
        display: none;
    }
  </style>

  <title>image cropper</title>
</head>

<body>
  <div class="container mt-3">
    <div id="alert-box"></div>
    <div id="image-box" class="mb-3"></div>
    <form action="" id="image-form">
      {% csrf_token %}
      {{form.as_p}}
    </form>
    <button class="btn btn-primary mt-3 not-visible" id="confirm-btn">confirm</button>
  </div>
</body>

</html>

Now lets create static files. In project directory, create a folder named static and inside it crop-image.js and paste the below code

const alertBox = document.getElementById('alert-box')
const imageBox = document.getElementById('image-box')
const imageForm = document.getElementById('image-form')
const confirmBtn = document.getElementById('confirm-btn')
const input = document.getElementById('id_file')

const csrf = document.getElementsByName('csrfmiddlewaretoken')

input.addEventListener('change', () => {
    alertBox.innerHTML = ""
    confirmBtn.classList.remove('not-visible')
    const img_data = input.files[0]
    const url = URL.createObjectURL(img_data)

    imageBox.innerHTML = `<img src="${url}" id="image" width="700px">`
    var $image = $('#image')
    console.log($image)

    $image.cropper({
        aspectRatio: 16 / 9,
        crop: function (event) {
            console.log(event.detail.x);
            console.log(event.detail.y);
            console.log(event.detail.width);
            console.log(event.detail.height);
            console.log(event.detail.rotate);
            console.log(event.detail.scaleX);
            console.log(event.detail.scaleY);
        }
    });

    var cropper = $image.data('cropper');
    confirmBtn.addEventListener('click', () => {
        cropper.getCroppedCanvas().toBlob((blob) => {
            console.log('confirmed')
            const fd = new FormData();
            fd.append('csrfmiddlewaretoken', csrf[0].value)
            fd.append('file', blob, 'my-image.png');

            $.ajax({
                type: 'POST',
                url: imageForm.action,
                enctype: 'multipart/form-data',
                data: fd,
                success: function (response) {
                    console.log('success', response)
                    alertBox.innerHTML = `<div class="alert alert-success" role="alert">
                                            Successfully saved and cropped the selected image
                                        </div>`
                },
                error: function (error) {
                    console.log('error', error)
                    alertBox.innerHTML = `<div class="alert alert-danger" role="alert">
                                            Ups...something went wrong
                                        </div>`
                },
                cache: false,
                contentType: false,
                processData: false,
            })
        })
    })
})

That’s it! You’ve now implemented image cropping before upload in your Django website. Users can select an image, crop it as desired, and then upload the cropped version.

Run the project and go http://localhost:8000/crop-image/

python manage.py runserver

Find this project on Github.

Blogs You Might Like to Read!