mixbytes.py

Preview

Download here: mixbytes.py

Back to the article: Corrupting PNGs for glitchart patterns

import sys
import os
import random
import subprocess
from PIL import Image

def compare_images(filename1, filename2):
    image1 = Image.open(filename1)
    image2 = Image.open(filename2)

    width, height = image1.size

    for x in range(width):
        for y in range(height):
            if image1.getpixel((x,y)) != image2.getpixel((x,y)):
                return False

    print('Images are the same')
    return True

def gimp_resave(filename):
    print(f'{" gimp start ":=^50}')
    result = subprocess.run([
        'gimp',
        '-i',
        '-b',
        f'(define (resave filename) (let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename filename))) (drawable (car (gimp-image-get-active-layer image)))) (gimp-file-save RUN-NONINTERACTIVE image drawable filename filename) (gimp-image-delete image))) (resave "{filename}")',
        '-b',
        '(gimp-quit 0)'
    ])
    print(result)  
    print(f'{" gimp end ":=^50}')
    print()


filename = sys.argv[1]

with open(filename, 'rb') as f:
    image_data = f.read()

folder = 'generated/'+filename[:filename.rfind('.')]
postfix = ''
id = 1
while os.path.exists(folder + postfix):
    postfix = f' ({id})'
    id += 1

folder = folder + postfix
os.mkdir(folder)

iteration = 1

while iteration <= 2 or not compare_images(f'{folder}/{iteration-2}.png', f'{folder}/{iteration-1}.png'):
    print(f'iteration {iteration}')

    byte_index = random.randint(0, len(image_data))
    new_value = random.randint(0, 256)

    print(f'    changing byte {byte_index}')
    print(f'    from {int(image_data[byte_index])} to {new_value}')

    image_data = image_data[:byte_index] + new_value.to_bytes(1, 'big') + image_data[byte_index+1:]

    print(f'    saving {iteration}.png')
    print()

    file_path = f'{folder}/{iteration}.png'
    with open(file_path, 'wb') as f:
        f.write(image_data)

    gimp_resave(file_path)

    with open(file_path, 'rb') as f:
        image_data = f.read()

    iteration += 1

    print()

print('Done!')