[file2png] Convert (encrypted) binary data to .png images and back

Onion Courier <[email protected]>
Newsgroups alt.cypherpunks,alt.privacy
Organization dizum.com - The Internet Problem Provider
Message-ID <[email protected]>
Hi all,

here is a Python3 implementation of my file2png program,
available here: https://github.com/706f6c6c7578/file2png

Hope you find it useful, when for example uploading such
images to platforms like X, which does not compress .png
images, as I have tested!

import argparse
import math
import os
import struct
from PIL import Image
import sys

def encode_file(input_stream, output_stream):
    data = input_stream.read()
    file_size = len(data)
    pixel_count = (file_size + 8) // 3
    dimension = math.ceil(math.sqrt(pixel_count))

    img = Image.new('RGBA', (dimension, dimension), (0, 0, 0, 255))
    pixels = img.load()

    size_buf = struct.pack('<Q', file_size)
    x, y = 0, 0

    for i in range(0, 8, 3):
        r = size_buf[i]
        g = size_buf[i+1] if i+1 < 8 else 0
        b = size_buf[i+2] if i+2 < 8 else 0
        pixels[x, y] = (r, g, b, 255)
        x += 1
        if x >= dimension:
            x = 0
            y += 1

    for i in range(0, len(data), 3):
        r = data[i]
        g = data[i+1] if i+1 < len(data) else 0
        b = data[i+2] if i+2 < len(data) else 0
        pixels[x, y] = (r, g, b, 255)
        x += 1
        if x >= dimension:
            x = 0
            y += 1

    img.save(output_stream, format='PNG')

def decode_file(input_stream, output_stream):
    img = Image.open(input_stream)
    pixels = img.load()
    width, height = img.size

    size_buf = bytearray(8)
    pixel_index = 0
    for i in range(0, 8, 3):
        x = pixel_index % width
        y = pixel_index // width
        r, g, b, _ = pixels[x, y]
        size_buf[i] = r
        if i+1 < 8:
            size_buf[i+1] = g
        if i+2 < 8:
            size_buf[i+2] = b
        pixel_index += 1

    file_size = struct.unpack('<Q', size_buf)[0]
    data = bytearray(file_size)

    data_index = 0
    start_pixel = (8 + 2) // 3
    for y in range(start_pixel // width, height):
        start_x = 0 if y != start_pixel // width else start_pixel % width
        for x in range(start_x, width):
            if data_index >= file_size:
                break
            r, g, b, _ = pixels[x, y]
            data[data_index] = r
            if data_index + 1 < file_size:
                data[data_index+1] = g
            if data_index + 2 < file_size:
                data[data_index+2] = b
            data_index += 3

    output_stream.write(data[:file_size])

def main():
    parser = argparse.ArgumentParser(description="file2png - Convert any file to PNG and back")
    parser.add_argument("-d", action="store_true", help="decode PNG to file")
    parser.add_argument("input", nargs="?", default="-", help="Input file (default: stdin)")
    parser.add_argument("output", nargs="?", default="-", help="Output file (default: stdout)")

    args = parser.parse_args()

    input_stream = sys.stdin.buffer if args.input == "-" else open(args.input, "rb")
    output_stream = sys.stdout.buffer if args.output == "-" else open(args.output, "wb")

    try:
        if args.d:
            decode_file(input_stream, output_stream)
        else:
            encode_file(input_stream, output_stream)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)
    finally:
        if input_stream is not sys.stdin.buffer:
            input_stream.close()
        if output_stream is not sys.stdout.buffer:
            output_stream.close()

if __name__ == "__main__":
    main()

-- 
Regards
Stefan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.