2019-08-29 16:17:07 +01:00
/**
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
2019-09-04 13:54:59 +01:00
import Utils from "../Utils.mjs" ;
import { isImage } from "../lib/FileType.mjs" ;
2019-08-29 16:17:07 +01:00
import { runHash } from "../lib/Hash.mjs" ;
2019-09-04 13:54:59 +01:00
import { toBase64 } from "../lib/Base64.mjs" ;
2026-02-18 11:34:31 +00:00
import { Jimp } from "jimp" ;
2019-08-29 16:17:07 +01:00
/**
* Randomize Colour Palette operation
*/
class RandomizeColourPalette extends Operation {
/**
* RandomizeColourPalette constructor
*/
constructor () {
super ();
this . name = "Randomize Colour Palette" ;
this . module = "Image" ;
2026-02-18 11:34:31 +00:00
this . description =
"Randomizes each colour in an image's colour palette. This can often reveal text or symbols that were previously a very similar colour to their surroundings, a technique sometimes used in Steganography." ;
2019-09-04 13:54:59 +01:00
this . infoURL = "https://wikipedia.org/wiki/Indexed_color" ;
this . inputType = "ArrayBuffer" ;
this . outputType = "ArrayBuffer" ;
2019-08-29 16:17:07 +01:00
this . presentType = "html" ;
this . args = [
{
name : "Seed" ,
type : "string" ,
2026-02-18 11:34:31 +00:00
value : "" ,
},
2019-08-29 16:17:07 +01:00
];
}
/**
2019-09-04 13:54:59 +01:00
* @param {ArrayBuffer} input
2019-08-29 16:17:07 +01:00
* @param {Object[]} args
2019-09-04 13:54:59 +01:00
* @returns {ArrayBuffer}
2019-08-29 16:17:07 +01:00
*/
async run ( input , args ) {
2026-02-18 11:34:31 +00:00
if ( ! isImage ( input ))
throw new OperationError ( "Please enter a valid image file." );
2019-08-29 16:17:07 +01:00
2026-02-18 11:34:31 +00:00
const seed = args [ 0 ] || Math . random (). toString (). substr ( 2 ),
2024-06-11 18:07:22 +01:00
parsedImage = await Jimp . read ( input ),
2019-08-29 16:17:07 +01:00
width = parsedImage . bitmap . width ,
height = parsedImage . bitmap . height ;
let rgbString , rgbHash , rgbHex ;
2026-02-18 11:34:31 +00:00
parsedImage . scan ( 0 , 0 , width , height , function ( x , y , idx ) {
rgbString = this . bitmap . data . slice ( idx , idx + 3 ). join ( "." );
2019-08-29 16:17:07 +01:00
rgbHash = runHash ( "md5" , Utils . strToArrayBuffer ( seed + rgbString ));
rgbHex = rgbHash . substr ( 0 , 6 ) + "ff" ;
parsedImage . setPixelColor ( parseInt ( rgbHex , 16 ), x , y );
});
2026-02-18 11:34:31 +00:00
const imageBuffer = await parsedImage . getBuffer ( parsedImage . mime );
2019-08-29 16:17:07 +01:00
2019-09-04 13:54:59 +01:00
return new Uint8Array ( imageBuffer ). buffer ;
2019-08-29 16:17:07 +01:00
}
/**
* Displays the extracted data as an image for web apps.
2019-09-04 13:54:59 +01:00
* @param {ArrayBuffer} data
2019-08-29 16:17:07 +01:00
* @returns {html}
*/
present ( data ) {
2019-09-04 13:54:59 +01:00
if ( ! data . byteLength ) return "" ;
2019-08-29 16:17:07 +01:00
const type = isImage ( data );
return `<img src="data: ${ type } ;base64, ${ toBase64 ( data ) } ">` ;
}
}
export default RandomizeColourPalette ;