Image Steganography Tool
This utility allows you to hide secret text messages inside an image file (Steganography) and retrieve them later. It uses the Least Significant Bit (LSB) technique, which modifies the last bit of the pixel color values. These changes are so subtle that they are invisible to the human eye.
Modules Used:
Installation
pip install Pillow
The Code
Save this as stego.py.
from PIL import Image
import argparse
import os
import sys
DELIMITER = "#####"
def text_to_bin(text):
"""Convert text to a binary string."""
return ''.join(format(ord(char), '08b') for char in text)
def encode(image_path, secret_text, output_path):
print(f"Encoding message into '{image_path}'...")
img = Image.open(image_path)
img = img.convert("RGB") # Ensure 3 channels
pixels = img.load()
# Add delimiter so we know when to stop decoding
full_text = secret_text + DELIMITER
binary_secret = text_to_bin(full_text)
data_len = len(binary_secret)
width, height = img.size
# Check if image is large enough
if data_len > width * height * 3:
raise ValueError(f"Text is too long for this image. Max bits: {width*height*3}")
data_index = 0
for y in range(height):
for x in range(width):
r, g, b = pixels[x, y]
# Modify LSB of Red, Green, and Blue channels
# (val & ~1) clears the last bit, | int(bit) sets it
if data_index < data_len:
r = (r & ~1) | int(binary_secret[data_index])
data_index += 1
if data_index < data_len:
g = (g & ~1) | int(binary_secret[data_index])
data_index += 1
if data_index < data_len:
b = (b & ~1) | int(binary_secret[data_index])
data_index += 1
pixels[x, y] = (r, g, b)
if data_index >= data_len:
break
if data_index >= data_len:
break
img.save(output_path)
print(f"Success! Encoded image saved to '{output_path}'")
def decode(image_path):
print(f"Decoding message from '{image_path}'...")
img = Image.open(image_path)
img = img.convert("RGB")
pixels = img.load()
binary_data = ""
width, height = img.size
for y in range(height):
for x in range(width):
r, g, b = pixels[x, y]
# Extract LSB
binary_data += str(r & 1)
binary_data += str(g & 1)
binary_data += str(b & 1)
# Convert binary to text and look for delimiter
decoded_text = ""
for i in range(0, len(binary_data), 8):
byte = binary_data[i:i+8]
if len(byte) < 8: break
decoded_text += chr(int(byte, 2))
if decoded_text.endswith(DELIMITER):
print("\n--- Hidden Message ---")
print(decoded_text[:-len(DELIMITER)])
print("----------------------")
return
print("No hidden message found (delimiter missing).")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Image Steganography Tool")
subparsers = parser.add_subparsers(dest="command", required=True)
# Encode Command
enc_parser = subparsers.add_parser("encode", help="Hide text in an image")
enc_parser.add_argument("image", help="Input image path")
enc_parser.add_argument("text", help="Secret text to hide")
enc_parser.add_argument("-o", "--output", default="secret.png", help="Output image path (must be PNG)")
# Decode Command
dec_parser = subparsers.add_parser("decode", help="Reveal text from an image")
dec_parser.add_argument("image", help="Image with hidden text")
args = parser.parse_args()
if args.command == "encode":
# PNG is required because JPEG compression destroys LSB data
if not args.output.lower().endswith(".png"):
print("Error: Output file must be a .png to prevent data loss.")
else:
encode(args.image, args.text, args.output)
elif args.command == "decode":
decode(args.image)
Usage
# Hide a message
python stego.py encode landscape.jpg "The treasure is buried under the palm tree." -o secret_image.png
# Reveal the message
python stego.py decode secret_image.png