From 9f3ed397d4963d0ba068ae5ef2d5351797fc2d03 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Sat, 28 Dec 2024 00:17:16 -0800 Subject: [PATCH] main: parallelize image processing This reduces the procsesing time of the 1to10.note from about 7 seconds to 1.5s. It should be significant for anyone with note files with many pages. --- esbuild.config.mjs | 7 +- package-lock.json | 190 ++++++++++++++++++++++++++++++++--------- package.json | 1 + main.ts => src/main.ts | 139 ++++++++++++++++++++++++++++-- src/myworker.worker.ts | 45 ++++++++++ src/worker.d.ts | 4 + tsconfig.json | 15 ++-- 7 files changed, 346 insertions(+), 55 deletions(-) rename main.ts => src/main.ts (75%) create mode 100644 src/myworker.worker.ts create mode 100644 src/worker.d.ts diff --git a/esbuild.config.mjs b/esbuild.config.mjs index ad06f8f..634cc9b 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -1,6 +1,7 @@ import esbuild from "esbuild"; import process from "process"; import builtins from "builtin-modules"; +import inlineWorkerPlugin from "esbuild-plugin-inline-worker"; const banner = `/* @@ -15,8 +16,12 @@ const context = await esbuild.context({ banner: { js: banner, }, - entryPoints: ["main.ts"], + entryPoints: ["src/main.ts"], + alias: { + 'supernote-typescript': 'supernote-typescript' + }, bundle: true, + plugins: [inlineWorkerPlugin()], external: [ "obsidian", "electron", diff --git a/package-lock.json b/package-lock.json index 48020fc..f4514a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "2.3.0", "license": "MIT", "dependencies": { + "esbuild-plugin-inline-worker": "^0.1.1", "image-js": "^0.35.5", "supernote": "github:philips/supernote-typescript" }, @@ -189,7 +190,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -205,7 +205,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -221,7 +220,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "android" @@ -237,7 +235,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -253,7 +250,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -269,7 +265,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -285,7 +280,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -301,7 +295,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -317,7 +310,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -333,7 +325,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "linux" @@ -349,7 +340,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -365,7 +355,6 @@ "cpu": [ "mips64el" ], - "dev": true, "optional": true, "os": [ "linux" @@ -381,7 +370,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -397,7 +385,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -413,7 +400,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -429,7 +415,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -445,7 +430,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -461,7 +445,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -477,7 +460,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "sunos" @@ -493,7 +475,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -509,7 +490,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -525,7 +505,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1567,12 +1546,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1673,6 +1653,12 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1681,10 +1667,11 @@ "peer": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "path-key": "^3.1.0", @@ -1765,7 +1752,6 @@ "version": "0.17.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz", "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==", - "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -1798,6 +1784,16 @@ "@esbuild/win32-x64": "0.17.3" } }, + "node_modules/esbuild-plugin-inline-worker": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-inline-worker/-/esbuild-plugin-inline-worker-0.1.1.tgz", + "integrity": "sha512-VmFqsQKxUlbM51C1y5bRiMeyc1x2yTdMXhKB6S//++g9aCBg8TfGsbKxl5ZDkCGquqLY+RmEk93TBNd0i35dPA==", + "license": "MIT", + "dependencies": { + "esbuild": "latest", + "find-cache-dir": "^3.3.1" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2173,10 +2169,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2184,6 +2181,23 @@ "node": ">=8" } }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2510,6 +2524,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2731,6 +2746,30 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/median-quickselect": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/median-quickselect/-/median-quickselect-1.0.1.tgz", @@ -2746,12 +2785,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3080,6 +3120,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", @@ -3102,8 +3151,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -3155,6 +3202,70 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3531,6 +3642,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, diff --git a/package.json b/package.json index 710b031..71dfbef 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "typescript": "4.7.4" }, "dependencies": { + "esbuild-plugin-inline-worker": "^0.1.1", "image-js": "^0.35.5", "supernote": "github:philips/supernote-typescript" } diff --git a/main.ts b/src/main.ts similarity index 75% rename from main.ts rename to src/main.ts index 542288f..b692915 100644 --- a/main.ts +++ b/src/main.ts @@ -1,5 +1,8 @@ -import { App, Modal, TFolder, TFile, Plugin, PluginSettingTab, Editor, Setting, MarkdownView, WorkspaceLeaf, FileView } from 'obsidian'; -import { SupernoteX, toImage, fetchMirrorFrame } from 'supernote-typescript'; +import { App, Modal, TFile, Plugin, PluginSettingTab, Editor, Setting, MarkdownView, WorkspaceLeaf, FileView } from 'obsidian'; +import { SupernoteX, fetchMirrorFrame } from 'supernote-typescript'; +import { Image } from 'image-js' +import { SupernoteWorkerMessage, SupernoteWorkerResponse } from './myworker.worker'; +import Worker from 'myworker.worker'; interface SupernotePluginSettings { mirrorIP: string; @@ -32,6 +35,107 @@ function generateTimestamp(): string { return timestamp; } +function dataUrlToBuffer(dataUrl: string): ArrayBuffer { + // Remove data URL prefix (e.g., "data:image/png;base64,") + const base64 = dataUrl.split(',')[1]; + // Convert base64 to binary string + const binaryString = atob(base64); + // Create buffer and view + const bytes = new Uint8Array(binaryString.length); + // Convert binary string to buffer + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes.buffer; +} + +export class WorkerPool { + private workers: Worker[]; + + constructor(private maxWorkers: number = navigator.hardwareConcurrency) { + this.workers = Array(maxWorkers).fill(null).map(() => + new Worker() + ); + } + + private processChunk(worker: Worker, note: SupernoteX, pageNumbers: number[]): Promise { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + worker.onmessage = (e: MessageEvent) => { + const duration = Date.now() - startTime; + //console.log(`Processed pages ${pageNumbers.join(',')} in ${duration}ms`); + + if (e.data.error) { + reject(new Error(e.data.error)); + } else { + resolve(e.data.images); + } + }; + + worker.onerror = (error) => { + console.error('Worker error:', error); + reject(error); + }; + + const message: SupernoteWorkerMessage = { + type: 'convert', + note, + pageNumbers + }; + + worker.postMessage(message); + }); + } + + async processPages(note: SupernoteX, allPageNumbers: number[]): Promise { + //console.time('Total processing time'); + + // Split pages into chunks based on number of workers + const chunkSize = Math.ceil(allPageNumbers.length / this.workers.length); + const chunks: number[][] = []; + + for (let i = 0; i < allPageNumbers.length; i += chunkSize) { + chunks.push(allPageNumbers.slice(i, i + chunkSize)); + } + + //console.log(`Processing ${allPageNumbers.length} pages in ${chunks.length} chunks`); + + // Process chunks in parallel using available workers + const results = await Promise.all( + chunks.map((chunk, index) => + this.processChunk(this.workers[index % this.workers.length], note, chunk) + ) + ); + + //console.timeEnd('Total processing time'); + return results.flat(); + } + + terminate() { + this.workers.forEach(worker => worker.terminate()); + this.workers = []; + } +} + +export class ImageConverter { + private workerPool: WorkerPool; + + constructor(maxWorkers = navigator.hardwareConcurrency) { // Default to 4 workers + this.workerPool = new WorkerPool(maxWorkers); + } + + async convertToImages(note: SupernoteX, pageNumbers?: number[]): Promise { + const pages = pageNumbers ?? Array.from({length: note.pages.length}, (_, i) => i+1); + const results = await this.workerPool.processPages(note, pages); + return results; + } + + terminate() { + this.workerPool.terminate(); + } +} + class VaultWriter { app: App; settings: SupernotePluginSettings; @@ -74,11 +178,21 @@ class VaultWriter { } async writeImageFiles(file: TFile, sn: SupernoteX): Promise { - let images = await toImage(sn); + let images: string[] = []; + + const converter = new ImageConverter(); + try { + images = await converter.convertToImages(sn); + } finally { + // Clean up the worker when done + converter.terminate(); + } + let imgs: TFile[] = []; for (let i = 0; i < images.length; i++) { let filename = await this.app.fileManager.getAvailablePathForAttachment(`${file.basename}-${i}.png`); - imgs.push(await this.app.vault.createBinary(filename, images[i].toBuffer())); + const buffer = dataUrlToBuffer(images[i]); + imgs.push(await this.app.vault.createBinary(filename, buffer)); } return imgs; } @@ -128,7 +242,15 @@ export class SupernoteView extends FileView { const note = await this.app.vault.readBinary(file); let sn = new SupernoteX(new Uint8Array(note)); - let images = await toImage(sn); + let images: string[] = []; + + const converter = new ImageConverter(); + try { + images = await converter.convertToImages(sn); + } finally { + // Clean up the worker when done + converter.terminate(); + } if (this.settings.showExportButtons) { const exportNoteBtn = container.createEl("p").createEl("button", { @@ -163,7 +285,7 @@ export class SupernoteView extends FileView { } for (let i = 0; i < images.length; i++) { - const imageDataUrl = images[i].toDataURL(); + const imageDataUrl = images[i]; const pageContainer = container.createEl("div", { cls: 'page-container', @@ -214,7 +336,8 @@ export class SupernoteView extends FileView { saveButton.addEventListener("click", async () => { const filename = await this.app.fileManager.getAvailablePathForAttachment(`${file.basename}}.png`); - await this.app.vault.createBinary(filename, images[i].toBuffer()); + const buffer = dataUrlToBuffer(imageDataUrl); + await this.app.vault.createBinary(filename, buffer); }); } } @@ -472,7 +595,7 @@ class SupernoteSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }) ); - + new Setting(containerEl) .setName('Max image side length in .note files') .setDesc('Maximum width and height (in pixels) of the note image when viewing .note files. Does not affect exported images and markdown.') diff --git a/src/myworker.worker.ts b/src/myworker.worker.ts new file mode 100644 index 0000000..87752af --- /dev/null +++ b/src/myworker.worker.ts @@ -0,0 +1,45 @@ +import { SupernoteX, toImage } from 'supernote-typescript'; +import { Image } from 'image-js' + +export {}; + +export type SupernoteWorkerMessage = { + type: 'convert'; + note: SupernoteX; + pageNumbers?: number[]; +} + +export type SupernoteWorkerResponse = { + type: 'result'; + images: string[]; + error?: string; +} + +self.onmessage = async (e: MessageEvent) => { + try { + const { type, note, pageNumbers } = e.data; + + if (type === 'convert') { + const results = await toImage(note, pageNumbers); + // Convert canvas/images to data URLs before sending + const dataUrls = results.map(result => { + if (result && typeof result.toDataURL === 'function') { + return result.toDataURL(); + } + console.error('Result is not a canvas or does not support toDataURL'); + return null; + }); + + self.postMessage({ + type: 'result', + images: dataUrls + }); + } + } catch (error) { + self.postMessage({ + type: 'result', + images: [], + error: error instanceof Error ? error.message : 'Unknown error occurred' + }); + } +}; \ No newline at end of file diff --git a/src/worker.d.ts b/src/worker.d.ts new file mode 100644 index 0000000..7e0df84 --- /dev/null +++ b/src/worker.d.ts @@ -0,0 +1,4 @@ +declare module 'myworker.worker' { + const WorkerFactory: new () => Worker; + export default WorkerFactory; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7129a28..91281a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,9 @@ { "compilerOptions": { - "baseUrl": ".", + "baseUrl": "./src/", + "paths": { + "supernote-typescript": ["../supernote-typescript/src/"] + }, "inlineSourceMap": true, "inlineSources": true, "module": "ESNext", @@ -11,18 +14,16 @@ "moduleResolution": "node", "importHelpers": true, "isolatedModules": true, - "strictNullChecks": true, + "strictNullChecks": true, "lib": [ "DOM", "ES5", "ES6", - "ES7" + "ES7", + "DOM.Iterable" ] }, "exclude": [ - "supernote-typescript/**/*.ts" - ], - "include": [ - "**/*.ts" + "supernote-typescript/tests/*.ts" ] }