ResizeImage.mjs 3.7 KB

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