from PIL import Image import numpy as np import streamlit as st import io import time import random # Resize image to prevent memory issues with large images def resize_image(img, max_size=(3000, 3000)): """ Resize image to fit within max_size while maintaining aspect ratio. """ img.thumbnail(max_size, Image.Resampling.LANCZOS) return img # Logistic map function def logistic_map(r, x): return r * x * (1 - x) # Generate chaotic key based on the logistic map def generate_key(seed, n): key = [] x = seed for _ in range(n): x = logistic_map(3.9, x) key.append(int(x * 255) % 256) # Map to 0-255 return np.array(key, dtype=np.uint8) # Shuffle pixels using a chaotic sequence def shuffle_pixels(img_array, seed): h, w, c = img_array.shape num_pixels = h * w flattened = img_array.reshape(-1, c) indices = np.arange(num_pixels) random.seed(seed) random.shuffle(indices) # Shuffle indices shuffled = flattened[indices] return shuffled.reshape(h, w, c), indices # Multi-layer encryption using logistic map and pixel shuffling def encrypt_image(img_array, seed): h, w, c = img_array.shape flat_image = img_array.flatten() # Generate chaotic key chaotic_key = generate_key(seed, len(flat_image)) # XOR-based encryption encrypted_flat = [pixel ^ chaotic_key[i] for i, pixel in enumerate(flat_image)] encrypted_array = np.array(encrypted_flat, dtype=np.uint8).reshape(h, w, c) # Pixel shuffling shuffled_array, indices = shuffle_pixels(encrypted_array, seed) # Second layer of logistic map encryption chaotic_key_2 = generate_key(seed * 1.1, len(flat_image)) shuffled_flat = shuffled_array.flatten() doubly_encrypted_flat = [pixel ^ chaotic_key_2[i] for i, pixel in enumerate(shuffled_flat)] doubly_encrypted_array = np.array(doubly_encrypted_flat, dtype=np.uint8).reshape(h, w, c) return doubly_encrypted_array # Decrypt function def decrypt_image(encrypted_array, seed, original_shape): h, w, c = original_shape flat_image = encrypted_array.flatten() # Generate the second chaotic key chaotic_key_2 = generate_key(seed * 1.1, len(flat_image)) # Reverse the second XOR encryption xor_reversed_flat = [pixel ^ chaotic_key_2[i] for i, pixel in enumerate(flat_image)] xor_reversed_array = np.array(xor_reversed_flat, dtype=np.uint8).reshape(h, w, c) # Reverse pixel shuffling shuffled_array = xor_reversed_array num_pixels = h * w flattened = shuffled_array.reshape(-1, c) indices = np.arange(num_pixels) random.seed(seed) random.shuffle(indices) # Reuse the same shuffle logic unshuffled = np.zeros_like(flattened) unshuffled[indices] = flattened unshuffled_array = unshuffled.reshape(h, w, c) # Generate the first chaotic key chaotic_key_1 = generate_key(seed, len(flat_image)) # Reverse the first XOR encryption decrypted_flat = [pixel ^ chaotic_key_1[i] for i, pixel in enumerate(unshuffled_array.flatten())] decrypted_array = np.array(decrypted_flat, dtype=np.uint8).reshape(h, w, c) return decrypted_array # Streamlit App def main(): st.title("Enhanced Chaotic Logistic Map Image Encryption") st.write("Upload an image to encrypt and decrypt using advanced chaotic logistic map methods.") uploaded_file = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"]) if uploaded_file is not None: with st.spinner("Processing upload..."): # Simulate a loading delay for upload progress progress_bar = st.progress(0) for percent_complete in range(0, 101, 20): time.sleep(0.1) # Simulate progress progress_bar.progress(percent_complete) # Load the uploaded image input_image = Image.open(uploaded_file) # Resize the image if necessary input_image = resize_image(input_image) # Display original image st.image(input_image, caption="Uploaded Image", use_container_width=True) # Convert image to numpy array img_array = np.array(input_image) # Key input key_seed = st.slider("Set the encryption key seed (0 < key < 1)", min_value=0.001, max_value=0.999, step=0.001) # Encrypt Image if st.button("Encrypt Image"): with st.spinner("Encrypting image..."): # Simulate a loading delay for encryption progress progress_bar = st.progress(0) for percent_complete in range(0, 101, 20): time.sleep(0.1) # Simulate progress progress_bar.progress(percent_complete) # Encrypt the image encrypted_array = encrypt_image(img_array, key_seed) encrypted_image = Image.fromarray(encrypted_array) # Store encrypted array in session state st.session_state["encrypted_array"] = encrypted_array st.session_state["original_shape"] = img_array.shape st.session_state["key_seed"] = key_seed # Display encrypted image st.image(encrypted_image, caption="Encrypted Image", use_container_width=True) # Save encrypted image to a buffer buffer = io.BytesIO() encrypted_image.save(buffer, format="PNG") buffer.seek(0) # Download button for encrypted image st.download_button( label="Download Encrypted Image", data=buffer, file_name="encrypted_image.png", mime="image/png" ) # Decrypt Image if st.button("Decrypt Image"): if "encrypted_array" in st.session_state: with st.spinner("Decrypting image..."): decrypted_array = decrypt_image( st.session_state["encrypted_array"], st.session_state["key_seed"], st.session_state["original_shape"] ) decrypted_image = Image.fromarray(decrypted_array) # Display decrypted image st.image(decrypted_image, caption="Decrypted Image", use_container_width=True) else: st.error("No encrypted image found. Please encrypt an image first.") if __name__ == "__main__": main()