You need an specification of how your data will be represented when used as an image.
That is far more important than an existing piece of code that does the encoding.
On the case of the Piet Language, it is exactly what happens - this is the "language specification". From it people did build itnerpreters and tools (in a variety of other languages, including a Python interpreter).
But if you want to encode arbitrary data to an image, and then decode it back you first have to say how you want to encode it. The most straightforward way is one in which each byte of data is a color channel for one pixel, and a way to determine the exact length of the encoded data, and padding the bottom most image rows.
This would be straightforward to do with Python Imaging Library (Pillow)'s Image.frombytes
method - though it would hardly result in a pleasing image.
One could also build a Python program to compile a Piet program that just "spills out" the input data back, given arbitrary data - and then, the piet interpreter above could decode the data.
The example bellow will pack a .wav sound file (I just did this at the Python console) as a colorfull image, pre-pending 4 bytes for the data length, and padding the bottom pixels with black.
import struct
from PIL import Image
data = open("2600PacManDies.wav", "rb").read()
size = struct.pack("<I", len(data))
image_side = int(((len(data) + len(size)) / 3.0) ** 0.5) + 1
img = Image.frombytes("RGB", (image_side, image_side) , size + data + b"\x00" * (image_side ** 2 * 3 - (len(size) + len(data)) ) )
img.save("2600_pacman_dies.png")

(Although as I've used a raw sound data file, one can even discover some patterns in the data looking at the image - the black stripes meaning the silent moments being the most obvious)