Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebWorker support round 3 #2382

Closed
jsoo1 opened this issue Apr 3, 2019 · 15 comments
Closed

WebWorker support round 3 #2382

jsoo1 opened this issue Apr 3, 2019 · 15 comments

Comments

@jsoo1
Copy link

jsoo1 commented Apr 3, 2019

Two issues have been filed for webworker support (#57, #996). I still would benefit from having better support for webworkers aside from forking and building my own version of jsPDF. Currently even importing the version of jsPDF that is available on npm causes a crash with Uncaught ReferenceError: window is not defined. I have created a minimal runnable example at https://github.com/jsoo1/minimal-webworker-crash to demonstrate the issue. I think part of the webworker support issue is that there are really three problems:

  1. Building and shipping a separate module for webworker support (like npm run build type=node)
  2. Running a limited version of jsPDF in a worker context.
  3. Supporting all plugins for webworkers
    according to Make it webworker compatible #57, the problematic plugins in webworkers are:
    • zlib
    • png_support and
    • acroform

Maybe some of 2 would be solved by 1. I can think of one way to help with png_support. The OffscreenCanvas object should allow the worker to use canvas without the document or window.

In any case, thank you for this library and your maintenance. Would you accept any PRs for any of these goals?

@Uzlopak
Copy link
Collaborator

Uzlopak commented Apr 4, 2019

I refactored alot since then. Most code is now window independent. I think that i should drop all the canvas fallback solutions for image processing. We have nearly all image formats supported (except tiff) so we should not regress to the old days.

Why not use the node build for the WebWorker Use Case? In the node build i dont bundle blob, FileSaver.

If you clone latest you can do npm run test-node

@Uzlopak
Copy link
Collaborator

Uzlopak commented Apr 4, 2019

And yes. We accept pull requests

@jsoo1
Copy link
Author

jsoo1 commented Apr 4, 2019

Thanks! I will try the node version out for my use case and report back.

@jsoo1
Copy link
Author

jsoo1 commented May 28, 2019

So I think with just a couple changes, jsPDF could run in a webworker.

  • The node build is a little broken right now due to the reference to window on this line: https://github.com/MrRio/jsPDF/blob/master/rollup.config.js#L37
  • If the user can provide an interface for canvas (creation, creating dataURLs), I think jsPDF can run in a webworker (or node, or in the regular DOM context) with PNG support (one of my requirements)

I started working on the user-provided interface for canvas. It seemed promising but it involved touching png.js. I don't know if that was ok.

@bwl21
Copy link
Contributor

bwl21 commented Aug 12, 2019

Did you make progress with running jspdf in a worker?

@jsoo1
Copy link
Author

jsoo1 commented Aug 12, 2019 via email

@bwl21
Copy link
Contributor

bwl21 commented Aug 25, 2019

I even would not need html2pdf. But I need image support. I would higly appreciate if jspdf worsk in webworker.

@bwl21
Copy link
Contributor

bwl21 commented Sep 2, 2019

I managed to compile a version suitable for worker with jspdf.worker.conf.js as below.

In the compiled file I have to remove two occurences of

window.tmp = ...

import './src/license.js';
import './src/jspdf.js';

//import './src/modules/acroform';
import './src/modules/addimage';
import './src/modules/annotations';
import './src/modules/arabic';
import './src/modules/autoprint';
import './src/modules/canvas';
import './src/modules/cell';
import './src/modules/context2d';
import './src/modules/filters';
import './src/modules/fileloading';
import './src/modules/html';
import './src/modules/javascript';
import './src/modules/outline';
import './src/modules/jpeg_support';
import './src/modules/png_support';
import './src/modules/gif_support';
import './src/modules/bmp_support';
import './src/modules/webp_support';
import './src/modules/setlanguage';
import './src/modules/split_text_to_size';
import './src/modules/standard_fonts_metrics';
//import './src/modules/ttfsupport';
import './src/modules/svg';
import './src/modules/total_pages';
import './src/modules/viewerpreferences';
import './src/modules/xmp_metadata';
import './src/modules/utf8';
//import './src/modules/vfs';

//import './src/node.js';

import './src/libs/adler32cs.js';
import './src/libs/bidiEngine.js';
import './src/libs/JPEGEncoder.js';
import './src/libs/BMPDecoder.js';
import './src/libs/WebPDecoder.js';
import './src/libs/Deflater.js';
import './src/libs/rgbcolor.js';
import './src/libs/ttffont.js';
import './src/libs/png.js';
import './src/libs/zlib.js';

bwl21 pushed a commit to bwl21/jsPDF_1.5 that referenced this issue Sep 2, 2019
@evanrelf
Copy link

evanrelf commented Oct 25, 2019

I'm trying to build PDFs from a Node CLI program (using node-canvas) by adding PNGs to each page of the PDF using addImage(), like:

pdf.addImage(dataUrl, 'PNG', 0, 0, width, height, '', 'NONE')

The problem is that the images come out distorted or a solid color. I tried other PNGs to test and they came out completely black, and then tried a JPEG and it came out completely white.

Here's where I've gotten so far:

Diff of code changes required to run

rollup.config.js

@@ -34,7 +34,7 @@ function rawjs(opts) {
       var variable = opts[id.split('/').pop()]
       if (!variable) return code

-      var keepStr = '/*rollup-keeper-start*/window.tmp=' + variable +
+      var keepStr = '/*rollup-keeper-start*/global.tmp=' + variable +
         ';/*rollup-keeper-end*/'
       return code + keepStr
     },

Allow passing in a custom canvas from node-canvas.

src/libs/png.js

@@ -25,7 +25,7 @@

 (function (global) {
   global.PNG = (function () {
-    var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
+    var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, makeCanvas, scratchCanvas, scratchCtx;

     APNG_DISPOSE_OP_NONE = 0;

@@ -37,7 +37,7 @@

     APNG_BLEND_OP_OVER = 1;

-    function PNG(data) {
+    function PNG(data, mkCanvas) {
       var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
       this.data = data;
       this.pos = 8;
@@ -46,6 +46,7 @@
       this.transparency = {};
       this.animation = null;
       this.text = {};
+      makeCanvas = mkCanvas || function () { return global.document.createElement('canvas'); };
       frame = null;
       while (true) {
         chunkSize = this.readUInt32();
@@ -388,23 +389,19 @@
       return ret;
     };

-    var hasBrowserCanvas = function () {
-      if (Object.prototype.toString.call(global) === "[object Window]") {
-        try {
-          scratchCanvas = global.document.createElement('canvas');
-          scratchCtx = scratchCanvas.getContext('2d');
-        } catch (e) {
-          return false;
-        }
-        return true;
+    var hasBrowserCanvas = function (makeCanvas) {
+      try {
+        scratchCanvas = makeCanvas();
+        scratchCtx = scratchCanvas.getContext('2d');
+      } catch (e) {
+        return false;
       }
-      return false;
     }

-    hasBrowserCanvas();
+    hasBrowserCanvas(makeCanvas);

     makeImage = function (imageData) {
-      if (hasBrowserCanvas() === true) {
+      if (hasBrowserCanvas(makeCanvas) === true) {
         var img;
         scratchCtx.width = imageData.width;
         scratchCtx.height = imageData.height;

src/modules/png_support.js

@@ -318,7 +318,7 @@
         throw new Error("PNG support requires png.js and zlib.js");
       }

-      image = new PNG(imageData);
+      image = new PNG(imageData, this.makeCanvas);
       imageData = image.imgData;
       bitsPerComponent = image.bits;
       colorSpace = image.colorSpace;
Generated PDF
Expected Actual (PDF)

@jsoo1
Copy link
Author

jsoo1 commented Oct 25, 2019

@evanrelf and I have been working on this together. I'd be really curious what is going on here. It looks like the page width is correct but the image size is really distorted. We've looked through addImage a little but we can really use some help figuring out what's going on here.

bwl21 added a commit to bwl21/jsPDF_1.5 that referenced this issue Feb 7, 2020
Uzlopak added a commit that referenced this issue Feb 10, 2020
see #2382 add a build type for use in a webworker
@bsparacino
Copy link

@jsoo1 @evanrelf Have either of you figured out a solution for PNGs?
I am running with just node and PNGs are also a requirement for me.

Is the node-canvas method working?

@bsparacino
Copy link

I am not using a worker, just nodejs.
The base code inside jsPDF does not seam to work with node, only canvas, so try using this file instead.

https://gist.github.com/bsparacino/435edfbe360580a5a52f82bf1264f000

Just add it to your project and require it
global.PNG = require('../../modules/png-node');

@evanrelf
Copy link

evanrelf commented Apr 8, 2020

@bsparacino I'm no longer working on the project, but we gave up on jsPDF and switched to PDFKit. It worked much better for our needs.

@github-actions
Copy link

This issue is stale because it has been open 90 days with no activity. It will be closed soon. Please comment/reopen if this issue is still relevant.

@HackbrettXXX
Copy link
Collaborator

With #2804 jsPDF runs in a webworker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants