Home / Blogs

How to Compress Images Using Python in a Django Project [2024]

Django
·

December 29, 2023

how-to-compress-images-using-python-in-a-django-project

In web development, efficiently managing and optimizing images is a common challenge. Large image files can significantly impact website performance, leading to slow loading times. A practical solution to this issue is image compression.

In this blog post, we’ll explore the concept of image compression and delve into a Python code snippet that demonstrates how to implement image compression in a Django application.

The code utilizes the Python Imaging Library (PIL) to handle tasks such as resizing, orientation correction, and saving the compressed image.

To read more about removing the background of an image using rembg in Python, refer to our blog How to Remove the Background of Image Using Rembg in Python

Understanding Image Compression

Image compression involves reducing the file size of an image while attempting to retain its visual quality. This is achieved by removing redundant or unnecessary information from the image data. In the context of web development, compressed images contribute to faster page loading times, improved user experience, and reduced storage requirements.

The Code Implementation

Now, let’s dive into a Python code snippet that illustrates how to compress images in a Django application. The code covers essential steps such as handling orientation, maintaining the aspect ratio, converting to the appropriate mode, and saving the compressed image.

# Import necessary libraries and modules
from PIL import Image, ExifTags
import os
import uuid
from django.conf import settings

# Your Django model definition
class YourModelName(models.Model):
    # ... your model fields here ...

    # Method for image compression
    def compress_image(self, source_field, target_field, size):
        if not getattr(self, source_field):
            # If the source_field is empty, no need to proceed
            return

The code begins by importing the required libraries and modules, including Image and ExifTags from the Python Imaging Library (PIL), as well as standard modules such as os, uuid, and settings from Django. The YourModelName class represents a Django model, and within it, there is a method named compress_image designed for image compression.

The first few lines of the method check if the source field, representing the original image, is empty. If it is, the compression process is skipped, avoiding unnecessary operations on non-existent images.

# Open the original image
        img = Image.open(getattr(self, source_field))

The next line opens the original image using the Image.open method. The image file path is obtained using getattr(self, source_field), where self refers to the current instance of the model, and source_field is the attribute containing the file path of the original image.

# Check for EXIF orientation and rotate if necessary
        for orientation in ExifTags.TAGS.keys():
            if ExifTags.TAGS[orientation] == 'Orientation':
                try:
                    exif = dict(img._getexif().items())
                    if exif[orientation] == 3:
                        img = img.rotate(180, expand=True)
                    elif exif[orientation] == 6:
                        img = img.rotate(270, expand=True)
                    elif exif[orientation] == 8:
                        img = img.rotate(90, expand=True)
                except (AttributeError, KeyError, IndexError):
                    # No EXIF data or invalid data, don't perform rotation
                    pass

This section addresses the issue of image orientation. Images may have an EXIF orientation tag indicating how the image should be displayed. The code iterates through the EXIF tags and checks for the ‘Orientation’ tag. If found, it attempts to read the orientation value and rotates the image accordingly to ensure it is displayed correctly. This is crucial for images that might have been captured in a different orientation.

# Calculate the aspect ratio to maintain proportions when resizing
        aspect_ratio = img.width / img.height

Here, the code calculates the aspect ratio of the image. The aspect ratio is the ratio of the image’s width to its height and is crucial for maintaining the proportions of the image when resizing.

# Resize the image to the specified size
        img = img.resize((size, int(size / aspect_ratio)), Image.ANTIALIAS)

The image is resized using the resize method. The target size is specified, and the aspect ratio is used to determine the corresponding height, maintaining the original proportions. The Image.ANTIALIAS mode is employed for high-quality resizing.

# Convert the image to RGB mode if it's in RGBA mode
        if img.mode == 'RGBA':
            img = img.convert('RGB')

In this section, the code checks if the image is in RGBA (Red, Green, Blue, Alpha) mode. If so, it converts the image to RGB mode. This is necessary for compatibility with the JPEG format, which does not support an alpha channel.

 # Save the compressed image to the target_field's upload_to path inside MEDIA_ROOT
 target_upload_to = getattr(self.__class__, target_field).field.upload_to

        img_path = getattr(self, source_field).path
        img_name, img_ext = os.path.splitext(os.path.basename(img_path))
        unique_id = str(uuid.uuid4())
        compressed_img_name = f'{img_name}{unique_id}_{size}{img_ext}'
        compressed_img_path = os.path.join(settings.MEDIA_ROOT, target_upload_to, compressed_img_name)

Here, the code prepares for saving the compressed image. It determines the upload path for the compressed image based on the upload_to attribute of the target field in the model. It also extracts the original image’s path, name, and extension, and generates a unique identifier to create a unique name for the compressed image.

# Ensure that the target directory exists before saving
 os.makedirs(os.path.dirname(compressed_img_path), exist_ok=True)

This line ensures that the directory where the compressed image will be saved exists. If not, it creates the necessary directory structure.

# Save the image as JPEG
  img.save(compressed_img_path, 'JPEG')

The compressed image is saved using the save method. In this case, the image is saved in JPEG format.

# Set the target_field with the compressed image path relative to MEDIA_ROOT
setattr(self, target_field, os.path.relpath(compressed_img_path, settings.MEDIA_ROOT))

Finally, the target field of the Django model is updated with the relative path to the compressed image. This path is relative to the MEDIA_ROOT setting in the Django project.

To read more about using the UPS Express API in Django DRF, refer to our blog How to Use the UPS Express API in Django DRF in 2024

Conclusion

In this blog post, we’ve explored the concept of image compression and walked through a Python code snippet that demonstrates how to implement image compression in a Django application. The provided code covers crucial steps such as handling orientation, maintaining the aspect ratio, converting to the appropriate mode, and saving the compressed image. By understanding and incorporating this code into your Django models, you can seamlessly integrate image compression into your web application, enhancing performance and user experience.

Horilla Editorial Team Author

Horilla Editorial Team is a group of experienced writers and editors who are passionate about HR software. We have a deep understanding of the HR landscape and are committed to providing our readers with the most up-to-date and informative content. We have written extensively on a variety of HR software topics, including applicant tracking systems, performance management software, and payroll software etc. We are always looking for new ways to share our knowledge with the HR community. If you have a question about HR software, please don't hesitate to contact us.