Skip to main content
2 of 2
added 1891 characters in body
Mark Tolonen
  • 181.2k
  • 26
  • 184
  • 279

In Python, using 3rd party Pillow module (pip install pillow) for processing images:

from PIL import Image
import math

def extract_lsbs(data):
    '''Extract LSBs from RGB data as a string of 1s and 0s.
    '''
    s = []
    for r,g,b in data:
        s.extend([str(r & 1), str(g & 1), str(b & 1)])
    return ''.join(s)

def decode00(bits):
    '''Decode Header: [0, 0]
       Next 16-bits: message length in bits
       Followed by the message itself, ASCII characters encoded by groups of 8bit, most-significant bit (MSB) first
       Return the decoded string
    '''
    LENGTH_START = 2
    DATA_START = 18
    if bits[:LENGTH_START] != '00':
        raise ValueError('incorrect header')
    length = int(bits[LENGTH_START:18], 2)
    if length % 8 != 0:  # Assume message length is a multiple of 8 bits given description.
        raise ValueError('length not multiple of 8 bits')
    reqlen = DATA_START + length
    if reqlen > len(bits):  # Sanity check
        raise ValueError('length exceeds data')
    databits = bits[DATA_START:reqlen]
    return int(databits, 2).to_bytes(length // 8).decode()

def decode10(bits):
    '''Decode Header: [1, 0]
       Next 16 bits: image width in pixels
       Next 16 bits: image height in pixels
       Raw pixels of the binary image
       Return the decoded image.
    '''
    WIDTH_START = 2
    HEIGHT_START = 18
    DATA_START = 34
    if bits[:WIDTH_START] != '10':
        raise ValueError('incorrect header')
    width = int(bits[WIDTH_START:HEIGHT_START], 2)
    height = int(bits[HEIGHT_START:DATA_START], 2)
    reqlen = DATA_START + width * height
    if reqlen > len(bits):
        raise ValueError('length exceeds data')
    databits = bits[DATA_START:reqlen]

    # Collect row data
    pad = 8 - width % 8  # Image requires row data to be multiple of 8 bits.
    rowbytes = math.ceil(width / 8)  # Number of bytes needed for a row
    imdata = bytearray()
    for row in range(height):
        rowbits = databits[row * width:(row + 1) * width] + '0' * pad
        imdata.extend(int(rowbits, 2).to_bytes(length=rowbytes))
    return Image.frombytes('1', (width, height), imdata)
        
for filename in ('black.png', 'contrast.png', 'flower.png', 'cat.png'):
    im = Image.open(filename)
    data = im.get_flattened_data()
    print(decode00(extract_lsbs(data)))

im = Image.open('butterfly.png')
data = im.get_flattened_data()
im2 = decode10(extract_lsbs(data))
im2.show()

Output:

Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test
The first part of the sentence is "Three may keep a secret, ...".

### Task 2: Decode a binary image

A binary image is hidden in the least significant bits of the butterfly image, the encoding scheme is:

- Simple LSB Encoding**
- Header: `[1, 0]`
- Next 16 bits: image `width` in pixels
- Next 16 bits: image `height` in pixels
- Raw pixels of the binary image

Hint: Create and fill an image array of the derived `width` and `height` with the encoded hidden pixels.
In order to view your image in classic viewers, it might be helpful to map 0 -> 0 and 1 -> 255.
Derive the second part of the sentence and answer the question about the image.

The final image is of Ben Franklin flying a kite and reaching to touch a key.

The first image has the text "Three may keep a secret, ...", and the second:

... if two of them are dead.
Benjamin Franklin