Today, we're going to dive into an exciting project that combines image processing with basic encryption techniques. We'll be exploring a Python program that can encrypt and decrypt images using a simple yet effective method. Let's break it down step by step!
Prerequisites
To follow along, you should have:
- Basic knowledge of Python programming.
- Python installed on your computer.
Pillow library which is a python imaging Library used for handling images. Use
pip install pillow
to install.Tkinter which is a python library used for building graphical user interfaces (GUIs). Use
pip install tk
to install.
What Does This Program Do?
This program creates a graphical user interface (GUI) that allows users to:
- Select an image file
- Choose an output location
- Enter a seed key
- Encrypt or decrypt the image
The encryption process shuffles the pixels of the image based on a seed key, making the image unrecognizable. The decryption process reverses this, restoring the original image.
Code Explanation
Importing Required Libraries
import os
from tkinter import Tk, Button, Label, Entry, filedialog, messagebox
from PIL import Image
import random
-
os
provides functions to interact with the operating system. -
tkinter
provides GUI elements like buttons, labels, and input fields. -
PIL
(Pillow) allows us to open, manipulate, and save images. -
random
helps us shuffle the pixels in a deterministic way, using a seed.
Seeded Random Generator Function
def get_seeded_random(seed):
"""Returns a seeded random generator."""
return random.Random(seed)
The get_seeded_random
function returns a random object that can shuffle items the same way every time if given the same seed value.
This is key to both encrypting and decrypting images consistently.
Image Encryption
def encrypt_image(input_image_path, output_image_path, seed):
"""Encrypts the image by manipulating pixel values."""
image = Image.open(input_image_path)
width, height = image.size
# Get pixel data as a list
pixels = list(image.getdata())
random_gen = get_seeded_random(seed)
# Create a list of pixel indices
indices = list(range(len(pixels)))
# Shuffle the indices using the seeded random generator
random_gen.shuffle(indices)
# Reorder pixels based on shuffled indices
encrypted_pixels = [pixels[i] for i in indices]
# Create new image
encrypted_image = Image.new(image.mode, (width, height))
# Apply encrypted pixels to the new image
encrypted_image.putdata(encrypted_pixels)
# Save the encrypted image
encrypted_image.save(output_image_path)
return True
In this encrypt_image
function:
- We load the image and extract its pixel data.
- The pixel order is shuffled using a seeded random generator to ensure the same shuffle order is maintained when decrypting.
- We create a new image with the shuffled pixel values and save it as the encrypted image.
Image Decryption
def decrypt_image(input_image_path, output_image_path, seed):
"""Decrypts the image by reversing the encryption process."""
image = Image.open(input_image_path)
width, height = image.size
# Get encrypted pixel data as a list
encrypted_pixels = list(image.getdata())
random_gen = get_seeded_random(seed)
# Create a new list to hold pixel indices in their original order
indices = list(range(len(encrypted_pixels)))
# Shuffle the indices again to get the original order
random_gen.shuffle(indices)
# Create a new image to hold the decrypted data
decrypted_pixels = [None] * len(encrypted_pixels)
# Restore original pixels using the shuffled indices
for original_index, shuffled_index in enumerate(indices):
decrypted_pixels[shuffled_index] = encrypted_pixels[original_index]
# Save the decrypted image
decrypted_image = Image.new(image.mode, (width, height))
decrypted_image.putdata(decrypted_pixels)
decrypted_image.save(output_image_path)
return True
This decrypt_image
function works by reversing the encryption process. It:
- Loads the encrypted image.
- Uses the same random seed to reshuffle the pixels back into their original order.
- Creates and saves a new image with the decrypted pixels.
File Selection Functions
def select_input_image():
"""Opens a file dialog to select an input image."""
input_image_path = filedialog.askopenfilename(title="Select Image")
input_image_label.config(text=input_image_path)
def select_output_image():
"""Opens a file dialog to select an output image path."""
output_image_path = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG files", "*.png"),("JPEG files", "*.jpg;*.jpeg"),("All files", "*.*")], title="Save Encrypted/Decrypted Image")
output_image_label.config(text=output_image_path)
The select_input_image
function allows the user to select the image they want to encrypt or decrypt by using a file dialog.
The selected image path is then displayed on the GUI.
Similarly, the select_output_image
function allows users to choose where to save the output image.
Encrypt and Decrypt Button Functions
def encrypt():
input_image_path = input_image_label.cget("text")
output_image_path = output_image_label.cget("text")
seed = seed_entry.get()
if not input_image_path or not output_image_path:
messagebox.showerror("Error", "Please select input and output images.")
return
if encrypt_image(input_image_path, output_image_path, seed):
messagebox.showinfo("Success", "Image encrypted successfully!")
def decrypt():
input_image_path = input_image_label.cget("text")
output_image_path = output_image_label.cget("text")
seed = seed_entry.get()
if not input_image_path or not output_image_path:
messagebox.showerror("Error", "Please select input and output images.")
return
if decrypt_image(input_image_path, output_image_path, seed):
messagebox.showinfo("Success", "Image decrypted successfully!")
The encrypt
and decrypt
functions:
- Gets the selected file paths and the seed value entered by the user.
- Ensures the user has selected both input and output image paths before proceeding.
- Calls the respective
encrypt_image()
ordecrypt_image()
functions and displays success messages once done.
Creating the GUI
root = Tk()
root.title("Image Encryption Tool")
# Create and place widgets
Label(root, text="Select Image to Encrypt/Decrypt:").pack(pady=5)
input_image_label = Label(root, text="No image selected")
input_image_label.pack(pady=5)
Button(root, text="Browse", command=select_input_image).pack(pady=5)
Label(root, text="Output Image Path:").pack(pady=5)
output_image_label = Label(root, text="No output path selected")
output_image_label.pack(pady=5)
Button(root, text="Save As", command=select_output_image).pack(pady=5)
Label(root, text="Enter Seed Key:").pack(pady=5)
seed_entry = Entry(root)
seed_entry.pack(pady=5)
Button(root, text="Encrypt Image", command=encrypt).pack(pady=5)
Button(root, text="Decrypt Image", command=decrypt).pack(pady=5)
root.mainloop()
Labels, buttons, and text entry fields are placed using pack()
.
The root.mainloop
function keeps the window open and responsive to user input.
Program in Action
Conclusion
This program demonstrates how we can manipulate digital images at the pixel level and how we can use pseudo-random number generators for basic encryption tasks.
Happy coding, and stay secure!
Top comments (0)