ViewBitPlane.mjs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /**
  2. * @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
  3. * @copyright Crown Copyright 2019
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation.mjs";
  7. import OperationError from "../errors/OperationError.mjs";
  8. import Utils from "../Utils.mjs";
  9. import { isImage } from "../lib/FileType.mjs";
  10. import { toBase64 } from "../lib/Base64.mjs";
  11. import jimp from "jimp";
  12. /**
  13. * View Bit Plane operation
  14. */
  15. class ViewBitPlane extends Operation {
  16. /**
  17. * ViewBitPlane constructor
  18. */
  19. constructor() {
  20. super();
  21. this.name = "View Bit Plane";
  22. this.module = "Image";
  23. 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.";
  24. this.infoURL = "https://wikipedia.org/wiki/Bit_plane";
  25. this.inputType = "ArrayBuffer";
  26. this.outputType = "ArrayBuffer";
  27. this.presentType = "html";
  28. this.args = [
  29. {
  30. name: "Colour",
  31. type: "option",
  32. value: COLOUR_OPTIONS
  33. },
  34. {
  35. name: "Bit",
  36. type: "number",
  37. value: 0
  38. }
  39. ];
  40. }
  41. /**
  42. * @param {ArrayBuffer} input
  43. * @param {Object[]} args
  44. * @returns {ArrayBuffer}
  45. */
  46. async run(input, args) {
  47. if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
  48. const [colour, bit] = args,
  49. parsedImage = await jimp.read(input),
  50. width = parsedImage.bitmap.width,
  51. height = parsedImage.bitmap.height,
  52. colourIndex = COLOUR_OPTIONS.indexOf(colour),
  53. bitIndex = 7-bit;
  54. if (bit < 0 || bit > 7) {
  55. throw new OperationError("Error: Bit argument must be between 0 and 7");
  56. }
  57. let pixel, bin, newPixelValue;
  58. parsedImage.scan(0, 0, width, height, function(x, y, idx) {
  59. pixel = this.bitmap.data[idx + colourIndex];
  60. bin = Utils.bin(pixel);
  61. newPixelValue = 255;
  62. if (bin.charAt(bitIndex) === "1") newPixelValue = 0;
  63. for (let i=0; i < 3; i++) {
  64. this.bitmap.data[idx + i] = newPixelValue;
  65. }
  66. this.bitmap.data[idx + 3] = 255;
  67. });
  68. const imageBuffer = await parsedImage.getBufferAsync(jimp.AUTO);
  69. return new Uint8Array(imageBuffer).buffer;
  70. }
  71. /**
  72. * Displays the extracted data as an image for web apps.
  73. * @param {ArrayBuffer} data
  74. * @returns {html}
  75. */
  76. present(data) {
  77. if (!data.length) return "";
  78. const type = isImage(data);
  79. return `<img src="data:${type};base64,${toBase64(data)}">`;
  80. }
  81. }
  82. const COLOUR_OPTIONS = [
  83. "Red",
  84. "Green",
  85. "Blue",
  86. "Alpha"
  87. ];
  88. export default ViewBitPlane;