From 2fa1fc86623989c0d47618729dbfeea75c866011 Mon Sep 17 00:00:00 2001 From: 01zulfi <85733202+01zulfi@users.noreply.github.com> Date: Wed, 18 Jun 2025 12:48:44 +0500 Subject: [PATCH] clipper: fix screenshot clip Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com> --- packages/clipper/package-lock.json | 218 +++++++---------------------- packages/clipper/package.json | 1 + packages/clipper/src/domtoimage.ts | 8 +- packages/clipper/src/index.ts | 6 +- 4 files changed, 58 insertions(+), 175 deletions(-) diff --git a/packages/clipper/package-lock.json b/packages/clipper/package-lock.json index 4cd23cfa0..8db352740 100644 --- a/packages/clipper/package-lock.json +++ b/packages/clipper/package-lock.json @@ -11,6 +11,7 @@ "license": "GPL-3.0-or-later", "dependencies": { "@mozilla/readability": "^0.4.2", + "html2canvas": "^1.4.1", "hyperapp": "^2.0.22" }, "devDependencies": { @@ -19,34 +20,6 @@ "slugify": "1.6.6" } }, - "node_modules/@emnapi/core": { - "version": "1.6.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.6.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@module-federation/error-codes": { "version": "0.18.0", "dev": true, @@ -101,17 +74,6 @@ "node": ">=10.0.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@tybys/wasm-util": "^0.10.1" - } - }, "node_modules/@playwright/test": { "version": "1.48.2", "dev": true, @@ -173,132 +135,6 @@ "win32" ] }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-darwin-arm64": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.8.tgz", - "integrity": "sha512-spJfpOSN3f7V90ic45/ET2NKB2ujAViCNmqb0iGurMNQtFRq+7Kd+jvVKKGXKBHBbsQrFhidSWbbqy2PBPGK8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-darwin-x64": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.8.tgz", - "integrity": "sha512-YFOzeL1IBknBcri8vjUp43dfUBylCeQnD+9O9p0wZmLAw7DtpN5JEOe2AkGo8kdTqJjYKI+cczJPKIw6lu1LWw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.8.tgz", - "integrity": "sha512-UAWCsOnpkvy8eAVRo0uipbHXDhnoDq5zmqWTMhpga0/a3yzCp2e+fnjZb/qnFNYb5MeL0O1mwMOYgn1M3oHILQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.8.tgz", - "integrity": "sha512-GnSvGT4GjokPSD45cTtE+g7LgghuxSP1MRmvd+Vp/I8pnxTVSTsebRod4TAqyiv+l11nuS8yqNveK9qiOkBLWw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.8.tgz", - "integrity": "sha512-XLxh5n/pzUfxsugz/8rVBv+Tx2nqEM+9rharK69kfooDsQNKyz7PANllBQ/v4svJ+W0BRHnDL4qXSGdteZeEjA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.8.tgz", - "integrity": "sha512-gE0+MZmwF+01p9/svpEESkzkLpBkVUG2o03YMpwXYC/maeRRhWvF8BJ7R3i/Ls/jFGSE87dKX5NbRLVzqksq/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-wasm32-wasi": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.8.tgz", - "integrity": "sha512-cfg3niNHeJuxuml1Vy9VvaJrI/5TakzoaZvKX2g5S24wfzR50Eyy4JAsZ+L2voWQQp1yMJbmPYPmnTCTxdJQBQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.5" - } - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.8.tgz", - "integrity": "sha512-7i3ZTHFXKfU/9Jm9XhpMkrdkxO7lfeYMNVEGkuU5dyBfRMQj69dRgPL7zJwc2plXiqu9LUOl+TwDNTjap7Q36g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rspack/binding/node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.8.tgz", - "integrity": "sha512-7ZPPWO11J+soea1+mnfaPpQt7GIodBM7A86dx6PbXgVEoZmetcWPrCF2NBfXxQWOKJ9L3RYltC4z+ZyXRgMOrw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@rspack/core": { "version": "1.5.8", "dev": true, @@ -336,13 +172,13 @@ "tslib": "^2.8.0" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "dev": true, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "engines": { + "node": ">= 0.6.0" } }, "node_modules/core-js": { @@ -355,6 +191,28 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/hyperapp": { "version": "2.0.22", "license": "MIT" @@ -403,10 +261,28 @@ "node": ">=8.0.0" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/tslib": { "version": "2.8.1", "dev": true, "license": "0BSD" + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } } } } diff --git a/packages/clipper/package.json b/packages/clipper/package.json index 06e404312..eb34b1340 100644 --- a/packages/clipper/package.json +++ b/packages/clipper/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@mozilla/readability": "^0.4.2", + "html2canvas": "^1.4.1", "hyperapp": "^2.0.22" } } diff --git a/packages/clipper/src/domtoimage.ts b/packages/clipper/src/domtoimage.ts index 0b1959e86..53194b034 100644 --- a/packages/clipper/src/domtoimage.ts +++ b/packages/clipper/src/domtoimage.ts @@ -29,6 +29,7 @@ import { isSVGElement } from "./utils.js"; import { cloneNode } from "./clone.js"; +import html2canvas from "html2canvas"; // Default impl options const defaultOptions: Options = { @@ -101,10 +102,11 @@ function toPng(node: HTMLElement, options: Options) { }); } -function toJpeg(node: HTMLElement, options: Options) { +async function toJpeg(node: HTMLElement, options: Options) { options.raster = true; - return draw(node, options).then(function (canvas) { - return canvas?.toDataURL("image/jpeg", options.quality || 1.0); + + return html2canvas(node).then(function (canvas) { + return canvas.toDataURL("image/jpeg", options.quality || 1.0); }); } diff --git a/packages/clipper/src/index.ts b/packages/clipper/src/index.ts index 0b02c2814..5273968d5 100644 --- a/packages/clipper/src/index.ts +++ b/packages/clipper/src/index.ts @@ -24,6 +24,7 @@ import { getInlinedNode, toBlob, toJpeg, toPng } from "./domtoimage.js"; import { Config, InlineOptions } from "./types.js"; import { FetchOptions } from "./fetch.js"; import { addStylesToHead } from "./styles.js"; +import { inlineAllImages } from "./images.js"; type ReadabilityEnhanced = Readability & { PRESENTATIONAL_ATTRIBUTES: string[]; @@ -99,13 +100,16 @@ async function clipScreenshot< ): Promise { const screenshotTarget = target || document.body; + const fetchOptions = resolveFetchOptions(config); + await inlineAllImages(screenshotTarget, fetchOptions); + const func = output === "jpeg" ? toJpeg : output === "png" ? toPng : toBlob; const screenshot = await func(screenshotTarget, { quality: 1, backgroundColor: "white", width: document.body.scrollWidth, height: document.body.scrollHeight, - fetchOptions: resolveFetchOptions(config), + fetchOptions, inlineOptions: { inlineImages: true, fonts: true,