As usual, create a directory to hold today's files. All programs that you write today should be stored in this directory.
$ cd ~/cs120/labs $ mkdir lab28 $ cd lab28
All computer memory is binary, so whether an integer is represented as a string or as a number, it is still represented as a number in binary.
Write a function called parse_binary(binary_string)
in
a file called parse_bin.py. The function should return an
int value that is equivalent to the binary integer represented
with binary_string
. The function should assume
that binary_string
consists of only the characters '0'
and '1'.
Make sure your program handles all necessary cases gracefully. What additional test cases should you check?
Function Call | Expected Output |
---|---|
parse_int('101') | 5 |
type(parse_int('101')) | <class 'int'> |
To convert the binary string to an int, the function will
need to convert and accumulate each digit in the input
string. The function will therefore follow the accumulator
pattern that we have seen multiple times. However, the code
is slightly easier to write if the function iterates over
the input string's digits in reverse order. The least
significant digits of the input string are the characters
with the highest indices. So by iterating in reverse order
the input string's digits can be converted in order of
ascending significance. To create a loop that iterates over
the characters in reverse order, use the for i in
range
version of the for loop. You can print the
characters at each iteration of the loop to verify that the
loop is written correctly.
Converting each digit character to an int is not sufficient. For example, in the number 100 the digit 1 has the value 4. So, the first digit must be multiplied by 1, the second by 2, the third by 4, and so on. To do this, create an integer before the loop that is initially 1 and represents the digit's place. In side the loop the integer should increase by a multiple of 2 each iteration. Print the variable to make sure that it is increasing as desired.
Finally, add an accumulator variable that is initially 0. Each iteration of the loop increase the accumulator by the current digit multiplied by the place integer. Don't forget to return the accumulated value.
int_to_binary_string(an_int)
, which takes an
integer as input. Your function should return a string of 1's and
0's, the binary representation of the input integer.
Cryptography can be used to make the contents of a message secret, but sometimes you want to hide that a message is even being sent. Steganography is one way to hide messages, and a common technique takes advantage of our inability to perceive small changes in colors. For example the image below consists of two boxes with different colors.
The left box has the RGB values (161, 187, 150). The box on the right has the RGB values (162, 188, 151). The two boxes appear to be the same color because the RGB values are similar. A message can be hidden in an image by making small changes to the RGB values of an existing image.
A common way of modifying an image is to change only the least significant bits of the RGB values. The least significant bit of a number is the right-most bit and represents the value 20, or 1. Therefore, the most a color value will change if the least significant bit is change is 1, which the above image demonstrates as imperceptible. The following whale image, for example, has a message encoded in it.
Create a function called decode_image(ppm_file_name)
in
a file called steganography.py
. The program should
return the secret message that is embedded in the specified image
file. The message is encoded as 8-bit ASCII in the least
significant bit of the image's color data. Assume that the number
of color values in the file is a factor of 8. Once you have tested
your program on a simple example, you can test it on the
above
whale image.
Some things to keep in mind:
The first three lines of a PPM file specify header information for the image. You will have to skip these three lines.
Each subsequent line specifies one color value of a pixel (Red, Green, and Blue respectively). You need to extract the least significant bit of each of these values.
Once you have processed 8 color values, you will have to convert the binary sequence represented by their least significant bits into a single character. This is one character in the hidden message.
>>> image_file = open("demo.ppm", "r") >>> print(image_file.read()) P3 1 8 255 122 101 215 42 2 128 200 13 64 203 155 130 36 172 91 180 88 77 55 22 44 66 33 99 >>> print(decode_image("demo.ppm")) abc
You are going to use the accumulator pattern here for strings, accumulating the least significant bit of the color values into a string. A number that is odd has a 1 as the least significant bit, a number that is even has a 0 as the least significant bit.
You can convert a binary string to a base-10 integer by
using your parse_binary
function from above.
You can convert an integer to a character using the
built-in chr
function.
Write a function that can embed messages into images. The function should take three parameters: a message, an input image file name, and an output image file name. It should read in the input image, modify the least significant bits of the color values to embed the message, and write the new image to the specified output file.