|
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