pythonpython-imaging-librarysteganography

Extract image hidden after EOF


For a little lesson in steganography, I am appending an image to another image file like so:

my_image = open(output_image_path, "wb")
my_image.write(open(visible_image, "rb").read())
my_image.write(open(hidden_image, "rb").read())
my_image.close()

Now I want to extract the hidden image again. How would I do this? I tried with PIL by reading the image or by reading in the file as a bytes stream and then converting it, but I only get the visible image.

In case it matters, I should specify that all images are saved in .jpg format


Solution

  • I was preparing an answer, and just while typing you added your solution. Nevertheless, here's my version, capable extracting all images stored in the output image:

    from io import BytesIO
    from PIL import Image
    
    # Create "image to the world"
    my_image = open('to_the_world.jpg', 'wb')
    my_image.write(open('images/0.jpg', 'rb').read())   # size=640x427
    my_image.write(open('images/1.jpg', 'rb').read())   # size=1920x1080
    my_image.write(open('images/2.jpg', 'rb').read())   # size=1920x1200
    my_image.close()
    
    # Try to read "image to the world" via Pillow
    image = Image.open('to_the_world.jpg')
    print('Read image via Pillow:\n{}\n'.format(image))
    
    # Read "image to the world" via binary data
    image = open('to_the_world.jpg', 'rb').read()
    
    # Look for JPG "Start Of Image" segments, and split byte blocks
    images = image.split(b'\xff\xd8')[1:]
    
    # Convert byte blocks to Pillow Image objects
    images = [Image.open(BytesIO(b'\xff\xd8' + image)) for image in images]
    for i, image in enumerate(images):
        print('Extracted image #{}:\n{}\n'.format(i+1, image))
    

    Of course, I also used the binary data of the output image, and split the binary data using the JPEG file format structure, the "Start of Image" segment FF D8 to be precise.

    For the set of images, I used, the output would be the following:

    Read image via Pillow:
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x427 at 0x1ECC333FF40>
    
    Extracted image #1:
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x427 at 0x1ECC333FF10>
    
    Extracted image #2:
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1920x1080 at 0x1ECC37D4C70>
    
    Extracted image #3:
    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1920x1200 at 0x1ECC37D4D30>
    
    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.16299-SP0
    Python:        3.9.1
    PyCharm:       2021.1.1
    Pillow:        8.2.0
    ----------------------------------------