@napi-rs/canvas 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +34 -0
- package/README.md +30 -49
- package/geometry.js +166 -33
- package/index.d.ts +232 -47
- package/index.js +578 -25
- package/load-image.js +18 -12
- package/node-canvas.d.ts +6 -1
- package/node-canvas.js +22 -3
- package/package.json +13 -18
package/LICENSE
CHANGED
|
@@ -19,3 +19,37 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
src/svg_doc/broken_image.png is Chromium's broken-image icon
|
|
26
|
+
(third_party/blink/public/default_100_percent/blink/broken_image.png),
|
|
27
|
+
used under the Chromium license:
|
|
28
|
+
|
|
29
|
+
Copyright 2015 The Chromium Authors
|
|
30
|
+
|
|
31
|
+
Redistribution and use in source and binary forms, with or without
|
|
32
|
+
modification, are permitted provided that the following conditions are
|
|
33
|
+
met:
|
|
34
|
+
|
|
35
|
+
* Redistributions of source code must retain the above copyright
|
|
36
|
+
notice, this list of conditions and the following disclaimer.
|
|
37
|
+
* Redistributions in binary form must reproduce the above
|
|
38
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
39
|
+
in the documentation and/or other materials provided with the
|
|
40
|
+
distribution.
|
|
41
|
+
* Neither the name of Google LLC nor the names of its
|
|
42
|
+
contributors may be used to endorse or promote products derived from
|
|
43
|
+
this software without specific prior written permission.
|
|
44
|
+
|
|
45
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
46
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
47
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
48
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
49
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
50
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
51
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
52
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
53
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
54
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
55
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# `skr canvas`
|
|
2
2
|
|
|
3
3
|
[](https://github.com/Brooooooklyn/canvas/actions/workflows/CI.yaml)
|
|
4
|
-

|
|
5
5
|
[](https://packagephobia.com/result?p=@napi-rs/canvas)
|
|
6
6
|
[](https://npmcharts.com/compare/@napi-rs/canvas?minimal=true)
|
|
7
7
|
|
|
@@ -92,6 +92,34 @@ main()
|
|
|
92
92
|
|
|
93
93
|

|
|
94
94
|
|
|
95
|
+
## Image metadata
|
|
96
|
+
|
|
97
|
+
`toBuffer`, `encode` and `encodeSync` can write the resolution (DPI) and a few text fields into PNG and JPEG output. Put them in the options object:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const png = canvas.toBuffer('image/png', {
|
|
101
|
+
resolution: 300, // pixels per inch, the same option as node-canvas
|
|
102
|
+
title: 'Floor plan',
|
|
103
|
+
author: 'Jane Doe',
|
|
104
|
+
description: 'Ground floor, 1:100',
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// JPEG: use encode / encodeSync to set the quality as well
|
|
108
|
+
const jpeg = await canvas.encode('jpeg', { quality: 90, resolution: 300, copyright: '© 2026 Jane Doe' })
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| Option | PNG | JPEG |
|
|
112
|
+
| ------------- | ------------------ | ---------------------------- |
|
|
113
|
+
| `resolution` | `pHYs` chunk | JFIF density (dots per inch) |
|
|
114
|
+
| `title` | `Title` text chunk | XMP `dc:title` |
|
|
115
|
+
| `author` | `Author` | XMP `dc:creator` |
|
|
116
|
+
| `description` | `Description` | XMP `dc:description` |
|
|
117
|
+
| `copyright` | `Copyright` | XMP `dc:rights` |
|
|
118
|
+
| `software` | `Software` | XMP `xmp:CreatorTool` |
|
|
119
|
+
| `comment` | `Comment` | `COM` segment |
|
|
120
|
+
|
|
121
|
+
WebP, AVIF and GIF output ignore these options. `toDataURL`, `toDataURLAsync`, `toBlob`, `convertToBlob`, `encodeStream` and `savePng` never write metadata. To save a file with metadata, write the Buffer from `toBuffer` or `encode`. With an options object, `toBuffer('image/jpeg', ...)` encodes at quality 92; use `encode` or `encodeSync` for another quality.
|
|
122
|
+
|
|
95
123
|
## Emoji text
|
|
96
124
|
|
|
97
125
|
```js
|
|
@@ -121,53 +149,6 @@ writeFileSync(join(__dirname, 'draw-emoji.png'), b)
|
|
|
121
149
|
|
|
122
150
|

|
|
123
151
|
|
|
124
|
-
# Performance
|
|
125
|
-
|
|
126
|
-
See [benchmark](./benchmark) for benchmark code.
|
|
127
|
-
|
|
128
|
-
Hardware info:
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
,MMMM. Host - xxxxxxxxxxxxxxxxxxxxxxx
|
|
132
|
-
.MMMMMM Machine - Mac15,9
|
|
133
|
-
MMMMM, Kernel - 24.0.0
|
|
134
|
-
.;MMMMM:' MMMMMMMMMM;. OS - macOS 15.0.1 Sequoia
|
|
135
|
-
MMMMMMMMMMMMNWMMMMMMMMMMM: DE - Aqua
|
|
136
|
-
.MMMMMMMMMMMMMMMMMMMMMMMMWM. WM - Quartz Compositor
|
|
137
|
-
MMMMMMMMMMMMMMMMMMMMMMMMM. Packages - 194 (Homebrew), 32 (cargo)
|
|
138
|
-
;MMMMMMMMMMMMMMMMMMMMMMMM: Shell - zsh
|
|
139
|
-
:MMMMMMMMMMMMMMMMMMMMMMMM: Terminal - warpterminal (Version v0.2024.10.23.14.49.stable_00)
|
|
140
|
-
.MMMMMMMMMMMMMMMMMMMMMMMMM. Resolution - 5120x2880@160fps (as 2560x1440)
|
|
141
|
-
MMMMMMMMMMMMMMMMMMMMMMMMMMM. 2992x1934@120fps (as 1496x967)
|
|
142
|
-
.MMMMMMMMMMMMMMMMMMMMMMMMMM. 2232x1512@60fps (as 1116x756)
|
|
143
|
-
MMMMMMMMMMMMMMMMMMMMMMMM Uptime - 1d 2h 32m
|
|
144
|
-
;MMMMMMMMMMMMMMMMMMMM. CPU - Apple M3 Max (16)
|
|
145
|
-
.MMMM,. .MMMM,. CPU Load - 16%
|
|
146
|
-
Memory - 50.1 GB / 134.2 GB
|
|
147
|
-
Battery - 78% & Discharging
|
|
148
|
-
Disk Space - 624.0 GB / 994.7 GB
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
```
|
|
152
|
-
❯ yarn bench
|
|
153
|
-
Draw a House and export to PNG
|
|
154
|
-
┌─────────┬─────────────────┬───────────────────────┬──────────────────────────┬────────────────────────────┬───────────────────────────┬─────────┐
|
|
155
|
-
│ (index) │ Task name │ Latency average (ns) │ Latency median (ns) │ Throughput average (ops/s) │ Throughput median (ops/s) │ Samples │
|
|
156
|
-
├─────────┼─────────────────┼───────────────────────┼──────────────────────────┼────────────────────────────┼───────────────────────────┼─────────┤
|
|
157
|
-
│ 0 │ '@napi-rs/skia' │ '14676992.14 ± 0.68%' │ '14602333.00' │ '68 ± 0.59%' │ '68' │ 69 │
|
|
158
|
-
│ 1 │ 'skia-canvas' │ '21167809.17 ± 2.05%' │ '20960021.00 ± 13646.00' │ '47 ± 1.31%' │ '48' │ 64 │
|
|
159
|
-
│ 2 │ 'node-canvas' │ '16552027.42 ± 0.70%' │ '16451291.50 ± 2208.50' │ '60 ± 0.62%' │ '61' │ 64 │
|
|
160
|
-
└─────────┴─────────────────┴───────────────────────┴──────────────────────────┴────────────────────────────┴───────────────────────────┴─────────┘
|
|
161
|
-
Draw Gradient and export to PNG
|
|
162
|
-
┌─────────┬─────────────────┬───────────────────────┬─────────────────────────┬────────────────────────────┬───────────────────────────┬─────────┐
|
|
163
|
-
│ (index) │ Task name │ Latency average (ns) │ Latency median (ns) │ Throughput average (ops/s) │ Throughput median (ops/s) │ Samples │
|
|
164
|
-
├─────────┼─────────────────┼───────────────────────┼─────────────────────────┼────────────────────────────┼───────────────────────────┼─────────┤
|
|
165
|
-
│ 0 │ '@napi-rs/skia' │ '15228495.58 ± 0.53%' │ '15146312.50 ± 1187.50' │ '66 ± 0.48%' │ '66' │ 66 │
|
|
166
|
-
│ 1 │ 'skia-canvas' │ '21725564.41 ± 2.20%' │ '21412520.50 ± 2104.50' │ '46 ± 1.39%' │ '47' │ 64 │
|
|
167
|
-
│ 2 │ 'node-canvas' │ '17976022.14 ± 1.53%' │ '17563479.50 ± 5104.50' │ '56 ± 1.38%' │ '57' │ 64 │
|
|
168
|
-
└─────────┴─────────────────┴───────────────────────┴─────────────────────────┴────────────────────────────┴───────────────────────────┴─────────┘
|
|
169
|
-
```
|
|
170
|
-
|
|
171
152
|
# Features
|
|
172
153
|
|
|
173
154
|
## Path2D
|
|
@@ -411,7 +392,7 @@ $ node scripts/build-skia.js
|
|
|
411
392
|
|
|
412
393
|
# Install NPM packages, build the Node.js addon:
|
|
413
394
|
$ npm install -g yarn
|
|
414
|
-
$ yarn install --mode=skip-build #
|
|
395
|
+
$ yarn install --mode=skip-build # `canvas` (node-canvas) is a native module that only the node-canvas compat tests use and is hard to install, you can skip building it by specifying `--mode=skip-build`
|
|
415
396
|
$ sudo dnf install clang # https://fedora.pkgs.org/34/fedora-x86_64/clang-12.0.0-0.3.rc1.fc34.x86_64.rpm.html
|
|
416
397
|
$ yarn build
|
|
417
398
|
|
package/geometry.js
CHANGED
|
@@ -26,20 +26,17 @@ class DOMPoint {
|
|
|
26
26
|
)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// matrixTransform(optional DOMMatrixInit matrix = {})
|
|
29
30
|
matrixTransform(matrix) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.x * matrix.b + this.y * matrix.d + matrix.f,
|
|
34
|
-
0,
|
|
35
|
-
1,
|
|
36
|
-
)
|
|
31
|
+
const { values: m, is2D } = matrixFromInit(matrix, MATRIX_TRANSFORM)
|
|
32
|
+
if (is2D && this.z === 0 && this.w === 1) {
|
|
33
|
+
return new DOMPoint(this.x * m[M11] + this.y * m[M21] + m[M41], this.x * m[M12] + this.y * m[M22] + m[M42], 0, 1)
|
|
37
34
|
} else {
|
|
38
35
|
return new DOMPoint(
|
|
39
|
-
this.x *
|
|
40
|
-
this.x *
|
|
41
|
-
this.x *
|
|
42
|
-
this.x *
|
|
36
|
+
this.x * m[M11] + this.y * m[M21] + this.z * m[M31] + this.w * m[M41],
|
|
37
|
+
this.x * m[M12] + this.y * m[M22] + this.z * m[M32] + this.w * m[M42],
|
|
38
|
+
this.x * m[M13] + this.y * m[M23] + this.z * m[M33] + this.w * m[M43],
|
|
39
|
+
this.x * m[M14] + this.y * m[M24] + this.z * m[M34] + this.w * m[M44],
|
|
43
40
|
)
|
|
44
41
|
}
|
|
45
42
|
}
|
|
@@ -211,6 +208,152 @@ const newInstance = (values) => {
|
|
|
211
208
|
return instance
|
|
212
209
|
}
|
|
213
210
|
|
|
211
|
+
// DOMMatrixInit dictionaries (Geometry Interfaces 1: "validate and fixup",
|
|
212
|
+
// "create a DOMMatrix from the dictionary"), with Chrome's errors.
|
|
213
|
+
//
|
|
214
|
+
// matrixFromInit(init, prefix)
|
|
215
|
+
// DOMMatrix -> its values and is2D
|
|
216
|
+
// undefined / null -> {}
|
|
217
|
+
// other non-object -> TypeError "not of type 'DOMMatrixInit'"
|
|
218
|
+
// object -> read members (toMatrixInit), validate and fix up
|
|
219
|
+
|
|
220
|
+
const FROM_MATRIX = "Failed to execute 'fromMatrix' on 'DOMMatrix': "
|
|
221
|
+
const MULTIPLY = "Failed to execute 'multiply' on 'DOMMatrixReadOnly': "
|
|
222
|
+
const MULTIPLY_SELF = "Failed to execute 'multiplySelf' on 'DOMMatrix': "
|
|
223
|
+
const PRE_MULTIPLY_SELF = "Failed to execute 'preMultiplySelf' on 'DOMMatrix': "
|
|
224
|
+
const MATRIX_TRANSFORM = "Failed to execute 'matrixTransform' on 'DOMPointReadOnly': "
|
|
225
|
+
|
|
226
|
+
// The members in the order Chrome reads them: the inherited dictionary's
|
|
227
|
+
// first, each dictionary's in lexicographic order.
|
|
228
|
+
const MATRIX_2D_INIT_MEMBERS = ['a', 'b', 'c', 'd', 'e', 'f', 'm11', 'm12', 'm21', 'm22', 'm41', 'm42']
|
|
229
|
+
const MATRIX_INIT_MEMBERS = ['m13', 'm14', 'm23', 'm24', 'm31', 'm32', 'm33', 'm34', 'm43', 'm44']
|
|
230
|
+
// [alias, member, default]: validate and fixup (2D).
|
|
231
|
+
const MATRIX_2D_ALIASES = [
|
|
232
|
+
['a', 'm11', 1],
|
|
233
|
+
['b', 'm12', 0],
|
|
234
|
+
['c', 'm21', 0],
|
|
235
|
+
['d', 'm22', 1],
|
|
236
|
+
['e', 'm41', 0],
|
|
237
|
+
['f', 'm42', 0],
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
const isObject = (value) => value !== null && (typeof value === 'object' || typeof value === 'function')
|
|
241
|
+
|
|
242
|
+
// ECMAScript ToNumber, written out so that the errors it throws itself can
|
|
243
|
+
// get Chrome's context (`fail`), while the errors thrown by user code
|
|
244
|
+
// (valueOf, toString, @@toPrimitive) pass through unchanged, as in Chrome.
|
|
245
|
+
// V8's messages; an object in a message is shown as #<Object>.
|
|
246
|
+
function toNumber(value, fail) {
|
|
247
|
+
if (!isObject(value)) {
|
|
248
|
+
if (typeof value === 'bigint') throw fail('Cannot convert a BigInt value to a number')
|
|
249
|
+
if (typeof value === 'symbol') throw fail('Cannot convert a Symbol value to a number')
|
|
250
|
+
return +value
|
|
251
|
+
}
|
|
252
|
+
const toPrimitive = value[Symbol.toPrimitive]
|
|
253
|
+
if (toPrimitive !== undefined && toPrimitive !== null) {
|
|
254
|
+
if (typeof toPrimitive !== 'function') {
|
|
255
|
+
const shown = isObject(toPrimitive) ? '#<Object>' : String(toPrimitive)
|
|
256
|
+
throw fail(
|
|
257
|
+
`'${shown}' returned for property 'Symbol(Symbol.toPrimitive)' of object '#<Object>' is not a function`,
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
const primitive = toPrimitive.call(value, 'number')
|
|
261
|
+
if (isObject(primitive)) throw fail('Cannot convert object to primitive value')
|
|
262
|
+
return toNumber(primitive, fail)
|
|
263
|
+
}
|
|
264
|
+
for (const name of ['valueOf', 'toString']) {
|
|
265
|
+
const method = value[name]
|
|
266
|
+
if (typeof method === 'function') {
|
|
267
|
+
const primitive = method.call(value)
|
|
268
|
+
if (!isObject(primitive)) return toNumber(primitive, fail)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
throw fail('Cannot convert object to primitive value')
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// WebIDL conversion to a DOMMatrixInit: the present members only.
|
|
275
|
+
function toMatrixInit(init, prefix) {
|
|
276
|
+
const dict = Object.create(null)
|
|
277
|
+
if (init === undefined || init === null) return dict
|
|
278
|
+
if (!isObject(init)) throw new TypeError(`${prefix}The provided value is not of type 'DOMMatrixInit'.`)
|
|
279
|
+
const read = (key, dictionary) => {
|
|
280
|
+
const value = init[key]
|
|
281
|
+
if (value !== undefined) {
|
|
282
|
+
dict[key] = toNumber(
|
|
283
|
+
value,
|
|
284
|
+
(msg) => new TypeError(`${prefix}Failed to read the '${key}' property from '${dictionary}': ${msg}`),
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (const key of MATRIX_2D_INIT_MEMBERS) read(key, 'DOMMatrix2DInit')
|
|
289
|
+
const is2D = init.is2D
|
|
290
|
+
if (is2D !== undefined) dict.is2D = Boolean(is2D)
|
|
291
|
+
for (const key of MATRIX_INIT_MEMBERS) read(key, 'DOMMatrixInit')
|
|
292
|
+
return dict
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const sameValueZero = (x, y) => x === y || (x !== x && y !== y)
|
|
296
|
+
|
|
297
|
+
// { values, is2D } of the matrix `init` describes. `values` may be the
|
|
298
|
+
// DOMMatrix's own array: read it, do not write it.
|
|
299
|
+
function matrixFromInit(init, prefix) {
|
|
300
|
+
if (init instanceof DOMMatrix && init[VALUES] instanceof Float64Array) {
|
|
301
|
+
return { values: init[VALUES], is2D: init[IS_2D] }
|
|
302
|
+
}
|
|
303
|
+
const dict = toMatrixInit(init, prefix)
|
|
304
|
+
// validate and fixup (2D)
|
|
305
|
+
for (const [alias, member] of MATRIX_2D_ALIASES) {
|
|
306
|
+
if (alias in dict && member in dict && !sameValueZero(dict[alias], dict[member])) {
|
|
307
|
+
throw new TypeError(`${prefix}Property mismatch on matrix initialization.`)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
for (const [alias, member, defaultValue] of MATRIX_2D_ALIASES) {
|
|
311
|
+
if (!(member in dict)) dict[member] = alias in dict ? dict[alias] : defaultValue
|
|
312
|
+
}
|
|
313
|
+
// validate and fixup: the members default to the identity.
|
|
314
|
+
const value = (key) => (key in dict ? dict[key] : key === 'm33' || key === 'm44' ? 1 : 0)
|
|
315
|
+
const is3D =
|
|
316
|
+
['m13', 'm14', 'm23', 'm24', 'm31', 'm32', 'm34', 'm43'].some((key) => value(key) !== 0) ||
|
|
317
|
+
value('m33') !== 1 ||
|
|
318
|
+
value('m44') !== 1
|
|
319
|
+
if (dict.is2D === true && is3D) {
|
|
320
|
+
throw new TypeError(`${prefix}The is2D member is set to true but the input matrix is a 3d matrix.`)
|
|
321
|
+
}
|
|
322
|
+
const is2D = dict.is2D === undefined ? !is3D : dict.is2D
|
|
323
|
+
const { m11, m12, m21, m22, m41, m42 } = dict
|
|
324
|
+
const values = is2D
|
|
325
|
+
? [m11, m12, 0, 0, m21, m22, 0, 0, 0, 0, 1, 0, m41, m42, 0, 1]
|
|
326
|
+
: [
|
|
327
|
+
m11,
|
|
328
|
+
m12,
|
|
329
|
+
value('m13'),
|
|
330
|
+
value('m14'),
|
|
331
|
+
m21,
|
|
332
|
+
m22,
|
|
333
|
+
value('m23'),
|
|
334
|
+
value('m24'),
|
|
335
|
+
value('m31'),
|
|
336
|
+
value('m32'),
|
|
337
|
+
value('m33'),
|
|
338
|
+
value('m34'),
|
|
339
|
+
m41,
|
|
340
|
+
m42,
|
|
341
|
+
value('m43'),
|
|
342
|
+
value('m44'),
|
|
343
|
+
]
|
|
344
|
+
return { values: new Float64Array(values), is2D }
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// `target` times (post) or after (pre) the matrix `other` describes.
|
|
348
|
+
function multiplyByInit(target, other, prefix, post) {
|
|
349
|
+
const { values, is2D } = matrixFromInit(other, prefix)
|
|
350
|
+
target[VALUES] = post ? multiply(values, target[VALUES]) : multiply(target[VALUES], values)
|
|
351
|
+
if (!is2D) {
|
|
352
|
+
target[IS_2D] = false
|
|
353
|
+
}
|
|
354
|
+
return target
|
|
355
|
+
}
|
|
356
|
+
|
|
214
357
|
const multiply = (first, second) => {
|
|
215
358
|
const dest = new Float64Array(16)
|
|
216
359
|
|
|
@@ -391,14 +534,13 @@ class DOMMatrix {
|
|
|
391
534
|
)
|
|
392
535
|
}
|
|
393
536
|
|
|
537
|
+
// fromMatrix(optional DOMMatrixInit other = {})
|
|
394
538
|
static fromMatrix(init) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
throw new TypeError('Expected DOMMatrix')
|
|
401
|
-
}
|
|
539
|
+
const { values, is2D } = matrixFromInit(init, FROM_MATRIX)
|
|
540
|
+
const matrix = new DOMMatrix()
|
|
541
|
+
matrix[VALUES] = new Float64Array(values)
|
|
542
|
+
matrix[IS_2D] = is2D
|
|
543
|
+
return matrix
|
|
402
544
|
}
|
|
403
545
|
|
|
404
546
|
static fromFloat32Array(init) {
|
|
@@ -513,28 +655,19 @@ class DOMMatrix {
|
|
|
513
655
|
}
|
|
514
656
|
}
|
|
515
657
|
|
|
658
|
+
// multiply, multiplySelf, preMultiplySelf(optional DOMMatrixInit other = {})
|
|
516
659
|
multiply(other) {
|
|
517
|
-
|
|
660
|
+
const result = newInstance(this[VALUES])
|
|
661
|
+
result[IS_2D] = this[IS_2D]
|
|
662
|
+
return multiplyByInit(result, other, MULTIPLY, true)
|
|
518
663
|
}
|
|
519
664
|
|
|
520
665
|
multiplySelf(other) {
|
|
521
|
-
this
|
|
522
|
-
|
|
523
|
-
if (!other.is2D) {
|
|
524
|
-
this[IS_2D] = false
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
return this
|
|
666
|
+
return multiplyByInit(this, other, MULTIPLY_SELF, true)
|
|
528
667
|
}
|
|
529
668
|
|
|
530
669
|
preMultiplySelf(other) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
if (!other.is2D) {
|
|
534
|
-
this[IS_2D] = false
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
return this
|
|
670
|
+
return multiplyByInit(this, other, PRE_MULTIPLY_SELF, false)
|
|
538
671
|
}
|
|
539
672
|
|
|
540
673
|
translate(tx, ty, tz) {
|