ResizeImage.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * @author j433866 [j433866@gmail.com]
  3. * @copyright Crown Copyright 2019
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. import OperationError from "../errors/OperationError";
  8. import { isImage } from "../lib/FileType";
  9. import { toBase64 } from "../lib/Base64.mjs";
  10. import jimp from "jimp";
  11. /**
  12. * Resize Image operation
  13. */
  14. class ResizeImage extends Operation {
  15. /**
  16. * ResizeImage constructor
  17. */
  18. constructor() {
  19. super();
  20. this.name = "Resize Image";
  21. this.module = "Image";
  22. this.description = "Resizes an image to the specified width and height values.";
  23. this.infoURL = "https://wikipedia.org/wiki/Image_scaling";
  24. this.inputType = "ArrayBuffer";
  25. this.outputType = "ArrayBuffer";
  26. this.presentType = "html";
  27. this.args = [
  28. {
  29. name: "Width",
  30. type: "number",
  31. value: 100,
  32. min: 1
  33. },
  34. {
  35. name: "Height",
  36. type: "number",
  37. value: 100,
  38. min: 1
  39. },
  40. {
  41. name: "Unit type",
  42. type: "option",
  43. value: ["Pixels", "Percent"]
  44. },
  45. {
  46. name: "Maintain aspect ratio",
  47. type: "boolean",
  48. value: false
  49. },
  50. {
  51. name: "Resizing algorithm",
  52. type: "option",
  53. value: [
  54. "Nearest Neighbour",
  55. "Bilinear",
  56. "Bicubic",
  57. "Hermite",
  58. "Bezier"
  59. ],
  60. defaultIndex: 1
  61. }
  62. ];
  63. }
  64. /**
  65. * @param {ArrayBuffer} input
  66. * @param {Object[]} args
  67. * @returns {byteArray}
  68. */
  69. async run(input, args) {
  70. let width = args[0],
  71. height = args[1];
  72. const unit = args[2],
  73. aspect = args[3],
  74. resizeAlg = args[4];
  75. const resizeMap = {
  76. "Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
  77. "Bilinear": jimp.RESIZE_BILINEAR,
  78. "Bicubic": jimp.RESIZE_BICUBIC,
  79. "Hermite": jimp.RESIZE_HERMITE,
  80. "Bezier": jimp.RESIZE_BEZIER
  81. };
  82. if (!isImage(new Uint8Array(input))) {
  83. throw new OperationError("Invalid file type.");
  84. }
  85. let image;
  86. try {
  87. image = await jimp.read(input);
  88. } catch (err) {
  89. throw new OperationError(`Error loading image. (${err})`);
  90. }
  91. try {
  92. if (unit === "Percent") {
  93. width = image.getWidth() * (width / 100);
  94. height = image.getHeight() * (height / 100);
  95. }
  96. if (ENVIRONMENT_IS_WORKER())
  97. self.sendStatusMessage("Resizing image...");
  98. if (aspect) {
  99. image.scaleToFit(width, height, resizeMap[resizeAlg]);
  100. } else {
  101. image.resize(width, height, resizeMap[resizeAlg]);
  102. }
  103. let imageBuffer;
  104. if (image.getMIME() === "image/gif") {
  105. imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
  106. } else {
  107. imageBuffer = await image.getBufferAsync(jimp.AUTO);
  108. }
  109. return imageBuffer.buffer;
  110. } catch (err) {
  111. throw new OperationError(`Error resizing image. (${err})`);
  112. }
  113. }
  114. /**
  115. * Displays the resized image using HTML for web apps
  116. * @param {ArrayBuffer} data
  117. * @returns {html}
  118. */
  119. present(data) {
  120. if (!data.byteLength) return "";
  121. const dataArray = new Uint8Array(data);
  122. const type = isImage(dataArray);
  123. if (!type) {
  124. throw new OperationError("Invalid file type.");
  125. }
  126. return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
  127. }
  128. }
  129. export default ResizeImage;