From b3d95d93074621fa8bccd6094750adcd075f393a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arno=C5=A1t=20Pleskot?= Date: Fri, 16 Jun 2023 23:49:28 +0200 Subject: [PATCH] feat: use upng --- package.json | 4 +-- src/data/blob.ts | 81 ++++++++---------------------------------------- src/global.d.ts | 4 --- yarn.lock | 26 ++++++++-------- 4 files changed, 28 insertions(+), 87 deletions(-) diff --git a/package.json b/package.json index b2be70aa3..8e2bb2b7e 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "png-chunk-text": "1.0.0", "png-chunks-encode": "1.0.0", "png-chunks-extract": "1.0.0", - "pngjs": "7.0.0", "points-on-curve": "0.2.0", "pwacompat": "2.0.17", "react": "18.2.0", @@ -54,6 +53,7 @@ "sass": "1.51.0", "socket.io-client": "2.3.1", "tunnel-rat": "0.1.2", + "upng-js": "2.1.0", "workbox-background-sync": "^6.5.4", "workbox-broadcast-update": "^6.5.4", "workbox-cacheable-response": "^6.5.4", @@ -75,11 +75,11 @@ "@types/lodash.throttle": "4.1.7", "@types/pako": "1.0.3", "@types/pica": "5.1.3", - "@types/pngjs": "6.0.1", "@types/react": "18.0.15", "@types/react-dom": "18.0.6", "@types/resize-observer-browser": "0.1.7", "@types/socket.io-client": "1.4.36", + "@types/upng-js": "2.1.2", "chai": "4.3.6", "dotenv": "16.0.1", "eslint-config-prettier": "8.5.0", diff --git a/src/data/blob.ts b/src/data/blob.ts index 1da33575b..4b85a549d 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -13,7 +13,7 @@ import { FileSystemHandle, nativeFileSystemSupported } from "./filesystem"; import { isValidExcalidrawData, isValidLibrary } from "./json"; import { restore, restoreLibraryItems } from "./restore"; import { ImportedLibraryData } from "./types"; -import { PNG } from "pngjs/browser"; +import UPNG from "upng-js"; const parseFileContents = async (blob: Blob | File) => { let contents: string; @@ -234,81 +234,26 @@ const _canvasToBlob = async (canvas: HTMLCanvasElement): Promise => { export const canvasToBlob = async ( canvas: HTMLCanvasElement, ): Promise => { - const tileWidth = 1000; - const tileHeight = 1000; - const tileDataArray: Uint8ClampedArray[][] = []; // Two-dimensional array to store tile data - - const { width: canvasWidth, height: canvasHeight } = canvas; - const ctx = canvas.getContext("2d"); if (!ctx) { throw new Error("No canvas context"); } - // Function to process each tile - function processTile(tileX: number, tileY: number) { - // Calculate the starting and ending coordinates for the tile - const startX = tileX * tileWidth; - const startY = tileY * tileHeight; - const endX = Math.min(startX + tileWidth, canvasWidth); - const endY = Math.min(startY + tileHeight, canvasHeight); - - // Get the image data for the tile directly from the main canvas - const imageData = ctx!.getImageData( - startX, - startY, - endX - startX, - endY - startY, - ).data; - - // Store the tile data in the two-dimensional array - tileDataArray[tileY] = tileDataArray[tileY] || []; - tileDataArray[tileY][tileX] = imageData; - } + console.time("getImageData"); + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + console.timeEnd("getImageData"); - console.time("tiling"); - // Iterate over the tiles and process each one - for (let tileY = 0; tileY < canvasHeight / tileHeight; tileY++) { - for (let tileX = 0; tileX < canvasWidth / tileWidth; tileX++) { - processTile(tileX, tileY); - } - } - console.timeEnd("tiling"); - - console.time("create png"); - // Create a new PNG image with the final dimensions - const finalImage = new PNG({ width: canvasWidth, height: canvasHeight }); - console.timeEnd("create png"); - - console.time("concat tiles"); - // Merge the tiles into the final image - for (let tileY = 0; tileY < canvasHeight / tileHeight; tileY++) { - for (let tileX = 0; tileX < canvasWidth / tileWidth; tileX++) { - const imageData = tileDataArray[tileY][tileX]; - const destX = tileX * tileWidth; - const destY = tileY * tileHeight; - - // Copy the pixels from the tile to the final image - for (let y = 0; y < tileHeight; y++) { - for (let x = 0; x < tileWidth; x++) { - const index = (y * tileWidth + x) * 4; - const destIndex = ((destY + y) * canvasWidth + destX + x) * 4; - finalImage.data[destIndex] = imageData[index]; - finalImage.data[destIndex + 1] = imageData[index + 1]; - finalImage.data[destIndex + 2] = imageData[index + 2]; - finalImage.data[destIndex + 3] = imageData[index + 3]; - } - } - } - } - console.timeEnd("concat tiles"); - - console.time("create buffer"); - const buffer = PNG.sync.write(finalImage); - console.timeEnd("create buffer"); + console.time("encode"); + const pngData = UPNG.encode( + [imageData.buffer], + canvas.width, + canvas.height, + 0, + ); + console.timeEnd("encode"); - return new Blob([buffer], { type: "image/png" }); + return new Blob([pngData], { type: "image/png" }); }; /** generates SHA-1 digest from supplied file (if not supported, falls back diff --git a/src/global.d.ts b/src/global.d.ts index feb8c2f46..3a666e11a 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -120,7 +120,3 @@ declare module "image-blob-reduce" { const reduce: ImageBlobReduce.ImageBlobReduceStatic; export = reduce; } - -declare module "pngjs/browser" { - export { PNG } from "pngjs"; -} diff --git a/yarn.lock b/yarn.lock index 2dbe1dea5..0d665cfcc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2714,13 +2714,6 @@ resolved "https://registry.yarnpkg.com/@types/pica/-/pica-5.1.3.tgz#5ef64529a1f83f7d6586a8bf75a8a00be32aca02" integrity sha512-13SEyETRE5psd9bE0AmN+0M1tannde2fwHfLVaVIljkbL9V0OfFvKwCicyeDvVYLkmjQWEydbAlsDsmjrdyTOg== -"@types/pngjs@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-6.0.1.tgz#c711ec3fbbf077fed274ecccaf85dd4673130072" - integrity sha512-J39njbdW1U/6YyVXvC9+1iflZghP8jgRf2ndYghdJb5xL49LYDB+1EuAxfbuJ2IBbWIL3AjHPQhgaTxT3YaYeg== - dependencies: - "@types/node" "*" - "@types/prettier@^2.1.5": version "2.7.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" @@ -2858,6 +2851,11 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== +"@types/upng-js@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/upng-js/-/upng-js-2.1.2.tgz#4680f700c3003eaf958b92418c6e19521bb1e034" + integrity sha512-sxCnLDEmGFDcnrdSMml3/mDSbfSAvt86Ld32J6Ac75Og7GzzmwHbUnJNTue74tfQC/3PPD/W0jG2dQuF9v6UOg== + "@types/ws@^8.5.1": version "8.5.4" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" @@ -8041,7 +8039,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@1.0.11: +pako@1.0.11, pako@^1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -8234,11 +8232,6 @@ png-chunks-extract@1.0.0: dependencies: crc-32 "^0.3.0" -pngjs@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" - integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== - points-on-curve@0.2.0, points-on-curve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1" @@ -10569,6 +10562,13 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" +upng-js@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/upng-js/-/upng-js-2.1.0.tgz#7176e73973db361ca95d0fa14f958385db6b9dd2" + integrity sha512-d3xzZzpMP64YkjP5pr8gNyvBt7dLk/uGI67EctzDuVp4lCZyVMo0aJO6l/VDlgbInJYDY6cnClLoBp29eKWI6g== + dependencies: + pako "^1.0.5" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"