diff --git a/.yarn/cache/html-to-image-npm-1.11.11-faab8eba97-b453beca72.zip b/.yarn/cache/html-to-image-npm-1.11.11-faab8eba97-b453beca72.zip deleted file mode 100644 index 133b21fcb..000000000 Binary files a/.yarn/cache/html-to-image-npm-1.11.11-faab8eba97-b453beca72.zip and /dev/null differ diff --git a/packages/clipper/package.json b/packages/clipper/package.json index 7f69243af..3f890a650 100644 --- a/packages/clipper/package.json +++ b/packages/clipper/package.json @@ -32,7 +32,6 @@ "webpack": "*" }, "dependencies": { - "@mozilla/readability": "^0.4.2", - "html-to-image": "^1.11.11" + "@mozilla/readability": "^0.4.2" } } diff --git a/packages/clipper/src/background/background.ts b/packages/clipper/src/background/background.ts index c4a969e1c..8f381ff77 100644 --- a/packages/clipper/src/background/background.ts +++ b/packages/clipper/src/background/background.ts @@ -1,4 +1,4 @@ -import { runtime, action, browserAction, windows, storage } from 'webextension-polyfill' +import { runtime, action, browserAction, windows, storage, tabs } from 'webextension-polyfill' import { ClipPayload, RuntimeMessage, RuntimeMessageTypes } from '../types/message' const isFirefox = navigator.userAgent.indexOf('Firefox/') !== -1 @@ -22,11 +22,15 @@ const openPopupAndClipSelection = async (payload: ClipPayload) => { void openPopup() } -runtime.onMessage.addListener((message: RuntimeMessage) => { +runtime.onMessage.addListener(async (message: RuntimeMessage) => { if (message.type === RuntimeMessageTypes.OpenPopupWithSelection) { if (!message.payload) { return } void openPopupAndClipSelection(message.payload) + } else if (message.type === RuntimeMessageTypes.CaptureVisibleTab) { + return await tabs.captureVisibleTab(undefined, { + format: 'png', + }) } }) diff --git a/packages/clipper/src/content/content.ts b/packages/clipper/src/content/content.ts index 376faf33c..6f5d55e3f 100644 --- a/packages/clipper/src/content/content.ts +++ b/packages/clipper/src/content/content.ts @@ -1,7 +1,6 @@ import { runtime } from 'webextension-polyfill' import { Readability } from '@mozilla/readability' import { RuntimeMessage, RuntimeMessageTypes } from '../types/message' -import { toPng } from 'html-to-image' let isSelectingNodeForClipping = false let isScreenshotMode = false @@ -47,7 +46,9 @@ runtime.onMessage.addListener(async (message: RuntimeMessage) => { } case RuntimeMessageTypes.GetFullPage: { if (isScreenshotMode) { - const content = await toPng(document.body) + const content = await runtime.sendMessage({ + type: RuntimeMessageTypes.CaptureVisibleTab, + }) return { title: document.title, content: content, url: window.location.href, isScreenshot: true } } @@ -101,6 +102,55 @@ const disableNodeSelection = () => { nodeOverlayElement.style.visibility = 'hidden' } +const imageFromBase64 = (base64: string) => { + return new Promise((resolve, reject) => { + const image = new Image() + image.onload = () => { + resolve(image) + } + image.onerror = reject + image.src = base64 + }) +} + +const toPng = async (element: HTMLElement) => { + const visibleTab: string = await runtime.sendMessage({ + type: RuntimeMessageTypes.CaptureVisibleTab, + }) + + const image = await imageFromBase64(visibleTab) + + const canvas = document.createElement('canvas') + + canvas.width = image.width + canvas.height = image.height + + const context = canvas.getContext('2d') + + if (!context) { + throw new Error('Could not get canvas context') + } + + context.drawImage(image, 0, 0) + + const elementRect = element.getBoundingClientRect() + + const x = elementRect.x + const y = elementRect.y + + const width = elementRect.width + const height = elementRect.height + + const imageData = context.getImageData(x, y, width, height) + + canvas.width = width + canvas.height = height + + context.putImageData(imageData, 0, 0) + + return canvas.toDataURL('image/png') +} + window.addEventListener('click', async (event) => { if (!isSelectingNodeForClipping) { return diff --git a/packages/clipper/src/manifest.v2.json b/packages/clipper/src/manifest.v2.json index 61c929017..555b7e3e9 100644 --- a/packages/clipper/src/manifest.v2.json +++ b/packages/clipper/src/manifest.v2.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "Standard Notes Clipper", "description": "Web clipper for Standard Notes", - "permissions": ["activeTab", "storage"], + "permissions": ["activeTab", "storage", ""], "browser_action": { "default_popup": "popup/index.html?route=extension" }, diff --git a/packages/clipper/src/types/message.ts b/packages/clipper/src/types/message.ts index c6303d5c5..60da6a8f6 100644 --- a/packages/clipper/src/types/message.ts +++ b/packages/clipper/src/types/message.ts @@ -6,6 +6,7 @@ export const RuntimeMessageTypes = { OpenPopupWithSelection: 'open-popup-with-selection', StartNodeSelection: 'start-node-selection', ToggleScreenshotMode: 'toggle-screenshot-mode', + CaptureVisibleTab: 'capture-visible-tab', } as const export type RuntimeMessageType = typeof RuntimeMessageTypes[keyof typeof RuntimeMessageTypes] @@ -24,6 +25,7 @@ export type RuntimeMessageReturnTypes = { [RuntimeMessageTypes.GetSelection]: ClipPayload [RuntimeMessageTypes.HasSelection]: boolean [RuntimeMessageTypes.GetFullPage]: ClipPayload + [RuntimeMessageTypes.CaptureVisibleTab]: string [RuntimeMessageTypes.OpenPopupWithSelection]: void [RuntimeMessageTypes.StartNodeSelection]: void [RuntimeMessageTypes.ToggleScreenshotMode]: void diff --git a/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx b/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx index 512e06f14..b6a5f7724 100644 --- a/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx +++ b/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx @@ -340,15 +340,9 @@ const ClipperView = ({ return } setClipPayload(payload) - if (isScreenshotMode) { - addToast({ - type: ToastType.Regular, - message: 'Capturing full page...', - }) - } }} > - Clip full page + {isScreenshotMode ? 'Capture visible' : 'Clip full page'} - Select elements to clip + Select elements to {isScreenshotMode ? 'capture' : 'clip'}
-
Default tag:
+
Default tag
{defaultTag && (