""" Note, this heavily builds upon https://gist.github.com/goelashwin36/6847a974c9b7b2ca500154d5c89d1d76 """ from email.mime import base import glob import random from PIL import Image def random_base_img(): img_fn = random.choice(glob.glob("./base_images/*.jpg")) return Image.open(img_fn, "r") def modify_pixel(pixel, data): data_lst = [format(ord(d), "08b") for d in data] data_len = len(data_lst) imdata = iter(pixel) for i in range(data_len): pix = [ value for value in imdata.__next__()[:3] + imdata.__next__()[:3] + imdata.__next__()[:3] ] # Pixel value should be made # odd for 1 and even for 0 for j in range(0, 8): if data_lst[i][j] == "0" and pix[j] % 2 != 0: pix[j] -= 1 elif data_lst[i][j] == "1" and pix[j] % 2 == 0: if pix[j] != 0: pix[j] -= 1 else: pix[j] += 1 # Eighth pixel of every set tells # whether to stop ot read further. # 0 means keep reading; 1 means thec # message is over. if i == data_len - 1: if pix[-1] % 2 == 0: if pix[-1] != 0: pix[-1] -= 1 else: pix[-1] += 1 else: if pix[-1] % 2 != 0: pix[-1] -= 1 pix = tuple(pix) yield pix[0:3] yield pix[3:6] yield pix[6:9] def encode(data): base_img = random_base_img() w = base_img.size[0] (x, y) = (0, 0) for pixel in modify_pixel(base_img.getdata(), data): base_img.putpixel((x, y), pixel) if x == w - 1: x = 0 y += 1 else: x += 1 return base_img.copy() def decode(img): data = "" imgdata = iter(img.getdata()) while True: pixels = [ value for value in imgdata.__next__()[:3] + imgdata.__next__()[:3] + imgdata.__next__()[:3] ] # string of binary data binstr = "" for i in pixels[:8]: if i % 2 == 0: binstr += "0" else: binstr += "1" data += chr(int(binstr, 2)) if pixels[-1] % 2 != 0: return data