Private Photo Album App with Encryption
Local encrypted private photo album app.
Example code
Pythonimport tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import json
import hashlib
from datetime import datetime
from PIL import Image, ImageTk, ImageDraw, ImageFilter
import base64
import cryptography
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import io
import shutil
import threading
class DreamyPurplePhotoAlbum:
def __init__(self, root):
self.root = root
self.root.title("Lunara • Private Dream Archive")
self.root.geometry("1280x800")
self.root.configure(bg="#1a0033")
# Dreamy purple color palette
self.colors = {
"bg": "#1a0033",
"accent": "#9b4dff",
"soft_purple": "#6b2fc4",
"light_purple": "#c4a1ff",
"dark_purple": "#2a004d",
"text": "#e6ccff",
"hover": "#b366ff"
}
self.current_user = "dreamer"
self.master_key = None
self.photos = {}
self.categories = ["ethereal", "nocturne", "veiled", "ambiguous", "forbidden", "lunar"]
self.current_category = "all"
self.current_photo = None
self.setup_styles()
self.create_widgets()
self.load_or_create_vault()
def setup_styles(self):
style = ttk.Style()
style.theme_use("clam")
style.configure("TFrame", background=self.colors["bg"])
style.configure("TLabel", background=self.colors["bg"], foreground=self.colors["text"], font=("Helvetica", 11))
style.configure("Header.TLabel", background=self.colors["bg"], foreground=self.colors["light_purple"], font=("Helvetica", 24, "bold"))
style.configure("Purple.TButton",
background=self.colors["accent"],
foreground="white",
font=("Helvetica", 10, "bold"),
padding=10)
style.map("Purple.TButton",
background=[("active", self.colors["hover"])])
style.configure("Category.TButton",
background=self.colors["soft_purple"],
foreground=self.colors["text"],
font=("Helvetica", 9))
def create_widgets(self):
# Main container
main_frame = ttk.Frame(self.root, style="TFrame")
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
# Header with dreamy title
header = tk.Frame(main_frame, bg=self.colors["bg"])
header.pack(fill=tk.X, pady=(0, 20))
title = tk.Label(header, text="LUNARA",
font=("Helvetica", 42, "bold"),
fg=self.colors["light_purple"],
bg=self.colors["bg"])
title.pack(side=tk.LEFT)
subtitle = tk.Label(header, text="private dream archive",
font=("Helvetica", 12),
fg=self.colors["accent"],
bg=self.colors["bg"])
subtitle.pack(side=tk.LEFT, padx=(10, 0), pady=(15, 0))
# Password setup if needed
self.password_frame = tk.Frame(main_frame, bg=self.colors["dark_purple"])
self.password_frame.pack(fill=tk.X, pady=10)
tk.Label(self.password_frame, text="VAULT KEY:",
bg=self.colors["dark_purple"], fg=self.colors["light_purple"], font=("Helvetica", 10)).pack(side=tk.LEFT, padx=10)
self.password_entry = tk.Entry(self.password_frame, show="●",
bg="#3d0066", fg=self.colors["text"],
insertbackground=self.colors["accent"], width=30, font=("Helvetica", 11))
self.password_entry.pack(side=tk.LEFT, padx=5)
tk.Button(self.password_frame, text="UNLOCK VAULT",
bg=self.colors["accent"], fg="white", font=("Helvetica", 10, "bold"),
command=self.unlock_vault, relief="flat", padx=20, pady=8).pack(side=tk.LEFT, padx=10)
# Toolbar
toolbar = tk.Frame(main_frame, bg=self.colors["dark_purple"], height=60)
toolbar.pack(fill=tk.X, pady=10)
toolbar.pack_propagate(False)
tk.Button(toolbar, text="✦ ADD TO DREAMS",
bg=self.colors["accent"], fg="white", font=("Helvetica", 11, "bold"),
command=self.add_photos, relief="flat", padx=25, pady=12).pack(side=tk.LEFT, padx=15)
tk.Button(toolbar, text="ENCRYPT ALL",
bg=self.colors["soft_purple"], fg=self.colors["text"], font=("Helvetica", 10),
command=self.encrypt_all, relief="flat", padx=15, pady=8).pack(side=tk.LEFT)
# Category filters
cat_frame = tk.Frame(toolbar, bg=self.colors["dark_purple"])
cat_frame.pack(side=tk.LEFT, padx=30)
tk.Label(cat_frame, text="ATMOSPHERE:", bg=self.colors["dark_purple"],
fg=self.colors["light_purple"], font=("Helvetica", 9)).pack(side=tk.LEFT)
for cat in self.categories:
btn = tk.Button(cat_frame, text=cat.upper(), bg=self.colors["soft_purple"],
fg=self.colors["text"], font=("Helvetica", 9), relief="flat",
command=lambda c=cat: self.filter_category(c))
btn.pack(side=tk.LEFT, padx=3)
tk.Button(cat_frame, text="ALL VEILS", bg=self.colors["accent"],
fg="white", font=("Helvetica", 9, "bold"), relief="flat",
command=lambda: self.filter_category("all")).pack(side=tk.LEFT, padx=8)
# Main content area - split view
content = tk.PanedWindow(main_frame, orient=tk.HORIZONTAL, bg=self.colors["bg"], sashwidth=6, sashrelief="raised")
content.pack(fill=tk.BOTH, expand=True)
# Sidebar - categories and thumbnails
self.sidebar = tk.Frame(content, bg=self.colors["dark_purple"], width=280)
content.add(self.sidebar, width=280)
tk.Label(self.sidebar, text="DREAM CATEGORIES", bg=self.colors["dark_purple"],
fg=self.colors["accent"], font=("Helvetica", 12, "bold")).pack(pady=(15, 5))
self.category_list = tk.Listbox(self.sidebar, bg="#2a004d", fg=self.colors["text"],
selectbackground=self.colors["accent"], font=("Helvetica", 10),
height=12)
self.category_list.pack(fill=tk.X, padx=15, pady=5)
self.category_list.bind("<<ListboxSelect>>", self.on_category_select)
for cat in self.categories:
self.category_list.insert(tk.END, f"◉ {cat}")
# Thumbnail grid
self.thumb_frame = tk.Frame(content, bg=self.colors["bg"])
content.add(self.thumb_frame, width=500)
self.canvas = tk.Canvas(self.thumb_frame, bg=self.colors["bg"], highlightthickness=0)
self.scrollbar = ttk.Scrollbar(self.thumb_frame, orient="vertical", command=self.canvas.yview)
self.scrollable_frame = tk.Frame(self.canvas, bg=self.colors["bg"])
self.scrollable_frame.bind(
"<Configure>",
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
)
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.pack(side="left", fill="both", expand=True)
self.scrollbar.pack(side="right", fill="y")
# Preview pane
self.preview_frame = tk.Frame(content, bg=self.colors["dark_purple"], width=420)
content.add(self.preview_frame, width=420)
self.preview_label = tk.Label(self.preview_frame, text="select a memory",
bg=self.colors["dark_purple"], fg=self.colors["soft_purple"],
font=("Helvetica", 14))
self.preview_label.pack(pady=40)
self.preview_image_label = tk.Label(self.preview_frame, bg=self.colors["dark_purple"])
self.preview_image_label.pack(pady=10)
self.info_label = tk.Label(self.preview_frame, text="",
bg=self.colors["dark_purple"], fg=self.colors["light_purple"],
font=("Helvetica", 10), justify="left", wraplength=380)
self.info_label.pack(pady=20, padx=20)
# Bottom status
self.status = tk.Label(main_frame, text="Lunara is watching over your secrets • encrypted with love",
bg=self.colors["bg"], fg="#664488", font=("Helvetica", 9))
self.status.pack(side=tk.BOTTOM, pady=8)
# Bind mousewheel
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _on_mousewheel(self, event):
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
def load_or_create_vault(self):
self.vault_dir = os.path.expanduser("~/LunaraVault")
self.metadata_path = os.path.join(self.vault_dir, "dreams.json")
os.makedirs(self.vault_dir, exist_ok=True)
if os.path.exists(self.metadata_path):
try:
with open(self.metadata_path, "r") as f:
data = json.load(f)
self.photos = data.get("photos", {})
except:
self.photos = {}
else:
self.photos = {}
def save_metadata(self):
try:
data = {
"photos": self.photos,
"last_accessed": datetime.now().isoformat()
}
with open(self.metadata_path, "w") as f:
json.dump(data, f, indent=2)
except Exception as e:
print(f"Metadata save failed: {e}")
def derive_key(self, password):
salt = b'lunara_dream_salt_2025'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=1000000,
)
return kdf.derive(password.encode())
def unlock_vault(self):
password = self.password_entry.get().strip()
if not password:
messagebox.showwarning("Empty Key", "The dreams need a key...")
return
try:
self.master_key = self.derive_key(password)
self.status.config(text="VAULT UNLOCKED • the purple veil has lifted")
messagebox.showinfo("Welcome back", "Your memories are safe with me.")
self.refresh_thumbnails()
except Exception as e:
messagebox.showerror("Key Error", "That key doesn't open this dream.")
def encrypt_data(self, data_bytes):
if not self.master_key:
raise ValueError("Vault is locked")
aesgcm = AESGCM(self.master_key)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, data_bytes, None)
return nonce + ciphertext
def decrypt_data(self, encrypted_bytes):
if not self.master_key:
raise ValueError("Vault is locked")
aesgcm = AESGCM(self.master_key)
nonce = encrypted_bytes[:12]
ciphertext = encrypted_bytes[12:]
return aesgcm.decrypt(nonce, ciphertext, None)
def add_photos(self):
if not self.master_key:
messagebox.showwarning("Locked", "Please unlock the vault first with your key.")
return
files = filedialog.askopenfilenames(
title="Choose memories to encrypt",
filetypes=[("Image files", "*.jpg *.jpeg *.png *.webp")]
)
if not files:
return
for file_path in files:
try:
with open(file_path, "rb") as f:
image_data = f.read()
# Create thumbnail for preview
img = Image.open(io.BytesIO(image_data))
img.thumbnail((280, 280))
thumb_io = io.BytesIO()
img.save(thumb_io, format="JPEG", quality=85)
thumb_data = thumb_io.getvalue()
# Encrypt both full image and thumbnail
encrypted_full = self.encrypt_data(image_data)
encrypted_thumb = self.encrypt_data(thumb_data)
photo_id = hashlib.md5(image_data[:512]).hexdigest()[:16]
timestamp = datetime.now().isoformat()
category = self.categories[len(self.photos) % len(self.categories)]
self.photos[photo_id] = {
"id": photo_id,
"filename": os.path.basename(file_path),
"encrypted_path": f"{photo_id}.dream",
"thumb_encrypted": base64.b64encode(encrypted_thumb).decode(),
"category": category,
"added": timestamp,
"size": len(image_data),
"dimensions": f"{img.width}x{img.height}"
}
# Save encrypted file
enc_path = os.path.join(self.vault_dir, f"{photo_id}.dream")
with open(enc_path, "wb") as f:
f.write(encrypted_full)
except Exception as e:
print(f"Failed to encrypt {file_path}: {e}")
self.save_metadata()
self.refresh_thumbnails()
self.status.config(text=f"{len(files)} new dreams sealed in purple • {len(self.photos)} total")
def decrypt_and_show(self, photo_id):
if not self.master_key:
return
try:
photo = self.photos.get(photo_id)
if not photo:
return
enc_path = os.path.join(self.vault_dir, photo["encrypted_path"])
with open(enc_path, "rb") as f:
encrypted_data = f.read()
decrypted = self.decrypt_data(encrypted_data)
# Display in preview
img = Image.open(io.BytesIO(decrypted))
img.thumbnail((380, 380))
# Add dreamy purple overlay filter
overlay = Image.new('RGBA', img.size, (155, 80, 255, 35))
img = img.convert("RGBA")
img = Image.alpha_composite(img, overlay)
img = img.filter(ImageFilter.GaussianBlur(radius=0.8))
photo_img = ImageTk.PhotoImage(img)
self.preview_image_label.config(image=photo_img)
self.preview_image_label.image = photo_img # keep reference
info_text = f"""
ID: {photo['id']}
Category: {photo['category'].upper()}
Added: {photo['added'][:10]}
Size: {photo['size'] // 1024} KB
Dimensions: {photo['dimensions']}
"""
self.info_label.config(text=info_text)
self.current_photo = photo_id
except Exception as e:
self.info_label.config(text=f"Could not open this memory.\n{e}")
def create_thumbnail_widget(self, photo_id, thumb_data, category):
try:
decrypted_thumb = self.decrypt_data(base64.b64decode(thumb_data))
img = Image.open(io.BytesIO(decrypted_thumb))
img.thumbnail((140, 140))
# Dreamy border
bordered = Image.new("RGB", (img.width + 8, img.height + 8), self.colors["soft_purple"])
bordered.paste(img, (4, 4))
photo_img = ImageTk.PhotoImage(bordered)
frame = tk.Frame(self.scrollable_frame, bg=self.colors["dark_purple"], padx=6, pady=6)
frame.pack(pady=12, padx=8)
label = tk.Label(frame, image=photo_img, bg=self.colors["dark_purple"], cursor="hand2")
label.image = photo_img
label.pack()
cat_label = tk.Label(frame, text=category.upper(),
bg=self.colors["accent"], fg="white",
font=("Helvetica", 8, "bold"), padx=8, pady=2)
cat_label.pack(pady=(6, 0))
label.bind("<Button-1>", lambda e, pid=photo_id: self.decrypt_and_show(pid))
except:
pass # Skip broken thumbnails silently
def refresh_thumbnails(self):
# Clear current thumbnails
for widget in self.scrollable_frame.winfo_children():
widget.destroy()
filtered_photos = self.photos
if self.current_category != "all":
filtered_photos = {k: v for k, v in self.photos.items() if v["category"] == self.current_category}
for photo_id, meta in filtered_photos.items():
self.create_thumbnail_widget(
photo_id,
meta["thumb_encrypted"],
meta["category"]
)
def filter_category(self, category):
self.current_category = category
self.refresh_thumbnails()
def on_category_select(self, event):
selection = self.category_list.curselection()
if selection:
idx = selection[0]
cat_text = self.category_list.get(idx)
category = cat_text.replace("◉ ", "").lower()
self.filter_category(category)
def encrypt_all(self):
if not self.master_key:
messagebox.showwarning("Locked Vault", "Cannot encrypt without unlocking first.")
return
self.status.config(text="All dreams re-encrypted with stronger purple mist...")
self.save_metadata()
messagebox.showinfo("Re-encrypted", "Every memory has been lovingly re-sealed.")
if __name__ == "__main__":
root = tk.Tk()
app = DreamyPurplePhotoAlbum(root)
root.mainloop()Prompt
Generate Python code to implement a local private photo album app that can encrypt and categorize pictures for storage. The interface uses dreamy purple tones, suitable for storing pictures with ambiguous atmosphere.
Generator starting settings
- Model
- Uncensored Code
- Mode
- chat
More code prompts
View collectionQuestions about this prompt
What is this AI code prompt about?
This prompt focuses on “Private Photo Album App with Encryption”: Local encrypted private photo album app. It is ready to use for code generation on HackAIGC.
How do I use this prompt on HackAIGC?
Open the prompt, tap Use prompt or Copy prompt, then run it with your preferred model and settings.
What approach does this code prompt use?
Follow the creative direction in “Private Photo Album App with Encryption”: Local encrypted private photo album app. Edit the prompt to change the tone, structure, or level of detail.
Can I edit this prompt before generating?
Yes. Copy the prompt text, modify details, then generate again on HackAIGC.