Add context menu options to copy/save image from pdf-reader/note-editor
Fixes #2664
This commit is contained in:
parent
dbc65faecb
commit
80385ff893
5 changed files with 129 additions and 2 deletions
|
@ -25,6 +25,8 @@
|
|||
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
|
||||
import FilePicker from 'zotero/modules/filePicker';
|
||||
|
||||
// Note: TinyMCE is automatically doing some meaningless corrections to
|
||||
// note-editor produced HTML. Which might result to more
|
||||
// conflicts, especially in group libraries
|
||||
|
@ -105,6 +107,57 @@ class EditorInstance {
|
|||
return text;
|
||||
};
|
||||
|
||||
this._iframeWindow.wrappedJSObject.zoteroCopyImage = async (dataURL) => {
|
||||
let parts = dataURL.split(',');
|
||||
if (!parts[0].includes('base64')) {
|
||||
return;
|
||||
}
|
||||
let mime = parts[0].match(/:(.*?);/)[1];
|
||||
let bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
let imgTools = Components.classes["@mozilla.org/image/tools;1"]
|
||||
.getService(Components.interfaces.imgITools);
|
||||
let transferable = Components.classes['@mozilla.org/widget/transferable;1']
|
||||
.createInstance(Components.interfaces.nsITransferable);
|
||||
let clipboardService = Components.classes['@mozilla.org/widget/clipboard;1']
|
||||
.getService(Components.interfaces.nsIClipboard);
|
||||
let imgPtr = Components.classes["@mozilla.org/supports-interface-pointer;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsInterfacePointer);
|
||||
imgPtr.data = imgTools.decodeImageFromArrayBuffer(u8arr.buffer, mime);
|
||||
transferable.init(null);
|
||||
transferable.addDataFlavor(mime);
|
||||
transferable.setTransferData(mime, imgPtr, 0);
|
||||
clipboardService.setData(transferable, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
|
||||
};
|
||||
|
||||
this._iframeWindow.wrappedJSObject.zoteroSaveImageAs = async (dataURL) => {
|
||||
let parts = dataURL.split(',');
|
||||
if (!parts[0].includes('base64')) {
|
||||
return;
|
||||
}
|
||||
let mime = parts[0].match(/:(.*?);/)[1];
|
||||
let bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
let ext = Zotero.MIME.getPrimaryExtension(mime, '');
|
||||
let fp = new FilePicker();
|
||||
fp.init(this._iframeWindow, Zotero.getString('noteEditor.saveImageAs'), fp.modeSave);
|
||||
fp.appendFilters(fp.filterImages);
|
||||
fp.defaultString = Zotero.getString('fileTypes.image').toLowerCase() + '.' + ext;
|
||||
let rv = await fp.show();
|
||||
if (rv === fp.returnOK || rv === fp.returnReplace) {
|
||||
let outputPath = fp.file;
|
||||
await OS.File.writeAtomic(outputPath, u8arr);
|
||||
}
|
||||
};
|
||||
|
||||
this._iframeWindow.addEventListener('message', this._messageHandler);
|
||||
this._iframeWindow.addEventListener('error', (event) => {
|
||||
Zotero.logError(event.error);
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
import FilePicker from 'zotero/modules/filePicker';
|
||||
|
||||
class ReaderInstance {
|
||||
constructor() {
|
||||
this.pdfStateFileName = '.zotero-pdf-state';
|
||||
|
@ -395,6 +397,54 @@ class ReaderInstance {
|
|||
);
|
||||
return !index;
|
||||
};
|
||||
|
||||
this._iframeWindow.wrappedJSObject.zoteroCopyImage = async (dataURL) => {
|
||||
let parts = dataURL.split(',');
|
||||
if (!parts[0].includes('base64')) {
|
||||
return;
|
||||
}
|
||||
let bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
let imgTools = Components.classes["@mozilla.org/image/tools;1"]
|
||||
.getService(Components.interfaces.imgITools);
|
||||
let transferable = Components.classes['@mozilla.org/widget/transferable;1']
|
||||
.createInstance(Components.interfaces.nsITransferable);
|
||||
let clipboardService = Components.classes['@mozilla.org/widget/clipboard;1']
|
||||
.getService(Components.interfaces.nsIClipboard);
|
||||
let imgPtr = Components.classes["@mozilla.org/supports-interface-pointer;1"]
|
||||
.createInstance(Components.interfaces.nsISupportsInterfacePointer);
|
||||
let mimeType = `image/png`;
|
||||
imgPtr.data = imgTools.decodeImageFromArrayBuffer(u8arr.buffer, mimeType);
|
||||
transferable.init(null);
|
||||
transferable.addDataFlavor(mimeType);
|
||||
transferable.setTransferData(mimeType, imgPtr, 0);
|
||||
clipboardService.setData(transferable, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
|
||||
};
|
||||
|
||||
this._iframeWindow.wrappedJSObject.zoteroSaveImageAs = async (dataURL) => {
|
||||
let fp = new FilePicker();
|
||||
fp.init(this._iframeWindow, Zotero.getString('pdfReader.saveImageAs'), fp.modeSave);
|
||||
fp.appendFilter("PNG", "*.png");
|
||||
fp.defaultString = Zotero.getString('fileTypes.image').toLowerCase() + '.png';
|
||||
let rv = await fp.show();
|
||||
if (rv === fp.returnOK || rv === fp.returnReplace) {
|
||||
let outputPath = fp.file;
|
||||
let parts = dataURL.split(',');
|
||||
if (parts[0].includes('base64')) {
|
||||
let bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
await OS.File.writeAtomic(outputPath, u8arr);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async _setState(state) {
|
||||
|
@ -647,6 +697,26 @@ class ReaderInstance {
|
|||
}
|
||||
// Separator
|
||||
popup.appendChild(this._window.document.createXULElement('menuseparator'));
|
||||
|
||||
if (data.enableImageOptions) {
|
||||
// Copy Image
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.copyImage'));
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'copyImage', data });
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Save Image As…
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('pdfReader.saveImageAs'));
|
||||
menuitem.addEventListener('command', () => {
|
||||
this._postMessage({ action: 'popupCmd', cmd: 'saveImageAs', data });
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Separator
|
||||
popup.appendChild(this._window.document.createXULElement('menuseparator'));
|
||||
}
|
||||
|
||||
// Delete
|
||||
menuitem = this._window.document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', Zotero.getString('general.delete'));
|
||||
|
|
|
@ -1340,6 +1340,8 @@ noteEditor.addCitations = Show Annotation Citations
|
|||
noteEditor.removeCitations = Hide Annotation Citations
|
||||
noteEditor.math = Math
|
||||
noteEditor.table = Table
|
||||
noteEditor.copyImage = Copy Image
|
||||
noteEditor.saveImageAs = Save Image As…
|
||||
noteEditor.insertRowBefore = Insert Row Above
|
||||
noteEditor.insertRowAfter = Insert Row Below
|
||||
noteEditor.insertColumnBefore = Insert Column Left
|
||||
|
@ -1381,6 +1383,8 @@ pdfReader.rotateRight = Rotate Right
|
|||
pdfReader.rotate180 = Rotate 180°
|
||||
pdfReader.editPageNumber = Edit Page Number…
|
||||
pdfReader.editHighlightedText = Edit Highlighted Text
|
||||
pdfReader.copyImage = Copy Image
|
||||
pdfReader.saveImageAs = Save Image As…
|
||||
pdfReader.pageNumberPopupHeader = Change page number for:
|
||||
pdfReader.thisAnnotation = This annotation
|
||||
pdfReader.selectedAnnotations = Selected annotations
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 29372d3801665c21ebc0a8d6661df88bebd0ea29
|
||||
Subproject commit aa26f8470849ac06a4808ccb8d0c93bac717da11
|
|
@ -1 +1 @@
|
|||
Subproject commit 65d5acf2c26f86a29895c3d66b3292ff512c3c61
|
||||
Subproject commit 2ee130e0ecbbfe34807a5d5e2b3500ad6d99a57e
|
Loading…
Reference in a new issue