Last active
July 28, 2024 05:06
-
-
Save FrostBird347/66c77eb97ecf7fa799e25f318308af5e to your computer and use it in GitHub Desktop.
An extremely simple and poorly written script that glitches images.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/node | |
//qoi180.js | |
//A terribly made script that: | |
// - encodes an input image into a "reversed" (horizontal+vertical flip) qoi | |
// - reverses the order of every chunk within the qoi file | |
// - saves the messed up file | |
//Note that it requires qoijs, imagemagick and arg | |
//It also has the same issues as copyimgdiff.js: It has not been tested on other systems, assigns a massive amount of ram, can't open images close to or above 1GB in size and doesn't support images with an alpha channel. | |
const qoi = require('qoijs'); | |
const fs = require('fs'); | |
const execFileSync = require('child_process').execFileSync; | |
const arg = require('arg'); | |
const versionString = "1.3.0"; | |
const args = arg({ | |
// Types | |
'--help': Boolean, | |
'--invert': Boolean, | |
'--alpha': Boolean, | |
'--vertical': Boolean, | |
'--colourspace': String, | |
'--start-with-cache': Boolean, | |
// Aliases | |
'-h': '--help', | |
'-i': '--invert', | |
'--flip': '--invert', | |
'-f': '--invert', | |
'--reverse': '--invert', | |
'-r': '--invert', | |
'-a': '--alpha', | |
'-v': '--vertical', | |
'-c': '--colourspace', | |
'-s': '--start-with-cache', | |
// Parity | |
'--parityNull': Boolean, | |
'-t': "--invert", | |
'-l': "--parityNull", | |
}, {permissive: true}); | |
//Display help page else verify that args are correct | |
if (args['--help'] || JSON.stringify(args) == '{"_":[]}') { | |
console.log(`qoi180.js (version ${versionString}) | |
Usage: | |
qoi180.js input_image output_image [-hia] | |
-h, --help Display this help page | |
-i, --invert Reverse the pixels at the end instead of the start | |
-f, --flip Alias for --invert | |
-r, --reverse Alias for --invert | |
-t Alias for --invert, for parity with previous versions | |
-l Does nothing, for parity with previous versions | |
-a, --alpha Keep the alpha channel if it exists | |
-v, --vertical Rotate the image by 90° while corrupting | |
-c, --colourspace Use a different colourspace (run "magick -list colorspace" to get a list of valid colourspaces) | |
-s, --start-with-cache Append flipped data to the bottom of the image and then crop, thus starting with the full cache`); | |
process.exit(0); | |
} else if (args['_'].length != 2 || args['_'][0].startsWith("-") || args['_'][1].startsWith("-")) { | |
console.error("Invalid arguments: Either too many/little files were specified or an unknown option was used!"); | |
console.log("Usage:\n qoi180.js input_image output_image [-hia]"); | |
process.exit(1); | |
} | |
//Gen args for loading the input image | |
let inputArgs = [args['_'][0], "-background", "transparent", "-layers", "flatten"]; | |
if (!args['--invert']) { | |
inputArgs.push("-flip", "-flop"); | |
} | |
if (args['--vertical']) { | |
inputArgs.push("-rotate", "90"); | |
} | |
if (!args['--alpha']) { | |
inputArgs.push("-alpha", "off"); | |
} | |
if (args['--colourspace'] != undefined) { | |
inputArgs.push("-colorspace", args['--colourspace'], "-set", "colorspace", "sRGB"); | |
} | |
inputArgs.push("QOI:-"); | |
//Load the image | |
let input; | |
try { | |
input = execFileSync("/usr/local/bin/convert", inputArgs, {maxBuffer: 10000000000}); | |
} catch(err) { | |
console.error("Failed to load the image!"); | |
process.exit(1); | |
} | |
outputSize = input.length; | |
if (args['--start-with-cache']) { | |
outputSize = (outputSize * 2) - 14 - 8; | |
} | |
//Use allocUnsafe because we are just reordering data in the input and thus the filesize should not change | |
let output = Buffer.allocUnsafe(outputSize); | |
let actions = []; | |
let jumpAmount = 1; | |
//Add an action to the actions list, using the current jump amount and the inputted index | |
function addAction(iB) { | |
let newAction = []; | |
for (let i = 0; i < jumpAmount; i++) { | |
newAction.push(input[iB + i]); | |
} | |
actions.push(newAction); | |
} | |
//Copy the header over to the output file | |
let iOut = 14; | |
input.copy(output, 0, 0, iOut); | |
if (args['--start-with-cache']) { | |
input.copy(output, 0, 0, input.length); | |
iOut += input.length - 8 - 14; | |
//Double the height | |
output.writeUint32BE(output.readUint32BE(8) * 2, 8); | |
} | |
//Then extract each action | |
for (let i = 14; i < input.length; i+= jumpAmount) { | |
if (input[i] == 0 && input[i+1] == 0 && input[i+2] == 0 && input[i+3] == 0 && input[i+4] == 0 && input[i+5] == 0 && input[i+6] == 0 && input[i+7] == 1) { | |
jumpAmount = 8; | |
addAction(i); | |
} else if (input[i] == 254) { | |
jumpAmount = 4; | |
addAction(i); | |
} else if (input[i] == 255) { | |
jumpAmount = 5; | |
addAction(i); | |
} else if ((input[i] & 0b11000000) === 0b00000000) { | |
jumpAmount = 1; | |
addAction(i); | |
} else if ((input[i] & 0b11000000) === 0b01000000) { | |
jumpAmount = 1; | |
addAction(i); | |
} else if ((input[i] & 0b11000000) === 0b10000000) { | |
jumpAmount = 2; | |
addAction(i); | |
} else if ((input[i] & 0b11000000) === 0b11000000) { | |
jumpAmount = 1; | |
addAction(i); | |
} else { | |
jumpAmount = 1; | |
actions.push(input[i]); | |
console.error("Unknown chunk!"); | |
} | |
} | |
//Append all the actions in the reverse order, skipping the last one | |
for (let i = actions.length - 2; i >= 0; i--) { | |
Buffer.from(actions[i]).copy(output, iOut, 0); | |
iOut += actions[i].length; | |
} | |
//Append the last action to the end of the file instead of the start: this is the end marker | |
Buffer.from(actions[actions.length - 1]).copy(output, iOut, 0); | |
//Gen args for saving the output image | |
let outputArgs = ["QOI:-"] | |
if (args['--start-with-cache']) { | |
outputArgs.push("-crop", input.readUint32BE(4) + "x" + input.readUint32BE(8) + "+0+" + input.readUint32BE(8) + "!"); | |
} | |
if (args['--invert']) { | |
outputArgs.push("-flip", "-flop"); | |
} | |
if (args['--vertical']) { | |
outputArgs.push("-rotate", "270"); | |
} | |
if (args['--colourspace'] != undefined) { | |
outputArgs.push("-set", "colorspace", args['--colourspace'], "-colorspace", 'sRGB'); | |
} | |
outputArgs.push(args['_'][1]); | |
//Save image | |
try { | |
execFileSync("/usr/local/bin/convert", outputArgs, {input: output}); | |
} catch(err) { | |
console.error("Failed to save the image!"); | |
process.exit(1); | |
} |
Author
FrostBird347
commented
Jul 28, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment