def _lsb_pixel_decode(image): r, g, b, *_ = image.split() r = ImageMath.eval("convert(c&0x1, 'L')", c=r) g = ImageMath.eval("convert(c&0x1, 'L')", c=g) b = ImageMath.eval("convert(c&0x1, 'L')", c=b) data = roundrobin(iter_pixels(r), iter_pixels(g), iter_pixels(b)) return bytes([reduce(lambda byte, bit: byte << 1 | bit, eight_bits) for eight_bits in grouper(data, 8, fillvalue=0)])
def _lsb_pixel_encode(image, output, message, nbits=1): assert fits_in_image(image, message, nbits) # TODO: can this be accomplished with Image.tobytes/frombytes/BytesIO or ImageChops with a dummy message Image # Encode nbits of the message into each of the three color-components (RGB) # for each pixel until we're at the end of the message. # The bit mask needs to capture the least nbits significant bits. pixels = image.load() bit_mask = (1 << nbits) - 1 msg_iterator = grouper(iter_bits(message, chunksize=nbits), 3) for xy, msg_part in zip(iter_coords(image), msg_iterator): rgb = tuple((component & ~bit_mask | chunk) if chunk is not None else component for component, chunk in zip(pixels[xy], msg_part)) pixels[xy] = rgb image.save(output) return image
def _lsb_dct_coefficient_decode(image): quantization_iter = chain(*image.quantization.values()) data = map(lambda x: x & 1, quantization_iter) return bytes([reduce(lambda byte, bit: byte << 1 | bit, eight_bits) for eight_bits in grouper(data, 8, fillvalue=0)])