-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Desktop: Resolves #9794: Plugin API: Add support for loading PDFs wit…
…h the imaging API (#10177)
- Loading branch information
1 parent
06c7c13
commit 06aa640
Showing
8 changed files
with
303 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
140 changes: 100 additions & 40 deletions
140
packages/app-cli/tests/support/plugins/imaging/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,110 @@ | ||
import joplin from 'api'; | ||
import { ToolbarButtonLocation } from 'api/types'; | ||
|
||
joplin.plugins.register({ | ||
onStart: async function() { | ||
await joplin.commands.register({ | ||
name: 'makeThumbnail', | ||
execute: async () => { | ||
// --------------------------------------------------------------- | ||
// Get the current note | ||
// --------------------------------------------------------------- | ||
|
||
const noteIds = await joplin.workspace.selectedNoteIds(); | ||
if (noteIds.length !== 1) return; | ||
const noteId = noteIds[0]; | ||
|
||
// --------------------------------------------------------------- | ||
// Get the top resource in that note (if any) | ||
// --------------------------------------------------------------- | ||
|
||
const result = await joplin.data.get(['notes', noteId, 'resources']); | ||
if (result.items.length <= 0) return; | ||
const resource = result.items[0]; | ||
|
||
// --------------------------------------------------------------- | ||
// Create an image object and resize it | ||
// --------------------------------------------------------------- | ||
|
||
const imageHandle = await joplin.imaging.createFromResource(resource.id); | ||
const resizedImageHandle = await joplin.imaging.resize(imageHandle, { width: 100 }); | ||
const registerMakeThumbnailCommand = async () => { | ||
await joplin.commands.register({ | ||
name: 'makeThumbnail', | ||
execute: async () => { | ||
// --------------------------------------------------------------- | ||
// Get the current note | ||
// --------------------------------------------------------------- | ||
|
||
const noteIds = await joplin.workspace.selectedNoteIds(); | ||
if (noteIds.length !== 1) return; | ||
const noteId = noteIds[0]; | ||
|
||
// --------------------------------------------------------------- | ||
// Get the top resource in that note (if any) | ||
// --------------------------------------------------------------- | ||
|
||
const result = await joplin.data.get(['notes', noteId, 'resources']); | ||
if (result.items.length <= 0) return; | ||
const resource = result.items[0]; | ||
|
||
// --------------------------------------------------------------- | ||
// Create an image object and resize it | ||
// --------------------------------------------------------------- | ||
|
||
// --------------------------------------------------------------- | ||
// Convert the image to a resource and add it to the note | ||
// --------------------------------------------------------------- | ||
const imageHandle = await joplin.imaging.createFromResource(resource.id); | ||
const resizedImageHandle = await joplin.imaging.resize(imageHandle, { width: 100 }); | ||
|
||
// --------------------------------------------------------------- | ||
// Convert the image to a resource and add it to the note | ||
// --------------------------------------------------------------- | ||
|
||
const newResource = await joplin.imaging.toJpgResource(resizedImageHandle, { title: "Thumbnail" }); | ||
await joplin.commands.execute('insertText', '\n![](:/' + newResource.id + ')'); | ||
|
||
// --------------------------------------------------------------- | ||
// Free up the image objects at the end | ||
// --------------------------------------------------------------- | ||
|
||
await joplin.imaging.free(imageHandle); | ||
await joplin.imaging.free(resizedImageHandle); | ||
}, | ||
}); | ||
|
||
await joplin.views.toolbarButtons.create('makeThumbnailButton', 'makeThumbnail', ToolbarButtonLocation.EditorToolbar); | ||
}; | ||
|
||
|
||
const newResource = await joplin.imaging.toJpgResource(resizedImageHandle, { title: "Thumbnail" }); | ||
await joplin.commands.execute('insertText', '\n![](:/' + newResource.id + ')'); | ||
const registerInlinePdfCommand = async () => { | ||
await joplin.commands.register({ | ||
name: 'inlinePdfs', | ||
execute: async () => { | ||
// --------------------------------------------------------------- | ||
// Get the current selection & extract a resource link | ||
// --------------------------------------------------------------- | ||
|
||
// --------------------------------------------------------------- | ||
// Free up the image objects at the end | ||
// --------------------------------------------------------------- | ||
const selection: string = await joplin.commands.execute('selectedText'); | ||
|
||
await joplin.imaging.free(imageHandle); | ||
await joplin.imaging.free(resizedImageHandle); | ||
}, | ||
}); | ||
// Matches content of the form | ||
// [text here](:/32-letter-or-num-characters-here) | ||
// Where ([a-z0-9]{32}) matches the resource ID. | ||
const resourceLinkRegex = /\[.*\]\(:\/([a-z0-9]{32})\)/; | ||
|
||
await joplin.views.toolbarButtons.create('makeThumbnailButton', 'makeThumbnail', ToolbarButtonLocation.EditorToolbar); | ||
const resourceLinkMatch = selection.match(resourceLinkRegex); | ||
if (!resourceLinkMatch) return; | ||
const resourceId = resourceLinkMatch[1]; // The text of the region matching ([a-z0-9]{32}) | ||
|
||
const resource = await joplin.data.get(['resources', resourceId], { fields: ['mime'] }); | ||
const isPdf = resource.mime === 'application/pdf'; | ||
if (!isPdf) return; | ||
|
||
// Clear the selection | ||
await joplin.commands.execute('replaceSelection', ''); | ||
await joplin.commands.execute('insertText', selection); | ||
|
||
// --------------------------------------------------------------- | ||
// Convert the PDF to images | ||
// --------------------------------------------------------------- | ||
|
||
const pdfInfo = await joplin.imaging.getPdfInfoFromResource(resourceId); | ||
const images = await joplin.imaging.createFromPdfResource( | ||
resourceId, | ||
// Convert at most 10 pages | ||
{ minPage: 1, maxPage: 10, scaleFactor: 0.5 }, | ||
); | ||
|
||
let pageNumber = 0; | ||
for (const image of images) { | ||
pageNumber++; | ||
const pageResource = await joplin.imaging.toJpgResource( | ||
image, { title: `Page ${pageNumber} of ${pdfInfo.pageCount}` } | ||
); | ||
await joplin.commands.execute('insertText', `\n- ![${pageResource.title}](:/${pageResource.id})`); | ||
} | ||
|
||
await joplin.imaging.free(images); | ||
}, | ||
}); | ||
|
||
await joplin.views.toolbarButtons.create('inlineSelectedPdfsButton', 'inlinePdfs', ToolbarButtonLocation.EditorToolbar); | ||
}; | ||
|
||
joplin.plugins.register({ | ||
onStart: async function() { | ||
await registerMakeThumbnailCommand(); | ||
await registerInlinePdfCommand(); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.