ContainImage.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. * Contain Image operation
  13. */
  14. class ContainImage extends Operation {
  15. /**
  16. * ContainImage constructor
  17. */
  18. constructor() {
  19. super();
  20. this.name = "Contain Image";
  21. this.module = "Image";
  22. this.description = "Scales an image to the specified width and height, maintaining the aspect ratio. The image may be letterboxed.";
  23. this.infoURL = "";
  24. this.inputType = "byteArray";
  25. this.outputType = "byteArray";
  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: "Horizontal align",
  42. type: "option",
  43. value: [
  44. "Left",
  45. "Center",
  46. "Right"
  47. ],
  48. defaultIndex: 1
  49. },
  50. {
  51. name: "Vertical align",
  52. type: "option",
  53. value: [
  54. "Top",
  55. "Middle",
  56. "Bottom"
  57. ],
  58. defaultIndex: 1
  59. },
  60. {
  61. name: "Resizing algorithm",
  62. type: "option",
  63. value: [
  64. "Nearest Neighbour",
  65. "Bilinear",
  66. "Bicubic",
  67. "Hermite",
  68. "Bezier"
  69. ],
  70. defaultIndex: 1
  71. }
  72. ];
  73. }
  74. /**
  75. * @param {byteArray} input
  76. * @param {Object[]} args
  77. * @returns {byteArray}
  78. */
  79. async run(input, args) {
  80. const [width, height, hAlign, vAlign, alg] = args;
  81. const resizeMap = {
  82. "Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
  83. "Bilinear": jimp.RESIZE_BILINEAR,
  84. "Bicubic": jimp.RESIZE_BICUBIC,
  85. "Hermite": jimp.RESIZE_HERMITE,
  86. "Bezier": jimp.RESIZE_BEZIER
  87. };
  88. const alignMap = {
  89. "Left": jimp.HORIZONTAL_ALIGN_LEFT,
  90. "Center": jimp.HORIZONTAL_ALIGN_CENTER,
  91. "Right": jimp.HORIZONTAL_ALIGN_RIGHT,
  92. "Top": jimp.VERTICAL_ALIGN_TOP,
  93. "Middle": jimp.VERTICAL_ALIGN_MIDDLE,
  94. "Bottom": jimp.VERTICAL_ALIGN_BOTTOM
  95. };
  96. if (!isImage(input)) {
  97. throw new OperationError("Invalid file type.");
  98. }
  99. let image;
  100. try {
  101. image = await jimp.read(Buffer.from(input));
  102. } catch (err) {
  103. throw new OperationError(`Error loading image. (${err})`);
  104. }
  105. try {
  106. if (ENVIRONMENT_IS_WORKER())
  107. self.sendStatusMessage("Containing image...");
  108. image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
  109. const imageBuffer = await image.getBufferAsync(jimp.AUTO);
  110. return [...imageBuffer];
  111. } catch (err) {
  112. throw new OperationError(`Error containing image. (${err})`);
  113. }
  114. }
  115. /**
  116. * Displays the contained image using HTML for web apps
  117. * @param {byteArray} data
  118. * @returns {html}
  119. */
  120. present(data) {
  121. if (!data.length) return "";
  122. const type = isImage(data);
  123. if (!type) {
  124. throw new OperationError("Invalid file type.");
  125. }
  126. return `<img src="data:${type};base64,${toBase64(data)}">`;
  127. }
  128. }
  129. export default ContainImage;