So, I am supposed to be encoding and decoding hidden messages in images. I have perfect the decoding hidden messages part, but am a bit stuck on the encoding part (encoding a message by changing the red value in the pixel color to the unicode number of the letter. I thought I would use a for loop in the function to loop to each position in the string for the message, but that doesn't seem to work right. All I end up getting is the letter at the last position repeated to the end of the number of pixels. I am not sure what to do about that. Also, I want it to stop when it reaches the last letter/number/symbol in the string, but it doesn't do that either.

from image import *
# ***** THIS IS WHERE YOUR FUNCTION DEFINITION SHOULD GO *****
def encode(im, secret):
    mySecret = im.copy()
    width = im.getWidth()
    height = im.getHeight()
    for row in range(0, height, 197):
    	for col in range(width):
    		t = 0
    		for i in range(1, 22, 1):
        		(r, g, b) = im.getPixel2D(col, row)
    			letter = secret[t]
        		mySecret.setPixel2D(col, row, (ord(letter), g, b))
	        	t = t + 1
    mySecret.save("mysecret.png")
    
def decode(im,imSecret):
    width = im.getWidth()
    height = im.getHeight()
    x = ""
    y = ""
    z = ""
    for col in range(width):
        for row in range(height):
            (r, g, b) = im.getPixel2D(col, row)
            (r1, g1, b1) = imSecret.getPixel2D(col, row)
            if r != r1:
                x = x + chr(r1) 
            if g != g1:
                y = y + chr(g1)
            if b != b1:
                z = z + chr(b1)
    return x
    return y
    return z
    
	
# *** The main part of the program ***
# Create a FileImage object from a specified image file
original = FileImage("nature_trail_2.png")
secret = "This is a secret code!"
encode1 = encode(original, secret)
# Create FileImage objects for the secret message files
secret1 = FileImage("secret.png")
secret2 = FileImage("secret2.png")
secret3 = FileImage("secret3.png")
secret4 = FileImage("mysecret.png")
#secret = raw_input("What do you want your secret to be: ")

# Call your function here
# *** YOU FILL THIS IN ***

message1 = decode(original, secret1)
message2 = decode(original, secret2)
message3 = decode(original, secret3)
message4 = decode(original, secret4)


# Determine if there was a secret message inside the file.  If so, print out
# the message.  If not, print out the statement "this file is clean."
if message1 == "":
    print "This file is clean."
else:
    print message1
if message2 == "":
    print "This file is clean."
else:
    print message2
if message3 == "":
    print "This file is clean."
else:
    print message3
if message4 == "":
    print "This file is clean."
else:
    print message4

Thanks.

Recommended Answers

All 9 Replies

for row in range(0, height, 197):
    	for col in range(width):
		    (r, g, b) = im.getPixel2D(col, row)
		    for i in range(0, 22, 1):
				mySecret.setPixel2D(col, row, (ord(secret[i]), g, b))

I cleaned it up a little. It still repeats the last position through the entire image. I can't seem to get rid of that. I can't get it to encode anything but the last position that I define (whether it be 22 or 13, for example).

You could insert the length of your secret message string as the first value.

First value where?

The red value of the first pixel. Then when you decode you read this length value first and use it in your loop for the next length characters.

I don't quite understand what you are saying to do. Show?

Anyone else have any ideas? I am completely stuck.

Your module image is propriatory, so it is very hard to test any code. I used the PIL module and Snee's idea and came up with these observations ...

# hide a short message in an image file (has to be .bmp or .png format)
# .jpg and .gif formats do not work!

from PIL import Image

def encode_image(img, msg):
    """
    use the red portion of an image (r, g, b) tuple to
    hide the msg string characters as ASCII values
    the red value of the first pixel is used for length of string  
    """
    length = len(msg)
    # limit length of message to 255
    if length > 255:
        return False
    # use a copy of image to hide the text in
    encoded = img.copy()
    width, height = img.size
    index = 0
    for row in range(height):
        for col in range(width):
            (r, g, b) = img.getpixel((col, row))
            # first value is length of msg
            if row == 0 and col == 0 and index < length:
                asc = length
            elif index <= length:
                c = msg[index -1]
                asc = ord(c)
            else:
                asc = r
            encoded.putpixel((col, row), (asc, g , b))
            index += 1
    return encoded

def decode_image(img):
    """
    check the red portion of an image (r, g, b) tuple for
    hidden message characters (ASCII values)
    the red value of the first pixel is used for length of string   
    """
    width, height = img.size
    msg = ""
    index = 0
    for row in range(height):
        for col in range(width):
            r, g, b = img.getpixel((col, row))
            # first pixel r value is length of message
            if row == 0 and col == 0:
                length = r
            elif index <= length:
                msg += chr(r)
            index += 1
    return msg


original_image_file = "french_flag.png"
encoded_image_file = "french_flag_enc.png"
img = Image.open(original_image_file)

# at this point don't exceed 255 characters
secret_msg = "this is a secret message added to the image"
img_encoded = encode_image(img, secret_msg)

if img_encoded:
    # save it ...
    img_encoded.save(encoded_image_file)
    # test it ...
    img2 = Image.open(encoded_image_file)
    print(decode_image(img2))
else:
    print("text too long! (don't exeed 255 characters)")
def encode(im, secret):
    mySecret = im.copy()
    width = im.getWidth()
    height = im.getHeight() 
    i = 0
    for row in range(0, height, 197):
		for col in range(width):
			if i < 22:
			    (r, g, b) = im.getPixel2D(col, row)
			    mySecret.setPixel2D(col, row, (ord(secret[i]), g, b))
			    i = i + 1
			else:
				break
    mySecret.save("mysecret.png")

I came up with that and it works. I am just trying to figure out how to get it to calculate the string length without me counting for the if i < 22 part.

Another way would be to give your secret text string a marker ending, like '~~' and stop encoding or decoding when detected.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.