diff --git a/.streamlit/config.toml b/.streamlit/config.toml new file mode 100644 index 0000000..887b8fd --- /dev/null +++ b/.streamlit/config.toml @@ -0,0 +1,5 @@ +[theme] +primaryColor="#ffffff" +backgroundColor="#181d27" +secondaryBackgroundColor = "#2c374d" +textColor = "#ffbf00" \ No newline at end of file diff --git a/docs/app.py b/docs/app.py new file mode 100644 index 0000000..6dd62bd --- /dev/null +++ b/docs/app.py @@ -0,0 +1,108 @@ +import streamlit as st +from image_cipher import ImageCipher +import tempfile +import os + + +def save_uploaded_file_to_temp(uploaded_file): + temp_dir = tempfile.mkdtemp() + temp_file_path = os.path.join(temp_dir, uploaded_file.name) + with open(temp_file_path, "wb") as f: + f.write(uploaded_file.getbuffer()) + return temp_file_path + + +def encrypt_image(image_path, message, encrypt): + cipher = ImageCipher() + encoded_image_path = cipher.encode(image_path, message, encrypt=encrypt) + return encoded_image_path, cipher.key + + +def decrypt_image(image_path, key): + cipher = ImageCipher() + decoded_message = cipher.decode(image_path, key) + return decoded_message + + +def main(): + st.sidebar.image("docs/assets/image1.png", use_column_width=True) + with open("docs/css/styles.css") as f: + st.markdown(f"", unsafe_allow_html=True) + st.sidebar.markdown( + """\ + """, + unsafe_allow_html=True, + ) + st.title("Image Cipher") + app_mode = st.sidebar.radio( + "Choose the app mode", ["Encrypt", "Decrypt", "About Us"] + ) + + if app_mode == "Encrypt": + st.header("Encrypt Image") + uploaded_image = st.file_uploader( + "Choose an image...", type=["png", "jpg", "jpeg"] + ) + message = st.text_area("Enter your message") + use_encryption = st.checkbox("Use Encryption") + + if st.button("Encrypt"): + if uploaded_image and message: + temp_image_path = save_uploaded_file_to_temp(uploaded_image) + encoded_image_path, key = encrypt_image( + temp_image_path, message, use_encryption + ) + if use_encryption: + st.markdown("### Encryption Key:") + st.markdown(f"```\n{key.decode()}\n```") + with open(encoded_image_path, "rb") as file: + st.download_button( + "Download Encrypted Image", + file, + file_name="encrypted_image.png", + ) + st.image(encoded_image_path, caption="Encrypted Image") + else: + st.error( + "Please upload an image and enter a message\ + to encrypt." + ) + + elif app_mode == "Decrypt": + st.header("Decrypt Image") + uploaded_image = st.file_uploader( + "Choose an image...", type=["png", "jpg", "jpeg"] + ) + key = st.text_input("Enter key (if any)") + + if st.button("Decrypt"): + try: + if uploaded_image: + temp_path = save_uploaded_file_to_temp(uploaded_image) + decrypted_message = decrypt_image(temp_path, key) + st.text_area( + "Decrypted Message", + value=decrypted_message, + height=200 + ) + + else: + st.error("Please upload an image to decrypt.") + + except Exception as e: + st.error(e) + + elif app_mode == "About Us": + st.header("About Us") + st.markdown( + "This project is developed by ", + unsafe_allow_html=True, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/css/styles.css b/docs/css/styles.css index 73997dd..f652f44 100644 --- a/docs/css/styles.css +++ b/docs/css/styles.css @@ -1,66 +1,97 @@ +/* Main container */ body { - display: flex; - font-family: Arial, sans-serif; - margin: 0; - padding: 0; + background-color: #181d27; + color: #ffbf00; } -.sidebar { - width: 200px; - background-color: #2c3e50; - color: white; - padding: 20px; +/* Sidebar */ +.css-1d391kg { + background-color: #4f535a; } -.sidebar .logo { - text-align: center; +.css-1lcbmhc, .css-1d2azem { + color: #ffbf00; } -.sidebar nav ul { - list-style-type: none; - padding: 0; +.css-1v8qudd { + background-color: #2c374d; + color: #ffbf00; } -.sidebar nav ul li { - margin: 20px 0; +/* Header */ +.css-1siy2j7 { + color: #ffbf00; } -.sidebar nav ul li a { - color: white; - text-decoration: none; +/* Radio buttons and text input */ +.css-1ex6qaa { + background-color: #2c374d; + color: #ffbf00; } -.content { - flex: 1; - padding: 20px; +.css-1ex6qaa input[type="radio"] { + background-color: #2c374d; + color: #ffbf00; } -#encrypt-section, #decrypt-section, #about-section { - max-width: 600px; - margin: 0 auto; +.css-1ex6qaa input[type="text"] { + background-color: #2c374d; + color: #ffbf00; } -input[type="file"], input[type="text"], textarea { - display: block; - width: 100%; - margin-bottom: 20px; +.css-1ex6qaa textarea { + background-color: #2c374d; + color: #ffbf00; } -button { - padding: 10px 20px; - background-color: #2980b9; - color: white; - border: none; - cursor: pointer; +/* Buttons */ +.css-1df45cr, .css-1f1iwnp, .css-1ktajzc { + background-color: #152544; + color: #ffbf00; } -button:hover { - background-color: #3498db; +.css-1df45cr:hover, .css-1f1iwnp:hover, .css-1ktajzc:hover { + background-color: #152544; + color: #ffffff; } -.logo { - margin-bottom: 1rem; /* Change to a smaller value */ + +/* Download button */ +.css-10trblm { + background-color: #152544; + color: #ffbf00; +} + +.css-10trblm:hover { + background-color: #152544; + color: #ffffff; +} + +/* Image */ +.css-11v1u3b img { + border: 2px solid #ffbf00; +} + +/* Text */ +.css-qrbaxs p { + color: #ffbf00; +} + +/* Error messages */ +.css-19hj99j { + background-color: #2c374d; + color: #ffbf00; +} + +/* Markdown */ +.css-1uix8eu h1, .css-1uix8eu h2, .css-1uix8eu h3, .css-1uix8eu h4, .css-1uix8eu h5, .css-1uix8eu h6, .css-1uix8eu p { + color: #ffbf00; +} + +/* Links */ +a { + color: #ffbf00; } -.nav { - margin-top: 0; /* Ensure no extra margin above the nav */ +a:hover { + color: #ffffff; } diff --git a/docs/decrypt.html b/docs/decrypt.html deleted file mode 100644 index 36eaea8..0000000 --- a/docs/decrypt.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - Decrypt Image - - - - -
-

Decrypt Image

-
- -
-
- -
- -
-
- - - - - - diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index bc66e56..0000000 --- a/docs/index.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - Image Cipher - - - - - - -
-
- -
-
-

Encrypt Image

-
- -
-
- -
- - -
- -
-
- - -
-
-
- - - - - - - diff --git a/docs/jss/script.js b/docs/jss/script.js deleted file mode 100644 index 28c2ded..0000000 --- a/docs/jss/script.js +++ /dev/null @@ -1,137 +0,0 @@ -async function main() { - console.log("Loading pyodide."); - window.pyodide = await loadPyodide(); - console.log("Loading imagcipher..."); - await pyodide.loadPackage("micropip"); - const pip = pyodide.pyimport("micropip"); - await pip.install("imagecipher", { headers: { pragma: "no-cache", "cache-control": "no-cache" } }); -} - -main(); - -function showSection(id) { - const sections = ['encrypt-section', 'decrypt-section', 'about-section']; - sections.forEach(section => { - document.getElementById(section).style.display = section === id ? 'block' : 'none'; - }); -} - -document.addEventListener('DOMContentLoaded', (event) => { - document.getElementById('encrypt-link').addEventListener('click', (event) => { - event.preventDefault(); - showSection('encrypt-section'); - }); - document.getElementById('decrypt-link').addEventListener('click', (event) => { - event.preventDefault(); - showSection('decrypt-section'); - }); - document.getElementById('about-link').addEventListener('click', (event) => { - event.preventDefault(); - showSection('about-section'); - }); - - // Initial display setup - showSection('encrypt-section'); - - document.getElementById('encrypt-button').addEventListener('click', handleEncrypt); - document.getElementById('decrypt-button').addEventListener('click', handleDecrypt); -}); - -async function encryptImage(imageFile, message) { - const base64Image = await fileToBase64(imageFile); - - const pythonCode = ` - from image_cipher import ImageCipher - from PIL import Image - from io import BytesIO - import base64 - import json - - def encrypt_image(base64_image, message): - image_data = base64.b64decode(base64_image.split(",")[1]) - image = Image.open(BytesIO(image_data)) - cipher = ImageCipher() - encrypted_image = cipher.encode(image, message) - - buffer = BytesIO() - encrypted_image.save(buffer, format="PNG") - encoded_image_str = base64.b64encode(buffer.getvalue()).decode("utf-8") - encoded_image_path = "data:image/png;base64," + encoded_image_str - - return json.dumps({"encoded_image_path": encoded_image_path}) - - encrypt_image("${base64Image}", "${message}") - `; - - const result = await pyodide.runPythonAsync(pythonCode); - return result; -} - -function fileToBase64(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result); - reader.onerror = (error) => reject(error); - reader.readAsDataURL(file); - }); -} - -async function decryptImage(imageFilePath, key) { - return pyodide.runPython(` -from image_cipher import ImageCipher -import json - -# Define a function to handle decryption -def decrypt_image(image_file_path, key): - cipher = ImageCipher() - decoded_message = cipher.decode(image_file_path, key) - return json.dumps({'decoded_message': decoded_message}) - -# Call the function with passed arguments -decrypt_image(image_file_path, key) - `, { image_file_path: imageFilePath, key }); // Pass JavaScript variables here -} - - -async function handleEncrypt() { - const imageFile = document.getElementById("encrypt-image").files[0]; - const message = document.getElementById("encrypt-message").value; - console.log("image:", imageFile); - - if (imageFile && message) { - // Create a URL for the file - const imageUrl = URL.createObjectURL(imageFile); - console.log("image URL:", imageUrl); - - // Display the image - document.getElementById("encrypt-result").innerHTML = `

Selected Image

Selected Image`; - - // Encrypt the image - const result = await encryptImage(imageFile, message); - const data = JSON.parse(result); - console.log(data); - - // Display the encrypted image - document.getElementById("encrypt-result").innerHTML += `

Encrypted Image

Encrypted Image
Download`; - } else { - alert("Please select an image and enter a message."); - } -} - -async function handleDecrypt() { - const imageFile = document.getElementById("decrypt-image").files[0]; - const key = document.getElementById("decrypt-key").value; - - if (imageFile) { - const reader = new FileReader(); - reader.onload = async function(event) { - const imageFilePath = event.target.result; - const result = await decryptImage(imageFilePath, key); - const data = JSON.parse(result); - document.getElementById("decrypt-result").innerHTML = `

Decrypted Message

${data.decoded_message}

`; - }; - reader.readAsDataURL(imageFile); - } else { - alert("Please select an image to decrypt."); - } -} diff --git a/docs/server.py b/docs/server.py deleted file mode 100644 index 7f69ff4..0000000 --- a/docs/server.py +++ /dev/null @@ -1,43 +0,0 @@ -from flask import Flask, request, send_file, jsonify -from image_cipher import ImageCipher -from werkzeug.utils import secure_filename -import os - -app = Flask(__name__) -cipher = ImageCipher() - -UPLOAD_FOLDER = 'uploads' -if not os.path.exists(UPLOAD_FOLDER): - os.makedirs(UPLOAD_FOLDER) - -@app.route('/encode', methods=['POST']) -def encode_image(): - if 'image' not in request.files or 'message' not in request.form: - return jsonify({'error': 'No image or message provided'}), 400 - - image = request.files['image'] - message = request.form['message'] - encrypt = request.form.get('encrypt', 'true').lower() == 'true' - - image_path = os.path.join(UPLOAD_FOLDER, secure_filename(image.filename)) - image.save(image_path) - - encoded_image_path = cipher.encode(image_path, message, encrypt) - return send_file(encoded_image_path, as_attachment=True) - -@app.route('/decode', methods=['POST']) -def decode_image(): - if 'image' not in request.files: - return jsonify({'error': 'No image provided'}), 400 - - image = request.files['image'] - key = request.form.get('key', None) - - image_path = os.path.join(UPLOAD_FOLDER, secure_filename(image.filename)) - image.save(image_path) - - message = cipher.decode(image_path, key) - return jsonify({'message': message}) - -if __name__ == '__main__': - app.run(debug=True) diff --git a/requirements.txt b/requirements.txt index 9434775..18771f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Pillow==10.4.0 cryptography==42.0.8 pytest==8.2.2 -flake8==7.1.0 \ No newline at end of file +flake8==7.1.0 +streamlit \ No newline at end of file