def reveal(input_image: Union[str, IO[bytes]], encoding: str = "UTF-8", shift: int = 0): """Find a message in an image (with the LSB technique). """ img = tools.open_image(input_image) width, height = img.size buff, count = 0, 0 bitab = [] limit = None for row in range(height): for col in range(width): if shift != 0: shift -= 1 continue # pixel = [r, g, b] or [r,g,b,a] pixel = img.getpixel((col, row)) if img.mode == "RGBA": pixel = pixel[:3] # ignore the alpha for color in pixel: buff += (color & 1) << (tools.ENCODINGS[encoding] - 1 - count) count += 1 if count == tools.ENCODINGS[encoding]: bitab.append(chr(buff)) buff, count = 0, 0 if bitab[-1] == ":" and limit is None: try: limit = int("".join(bitab[:-1])) except Exception: pass if len(bitab) - len(str(limit)) - 1 == limit: img.close() return "".join(bitab)[len(str(limit)) + 1:]
def hide( input_image_file, img_enc, secret_message=None, secret_file=None, img_format=None, ): """Hide a message (string) in an image. """ from zlib import compress from base64 import b64encode if secret_file is not None: with open(secret_file, "r") as f: secret_message = f.read() try: text = compress(b64encode(bytes(secret_message, "utf-8"))) except: text = compress(b64encode(secret_message)) img = tools.open_image(input_image_file) if img_format is None: img_format = img.format if "exif" in img.info: exif_dict = piexif.load(img.info["exif"]) else: exif_dict = {} exif_dict["0th"] = {} exif_dict["0th"][piexif.ImageIFD.ImageDescription] = text exif_bytes = piexif.dump(exif_dict) img.save(img_enc, format=img_format, exif=exif_bytes) img.close() return img
def reveal( input_image: Union[str, IO[bytes]], generator: Iterator[int], shift: int = 0, encoding: str = "UTF-8", ): """Find a message in an image (with the LSB technique). """ img = tools.open_image(input_image) img_list = list(img.getdata()) width, height = img.size buff, count = 0, 0 bitab = [] limit = None while shift != 0: next(generator) shift -= 1 while True: generated_number = next(generator) # color = [r, g, b] for color in img_list[generated_number][:3]: # ignore the alpha buff += (color & 1) << (tools.ENCODINGS[encoding] - 1 - count) count += 1 if count == tools.ENCODINGS[encoding]: bitab.append(chr(buff)) buff, count = 0, 0 if bitab[-1] == ":" and limit == None: if "".join(bitab[:-1]).isdigit(): limit = int("".join(bitab[:-1])) else: raise IndexError("Impossible to detect message.") if len(bitab) - len(str(limit)) - 1 == limit: return "".join(bitab)[len(str(limit)) + 1:]
def hide(input_image: Union[str, IO[bytes]], message: str): """ Hide a message (string) in an image. Use the red portion of a pixel (r, g, b) tuple to hide the message string characters as ASCII values. The red value of the first pixel is used for message_length of the string. """ message_length = len(message) assert message_length != 0, "message message_length is zero" assert message_length < 255, "message is too long" img = tools.open_image(input_image) # Use a copy of image to hide the text in encoded = img.copy() width, height = img.size index = 0 for row in range(height): for col in range(width): (r, g, b) = img.getpixel((col, row)) # first value is message_length of message if row == 0 and col == 0 and index < message_length: asc = message_length elif index <= message_length: c = message[index - 1] asc = ord(c) else: asc = r encoded.putpixel((col, row), (asc, g, b)) index += 1 img.close() return encoded
def reveal(input_image_file): """Find a message in an image. """ from base64 import b64decode from zlib import decompress img = tools.open_image(input_image_file) try: if img.format in ["JPEG", "TIFF"]: if "exif" in img.info: exif_dict = piexif.load(img.info.get("exif", b"")) description_key = piexif.ImageIFD.ImageDescription encoded_message = exif_dict["0th"][description_key] else: encoded_message = b"" else: raise ValueError("Given file is neither JPEG nor TIFF.") finally: img.close() return b64decode(decompress(encoded_message))
def reveal(input_image: Union[str, IO[bytes]]): """ Find a message in an image. Check the red portion of an pixel (r, g, b) tuple for hidden message characters (ASCII values). The red value of the first pixel is used for message_length of string. """ img = tools.open_image(input_image) width, height = img.size message = "" index = 0 for row in range(height): for col in range(width): r, g, b = img.getpixel((col, row)) # First pixel r value is length of message if row == 0 and col == 0: message_length = r elif index <= message_length: message += chr(r) index += 1 img.close() return message
def hide( input_image: Union[str, IO[bytes]], message: str, encoding: str = "UTF-8", shift: int = 0, auto_convert_rgb: bool = False, ): """Hide a message (string) in an image with the LSB (Least Significant Bit) technique. """ message_length = len(message) assert message_length != 0, "message length is zero" img = tools.open_image(input_image) if img.mode not in ["RGB", "RGBA"]: if not auto_convert_rgb: print("The mode of the image is not RGB. Mode is {}".format( img.mode)) answer = input("Convert the image to RGB ? [Y / n]\n") or "Y" if answer.lower() == "n": raise Exception("Not a RGB image.") img = img.convert("RGB") encoded = img.copy() width, height = img.size index = 0 message = str(message_length) + ":" + str(message) message_bits = "".join(tools.a2bits_list(message, encoding)) message_bits += "0" * ((3 - (len(message_bits) % 3)) % 3) npixels = width * height len_message_bits = len(message_bits) if len_message_bits > npixels * 3: raise Exception("The message you want to hide is too long: {}".format( message_length)) for row in range(height): for col in range(width): if shift != 0: shift -= 1 continue if index + 3 <= len_message_bits: # Get the colour component. pixel = img.getpixel((col, row)) r = pixel[0] g = pixel[1] b = pixel[2] # Change the Least Significant Bit of each colour component. r = tools.setlsb(r, message_bits[index]) g = tools.setlsb(g, message_bits[index + 1]) b = tools.setlsb(b, message_bits[index + 2]) # Save the new pixel if img.mode == "RGBA": encoded.putpixel((col, row), (r, g, b, pixel[3])) else: encoded.putpixel((col, row), (r, g, b)) index += 3 else: img.close() return encoded
def hide( input_image: Union[str, IO[bytes]], message: str, generator: Iterator[int], shift: int = 0, encoding: str = "UTF-8", auto_convert_rgb: bool = False, ): """Hide a message (string) in an image with the LSB (Least Significant Bit) technique. """ message_length = len(message) assert message_length != 0, "message length is zero" img = tools.open_image(input_image) if img.mode not in ["RGB", "RGBA"]: if not auto_convert_rgb: print("The mode of the image is not RGB. Mode is {}".format( img.mode)) answer = input("Convert the image to RGB ? [Y / n]\n") or "Y" if answer.lower() == "n": raise Exception("Not a RGB image.") img = img.convert("RGB") img_list = list(img.getdata()) width, height = img.size index = 0 message = str(message_length) + ":" + str(message) message_bits = "".join(tools.a2bits_list(message, encoding)) message_bits += "0" * ((3 - (len(message_bits) % 3)) % 3) npixels = width * height len_message_bits = len(message_bits) if len_message_bits > npixels * 3: raise Exception("The message you want to hide is too long: {}".format( message_length)) while shift != 0: next(generator) shift -= 1 while index + 3 <= len_message_bits: generated_number = next(generator) r, g, b, *a = img_list[generated_number] # Change the Least Significant Bit of each colour component. r = tools.setlsb(r, message_bits[index]) g = tools.setlsb(g, message_bits[index + 1]) b = tools.setlsb(b, message_bits[index + 2]) # Save the new pixel if img.mode == "RGBA": img_list[generated_number] = (r, g, b, *a) else: img_list[generated_number] = (r, g, b) index += 3 # create empty new image of appropriate format encoded = Image.new(img.mode, (img.size)) # insert saved data into the image encoded.putdata(img_list) return encoded