Fix and attach image annotation renderer
This commit is contained in:
parent
3e4ad18b2a
commit
83109fc076
3 changed files with 84 additions and 33 deletions
|
@ -977,6 +977,21 @@ class EditorInstance {
|
||||||
if (!annotations.length) {
|
if (!annotations.length) {
|
||||||
throw new Error("No annotations provided");
|
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');
|
let note = new Zotero.Item('note');
|
||||||
note.libraryID = annotations[0].libraryID;
|
note.libraryID = annotations[0].libraryID;
|
||||||
note.parentID = parentID;
|
note.parentID = parentID;
|
||||||
|
|
|
@ -82,7 +82,6 @@ class PDFWorker {
|
||||||
this._worker = new Worker(WORKER_URL);
|
this._worker = new Worker(WORKER_URL);
|
||||||
this._worker.addEventListener('message', async (event) => {
|
this._worker.addEventListener('message', async (event) => {
|
||||||
let message = event.data;
|
let message = event.data;
|
||||||
// console.log(event.data)
|
|
||||||
if (message.responseID) {
|
if (message.responseID) {
|
||||||
let { resolve, reject } = this._waitingPromises[message.responseID];
|
let { resolve, reject } = this._waitingPromises[message.responseID];
|
||||||
delete this._waitingPromises[message.responseID];
|
delete this._waitingPromises[message.responseID];
|
||||||
|
@ -141,8 +140,8 @@ class PDFWorker {
|
||||||
*
|
*
|
||||||
* @param {Integer} itemID
|
* @param {Integer} itemID
|
||||||
* @param {String} path
|
* @param {String} path
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
* @param {String} password
|
* @param {String} [password]
|
||||||
* @returns {Promise<Integer>} Number of written annotations
|
* @returns {Promise<Integer>} Number of written annotations
|
||||||
*/
|
*/
|
||||||
async export(itemID, path, isPriority, password) {
|
async export(itemID, path, isPriority, password) {
|
||||||
|
@ -165,7 +164,7 @@ class PDFWorker {
|
||||||
dateModified: item.dateModified
|
dateModified: item.dateModified
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let attachmentPath = await attachment.getFilePath();
|
let attachmentPath = await attachment.getFilePathAsync();
|
||||||
let buf = await OS.File.read(attachmentPath, {});
|
let buf = await OS.File.read(attachmentPath, {});
|
||||||
buf = new Uint8Array(buf).buffer;
|
buf = new Uint8Array(buf).buffer;
|
||||||
|
|
||||||
|
@ -193,7 +192,7 @@ class PDFWorker {
|
||||||
*
|
*
|
||||||
* @param {Zotero.Item} item
|
* @param {Zotero.Item} item
|
||||||
* @param {String} directory
|
* @param {String} directory
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
*/
|
*/
|
||||||
async exportParent(item, directory, isPriority) {
|
async exportParent(item, directory, isPriority) {
|
||||||
if (!item.isRegularItem()) {
|
if (!item.isRegularItem()) {
|
||||||
|
@ -218,8 +217,8 @@ class PDFWorker {
|
||||||
* Import annotations from PDF attachment
|
* Import annotations from PDF attachment
|
||||||
*
|
*
|
||||||
* @param {Integer} itemID Attachment item id
|
* @param {Integer} itemID Attachment item id
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
* @param {String} password
|
* @param {String} [password]
|
||||||
* @returns {Promise<Integer>} Number of annotations
|
* @returns {Promise<Integer>} Number of annotations
|
||||||
*/
|
*/
|
||||||
async import(itemID, isPriority, password) {
|
async import(itemID, isPriority, password) {
|
||||||
|
@ -244,7 +243,7 @@ class PDFWorker {
|
||||||
comment: annotation.annotationComment || ''
|
comment: annotation.annotationComment || ''
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let path = await attachment.getFilePath();
|
let path = await attachment.getFilePathAsync();
|
||||||
let buf = await OS.File.read(path, {});
|
let buf = await OS.File.read(path, {});
|
||||||
buf = new Uint8Array(buf).buffer;
|
buf = new Uint8Array(buf).buffer;
|
||||||
|
|
||||||
|
@ -284,7 +283,7 @@ class PDFWorker {
|
||||||
* Import annotations for each PDF attachment of parent item
|
* Import annotations for each PDF attachment of parent item
|
||||||
*
|
*
|
||||||
* @param {Zotero.Item} item
|
* @param {Zotero.Item} item
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
*/
|
*/
|
||||||
async importParent(item, isPriority) {
|
async importParent(item, isPriority) {
|
||||||
if (!item.isRegularItem()) {
|
if (!item.isRegularItem()) {
|
||||||
|
@ -379,6 +378,9 @@ class PDFRenderer {
|
||||||
this._browser.loadURI(RENDERER_URL);
|
this._browser.loadURI(RENDERER_URL);
|
||||||
|
|
||||||
let _handleMessage = async (event) => {
|
let _handleMessage = async (event) => {
|
||||||
|
if (event.source !== this._browser.contentWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let message = event.data;
|
let message = event.data;
|
||||||
if (message.responseID) {
|
if (message.responseID) {
|
||||||
let { resolve, reject } = this._waitingPromises[message.responseID];
|
let { resolve, reject } = this._waitingPromises[message.responseID];
|
||||||
|
@ -395,18 +397,29 @@ class PDFRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.action === 'initialized') {
|
if (message.action === 'initialized') {
|
||||||
|
this._browser.contentWindow.postMessage(
|
||||||
|
{ responseID: message.id, data: {} },
|
||||||
|
this._browser.contentWindow.origin
|
||||||
|
);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
else if (message.action === 'renderedAnnotation') {
|
else if (message.action === 'renderedAnnotation') {
|
||||||
let { id, image } = message.data.annotation;
|
let { id, image } = message.data.annotation;
|
||||||
let item = await Zotero.Items.getAsync(id);
|
|
||||||
let win = Zotero.getMainWindow();
|
try {
|
||||||
if (!win) {
|
let item = await Zotero.Items.getAsync(id);
|
||||||
return;
|
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);
|
this._browser.contentWindow.postMessage(
|
||||||
await Zotero.Notifier.trigger('modify', 'item', [item.id]);
|
{ responseID: message.id, data: {} },
|
||||||
|
this._browser.contentWindow.origin
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -416,7 +429,7 @@ class PDFRenderer {
|
||||||
* Render missing image annotation images for attachment
|
* Render missing image annotation images for attachment
|
||||||
*
|
*
|
||||||
* @param {Integer} itemID Attachment item id
|
* @param {Integer} itemID Attachment item id
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
* @returns {Promise<Integer>}
|
* @returns {Promise<Integer>}
|
||||||
*/
|
*/
|
||||||
async renderAttachmentAnnotations(itemID, isPriority) {
|
async renderAttachmentAnnotations(itemID, isPriority) {
|
||||||
|
@ -435,7 +448,7 @@ class PDFRenderer {
|
||||||
if (!annotations.length) {
|
if (!annotations.length) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let path = await attachment.getFilePath();
|
let path = await attachment.getFilePathAsync();
|
||||||
let buf = await OS.File.read(path, {});
|
let buf = await OS.File.read(path, {});
|
||||||
buf = new Uint8Array(buf).buffer;
|
buf = new Uint8Array(buf).buffer;
|
||||||
return this._query('renderAnnotations', { buf, annotations }, [buf]);
|
return this._query('renderAnnotations', { buf, annotations }, [buf]);
|
||||||
|
@ -446,7 +459,7 @@ class PDFRenderer {
|
||||||
* Render image annotation image
|
* Render image annotation image
|
||||||
*
|
*
|
||||||
* @param {Integer} itemID Attachment item id
|
* @param {Integer} itemID Attachment item id
|
||||||
* @param {Boolean} isPriority
|
* @param {Boolean} [isPriority]
|
||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
*/
|
*/
|
||||||
async renderAnnotation(itemID, isPriority) {
|
async renderAnnotation(itemID, isPriority) {
|
||||||
|
@ -456,7 +469,7 @@ class PDFRenderer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let attachment = await Zotero.Items.getAsync(annotation.parentID);
|
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, {});
|
let buf = await OS.File.read(path, {});
|
||||||
buf = new Uint8Array(buf).buffer;
|
buf = new Uint8Array(buf).buffer;
|
||||||
let annotations = [{
|
let annotations = [{
|
||||||
|
|
|
@ -31,7 +31,22 @@ function errObject(err) {
|
||||||
return JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(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 num = 0;
|
||||||
let pdfDocument = await window.pdfjsLib.getDocument({ data: buf }).promise;
|
let pdfDocument = await window.pdfjsLib.getDocument({ data: buf }).promise;
|
||||||
let pages = new Map();
|
let pages = new Map();
|
||||||
|
@ -54,10 +69,9 @@ async function renderAnnotations(buf, annotations, send) {
|
||||||
newCanvas.height = height;
|
newCanvas.height = height;
|
||||||
let newCanvasContext = newCanvas.getContext('2d');
|
let newCanvasContext = newCanvas.getContext('2d');
|
||||||
newCanvasContext.drawImage(canvas, left, top, width, height, 0, 0, width, height);
|
newCanvasContext.drawImage(canvas, left, top, width, height, 0, 0, width, height);
|
||||||
newCanvas.toBlob(async (blob) => {
|
let blob = await new Promise(resolve => newCanvas.toBlob(resolve, 'image/png'));
|
||||||
let image = await new Response(blob).arrayBuffer();
|
let image = await new Response(blob).arrayBuffer();
|
||||||
send({ id: annotation.id, image });
|
await query('renderedAnnotation', { annotation: { id: annotation.id, image } }, [image]);
|
||||||
}, 'image/png');
|
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,16 +105,25 @@ window.addEventListener('message', async (event) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let message = event.data;
|
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') {
|
if (message.action === 'renderAnnotations') {
|
||||||
try {
|
try {
|
||||||
let { buf, annotations } = message.data;
|
let { buf, annotations } = message.data;
|
||||||
let num = await renderAnnotations(
|
let num = await renderAnnotations(buf, annotations);
|
||||||
buf,
|
|
||||||
annotations,
|
|
||||||
(annotation) => {
|
|
||||||
parent.postMessage({ action: 'renderedAnnotation', data: { annotation } }, parent.origin, [annotation.image]);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
parent.postMessage({ responseID: message.id, data: num }, parent.origin);
|
parent.postMessage({ responseID: message.id, data: num }, parent.origin);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -114,5 +137,5 @@ window.addEventListener('message', async (event) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
parent.postMessage({ action: 'initialized' }, parent.origin);
|
query('initialized', {});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
Loading…
Reference in a new issue