CryptPix is a cutting-edge, open-source solution designed to shield your website’s images from automated scraping and make manual extraction a daunting, near-impossible task. Crafted for seamless integration with Django, CryptPix employs a sophisticated, multi-tiered defense system that transforms your images into a fortress of security. Whether you’re safeguarding product photos on an e-commerce platform, protecting a photography portfolio, or securing proprietary visuals in any industry, CryptPix ensures your images remain yours—viewable only by legitimate users on your site. With its blend of robust protection, developer-friendly integration, and flawless user experience, CryptPix stands as the ultimate tool for defending your visual content against theft.
CryptPix revolutionizes image protection by rendering your images unusable to scrapers while preserving their pristine quality for authorized viewers. Through a series of carefully engineered security layers, it transforms your images into a format that defies both automated bots and determined manual scrapers. Even if a scraper manages to download an image, what they get is a scrambled, incoherent mess—utterly useless without the specific conditions provided by your website’s rendering process. CryptPix achieves this without watermarks, overlays, or other obtrusive methods that degrade the user experience. Instead, it delivers crystal-clear visuals to your audience while ensuring that stolen assets are worthless.
At its heart, CryptPix integrates seamlessly with your Django application to protect images from the moment they’re uploaded. When you add an image to a model, CryptPix automatically processes it into a secure format, storing the necessary metadata to display it correctly. These images are served through tightly controlled, time-sensitive access mechanisms that restrict delivery to authorized users only. In the browser, CryptPix orchestrates a precise reconstruction process, ensuring images render correctly with pixel-perfect clarity. This tag provides essential styling to align and display the protected images, making it a critical component of the rendering process. The result is a system where images appear perfectly to legitimate visitors but remain indecipherable to anyone attempting to bypass your site’s protections.
The first layer of defense ensures that images are only accessible through secure, ephemeral channels tied to a user’s session, preventing bots from grabbing direct links or reusing URLs. The second layer transforms the image data into a format that’s meaningless outside the context of your website, rendering any downloaded file useless. The final layer leverages dynamic client-side rendering to reconstruct the image, requiring specific conditions that only your site can provide. Together, these layers create a system where scraping an image yields nothing but a garbled artifact, while legitimate users enjoy a flawless viewing experience.
Unlike traditional anti-scraping methods—such as watermarks that deface images, hotlink prevention that’s easily bypassed, or heavy server-side restrictions that slow performance—CryptPix offers a smarter, more resilient solution. Most alternatives rely on superficial barriers that savvy scrapers can circumvent with minimal effort. CryptPix, by contrast, fundamentally alters the image data itself, ensuring that even successful downloads are worthless without the intricate client-side logic only your site provides. This makes it exponentially harder for scrapers to succeed, as they face not just technical hurdles but a labyrinth of protections that require reverse-engineering multiple layers of security.
What sets CryptPix apart is its balance of security, simplicity, and scalability. It delivers ironclad protection without compromising performance or adding complexity to your workflow. The images remain pixel-perfect for users, with no visible artifacts or delays, while scrapers are left with unusable data. Its open-source nature invites community contributions, ensuring it evolves to counter new scraping techniques. Whether you’re protecting a single hero image or an entire gallery, CryptPix scales effortlessly, offering enterprise-grade security in a lightweight, developer-friendly package.
Getting started with CryptPix is straightforward, thanks to its tight integration with Django. Installation is a breeze:
- Install via pip:
pip install cryptpix - Add the
CryptPixModelMixinto any Django model with an image field. - Include the
{% cryptpix_css %}template tag in your templates to provide the necessary styling for correct image rendering. - Use the
{% cryptpix_image %}template tag to embed protected images in your templates.
Here’s an example of how to use CryptPix in your templates:
{% load cryptpix_tags %}
{% cryptpix_css %}
{% cryptpix_image photo width="100%" data-parent-size="true" %}
The {% cryptpix_css %} tag is required to ensure images render correctly, applying the essential styles for alignment and display. The {% cryptpix_image %} tag supports flexible options like responsive sizing and custom attributes, allowing you to tailor the display to your site’s design. Once integrated, CryptPix automatically processes images upon upload, storing the necessary data to render them securely. The Django admin interface includes previews and metadata for easy verification, ensuring developers can manage protected images with confidence.
CryptPix is a game-changer for any website that relies on visual content. E-commerce platforms can protect product images from competitors looking to scrape catalogs. Photographers and artists can safeguard high-resolution portfolios from unauthorized reproduction. News outlets can secure exclusive graphics, while educational platforms can shield proprietary diagrams and illustrations. In each case, CryptPix ensures that your images remain a valuable asset exclusive to your site, deterring theft without impacting the user experience.
The benefits extend beyond security. By automating the protection process, CryptPix saves developers time and effort, integrating seamlessly into existing workflows. Its responsive design support ensures images look great on any device, while its lightweight implementation avoids performance bottlenecks. Most importantly, it provides peace of mind: even if a scraper bypasses one layer of defense, the resulting image is a scrambled puzzle, useless for any practical purpose.
CryptPix isn’t just another anti-scraping tool—it’s a strategic advantage for any site owner or developer serious about protecting visual content. Its multi-layered defenses outsmart both automated bots and manual scrapers, offering a level of security that other solutions can’t match. Unlike clunky alternatives that rely on visible watermarks or restrictive access controls, CryptPix delivers invisible, robust protection that preserves the beauty of your images. Its open-source foundation fosters community-driven innovation, ensuring it stays ahead of evolving threats. For developers, its Django integration is a dream, requiring minimal setup to achieve maximum impact—starting with the essential {% cryptpix_css %} tag. For site owners, it’s a promise that your images are safe, accessible only to your intended audience.
Join the growing community of developers and businesses using CryptPix to protect their visual assets. Install it today, explore the documentation, and discover why CryptPix is the smarter, stronger way to keep your images secure.
CryptPix is a Django package that provides a minimal image obfuscation tool. It splits images into layered components for CSS-based reconstruction, enhancing image protection in your Django application by serving them through secure, signed URLs.
To install the cryptpix package, run the following command in your terminal:
pip install git+https://github.com/ArtoLabs/CryptPix.git- Python: Version 3.7 or later
- Django: Version 3.0 or later
- Pillow: Required for image processing
Install Pillow if it’s not already in your environment:
pip install PillowPillow may require additional system dependencies, such as libjpeg, to handle image processing. Ensure these are installed on your system. Refer to the Pillow documentation for platform-specific installation instructions.
For example:
- On Ubuntu:
sudo apt-get install libjpeg-dev - On macOS:
brew install libjpeg
Open your project’s settings.py file and add 'cryptpix' to the INSTALLED_APPS list:
INSTALLED_APPS = [
...
'cryptpix.apps.CryptPixConfig',
]Include the cryptpix URL configuration in your project’s urls.py:
from django.urls import path, include
urlpatterns = [
...
path('cryptpix/', include('cryptpix.urls')),
]This sets up the secure_image_view at /cryptpix/secure-image/<signed_value>/, which serves the protected image layers.
The cryptpix package includes a JavaScript file (resize_image_stacks.js) required for responsive image resizing with the breakpoints attribute. To make it available, ensure your project is configured to serve static files:
In settings.py, verify that STATIC_URL is defined (e.g., STATIC_URL = '/static/') and that STATICFILES_DIRS or STATIC_ROOT is set up for your project.
Run the following command to collect static files:
python manage.py collectstaticEnsure the {% load static %} tag is used in templates to reference static files (see Template Tags).
Add the {% cryptpix_css %} tag in your template’s <head> section to include the necessary CSS for layer reconstruction:
{% cryptpix_css %}Include the resize_image_stacks.js script on pages that use the {% cryptpix_image %} tag:
<script src="{% static 'cryptpix/resize_image_stacks.js' %}"></script>Important: The JavaScript file is required to dynamically adjust image sizes. Place it in the <body> or <head> section of your template, ensuring {% load static %} is included.
Run migrations to create the necessary database fields:
python manage.py migrateNo additional middleware, template tags, or static files are required beyond what’s described below.
Add CryptPixModelMixin to the model containing the image field you want to protect. By default, the mixin assumes the image field is named 'image'. This is controlled by the cryptpix_source_field attribute.
If your image field is named anything other than 'image', override cryptpix_source_field to match your field’s name.
from django.db import models
from cryptpix.django import CryptPixModelMixin
class MyModel(CryptPixModelMixin, models.Model):
image = models.ImageField(upload_to='images/')
# Default: cryptpix_source_field = 'image'
# If your field is named differently, e.g., 'photo', override it:
# cryptpix_source_field = 'photo'
In this example, since the field is named 'image', no override is needed.
When the model instance is saved with an image, the mixin:
- Distorts the image.
- Splits it into two layers.
- Stores these layers in the database, along with metadata.
The original image remains in the source field unless you restrict access (see next section).
In your Django template, load the cryptpix_tags:
{% load cryptpix_tags %}Use the cryptpix_image tag to display the protected image:
{% cryptpix_image my_model_instance %}Pass additional attributes to customize the display (applied to the top layer image). The width and height attributes can be specified in pixels (e.g., "500px") or percentages (e.g., "100%"), but not as "auto":
{% cryptpix_image my_model_instance width="500px" height="300px" class="my-class" %}or
{% cryptpix_image my_model_instance width="100%" height="50%" class="my-class" %}Note: Using height="auto" is not supported, as it may break the CSS-based reconstruction of the layered images. Always specify a concrete value for width and height.
The breakpoints attribute allows you to emulate CSS media queries by specifying different sizes for the image based on the viewport width. The breakpoints value is a JSON string defining viewport sizes and corresponding width and height values. This is useful for responsive designs.
Example:
{% cryptpix_image my_model_instance width="100%" height="50%" breakpoints='{"0": {"width": "100%", "height": "50%"}, "768": {"width": "500px", "height": "300px"}}' %}The breakpoints JSON object maps minimum viewport widths (in pixels) to an object containing width and height values.
In the example above:
- For viewports narrower than
768px, the image useswidth="100%"andheight="50%". - For viewports
768pxor wider, the image useswidth="500px"andheight="300px".
The breakpoints emulate CSS media queries by dynamically adjusting the image size based on the client’s viewport.
- Ensure the JSON is valid and properly formatted.
- Use pixel or percentage values for
widthandheightwithin the breakpoints, consistent with the mainwidthandheightattributes. - Test across different screen sizes to verify responsiveness.
Add in your template’s <head>. This step is required for the images to render correctly:
{% cryptpix_css %}- Signed URLs for
image_layer_1andimage_layer_2(default valid for 5 seconds). - Secure view checks against the user's session.
- Layers are stacked via CSS. The original image is not served unless manually exposed.
Important: Do not use {{ my_model_instance.image.url }}. Always use {% cryptpix_image %}.
Optionally, configure a private directory or custom storage backend.
In cases where you cannot use the {% cryptpix_image %} template tag (e.g., when passing an image URL to a third-party JavaScript application that does not support the CryptPix HTML snippet), you can use the get_secure_image_url function to generate a short-lived, secure URL for the original image. This approach bypasses the CryptPix distortion layers but still provides protection through a signed, ephemeral URL that prevents scraping.
Example Usage in a View:
from cryptpix.html import get_secure_image_url
def my_view(request):
title_media = MyModel.objects.get(pk=1) # Example model instance
image_pk = str(title_media.media.pk) + '_0' if title_media and title_media.media else None
media_url = get_secure_image_url(image_pk, request) if image_pk else None
return render(request, 'my_template.html', {'media_url': media_url})
Explanation:
- The
image_pkis constructed by appending'_0'to the model instance’s primary key (e.g.,media.pk). This ensures the original image is retrieved instead of the distorted layers. - The
get_secure_image_urlfunction generates a signed URL tied to the user’s session, which expires quickly (default: 5 seconds) to prevent unauthorized access or scraping. - Use this URL in contexts where a direct image URL is required, such as passing it to a third-party JavaScript library.
Template Usage:
Pass the generated URL to your template and use it in an <img> tag or JavaScript code:
<img src="{{ media_url }}" alt="Protected Image">
Important Notes:
- Always append
'_0'to the image’s primary key to retrieve the original image. - The generated URL is short-lived, providing a layer of protection against scraping, even without the CryptPix distortion layers.
- Avoid exposing the original image’s storage path (e.g.,
{{ object.image.url }}) to maintain security.
- Signed URL Expiry: Set
max_ageinunsign_image_token(default: 5s). - Image Processing: Modify
choose_tile_sizeordistort_imageincore.py. - Template Attributes: Pass
width,height,class, etc.
python manage.py runserverNavigate to a page using the {% cryptpix_image %} tag.
View:
from django.views.generic import DetailView
from .models import MyModel
class MyModelDetailView(DetailView):
model = MyModel
template_name = 'my_model_detail.html'
URL:
from django.urls import path
from .views import MyModelDetailView
urlpatterns = [
path('mymodel/<int:pk>/', MyModelDetailView.as_view(), name='mymodel-detail'),
]Template (my_model_detail.html):
<!DOCTYPE html>
<html>
<head>
{% cryptpix_css %}
</head>
<body>
{% load cryptpix_tags %}
{% cryptpix_image object width="100%" %}
</body>
</html>
Visit: /mymodel/1/ (assuming pk=1 exists).
- Image Display: Should render with layered protection.
- Protection Check: Direct access to layer URLs should fail after expiration or with an invalid session.
- Original Image: Remains accessible unless protected.
Use CryptPixAdminMixin for previews:
from django.contrib import admin
from cryptpix.admin import CryptPixAdminMixin
from .models import MyModel
@admin.register(MyModel)
class MyModelAdmin(CryptPixAdminMixin, admin.ModelAdmin):
list_display = ['id', 'display_thumbnail']
readonly_fields = (
'image_layer_1_preview',
'image_layer_2_preview',
'tile_size',
'image_width',
'image_height',
'hue_rotation',
)
Visit the admin interface to see thumbnails and layer previews.
- Image Not Displaying: Check
cryptpix_source_field. - CSS Missing: Ensure
{% cryptpix_css %}is in<head>. - Migrations: Run
python manage.py migrateif fields are missing. - Image Processing Fails: Ensure Pillow and dependencies like libjpeg are installed.
- URL Errors: Confirm
path('cryptpix/', include(...))is present. - Original Image Exposed: Avoid
{{ object.image.url }}. - Signed URL Issues: Check session validity and
max_agesettings.