Extract image hidden after EOF - python

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

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
----------------------------------------

Ok got it, this is how to show the hidden image:
from io import BytesIO
import cv2
from PIL import Image
with open(my_image, 'rb') as img_bin:
buff = BytesIO()
buff.write(img_bin.read())
buff.seek(0)
bytesarray = buff.read()
img = bytesarray.split(b"\xff\xd9")[1] + b"\xff\xd9"
img_out = BytesIO()
img_out.write(img)
img = Image.open(img_out)
img.show()

Related

Remove corrupt exif warnings with tiff images

I am trying to fix the corrupt exif warnings from tiff images and here's a code I am using
from PIL import Image
def remove_exif(image_name):
image = Image.open(image_name)
if not image.getexif():
return
print('removing EXIF from', image_name, '...')
data = list(image.getdata())
image_without_exif = Image.new(image.mode, image.size)
image_without_exif.putdata(data)
image_without_exif.save(image_name)
remove_exif('ggg.tiff')
print('Done')
The code is working and removed the exif but I got one page only while the tiff before the exif remove was of two pages.
Is it possible to keep all the pages of the tiff image?

How to convert Clipboard Image BMP to PNG using Pillow package without saving and then loading

I would like to convert an image obtained from the Windows Clipboard to PNG format without having to save and then reload.
As per the code below, I am saving the clipboard image and then reloading it.
Is there a way to convert the image to PNG format without those extra steps, such that the
PIL.BmpImagePlugin.DibImageFile gets converted to
PIL.PngImagePlugin.PngImageFile
Here is the current code:
from PIL import ImageGrab, Image
# Get the clipboard image
img1 = ImageGrab.grabclipboard()
# Save the image from the clipboard to file
img1.save('paste.png', 'PNG')
print("Image Type1:", type(img1))
# Load the image back in
img2 = Image.open('paste.png')
print("Image Type2:", type(img2))
OUTPUT:
Image Type1: <class 'PIL.BmpImagePlugin.DibImageFile'>
Image Type2: <class 'PIL.PngImagePlugin.PngImageFile'>
As per some help from Seon's comment, this got me on the right track, and fulfilled my requirements.
As per Seon:
"the idea is to save the image to an in-memory BytesIO object, and reload it from there. We're still saving and loading, but not to disk."
Which is exactly what I wanted.
Here is the code I used:
from PIL import ImageGrab, Image
import io
def convertImageFormat(imgObj, outputFormat="PNG"):
newImgObj = imgObj
if outputFormat and (imgObj.format != outputFormat):
imageBytesIO = io.BytesIO()
imgObj.save(imageBytesIO, outputFormat)
newImgObj = Image.open(imageBytesIO)
return newImgObj
# Get the clipboard image and convert to PNG
img1 = ImageGrab.grabclipboard()
img2 = convertImageFormat(img1)
# Check the types
print("Image Type1:", type(img1))
print("Image Type2:", type(img2))
OUTPUT:
Image Type1: <class 'PIL.BmpImagePlugin.DibImageFile'>
Image Type2: <class 'PIL.PngImagePlugin.PngImageFile'>

JPEG images converted to png - PIL.UnidentifiedImageError: cannot identify image file with

I'm working on a project where I receive a stream of JPEG images over WiFi, convert them to a bytearray, save them as PNG images and read them. The PIL.UnidentifiedImageError occurs when I attempt to open an saved PNG image.
This is how I save the bytearray of JPEG images into PNG images:
idx = random.randint(0,300)
image = Image.open(io.BytesIO(imgdata))
image.save(os.getcwd() + '/Frames/%d.png' % idx)
This is how I open the saved PNG images:
for file in os.listdir('/home/bitcraze/Desktop/AIdeck_examples/NINA/Frames/.'):
print (file)
if file.endswith(".png"):
full_file_path = '/home/Desktop/Frames/' + file
img_file = Image.open(full_file_path)
I checked other posts related to PIL.UnidentifiedImageError and it seems like it could be because the image is corrupted. The picture below shows how I receive the JPEG images:
EDIT: someone suggested I should include how I show the image.
img_loader = GdkPixbuf.PixbufLoader()
img_loader.write(imgdata)
img_loader.close()
pix = img_loader.get_pixbuf()
GLib.idle_add(self._update_image, pix)

HEIC to JPEG conversion with metadata

I'm trying to convert heic file in jpeg importing also all metadadata (like gps info and other stuff), unfurtunately with the code below the conversion is ok but no metadata are stored on the jpeg file created.
Anyone can describe me what I need to add in the conversion method?
heif_file = pyheif.read("/transito/126APPLE_IMG_6272.HEIC")
image = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
heif_file.mode,
heif_file.stride,
)
image.save("/transito/126APPLE_IMG_6272.JPEG", "JPEG")
Thanks, i found a solution, I hope can help others:
# Open the file
heif_file = pyheif.read(file_path_heic)
# Creation of image
image = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
heif_file.mode,
heif_file.stride,
)
# Retrive the metadata
for metadata in heif_file.metadata or []:
if metadata['type'] == 'Exif':
exif_dict = piexif.load(metadata['data'])
# PIL rotates the image according to exif info, so it's necessary to remove the orientation tag otherwise the image will be rotated again (1° time from PIL, 2° from viewer).
exif_dict['0th'][274] = 0
exif_bytes = piexif.dump(exif_dict)
image.save(file_path_jpeg, "JPEG", exif=exif_bytes)
HEIF to JPEG:
from PIL import Image
import pillow_heif
if __name__ == "__main__":
pillow_heif.register_heif_opener()
img = Image.open("any_image.heic")
img.save("output.jpeg")
JPEG to HEIF:
from PIL import Image
import pillow_heif
if __name__ == "__main__":
pillow_heif.register_heif_opener()
img = Image.open("any_image.jpg")
img.save("output.heic")
Rotation (EXIF of XMP) will be removed automatically when needed.
Call to register_heif_opener can be replaced by importing pillow_heif.HeifImagePlugin instead of pillow_heif
Metadata can be edited in Pillow's "info" dictionary and will be saved when saving to HEIF.
Here is an other approach to convert iPhone HEIC images to JPG preserving exif data
Pyhton 3.9 (I'm on Rasperry PI 4 64 bit)
install pillow_heif (0.8.0)
And run following code and you'll find exif data in the new JPEG image.
The trick is to get the dictionary information. No additional conversion required.
This is sample code, built your own wrapper around.
from PIL import Image
import pillow_heif
# open the image file
heif_file = pillow_heif.read_heif("/mnt/pictures/test/IMG_0001.HEIC")
#create the new image
image = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
heif_file.mode,
heif_file.stride,
)
print(heif_file.info.keys())
dictionary=heif_file.info
exif_dict=dictionary['exif']
# debug
print(exif_dict)
image.save('/tmp/test000.JPG', "JPEG", exif=exif_dict)

PIL unable to identify image file

The object list_of_contents[0] is based64. I am trying to convert it to it's original image.
image_64_decode = base64.b64decode(list_of_contents[0])
image_result = open('test.jpg', 'wb')
image_result.write(image_64_decode)
img = Image.open(r'C:\Users\st-am\CANCER_APP\test.jpg')
However, I get the following error:
PIL.UnidentifiedImageError: cannot identify image file 'C:\\Users\\st-am\\CANCER_APP\\test.jpg'
Anybody has an idea why PIL cannot identify the image?
Here is the image

Categories

Resources