2019-08-28 00:39:08 +01:00
/**
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
2019-09-04 13:54:59 +01:00
import Operation from "../Operation.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
import Utils from "../Utils.mjs" ;
import { isImage } from "../lib/FileType.mjs" ;
import { toBase64 } from "../lib/Base64.mjs" ;
2023-02-27 17:55:52 +00:00
import jimp from "jimp" ;
2019-08-28 00:39:08 +01:00
/**
* View Bit Plane operation
*/
class ViewBitPlane extends Operation {
/**
* ViewBitPlane constructor
*/
constructor () {
super ();
this . name = "View Bit Plane" ;
this . module = "Image" ;
2019-09-04 13:54:59 +01:00
this . description = "Extracts and displays a bit plane of any given image. These show only a single bit from each pixel, and can be used to hide messages in Steganography." ;
2019-08-28 00:39:08 +01:00
this . infoURL = "https://wikipedia.org/wiki/Bit_plane" ;
2019-09-04 13:54:59 +01:00
this . inputType = "ArrayBuffer" ;
this . outputType = "ArrayBuffer" ;
2019-08-28 00:39:08 +01:00
this . presentType = "html" ;
this . args = [
{
name : "Colour" ,
type : "option" ,
value : COLOUR_OPTIONS
},
{
name : "Bit" ,
type : "number" ,
value : 0
}
];
}
/**
2019-09-04 13:54:59 +01:00
* @param {ArrayBuffer} input
2019-08-28 00:39:08 +01:00
* @param {Object[]} args
2019-09-04 13:54:59 +01:00
* @returns {ArrayBuffer}
2019-08-28 00:39:08 +01:00
*/
async run ( input , args ) {
if ( ! isImage ( input )) throw new OperationError ( "Please enter a valid image file." );
const [ colour , bit ] = args ,
2019-09-04 13:54:59 +01:00
parsedImage = await jimp . read ( input ),
2019-08-28 00:39:08 +01:00
width = parsedImage . bitmap . width ,
height = parsedImage . bitmap . height ,
colourIndex = COLOUR_OPTIONS . indexOf ( colour ),
bitIndex = 7 - bit ;
if ( bit < 0 || bit > 7 ) {
throw new OperationError ( "Error: Bit argument must be between 0 and 7" );
}
let pixel , bin , newPixelValue ;
parsedImage . scan ( 0 , 0 , width , height , function ( x , y , idx ) {
pixel = this . bitmap . data [ idx + colourIndex ];
bin = Utils . bin ( pixel );
newPixelValue = 255 ;
if ( bin . charAt ( bitIndex ) === "1" ) newPixelValue = 0 ;
2019-08-28 17:03:55 +01:00
for ( let i = 0 ; i < 3 ; i ++ ) {
2019-08-28 00:39:08 +01:00
this . bitmap . data [ idx + i ] = newPixelValue ;
}
2019-08-28 17:03:55 +01:00
this . bitmap . data [ idx + 3 ] = 255 ;
2019-08-28 00:39:08 +01:00
});
const imageBuffer = await parsedImage . getBufferAsync ( jimp . AUTO );
2019-09-04 13:54:59 +01:00
return new Uint8Array ( imageBuffer ). buffer ;
2019-08-28 00:39:08 +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-28 00:39:08 +01:00
* @returns {html}
*/
present ( data ) {
2022-11-02 08:29:26 +09:00
if ( ! data . byteLength ) return "" ;
2019-08-28 00:39:08 +01:00
const type = isImage ( data );
return `<img src="data: ${ type } ;base64, ${ toBase64 ( data ) } ">` ;
}
}
const COLOUR_OPTIONS = [
"Red" ,
"Green" ,
"Blue" ,
"Alpha"
];
export default ViewBitPlane ;