|
1 | 1 | import UPNG from './UPNG' |
| 2 | +import Bowser from "bowser"; |
| 3 | +import MaxCanvasSize from './config/max-canvas-size' |
2 | 4 |
|
3 | 5 | const isBrowser = typeof window !== 'undefined' // change browser environment to support SSR |
4 | 6 |
|
@@ -102,14 +104,54 @@ export function loadImage (src) { |
102 | 104 | }) |
103 | 105 | } |
104 | 106 |
|
| 107 | +/** |
| 108 | + * approximateBelowCanvasMaximumSizeOfBrowser |
| 109 | + * |
| 110 | + * it uses binary search to converge below the browser's maximum Canvas size. |
| 111 | + * |
| 112 | + * ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size |
| 113 | + * |
| 114 | + * @param {number} initWidth |
| 115 | + * @param {number} initHeight |
| 116 | + * @returns {object} |
| 117 | + */ |
| 118 | +function approximateBelowMaximumCanvasSizeOfBrowser(initWidth, initHeight) { |
| 119 | + const browserName = getBrowserName() |
| 120 | + const maximumCanvasSize = MaxCanvasSize[browserName] |
| 121 | + |
| 122 | + let width = initWidth; |
| 123 | + let height = initHeight |
| 124 | + let size = width * height |
| 125 | + const ratio = width > height ? height / width : width / height |
| 126 | + |
| 127 | + while(size > maximumCanvasSize * maximumCanvasSize) { |
| 128 | + const halfSizeWidth = (maximumCanvasSize + width) / 2; |
| 129 | + const halfSizeHeight = (maximumCanvasSize + height) / 2; |
| 130 | + if(halfSizeWidth < halfSizeHeight) { |
| 131 | + height = halfSizeHeight |
| 132 | + width = halfSizeHeight * ratio |
| 133 | + } else { |
| 134 | + height = halfSizeWidth * ratio |
| 135 | + width = halfSizeWidth |
| 136 | + } |
| 137 | + |
| 138 | + size = width * height |
| 139 | + } |
| 140 | + |
| 141 | + return { |
| 142 | + width, height |
| 143 | + } |
| 144 | +} |
| 145 | + |
105 | 146 | /** |
106 | 147 | * drawImageInCanvas |
107 | 148 | * |
108 | 149 | * @param {HTMLImageElement} img |
109 | 150 | * @returns {HTMLCanvasElement | OffscreenCanvas} |
110 | 151 | */ |
111 | 152 | export function drawImageInCanvas (img) { |
112 | | - const [canvas, ctx] = getNewCanvasAndCtx(img.width, img.height) |
| 153 | + const {width, height} = approximateBelowMaximumCanvasSizeOfBrowser(img.width, img.height) |
| 154 | + const [canvas, ctx] = getNewCanvasAndCtx(width, height) |
113 | 155 | ctx.drawImage(img, 0, 0, canvas.width, canvas.height) |
114 | 156 | return canvas |
115 | 157 | } |
@@ -350,3 +392,20 @@ if (isBrowser) { |
350 | 392 | Math.floor(value) === value |
351 | 393 | } |
352 | 394 | } |
| 395 | + |
| 396 | +/** |
| 397 | + * getBrowserName |
| 398 | + * |
| 399 | + * Extracts the browser name from the useragent. |
| 400 | + * |
| 401 | + * @returns {string} |
| 402 | + */ |
| 403 | +export function getBrowserName() { |
| 404 | + const browserName = Bowser.parse(globalThis.navigator.userAgent).browser.name || '' |
| 405 | + const lowerCasedBrowserName = browserName.toLowerCase() |
| 406 | + if(['chrome', 'safari', 'firefox'].includes(lowerCasedBrowserName)) { |
| 407 | + return lowerCasedBrowserName |
| 408 | + } |
| 409 | + |
| 410 | + return 'etc' |
| 411 | +} |
0 commit comments