display_svg_spec.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* Copyright 2017 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. /* globals __non_webpack_require__ */
  16. import { buildGetDocumentParams } from "./test_utils.js";
  17. import { getDocument } from "../../src/display/api.js";
  18. import { isNodeJS } from "../../src/shared/is_node.js";
  19. import { SVGGraphics } from "../../src/display/svg.js";
  20. const XLINK_NS = "http://www.w3.org/1999/xlink";
  21. // withZlib(true, callback); = run test with require('zlib') if possible.
  22. // withZlib(false, callback); = run test without require('zlib').deflateSync.
  23. // The return value of callback is returned as-is.
  24. function withZlib(isZlibRequired, callback) {
  25. if (isZlibRequired) {
  26. // We could try to polyfill zlib in the browser, e.g. using pako.
  27. // For now, only support zlib functionality on Node.js
  28. if (!isNodeJS) {
  29. throw new Error("zlib test can only be run in Node.js");
  30. }
  31. return callback();
  32. }
  33. if (!isNodeJS) {
  34. // Assume that require('zlib') is unavailable in non-Node.
  35. return callback();
  36. }
  37. const zlib = __non_webpack_require__("zlib");
  38. const deflateSync = zlib.deflateSync;
  39. zlib.deflateSync = disabledDeflateSync;
  40. function disabledDeflateSync() {
  41. throw new Error("zlib.deflateSync is explicitly disabled for testing.");
  42. }
  43. function restoreDeflateSync() {
  44. if (zlib.deflateSync === disabledDeflateSync) {
  45. zlib.deflateSync = deflateSync;
  46. }
  47. }
  48. const promise = callback();
  49. promise.then(restoreDeflateSync, restoreDeflateSync);
  50. return promise;
  51. }
  52. describe("SVGGraphics", function () {
  53. let loadingTask;
  54. let page;
  55. beforeAll(async function () {
  56. loadingTask = getDocument(buildGetDocumentParams("xobject-image.pdf"));
  57. const doc = await loadingTask.promise;
  58. page = await doc.getPage(1);
  59. });
  60. afterAll(async function () {
  61. await loadingTask.destroy();
  62. });
  63. describe("paintImageXObject", function () {
  64. function getSVGImage() {
  65. let svgGfx;
  66. return page
  67. .getOperatorList()
  68. .then(function (opList) {
  69. const forceDataSchema = true;
  70. svgGfx = new SVGGraphics(page.commonObjs, page.objs, forceDataSchema);
  71. return svgGfx.loadDependencies(opList);
  72. })
  73. .then(function () {
  74. let svgImg;
  75. // A mock to steal the svg:image element from paintInlineImageXObject.
  76. const elementContainer = {
  77. append(...elements) {
  78. svgImg = elements.at(-1);
  79. },
  80. };
  81. // This points to the XObject image in xobject-image.pdf.
  82. const xobjectObjId = "img_p0_1";
  83. if (isNodeJS) {
  84. const { setStubs } = __non_webpack_require__(
  85. "../../examples/node/domstubs.js"
  86. );
  87. setStubs(global);
  88. }
  89. try {
  90. const imgData = svgGfx.objs.get(xobjectObjId);
  91. svgGfx.paintInlineImageXObject(imgData, elementContainer);
  92. } finally {
  93. if (isNodeJS) {
  94. const { unsetStubs } = __non_webpack_require__(
  95. "../../examples/node/domstubs.js"
  96. );
  97. unsetStubs(global);
  98. }
  99. }
  100. return svgImg;
  101. });
  102. }
  103. it('should fail require("zlib") unless in Node.js', function () {
  104. function testFunc() {
  105. __non_webpack_require__("zlib");
  106. }
  107. if (isNodeJS) {
  108. // Verifies that the script loader replaces __non_webpack_require__ with
  109. // require.
  110. expect(testFunc.toString()).toMatch(/\srequire\(["']zlib["']\)/);
  111. expect(testFunc).not.toThrow();
  112. } else {
  113. // require not defined, require('zlib') not a module, etc.
  114. expect(testFunc).toThrow();
  115. }
  116. });
  117. it("should produce a reasonably small svg:image", async function () {
  118. if (!isNodeJS) {
  119. pending("zlib.deflateSync is not supported in non-Node environments.");
  120. }
  121. const svgImg = await withZlib(true, getSVGImage);
  122. expect(svgImg.nodeName).toBe("svg:image");
  123. expect(svgImg.getAttributeNS(null, "width")).toBe("200px");
  124. expect(svgImg.getAttributeNS(null, "height")).toBe("100px");
  125. const imgUrl = svgImg.getAttributeNS(XLINK_NS, "href");
  126. // forceDataSchema = true, so the generated URL should be a data:-URL.
  127. expect(imgUrl).toMatch(/^data:image\/png;base64,/);
  128. // Test whether the generated image has a reasonable file size.
  129. // I obtained a data URL of size 366 with Node 8.1.3 and zlib 1.2.11.
  130. // Without zlib (uncompressed), the size of the data URL was excessive
  131. // (80246).
  132. expect(imgUrl.length).toBeLessThan(367);
  133. });
  134. it("should be able to produce a svg:image without zlib", async function () {
  135. const svgImg = await withZlib(false, getSVGImage);
  136. expect(svgImg.nodeName).toBe("svg:image");
  137. expect(svgImg.getAttributeNS(null, "width")).toBe("200px");
  138. expect(svgImg.getAttributeNS(null, "height")).toBe("100px");
  139. const imgUrl = svgImg.getAttributeNS(XLINK_NS, "href");
  140. expect(imgUrl).toMatch(/^data:image\/png;base64,/);
  141. // The size of our naively generated PNG file is excessive :(
  142. expect(imgUrl.length).toBe(80246);
  143. });
  144. });
  145. });