Playing around with JPGs to see how we can hide data in them.

Step 1: Can we modify and save a JPG, and still recover the data (i.e. still rely on our changes to appear correctly)?


In [5]:
import numpy as np
from PIL import Image

In [49]:
img = Image.open('images/image.jpg') # open a generic jpg
arr = np.asarray(img) # convert it to a np array

In [24]:
newarr = np.add([1], arr) # add 1 to each element of the array
out = Image.fromarray(newarr.astype('uint8')) # save out our new array
out.save("output.jpg")

In [26]:
img2 = Image.open('output.jpg')
arr2 = np.asarray(img2)

In [44]:
truearr = newarr == arr2 # creates array of t/f

# fraction that have been flipped = # false / # total
false_rate = (arr.size - np.count_nonzero(arr)) / arr.size

In [48]:
print("Our false rate is {}".format(false_rate * 100))


Our false rate is 0.9242592592592592

In summary:

When we add one to every element of an array (i.e. flip either the 1 or 2 least significant bits, at roughly 50% chance of either case), then save it as a JPG (which implies some compression), we end up with an error rate of 0.92% - at least, for specifically this image - when the image is reopened and compared against the original.