From 83109fc076cb8de97a479b2ab0205c8f6e059973 Mon Sep 17 00:00:00 2001 From: Martynas Bagdonas Date: Wed, 24 Feb 2021 16:33:06 +0200 Subject: [PATCH] Fix and attach image annotation renderer --- chrome/content/zotero/xpcom/editorInstance.js | 15 ++++++ .../content/zotero/xpcom/pdfWorker/manager.js | 53 ++++++++++++------- resource/pdf-renderer/renderer.js | 49 ++++++++++++----- 3 files changed, 84 insertions(+), 33 deletions(-) diff --git a/chrome/content/zotero/xpcom/editorInstance.js b/chrome/content/zotero/xpcom/editorInstance.js index 2dca0a3b9d..cd75518bb5 100644 --- a/chrome/content/zotero/xpcom/editorInstance.js +++ b/chrome/content/zotero/xpcom/editorInstance.js @@ -977,6 +977,21 @@ class EditorInstance { if (!annotations.length) { throw new Error("No annotations provided"); } + + for (let annotation of annotations) { + if (annotation.annotationType === 'image' + && !await Zotero.Annotations.hasCacheImage(annotation)) { + try { + await Zotero.PDFRenderer.renderAttachmentAnnotations(annotation.parentID); + } + catch (e) { + Zotero.debug(e); + throw e; + } + break; + } + } + let note = new Zotero.Item('note'); note.libraryID = annotations[0].libraryID; note.parentID = parentID; diff --git a/chrome/content/zotero/xpcom/pdfWorker/manager.js b/chrome/content/zotero/xpcom/pdfWorker/manager.js index 5cd2f8fcb7..8ac493036e 100644 --- a/chrome/content/zotero/xpcom/pdfWorker/manager.js +++ b/chrome/content/zotero/xpcom/pdfWorker/manager.js @@ -82,7 +82,6 @@ class PDFWorker { this._worker = new Worker(WORKER_URL); this._worker.addEventListener('message', async (event) => { let message = event.data; - // console.log(event.data) if (message.responseID) { let { resolve, reject } = this._waitingPromises[message.responseID]; delete this._waitingPromises[message.responseID]; @@ -141,8 +140,8 @@ class PDFWorker { * * @param {Integer} itemID * @param {String} path - * @param {Boolean} isPriority - * @param {String} password + * @param {Boolean} [isPriority] + * @param {String} [password] * @returns {Promise} Number of written annotations */ async export(itemID, path, isPriority, password) { @@ -165,7 +164,7 @@ class PDFWorker { dateModified: item.dateModified }); } - let attachmentPath = await attachment.getFilePath(); + let attachmentPath = await attachment.getFilePathAsync(); let buf = await OS.File.read(attachmentPath, {}); buf = new Uint8Array(buf).buffer; @@ -193,7 +192,7 @@ class PDFWorker { * * @param {Zotero.Item} item * @param {String} directory - * @param {Boolean} isPriority + * @param {Boolean} [isPriority] */ async exportParent(item, directory, isPriority) { if (!item.isRegularItem()) { @@ -218,8 +217,8 @@ class PDFWorker { * Import annotations from PDF attachment * * @param {Integer} itemID Attachment item id - * @param {Boolean} isPriority - * @param {String} password + * @param {Boolean} [isPriority] + * @param {String} [password] * @returns {Promise} Number of annotations */ async import(itemID, isPriority, password) { @@ -244,7 +243,7 @@ class PDFWorker { comment: annotation.annotationComment || '' })); - let path = await attachment.getFilePath(); + let path = await attachment.getFilePathAsync(); let buf = await OS.File.read(path, {}); buf = new Uint8Array(buf).buffer; @@ -284,7 +283,7 @@ class PDFWorker { * Import annotations for each PDF attachment of parent item * * @param {Zotero.Item} item - * @param {Boolean} isPriority + * @param {Boolean} [isPriority] */ async importParent(item, isPriority) { if (!item.isRegularItem()) { @@ -379,6 +378,9 @@ class PDFRenderer { this._browser.loadURI(RENDERER_URL); let _handleMessage = async (event) => { + if (event.source !== this._browser.contentWindow) { + return; + } let message = event.data; if (message.responseID) { let { resolve, reject } = this._waitingPromises[message.responseID]; @@ -395,18 +397,29 @@ class PDFRenderer { } if (message.action === 'initialized') { + this._browser.contentWindow.postMessage( + { responseID: message.id, data: {} }, + this._browser.contentWindow.origin + ); resolve(); } else if (message.action === 'renderedAnnotation') { let { id, image } = message.data.annotation; - let item = await Zotero.Items.getAsync(id); - let win = Zotero.getMainWindow(); - if (!win) { - return; + + try { + let item = await Zotero.Items.getAsync(id); + let win = Zotero.getMainWindow(); + let blob = new win.Blob([new Uint8Array(image)]); + await Zotero.Annotations.saveCacheImage(item, blob); + await Zotero.Notifier.trigger('modify', 'item', [item.id]); + } catch (e) { + Zotero.logError(e); } - let blob = new win.Blob([new Uint8Array(image)]); - await Zotero.Annotations.saveCacheImage(item, blob); - await Zotero.Notifier.trigger('modify', 'item', [item.id]); + + this._browser.contentWindow.postMessage( + { responseID: message.id, data: {} }, + this._browser.contentWindow.origin + ); } }; }); @@ -416,7 +429,7 @@ class PDFRenderer { * Render missing image annotation images for attachment * * @param {Integer} itemID Attachment item id - * @param {Boolean} isPriority + * @param {Boolean} [isPriority] * @returns {Promise} */ async renderAttachmentAnnotations(itemID, isPriority) { @@ -435,7 +448,7 @@ class PDFRenderer { if (!annotations.length) { return 0; } - let path = await attachment.getFilePath(); + let path = await attachment.getFilePathAsync(); let buf = await OS.File.read(path, {}); buf = new Uint8Array(buf).buffer; return this._query('renderAnnotations', { buf, annotations }, [buf]); @@ -446,7 +459,7 @@ class PDFRenderer { * Render image annotation image * * @param {Integer} itemID Attachment item id - * @param {Boolean} isPriority + * @param {Boolean} [isPriority] * @returns {Promise} */ async renderAnnotation(itemID, isPriority) { @@ -456,7 +469,7 @@ class PDFRenderer { return false; } let attachment = await Zotero.Items.getAsync(annotation.parentID); - let path = await attachment.getFilePath(); + let path = await attachment.getFilePathAsync(); let buf = await OS.File.read(path, {}); buf = new Uint8Array(buf).buffer; let annotations = [{ diff --git a/resource/pdf-renderer/renderer.js b/resource/pdf-renderer/renderer.js index e9f3349529..1cef87f91a 100644 --- a/resource/pdf-renderer/renderer.js +++ b/resource/pdf-renderer/renderer.js @@ -31,7 +31,22 @@ function errObject(err) { return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))); } -async function renderAnnotations(buf, annotations, send) { +let lastPromiseID = 0; +let waitingPromises = {}; + +async function query(action, data, transfer) { + return new Promise((resolve, reject) => { + lastPromiseID++; + waitingPromises[lastPromiseID] = { resolve, reject }; + parent.postMessage({ + id: lastPromiseID, + action, + data + }, parent.origin, transfer); + }); +} + +async function renderAnnotations(buf, annotations) { let num = 0; let pdfDocument = await window.pdfjsLib.getDocument({ data: buf }).promise; let pages = new Map(); @@ -54,10 +69,9 @@ async function renderAnnotations(buf, annotations, send) { newCanvas.height = height; let newCanvasContext = newCanvas.getContext('2d'); newCanvasContext.drawImage(canvas, left, top, width, height, 0, 0, width, height); - newCanvas.toBlob(async (blob) => { - let image = await new Response(blob).arrayBuffer(); - send({ id: annotation.id, image }); - }, 'image/png'); + let blob = await new Promise(resolve => newCanvas.toBlob(resolve, 'image/png')); + let image = await new Response(blob).arrayBuffer(); + await query('renderedAnnotation', { annotation: { id: annotation.id, image } }, [image]); num++; } } @@ -91,16 +105,25 @@ window.addEventListener('message', async (event) => { return; } let message = event.data; + + if (message.responseID) { + let { resolve, reject } = waitingPromises[message.responseID]; + delete waitingPromises[message.responseID]; + if (message.data) { + resolve(message.data); + } + else { + let err = new Error(message.error.message); + Object.assign(err, message.error); + reject(err); + } + return; + } + if (message.action === 'renderAnnotations') { try { let { buf, annotations } = message.data; - let num = await renderAnnotations( - buf, - annotations, - (annotation) => { - parent.postMessage({ action: 'renderedAnnotation', data: { annotation } }, parent.origin, [annotation.image]); - } - ); + let num = await renderAnnotations(buf, annotations); parent.postMessage({ responseID: message.id, data: num }, parent.origin); } catch (e) { @@ -114,5 +137,5 @@ window.addEventListener('message', async (event) => { }); setTimeout(() => { - parent.postMessage({ action: 'initialized' }, parent.origin); + query('initialized', {}); }, 100);