Initial Commit

This commit is contained in:
2026-01-15 21:52:12 +01:00
committed by erik
parent 3ed42cdeb6
commit 5a70f775f1
6702 changed files with 1389544 additions and 0 deletions

21
node_modules/loupedeck/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 foxxyz (Ivo Janssen <hello@ivo.la>)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

357
node_modules/loupedeck/README.md generated vendored Normal file
View File

@@ -0,0 +1,357 @@
Loupedeck: Node.js Interface
============================
![tests](https://github.com/foxxyz/loupedeck/actions/workflows/nodejs.yml/badge.svg?branch=master)
Unofficial Node.js API for [Loupedeck Live](https://loupedeck.com/products/loupedeck-live/), [Loupedeck Live S](https://loupedeck.com/products/loupedeck-live-s/), [Loupedeck CT](https://loupedeck.com/us/products/loupedeck-ct/) and [Razer Stream](https://www.razer.com/streaming-accessories/razer-stream-controller) controllers.
![Loupedeck Live Interface](/docs/live-front-small.png?raw=true)
![Razer Stream Controller Interface](/docs/rsc-front-small.png?raw=true)
![Razer Stream Controller X Interface](/docs/rscx-front-small.png?raw=true)
![Loupedeck Live S Interface](/docs/live-s-front-small.png?raw=true)
![Loupedeck CT Interface](/docs/ct-front-small.png?raw=true)
Supports:
* Reading button presses
* Reading knob turns
* Reading touch events
* Setting button colors
* Setting screen brightness
* Vibrating device
* Writing screen graphics
Requirements
------------
* Node 20+
* Supported Devices:
* Loupedeck Live
* Loupedeck Live S
* Loupedeck CT
* Razer Stream Controller (_"RSC"_)
* Razer Stream Controller X (_"RSCX"_)
This library has been tested with firmware versions 0.1.3, 0.1.79, 0.2.5, 0.2.8 and 0.2.23. Other versions may work.
**Note: Firmware version 0.2.26 does not seem to work on Linux. Recommendation is to downgrade to 0.2.23 (see #30)**
Installation
------------
```shell
npm install loupedeck
```
By default, Loupdeck devices uses RGB565 (16-bit) buffers for drawing (with small exceptions, see below), so the [`canvas` module](https://www.npmjs.com/package/canvas) is used to enable a more pleasant API that allows for drawing using [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) callbacks.
Usage Examples
--------------
_Note: Ensure Loupedeck software is not running as it may conflict with this library_
### Automatic Discovery
```javascript
import { discover } from 'loupedeck'
// Detects and opens first connected device
const device = await discover()
// Observe connect events
device.on('connect', () => {
console.info('Connection successful!')
})
// React to button presses
device.on('down', ({ id }) => {
console.info(`Button pressed: ${id}`)
})
// React to knob turns
device.on('rotate', ({ id, delta }) => {
console.info(`Knob ${id} rotated: ${delta}`)
})
```
### Manual Instantiation
```javascript
import { LoupedeckLiveS } from 'loupedeck'
const device = new LoupedeckLiveS({ path: '/dev/tty.usbmodem101', autoConnect: false })
await device.connect()
console.info('Connection successful!')
device.on('down', ({ id }) => {
console.info(`Button pressed: ${id}`)
})
```
For all examples, see the [`examples` folder](/examples/). Running some examples requires `canvas` to be installed (see above).
📝 API Docs
-----------
### `discover() : Promise<LoupedeckDevice>`
Find the first connected Loupedeck device and return it.
Returns an instance of `LoupedeckLive`, `LoupedeckLiveS`, `LoupedeckCT`, `RazerStreamController`, `RazerStreamControllerX`, or throws an `Error` in case none or unsupported devices are found.
### Class `LoupedeckLive`
Implements and supports all methods from the [`LoupedeckDevice` interface](#interface-loupedeckdevice).
#### `new LoupedeckLive({ path : String?, host : String?, autoConnect : Boolean? })`
Create a new Loupedeck Live device interface.
Most use-cases should omit the `host`/`path` parameter, unless you're using multiple devices or know specifically which IP or device path you want to connect to. Either use `path` OR `host`, never both.
- `path`: **(Firmware 0.2.X only)** Serial device path (example: `/dev/cu.ttymodem-1332` or `COM2`) (default: autodiscover)
- `host`: **(Firmware 0.1.X only)** Host or IP address to connect to (example: `127.100.1.1`) (default: autodiscover)
- `autoConnect`: Automatically connect during construction. (default: `true`) _Set to `false` if you'd prefer to call [`connect()`](#deviceconnect--promise). yourself._
- `reconnectInterval`: How many milliseconds to wait before attempting a reconnect after a failed connection (default: `3000`) _Set to `false` to turn off automatic reconnects._
### Class `LoupedeckCT`
Same interface as [`LoupedeckLive`](#class-loupedecklive).
### Class `LoupedeckLiveS`
Same interface as [`LoupedeckLive`](#class-loupedecklive).
### Class `RazerStreamController`
Same interface as [`LoupedeckLive`](#class-loupedecklive).
### Class `RazerStreamControllerX`
Same interface as [`LoupedeckLive`](#class-loupedecklive).
Does not implement vibration or button colors.
### Interface `LoupedeckDevice`
Shared device interface. Do not instantiate this manually, use one of the above classes instead or the [`discover()` function](#discover--promiseloupedeckdevice).
All incoming messages are emitted as action events and can be subscribed to via `device.on()`.
### `LoupedeckDevice.list({ ignoreSerial : Boolean?, ignoreWebsocket : Boolean?} = {}) : Promise<Array>`
Static method to scan for and return a list of all detected devices. This includes ones which are already opened.
- `ignoreSerial`: Ignore devices which operate over serial (Firmware 0.2.X) (default: false)
- `ignoreWebsocket`: Ignore devices which operate over websocket (Firmware 0.1.X) (default: false)
Device info can be directly passed on to the constructor below.
#### Event: `'connect'`
Emitted when connection to the device succeeds. Includes an info object containing:
- `address`: Connection address (E.G. serial path or websocket address)
#### Event: `'disconnect'`
Emitted when a device disconnects for any reason. First argument for the event is an `Error` object in case of an abnormal disconnect (otherwise `undefined`).
#### Event: `'down'`
Emitted when a button or knob is pressed down.
Arguments:
- `id`: Button ID ([see `constants.js` for possible IDs](/constants.js#L3))
#### Event: `'rotate'`
Emitted when a knob is rotated.
Arguments:
- `id`: Button ID ([see `constants.js` for possible IDs](/constants.js#L3))
- `delta`: Rotation direction, `-1` for counter-clockwise, `1` for clockwise.
#### Event: `'touchstart'`
Emitted when any part of the screen is touched for the first time.
Arguments:
- `changedTouches`: Array of new [touches](#touch-objects) created during this event
- `touches`: Array of all currently held [touches](#touch-objects) on screen
#### Event: `'touchmove'`
Emitted when a touch moves across the screen.
Arguments:
- `changedTouches`: Array of [touches](#touch-objects) changed during this event
- `touches`: Array of all currently held [touches](#touch-objects) on screen
#### Event: `'touchend'`
Emitted when a touch is no longer detected.
Arguments:
- `changedTouches`: Array of [touches](#touch-objects) removed during this event
- `touches`: Array of all currently held [touches](#touch-objects) on screen (if any)
#### Event: `'up'`
Emitted when a button or knob is released.
Arguments:
- `id`: Button ID ([see `constants.js` for possible IDs](/constants.js#L3))
#### `device.close() : Promise`
Close device connection.
Returns Promise which resolves once the device has been closed.
#### `device.connect() : Promise`
Manually connect. Resolves on success.
#### `device.drawBuffer({ id : String, width : Number, height : Number, x? : Number, y? : Number, autoRefresh? : Boolean }, buffer : Buffer) : Promise`
Draw graphics to a particular area using a RGB16-565 pixel buffer.
Lower-level method if [`drawKey()`](#devicedrawkeykey--number-buffercallback--bufferfunction--promise) or [`drawScreen()`](#devicedrawscreenscreenid--string-buffercallback--bufferfunction--promise) don't meet your needs.
- `id`: Screen to write to [`left`, `center`, `right`, `knob`] _(`left` and `right` available on Loupedeck Live / RSC only)_ _(`knob` available on Loupedeck CT only)_
- `width`: Width of area to draw
- `height`: Height of area to draw
- `x`: Starting X offset (default: `0`)
- `y`: Starting Y offset (default: `0`)
- `autoRefresh`: Whether to refresh the screen after drawing (default: `true`)
- `buffer`: RGB16-565 Buffer. Should be `width * height * 2` bytes long, with each pixel represented by 2 bytes (5 bits red, 6 bits green, 5 bits blue) in little-endian (LE). _Note: Loupedeck CT knob screen is the only exception, it uses big-endian (BE)_
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.drawCanvas({ id : String, width : Number, height : Number, x? : Number, y? : Number, autoRefresh? : Boolean }, callback : Function) : Promise`
Draw graphics to a particular area using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D).
Lower-level method if [`drawKey()`](#devicedrawkeykey--number-buffercallback--bufferfunction--promise) or [`drawScreen()`](#devicedrawscreenscreenid--string-buffercallback--bufferfunction--promise) don't meet your needs.
- `id`: Screen to write to [`left`, `center`, `right`, `knob`] _(`left` and `right` available on Loupedeck Live / RSC only)_ _(`knob` available on Loupedeck CT only)_
- `width`: Width of area to draw
- `height`: Height of area to draw
- `x`: Starting X offset (default: `0`)
- `y`: Starting Y offset (default: `0`)
- `autoRefresh`: Whether to refresh the screen after drawing (default: `true`)
- `callback`: Function to handle draw calls. Receives the following arguments:
1. `context`: [2d canvas graphics context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
2. `width`: Width of drawing area
3. `height`: Height of drawing area
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.drawKey(key : Number, buffer/callback : Buffer/Function) : Promise`
Draw graphics to a specific key.
Second argument can be either a RGB16-565 buffer or a callback. Width and height of callback will typically be `90`, as keys are mostly 90x90px (_RSCX_ being the exception - those keys are 96x96px).
- `key`: Key index to write to ([0-11] on _Loupedeck Live/Loupedeck CT/RSC_, [0-14] on _Loupedeck Live S_ and _RSCX_)
- `buffer`: RGB16-565 Buffer
- `callback`: Function to handle draw calls. Receives the following arguments:
1. `context`: [2d canvas graphics context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
2. `width`: Width of drawing area
3. `height`: Height of drawing area
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.drawScreen(screenID : String, buffer/callback : Buffer/Function) : Promise`
Draw graphics to a specific screen. Screen sizes are as follows:
Loupedeck CT:
* `left`: 60x270px
* `center`: 360x270px
* `right`: 60x270px
* `knob`: 240x240px _(Note: uses big-endian byte order!)_
Loupedeck Live / Razer Stream Controller:
* `left`: 60x270px
* `center`: 360x270px
* `right`: 60x270px
Loupedeck Live S:
* `center`: 480x270px
Razer Stream Controller X:
* `center`: 480x288px
Second argument can be either a RGB16-565 buffer or a callback.
- `screenID`: Screen to write to [`left`, `center`, `right`, `knob`] _(`left` and `right` available on Loupedeck Live and Razer Stream Controller only)_ _(`knob` available on Loupedeck CT only)_
- `buffer`: RGB16-565 Buffer (BE for `knob`, LE otherwise)
- `callback`: Function to handle draw calls. Receives the following arguments:
1. `context`: [2d canvas graphics context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)
2. `width`: Width of drawing area
3. `height`: Height of drawing area
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.getInfo() : Promise`
Request device information. Returns a promise resolving to object containing:
- `serial`: Device serial number
- `version`: Firmware version
If the device is not connected, the promise will reject.
#### `device.setBrightness(brightness : Number) : Promise`
Set screen brightness.
- `brightness`: Float between (0, 1) (`0` would turn the screen off, `1` for full brightness)
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.setButtonColor({ id : String, color : String }) : Promise`
Set a button LED to a particular color. _(Unavailable on RSCX)_
- `id`: Button ID (possible choices: 0-7 on _Loupedeck Live/CT/RSC_, 0-4 on _Loupedeck Live S_, [see `BUTTONS` for _Loupedeck CT_ square buttons](/constants.js#L19))
- `color`: Any [valid CSS color string](https://github.com/colorjs/color-parse#parsed-strings)
Returns a Promise which resolves once the command has been acknowledged by the device.
#### `device.vibrate(pattern? : byte) : Promise`
Make device vibrate. _(Unavailable on RSCX)_
- `pattern`: A valid vibration pattern ([see `HAPTIC` for valid patterns](/constants.js#L57)) (default: `HAPTIC.SHORT`)
Returns a Promise which resolves once the command has been acknowledged by the device.
### Touch Objects
Touch objects are emitted in the [`touchstart`](#event-touchstart), [`touchmove`](#event-touchmove), and [`touchend`](#event-touchend) events and have the following properties:
+ `id`: Unique touch identifier
+ `x`: Screen X-coordinate ([0, 480])
+ `y`: Screen Y-coordinate ([0, 270])
+ `target`:
* `screen`: Identifier of screen this touch was detected on ([`left`, `center`, `right`, `knob`]) (`center` only on _Loupedeck Live S_, `knob` only on _Loupedeck CT_)
* `key`: Index of key touched ([0-11] on _Loupedeck Live/CT/RSC_, [0-14] on _Loupedeck Live S_/_RSCX_)
Contributing & Tests
--------------------
1. Install development dependencies: `npm install`
2. Run tests: `npm test`
Thanks
------
Big thanks go out to [Max Maischein's earlier work in Perl](https://github.com/Corion/HID-LoupedeckCT) on this topic.
License
-------
MIT

104
node_modules/loupedeck/connections/serial.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
import { Emitter as EventEmitter } from 'strict-event-emitter'
import { SerialPort } from 'serialport'
import { MagicByteLengthParser } from '../parser.js'
const WS_UPGRADE_HEADER = `GET /index.html
HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: 123abc
`
const WS_UPGRADE_RESPONSE = 'HTTP/1.1'
const WS_CLOSE_FRAME = [0x88, 0x80, 0x00, 0x00, 0x00, 0x00]
const VENDOR_IDS = [
0x2ec2, // Loupedeck
0x1532, // Razer
]
const MANUFACTURERS = [
'Loupedeck',
'Razer'
]
export default class LoupedeckSerialConnection extends EventEmitter {
constructor({ path } = {}) {
super()
this.path = path
}
// Automatically find Loupedeck Serial device by scanning ports
static async discover() {
const results = []
for (const info of await SerialPort.list()) {
const { manufacturer, path, serialNumber } = info
const vendorId = parseInt(info.vendorId, 16)
const productId = parseInt(info.productId, 16)
if (!VENDOR_IDS.includes(vendorId) && !MANUFACTURERS.includes(manufacturer)) continue
results.push({
connectionType: this,
path,
vendorId,
productId,
serialNumber
})
}
return results
}
close() {
if (!this.connection) return
this.send(Buffer.from(WS_CLOSE_FRAME), true)
return new Promise(res => this.connection.close(res))
}
async connect() {
this.connection = new SerialPort({ path: this.path, baudRate: 256000 })
this.connection.on('error', this.onError.bind(this))
this.connection.on('close', this.onDisconnect.bind(this))
await new Promise(res => this.connection.once('open', res))
// Wait for the "websocket" handshake over serial (...)
await new Promise((res, rej) => {
this.connection.once('data', buff => {
if (buff.toString().startsWith(WS_UPGRADE_RESPONSE)) res()
else rej('Invalid handshake response: ', buff)
})
this.send(Buffer.from(WS_UPGRADE_HEADER), true)
})
// Set up data pipeline
const parser = new MagicByteLengthParser({ magicByte: 0x82 })
this.connection.pipe(parser)
parser.on('data', this.emit.bind(this, 'message'))
this.emit('connect', { address: this.path })
}
isReady() {
return this.connection !== undefined && this.connection.isOpen
}
onDisconnect(err) {
this.emit('disconnect', err)
}
onError(err) {
console.error(`Loupedeck Serial Error: ${err.message}`)
this.onDisconnect(err)
}
send(buff, raw = false) {
if (!raw) {
let prep
// Large messages
if (buff.length > 0xff) {
prep = Buffer.alloc(14)
prep[0] = 0x82
prep[1] = 0xff
prep.writeUInt32BE(buff.length, 6)
// Small messages
} else {
// Prepend each message with a send indicating the length to come
prep = Buffer.alloc(6)
prep[0] = 0x82
prep[1] = 0x80 + buff.length
}
this.connection.write(prep)
}
this.connection.write(buff)
}
}

161
node_modules/loupedeck/connections/web-serial.js generated vendored Normal file
View File

@@ -0,0 +1,161 @@
import { Emitter as EventEmitter } from 'strict-event-emitter'
const WS_UPGRADE_HEADER = `GET /index.html
HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: 123abc
`
const WS_UPGRADE_RESPONSE = 'HTTP/1.1'
// TransformStream version of ../parser.js
class MagicByteLengthParser {
constructor({ magicByte }) {
this.buffer = Buffer.alloc(0)
this.delimiter = magicByte
}
transform(chunk, controller) {
let data = Buffer.concat([this.buffer, chunk])
let position
while ((position = data.indexOf(this.delimiter)) !== -1) {
// We need to at least be able to read the length byte
if (data.length < position + 2) break
const nextLength = data[position + 1]
// Make sure we have enough bytes to meet this length
const expectedEnd = position + nextLength + 2
if (data.length < expectedEnd) break
controller.enqueue(data.slice(position + 2, expectedEnd))
data = data.slice(expectedEnd)
}
this.buffer = data
}
flush(controller) {
controller.enqueue(this.buffer)
}
}
// Async pipeline transformer that splits a stream by 0x82 magic bytes
async function *read(port, { signal }) {
const transformer = new TransformStream(new MagicByteLengthParser({ magicByte: 0x82 }))
const transformed = port.readable.pipeThrough(transformer, { signal })
const reader = transformed.getReader()
try {
while (true) {
const { value, done } = await reader.read()
if (done) break
yield value
}
} catch (error) {
console.error('error', error)
} finally {
reader.releaseLock()
}
}
export default class LoupedeckWebSerialConnection extends EventEmitter {
constructor({ port } = {}) {
super()
this.port = port
navigator.serial.addEventListener('disconnect', this.onDisconnect.bind(this))
}
// Automatically find Loupedeck Serial device by scanning ports
static async discover() {
// Return authorized ports if available
const ports = await navigator.serial.getPorts()
if (!ports.length) {
// Request a new port
ports.push(await navigator.serial.requestPort({ filters: [{ usbVendorId: 0x2ec2 }, { usbVendorId: 0x1532 }] }))
}
const connections = []
for (const port of ports) {
const info = await port.getInfo()
connections.push({
connectionType: this,
port,
productId: info.usbProductId,
vendorId: info.usbVendorId,
})
}
return connections
}
async close() {
this.aborter.abort('Manual close initiated')
await new Promise(res => this.on('readEnd', res))
this.writer.close()
this.writer.releaseLock()
// Without the line below, the serialport will refuse to close with
// "TypeError: Failed to execute 'close': Cannot cancel a locked stream"
//
// However, the port.readable stream should have been unlocked via reader.releaseLock() (see read() above)
//
// Apparently it unlocks after a one tick propagation (due to pipeThrough()), but there doesn't
// seem to be a promise anywhere to await this happening...
//
// Annoyingly, we have to wait one tick here which is really hacky,
// and we should find a way to do this more robustly
await new Promise(res => setTimeout(res, 10))
await this.port.close()
}
async connect() {
if (!this.isReady()) {
await this.port.open({ baudRate: 256000 })
}
const reader = this.port.readable.getReader()
this.writer = this.port.writable.getWriter()
// Wait for the "websocket" handshake over serial (...)
const nextMessage = reader.read()
this.send(Buffer.from(WS_UPGRADE_HEADER), true)
const { value: response } = await nextMessage
const stringResponse = new TextDecoder().decode(response)
if (!stringResponse.startsWith(WS_UPGRADE_RESPONSE)) throw new Error(`Invalid handshake response: ${stringResponse}`)
reader.releaseLock()
// Set up data pipeline
this.aborter = new AbortController()
this.readStream = read(this.port, this.aborter)
this.emit('connect', { address: 'web' })
this.read()
}
isReady() {
return this.port && this.port.readable
}
onDisconnect(err) {
// TODO
this.emit('disconnect', err)
}
onError(err) {
// TODO
console.error(`Loupedeck Serial Error: ${err.message}`)
this.onDisconnect(err)
}
async read() {
for await (const message of this.readStream) {
if (!this.port.readable) break
this.emit('message', message)
}
this.emit('readEnd')
}
send(buff, raw = false) {
if (!raw) {
let prep
// Large messages
if (buff.length > 0xff) {
prep = Buffer.alloc(14)
prep[0] = 0x82
prep[1] = 0xff
prep.writeUInt32BE(buff.length, 6)
// Small messages
} else {
// Prepend each message with a send indicating the length to come
prep = Buffer.alloc(6)
prep[0] = 0x82
prep[1] = 0x80 + buff.length
}
this.writer.write(prep)
}
return this.writer.write(buff)
}
}

80
node_modules/loupedeck/connections/ws.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import { Emitter as EventEmitter } from 'strict-event-emitter'
import { networkInterfaces } from 'node:os'
import WebSocket from 'ws'
import { CONNECTION_TIMEOUT } from '../constants.js'
const DISCONNECT_CODES = {
NORMAL: 1000,
TIMEOUT: 1006,
}
export default class LoupedeckWSConnection extends EventEmitter {
constructor({ host } = {}) {
super()
this.host = host
// Track last interaction time
this.lastTick = Date.now()
// How long until declaring a timed out connetion
this.connectionTimeout = CONNECTION_TIMEOUT
}
// Automatically find Loupedeck IP by scanning network interfaces
static discover() {
const results = []
const interfaces = Object.values(networkInterfaces()).flat()
for (const iface of interfaces) {
if (iface.address.startsWith('100.127')) {
results.push({
connectionType: this,
productId: 0x04,
host: iface.address.replace(/.2$/, '.1')
})
}
}
return results
}
checkConnected() {
this._keepAliveTimer = setTimeout(this.checkConnected.bind(this), this.connectionTimeout * 2)
if (Date.now() - this.lastTick > this.connectionTimeout) this.connection.terminate()
}
close() {
if (!this.connection) return
const closed = new Promise(res => this.connection.once('close', res))
this.connection.close()
return closed
}
connect() {
this.address = `ws://${this.host}`
this.connection = new WebSocket(this.address)
this.connection.on('open', this.onConnect.bind(this))
this.connection.on('message', this.onReceive.bind(this))
this.connection.on('close', this.onDisconnect.bind(this))
return new Promise(res => {
this._connectionResolver = res
})
}
isReady() {
return this.connection !== undefined && this.connection.readyState === this.connection.OPEN
}
onConnect() {
this.emit('connect', { address: this.address })
this._keepAliveTimer = setTimeout(this.checkConnected.bind(this), this.connectionTimeout * 2)
this._connectionResolver()
}
onDisconnect(errCode) {
let error = null
switch (errCode) {
case DISCONNECT_CODES.TIMEOUT:
error = new Error('Connection timeout - was the device disconnected?')
}
clearTimeout(this._keepAliveTimer)
this.emit('disconnect', error)
}
onReceive(buff) {
this.lastTick = Date.now()
this.emit('message', buff)
}
send(buff) {
this.connection.send(buff)
}
}

105
node_modules/loupedeck/constants.js generated vendored Normal file
View File

@@ -0,0 +1,105 @@
// Various constants used by the Loupedeck firmware
export const BUTTONS = {
0x00: 'knobCT',
0x01: 'knobTL',
0x02: 'knobCL',
0x03: 'knobBL',
0x04: 'knobTR',
0x05: 'knobCR',
0x06: 'knobBR',
0x07: 0,
0x08: 1,
0x09: 2,
0x0a: 3,
0x0b: 4,
0x0c: 5,
0x0d: 6,
0x0e: 7,
0x0f: 'home',
0x10: 'undo',
0x11: 'keyboard',
0x12: 'enter',
0x13: 'save',
0x14: 'fnL',
0x15: 'a',
0x16: 'c',
0x17: 'fnR',
0x18: 'b',
0x19: 'd',
0x1a: 'e',
// Below seem to be used only on the Razer Stream Controller X
0x1b: 0,
0x1c: 1,
0x1d: 2,
0x1e: 3,
0x1f: 4,
0x20: 5,
0x21: 6,
0x22: 7,
0x23: 8,
0x24: 9,
0x25: 10,
0x26: 11,
0x27: 12,
0x28: 13,
0x29: 14,
}
// How long without ticks until a connection is considered "timed out"
export const CONNECTION_TIMEOUT = 3000
export const COMMANDS = {
BUTTON_PRESS: 0x00,
KNOB_ROTATE: 0x01,
SET_COLOR: 0x02,
SERIAL: 0x03,
RESET: 0x06,
VERSION: 0x07,
SET_BRIGHTNESS: 0x09,
FRAMEBUFF: 0x10,
SET_VIBRATION: 0x1b,
MCU: 0x0d,
DRAW: 0x0f,
TOUCH: 0x4d,
TOUCH_CT: 0x52,
TOUCH_END: 0x6d,
TOUCH_END_CT: 0x72,
}
// How long until trying to reconnect after a disconnect
export const DEFAULT_RECONNECT_INTERVAL = 3000
export const HAPTIC = {
SHORT: 0x01,
MEDIUM: 0x0a,
LONG: 0x0f,
LOW: 0x31,
SHORT_LOW: 0x32,
SHORT_LOWER: 0x33,
LOWER: 0x40,
LOWEST: 0x41,
DESCEND_SLOW: 0x46,
DESCEND_MED: 0x47,
DESCEND_FAST: 0x48,
ASCEND_SLOW: 0x52,
ASCEND_MED: 0x53,
ASCEND_FAST: 0x58,
REV_SLOWEST: 0x5e,
REV_SLOW: 0x5f,
REV_MED: 0x60,
REV_FAST: 0x61,
REV_FASTER: 0x62,
REV_FASTEST: 0x63,
RISE_FALL: 0x6a,
BUZZ: 0x70,
RUMBLE5: 0x77, // lower frequencies in descending order
RUMBLE4: 0x78,
RUMBLE3: 0x79,
RUMBLE2: 0x7a,
RUMBLE1: 0x7b,
VERY_LONG: 0x76, // 10 sec high freq (!)
}
// Maximum brightness value
export const MAX_BRIGHTNESS = 10

385
node_modules/loupedeck/device.js generated vendored Normal file
View File

@@ -0,0 +1,385 @@
import { Emitter as EventEmitter } from 'strict-event-emitter'
import rgba from 'color-rgba'
let SerialConnection, WSConnection
// Only import when in a browser environment
if (typeof navigator !== 'undefined' && navigator.serial || import.meta.env?.PROD) {
SerialConnection = (await import('./connections/web-serial.js')).default
} else {
SerialConnection = (await import('./connections/serial.js')).default
WSConnection = (await import('./connections/ws.js')).default
}
let canvasModule
try {
canvasModule = await import('canvas')
// eslint-disable-next-line
} catch (e) {
// No canvas is ok, do check in `drawCanvas`
}
import {
BUTTONS,
COMMANDS,
DEFAULT_RECONNECT_INTERVAL,
HAPTIC,
MAX_BRIGHTNESS,
} from './constants.js'
import { rgba2rgb565 } from './util.js'
export class LoupedeckDevice extends EventEmitter {
static async list({ ignoreSerial = false, ignoreWebsocket = false } = {}) {
const ps = []
if (!ignoreSerial) ps.push(SerialConnection.discover())
if (!ignoreWebsocket && WSConnection) ps.push(WSConnection.discover())
// Run them in parallel
const rawDevices = await Promise.all(ps)
return rawDevices.flat()
}
keySize = 90
constructor({ host, path, autoConnect = true, reconnectInterval = DEFAULT_RECONNECT_INTERVAL } = {}) {
super()
this.transactionID = 0
this.touches = {}
this.handlers = {
[COMMANDS.BUTTON_PRESS]: this.onButton.bind(this),
[COMMANDS.KNOB_ROTATE]: this.onRotate.bind(this),
[COMMANDS.SERIAL]: buff => buff.toString().trim(),
[COMMANDS.TICK]: () => {},
[COMMANDS.TOUCH]: this.onTouch.bind(this, 'touchmove'),
[COMMANDS.TOUCH_END]: this.onTouch.bind(this, 'touchend'),
[COMMANDS.VERSION]: buff => `${buff[0]}.${buff[1]}.${buff[2]}`,
[COMMANDS.TOUCH_CT]: this.onTouch.bind(this, 'touchmove'),
[COMMANDS.TOUCH_END_CT]: this.onTouch.bind(this, 'touchend'),
}
// Track pending transactions
this.pendingTransactions = {}
// How long between reconnect attempts
this.reconnectInterval = reconnectInterval
// Host for websocket connections
this.host = host
// Path for serial connections
this.path = path
// Automatically connect?
if (autoConnect) this._connectBlind()
}
close() {
if (!this.connection) return
return this.connection.close()
}
async connect() {
// Explicitly asked for a serial connection (V0.2.X)
if (this.path) this.connection = new SerialConnection({ path: this.path })
// Explicitly asked for a websocket connection (V0.1.X)
else if (this.host) this.connection = new WSConnection({ host: this.host })
// Autodiscover
else {
const devices = await this.constructor.list()
if (devices.length > 0) {
const { connectionType, ...args } = devices[0]
this.connection = new connectionType(args)
}
if (!this.connection) {
return Promise.reject(this.onDisconnect(new Error('No devices found')))
}
}
this.connection.on('connect', this.onConnect.bind(this))
this.connection.on('message', this.onReceive.bind(this))
this.connection.on('disconnect', this.onDisconnect.bind(this))
return this.connection.connect()
}
_connectBlind() {
return this.connect().catch(() => {})
}
// Draw an arbitrary buffer to the device
// Buffer format must be 16bit 5-6-5 (LE, except BE for the Loupedeck CT Knob screen)
async drawBuffer({ id, width, height, x = 0, y = 0, autoRefresh = true }, buffer) {
const displayInfo = this.displays[id]
if (!displayInfo) throw new Error(`Display '${id}' is not available on this device!`)
if (!width) width = displayInfo.width
if (!height) height = displayInfo.height
if (displayInfo.offset) {
x += displayInfo.offset[0]
y += displayInfo.offset[1]
}
const pixelCount = width * height * 2
if (buffer.length !== pixelCount) {
throw new Error(`Expected buffer length of ${pixelCount}, got ${buffer.length}!`)
}
// Header with x/y/w/h and display ID
const header = Buffer.alloc(8)
header.writeUInt16BE(x, 0)
header.writeUInt16BE(y, 2)
header.writeUInt16BE(width, 4)
header.writeUInt16BE(height, 6)
// Write to frame buffer
await this.send(COMMANDS.FRAMEBUFF, Buffer.concat([displayInfo.id, header, buffer]))
// Draw to display
if (autoRefresh) await this.refresh(id)
}
// Create a canvas with correct dimensions and pass back for drawing
drawCanvas({ id, width, height, ...args }, cb) {
const displayInfo = this.displays[id]
if (!displayInfo) throw new Error(`Display '${id}' is not available on this device!`)
if (!width) width = displayInfo.width
if (!height) height = displayInfo.height
if (!canvasModule || !canvasModule.createCanvas) {
throw new Error('Using callbacks requires the `canvas` library to be installed. Install it using `npm install canvas`.')
}
const canvas = canvasModule.createCanvas(width, height)
const ctx = canvas.getContext('2d', { pixelFormat: 'RGB16_565' }) // Loupedeck uses 16-bit (5-6-5) LE RGB colors
cb(ctx, width, height)
let buffer
// If using NodeJS canvas package
if (canvas.toBuffer) {
buffer = canvas.toBuffer('raw')
// If using browser canvas API
} else {
const imageData = ctx.getImageData(0, 0, width, height)
const rgba = imageData.data
// Convert from RGBA to RGB16_565
buffer = rgba2rgb565(rgba, width * height)
}
// Swap endianness depending on display
if (displayInfo.endianness === 'be') buffer.swap16()
return this.drawBuffer({ id, width, height, ...args }, buffer)
}
// Draw to a specific key index (0-11 on Live, 0-14 on Live S)
drawKey(index, cb) {
// Get offset x/y for key index
if (index < 0 || index >= this.columns * this.rows) throw new Error(`Key ${index} is not a valid key`)
const width = this.keySize
const height = this.keySize
const x = this.visibleX[0] + index % this.columns * width
const y = Math.floor(index / this.columns) * height
return this[cb instanceof Buffer ? 'drawBuffer' : 'drawCanvas']({ id: 'center', x, y, width, height }, cb)
}
// Draw to a specific screen
drawScreen(id, cb) {
return this[cb instanceof Buffer ? 'drawBuffer' : 'drawCanvas']({ id }, cb)
}
async getInfo() {
if (!this.connection || !this.connection.isReady()) throw new Error('Not connected!')
return {
serial: await this.send(COMMANDS.SERIAL),
version: await this.send(COMMANDS.VERSION)
}
}
onButton(buff) {
if (buff.length < 2) return
const id = BUTTONS[buff[0]]
const event = buff[1] === 0x00 ? 'down' : 'up'
this.emit(event, { id })
}
onConnect(info) {
this.emit('connect', info)
}
onDisconnect(error) {
this.emit('disconnect', error)
clearTimeout(this._reconnectTimer)
this.connection = null
// Normal disconnect, do not reconnect
if (!error) return
// Reconnect if desired
if (this.reconnectInterval) {
this._reconnectTimer = setTimeout(this._connectBlind.bind(this), this.reconnectInterval)
}
return error.message
}
onReceive(buff) {
const msgLength = buff[0]
const handler = this.handlers[buff[1]]
const transactionID = buff[2]
const response = handler ? handler(buff.slice(3, msgLength)) : buff
const resolver = this.pendingTransactions[transactionID]
if (resolver) resolver(response)
return response
}
onRotate(buff) {
const id = BUTTONS[buff[0]]
const delta = buff.readInt8(1)
this.emit('rotate', { id, delta })
}
onTouch(event, buff) {
const x = buff.readUInt16BE(1)
const y = buff.readUInt16BE(3)
const id = buff[5]
// Create touch
const touch = { x, y, id, target: this.getTarget(x, y, id) }
// End touch, remove from local cache
if (event === 'touchend') {
delete this.touches[touch.id]
} else {
// First time seeing this touch, emit touchstart instead of touchmove
if (!this.touches[touch.id]) event = 'touchstart'
this.touches[touch.id] = touch
}
this.emit(event, { touches: Object.values(this.touches), changedTouches: [touch] })
}
// Display the current framebuffer
refresh(id) {
const displayInfo = this.displays[id]
return this.send(COMMANDS.DRAW, displayInfo.id)
}
send(command, data = Buffer.alloc(0)) {
if (!this.connection || !this.connection.isReady()) return
this.transactionID = (this.transactionID + 1) % 256
// Skip transaction ID's of zero since the device seems to ignore them
if (this.transactionID === 0) this.transactionID++
const header = Buffer.alloc(3)
header[0] = Math.min(3 + data.length, 0xff)
header[1] = command
header[2] = this.transactionID
const packet = Buffer.concat([header, data])
this.connection.send(packet)
return new Promise(res => {
this.pendingTransactions[this.transactionID] = res
})
}
setBrightness(value) {
const byte = Math.max(0, Math.min(MAX_BRIGHTNESS, Math.round(value * MAX_BRIGHTNESS)))
return this.send(COMMANDS.SET_BRIGHTNESS, Buffer.from([byte]))
}
setButtonColor({ id, color }) {
const key = Object.keys(BUTTONS).find(k => BUTTONS[k] === id)
if (!key) throw new Error(`Invalid button ID: ${id}`)
const [r, g, b] = rgba(color)
const data = Buffer.from([key, r, g, b])
return this.send(COMMANDS.SET_COLOR, data)
}
vibrate(pattern = HAPTIC.SHORT) {
return this.send(COMMANDS.SET_VIBRATION, Buffer.from([pattern]))
}
}
export class LoupedeckLive extends LoupedeckDevice {
static productId = 0x0004
static vendorId = 0x2ec2
buttons = [0, 1, 2, 3, 4, 5, 6, 7]
knobs = ['knobCL', 'knobCR', 'knobTL', 'knobTR', 'knobBL', 'knobBR']
columns = 4
// All displays are addressed as the same screen
// So we add offsets
displays = {
center: { id: Buffer.from('\x00M'), width: 360, height: 270, offset: [60, 0] },
left: { id: Buffer.from('\x00M'), width: 60, height: 270 },
right: { id: Buffer.from('\x00M'), width: 60, height: 270, offset: [420, 0] },
}
rows = 3
type = 'Loupedeck Live'
visibleX = [0, 480]
// Determine touch target based on x/y position
getTarget(x, y) {
if (x < this.displays.left.width) return { screen: 'left' }
if (x >= this.displays.left.width + this.displays.center.width) return { screen: 'right' }
const column = Math.floor((x - this.displays.left.width) / this.keySize)
const row = Math.floor(y / this.keySize)
const key = row * this.columns + column
return {
screen: 'center',
key
}
}
}
export class LoupedeckCT extends LoupedeckLive {
static productId = 0x0003
buttons = [0, 1, 2, 3, 4, 5, 6, 7, 'home', 'enter', 'undo', 'save', 'keyboard', 'fnL', 'a', 'b', 'c', 'd', 'fnR', 'e']
displays = {
center: { id: Buffer.from('\x00A'), width: 360, height: 270 }, // "A"
left: { id: Buffer.from('\x00L'), width: 60, height: 270 }, // "L"
right: { id: Buffer.from('\x00R'), width: 60, height: 270 }, // "R"
knob: { id: Buffer.from('\x00W'), width: 240, height: 240, endianness: 'be' }, // "W"
}
type = 'Loupedeck CT'
// Determine touch target based on x/y position
getTarget(x, y, id) {
if (id === 0) return { screen: 'knob' }
return super.getTarget(x, y)
}
}
export class LoupedeckLiveS extends LoupedeckDevice {
static productId = 0x0006
static vendorId = 0x2ec2
buttons = [0, 1, 2, 3]
knobs = ['knobCL', 'knobTL']
columns = 5
displays = {
center: { id: Buffer.from('\x00M'), width: 480, height: 270 },
}
rows = 3
type = 'Loupedeck Live S'
visibleX = [15, 465]
// Determine touch target based on x/y position
getTarget(x, y) {
if (x < this.visibleX[0] || x >= this.visibleX[1]) return {}
const column = Math.floor((x - this.visibleX[0]) / this.keySize)
const row = Math.floor(y / this.keySize)
const key = row * this.columns + column
return {
screen: 'center',
key
}
}
}
export class RazerStreamController extends LoupedeckLive {
static productId = 0x0d06
static vendorId = 0x1532
type = 'Razer Stream Controller'
}
export class RazerStreamControllerX extends LoupedeckDevice {
static productId = 0x0d09
static vendorId = 0x1532
type = 'Razer Stream Controller X'
buttons = []
columns = 5
displays = {
center: { id: Buffer.from('\x00M'), width: 480, height: 288 },
}
rows = 3
visibleX = [0, 480]
keySize = 96
// Emit an extra touchstart event since we are touching keys
onButton(buff) {
super.onButton(buff)
const event = buff[1] === 0x00 ? 'touchstart' : 'touchend'
const key = BUTTONS[buff[0]]
const row = Math.floor(key / this.columns)
const col = key % this.columns
const touch = {
id: 0,
// Add half so touch is in the center of the key
x: (col + 0.5) * this.keySize,
y: (row + 0.5) * this.keySize,
target: { key }
}
this.emit(event, {
touches: event === 'touchstart' ? [touch] : [],
changedTouches: [touch],
})
}
// eslint-disable-next-line class-methods-use-this
setButtonColor() {
throw new Error('Setting key color not available on this device!')
}
// eslint-disable-next-line class-methods-use-this
vibrate() {
throw new Error('Vibration not available on this device!')
}
}

11
node_modules/loupedeck/discovery.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import * as ALL_DEVICES from './device.js'
export async function discover(args) {
const devices = await ALL_DEVICES.LoupedeckDevice.list()
if (devices.length === 0) throw new Error('No devices found')
const { productId, ...connectArgs } = devices[0]
const deviceType = Object.values(ALL_DEVICES).find(dev => dev.productId === productId)
if (!deviceType) throw new Error(`Device with product ID ${productId} not yet supported! Please file an issue at https://github.com/foxxyz/loupedeck/issues`)
const device = new deviceType({ ...args, ...connectArgs })
return device
}

3
node_modules/loupedeck/index.js generated vendored Executable file
View File

@@ -0,0 +1,3 @@
export * from './device.js'
export { HAPTIC } from './constants.js'
export { discover } from './discovery.js'

657
node_modules/loupedeck/node_modules/canvas/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,657 @@
# node-canvas
![Test](https://github.com/Automattic/node-canvas/workflows/Test/badge.svg)
[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas)
node-canvas is a [Cairo](http://cairographics.org/)-backed Canvas implementation for [Node.js](http://nodejs.org).
## Installation
```bash
$ npm install canvas
```
By default, pre-built binaries will be downloaded if you're on one of the following platforms:
- macOS x86/64
- macOS aarch64 (aka Apple silicon)
- Linux x86/64 (glibc only)
- Windows x86/64
If you want to build from source, use `npm install --build-from-source` and see the **Compiling** section below.
The minimum version of Node.js required is **18.12.0**.
### Compiling
If you don't have a supported OS or processor architecture, or you use `--build-from-source`, the module will be compiled on your system. This requires several dependencies, including Cairo and Pango.
For detailed installation information, see the [wiki](https://github.com/Automattic/node-canvas/wiki/_pages). One-line installation instructions for common OSes are below. Note that libgif/giflib, librsvg and libjpeg are optional and only required if you need GIF, SVG and JPEG support, respectively. Cairo v1.10.0 or later is required.
OS | Command
----- | -----
macOS | Using [Homebrew](https://brew.sh/):<br/>`brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman python-setuptools`
Ubuntu | `sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev`
Fedora | `sudo yum install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel`
Solaris | `pkgin install cairo pango pkg-config xproto renderproto kbproto xextproto`
OpenBSD | `doas pkg_add cairo pango png jpeg giflib`
Windows | See the [wiki](https://github.com/Automattic/node-canvas/wiki/Installation:-Windows)
Others | See the [wiki](https://github.com/Automattic/node-canvas/wiki)
**Mac OS X v10.11+:** If you have recently updated to Mac OS X v10.11+ and are experiencing trouble when compiling, run the following command: `xcode-select --install`. Read more about the problem [on Stack Overflow](http://stackoverflow.com/a/32929012/148072).
If you have xcode 10.0 or higher installed, in order to build from source you need NPM 6.4.1 or higher.
## Quick Example
```javascript
const { createCanvas, loadImage } = require('canvas')
const canvas = createCanvas(200, 200)
const ctx = canvas.getContext('2d')
// Write "Awesome!"
ctx.font = '30px Impact'
ctx.rotate(0.1)
ctx.fillText('Awesome!', 50, 100)
// Draw line under text
var text = ctx.measureText('Awesome!')
ctx.strokeStyle = 'rgba(0,0,0,0.5)'
ctx.beginPath()
ctx.lineTo(50, 102)
ctx.lineTo(50 + text.width, 102)
ctx.stroke()
// Draw cat with lime helmet
loadImage('examples/images/lime-cat.jpg').then((image) => {
ctx.drawImage(image, 50, 0, 70, 70)
console.log('<img src="' + canvas.toDataURL() + '" />')
})
```
## Upgrading from 1.x to 2.x
See the [changelog](https://github.com/Automattic/node-canvas/blob/master/CHANGELOG.md) for a guide to upgrading from 1.x to 2.x.
For version 1.x documentation, see [the v1.x branch](https://github.com/Automattic/node-canvas/tree/v1.x).
## Documentation
This project is an implementation of the Web Canvas API and implements that API as closely as possible. For API documentation, please visit [Mozilla Web Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). (See [Compatibility Status](https://github.com/Automattic/node-canvas/wiki/Compatibility-Status) for the current API compliance.) All utility methods and non-standard APIs are documented below.
### Utility methods
* [createCanvas()](#createcanvas)
* [createImageData()](#createimagedata)
* [loadImage()](#loadimage)
* [registerFont()](#registerfont)
* [deregisterAllFonts()](#deregisterAllFonts)
### Non-standard APIs
* [Image#src](#imagesrc)
* [Image#dataMode](#imagedatamode)
* [Canvas#toBuffer()](#canvastobuffer)
* [Canvas#createPNGStream()](#canvascreatepngstream)
* [Canvas#createJPEGStream()](#canvascreatejpegstream)
* [Canvas#createPDFStream()](#canvascreatepdfstream)
* [Canvas#toDataURL()](#canvastodataurl)
* [CanvasRenderingContext2D#patternQuality](#canvasrenderingcontext2dpatternquality)
* [CanvasRenderingContext2D#quality](#canvasrenderingcontext2dquality)
* [CanvasRenderingContext2D#textDrawingMode](#canvasrenderingcontext2dtextdrawingmode)
* [CanvasRenderingContext2D#globalCompositeOperation = 'saturate'](#canvasrenderingcontext2dglobalcompositeoperation--saturate)
* [CanvasRenderingContext2D#antialias](#canvasrenderingcontext2dantialias)
### createCanvas()
> ```ts
> createCanvas(width: number, height: number, type?: 'PDF'|'SVG') => Canvas
> ```
Creates a Canvas instance. This method works in both Node.js and Web browsers, where there is no Canvas constructor. (See `browser.js` for the implementation that runs in browsers.)
```js
const { createCanvas } = require('canvas')
const mycanvas = createCanvas(200, 200)
const myPDFcanvas = createCanvas(600, 800, 'pdf') // see "PDF Support" section
```
### createImageData()
> ```ts
> createImageData(width: number, height: number) => ImageData
> createImageData(data: Uint8ClampedArray, width: number, height?: number) => ImageData
> // for alternative pixel formats:
> createImageData(data: Uint16Array, width: number, height?: number) => ImageData
> ```
Creates an ImageData instance. This method works in both Node.js and Web browsers.
```js
const { createImageData } = require('canvas')
const width = 20, height = 20
const arraySize = width * height * 4
const mydata = createImageData(new Uint8ClampedArray(arraySize), width)
```
### loadImage()
> ```ts
> loadImage() => Promise<Image>
> ```
Convenience method for loading images. This method works in both Node.js and Web browsers.
```js
const { loadImage } = require('canvas')
const myimg = loadImage('http://server.com/image.png')
myimg.then(() => {
// do something with image
}).catch(err => {
console.log('oh no!', err)
})
// or with async/await:
const myimg = await loadImage('http://server.com/image.png')
// do something with image
```
### registerFont()
> ```ts
> registerFont(path: string, { family: string, weight?: string, style?: string }) => void
> ```
To use a font file that is not installed as a system font, use `registerFont()` to register the font with Canvas.
```js
const { registerFont, createCanvas } = require('canvas')
registerFont('comicsans.ttf', { family: 'Comic Sans' })
const canvas = createCanvas(500, 500)
const ctx = canvas.getContext('2d')
ctx.font = '12px "Comic Sans"'
ctx.fillText('Everyone hates this font :(', 250, 10)
```
The second argument is an object with properties that resemble the CSS properties that are specified in `@font-face` rules. You must specify at least `family`. `weight`, and `style` are optional and default to `'normal'`.
### deregisterAllFonts()
> ```ts
> deregisterAllFonts() => void
> ```
Use `deregisterAllFonts` to unregister all fonts that have been previously registered. This method is useful when you want to remove all registered fonts, such as when using the canvas in tests
```ts
const { registerFont, createCanvas, deregisterAllFonts } = require('canvas')
describe('text rendering', () => {
afterEach(() => {
deregisterAllFonts();
})
it('should render text with Comic Sans', () => {
registerFont('comicsans.ttf', { family: 'Comic Sans' })
const canvas = createCanvas(500, 500)
const ctx = canvas.getContext('2d')
ctx.font = '12px "Comic Sans"'
ctx.fillText('Everyone loves this font :)', 250, 10)
// assertScreenshot()
})
})
```
### Image#src
> ```ts
> img.src: string|Buffer
> ```
As in browsers, `img.src` can be set to a `data:` URI or a remote URL. In addition, node-canvas allows setting `src` to a local file path or `Buffer` instance.
```javascript
const { Image } = require('canvas')
// From a buffer:
fs.readFile('images/squid.png', (err, squid) => {
if (err) throw err
const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = squid
})
// From a local file path:
const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = 'images/squid.png'
// From a remote URL:
img.src = 'http://picsum.photos/200/300'
// ... as above
// From a `data:` URI:
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
// ... as above
```
*Note: In some cases, `img.src=` is currently synchronous. However, you should always use `img.onload` and `img.onerror`, as we intend to make `img.src=` always asynchronous as it is in browsers. See https://github.com/Automattic/node-canvas/issues/1007.*
### Image#dataMode
> ```ts
> img.dataMode: number
> ```
Applies to JPEG images drawn to PDF canvases only.
Setting `img.dataMode = Image.MODE_MIME` or `Image.MODE_MIME|Image.MODE_IMAGE` enables MIME data tracking of images. When MIME data is tracked, PDF canvases can embed JPEGs directly into the output, rather than re-encoding into PNG. This can drastically reduce filesize and speed up rendering.
```javascript
const { Image, createCanvas } = require('canvas')
const canvas = createCanvas(w, h, 'pdf')
const img = new Image()
img.dataMode = Image.MODE_IMAGE // Only image data tracked
img.dataMode = Image.MODE_MIME // Only mime data tracked
img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE // Both are tracked
```
If working with a non-PDF canvas, image data *must* be tracked; otherwise the output will be junk.
Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.
### Canvas#toBuffer()
> ```ts
> canvas.toBuffer((err: Error|null, result: Buffer) => void, mimeType?: string, config?: any) => void
> canvas.toBuffer(mimeType?: string, config?: any) => Buffer
> ```
Creates a [`Buffer`](https://nodejs.org/api/buffer.html) object representing the image contained in the canvas.
* **callback** If provided, the buffer will be provided in the callback instead of being returned by the function. Invoked with an error as the first argument if encoding failed, or the resulting buffer as the second argument if it succeeded. Not supported for mimeType `raw` or for PDF or SVG canvases.
* **mimeType** A string indicating the image format. Valid options are `image/png`, `image/jpeg` (if node-canvas was built with JPEG support), `raw` (unencoded data in BGRA order on little-endian (most) systems, ARGB on big-endian systems; top-to-bottom), `application/pdf` (for PDF canvases) and `image/svg+xml` (for SVG canvases). Defaults to `image/png` for image canvases, or the corresponding type for PDF or SVG canvas.
* **config**
* For `image/jpeg`, an object specifying the quality (0 to 1), if progressive compression should be used and/or if chroma subsampling should be used: `{quality: 0.75, progressive: false, chromaSubsampling: true}`. All properties are optional.
* For `image/png`, an object specifying the ZLIB compression level (between 0 and 9), the compression filter(s), the palette (indexed PNGs only), the the background palette index (indexed PNGs only) and/or the resolution (ppi): `{compressionLevel: 6, filters: canvas.PNG_ALL_FILTERS, palette: undefined, backgroundIndex: 0, resolution: undefined}`. All properties are optional.
Note that the PNG format encodes the resolution in pixels per meter, so if you specify `96`, the file will encode 3780 ppm (~96.01 ppi). The resolution is undefined by default to match common browser behavior.
* For `application/pdf`, an object specifying optional document metadata: `{title: string, author: string, subject: string, keywords: string, creator: string, creationDate: Date, modDate: Date}`. All properties are optional and default to `undefined`, except for `creationDate`, which defaults to the current date. *Adding metadata requires Cairo 1.16.0 or later.*
For a description of these properties, see page 550 of [PDF 32000-1:2008](https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf).
Note that there is no standard separator for `keywords`. A space is recommended because it is in common use by other applications, and Cairo will enclose the list of keywords in quotes if a comma or semicolon is used.
**Return value**
If no callback is provided, a [`Buffer`](https://nodejs.org/api/buffer.html). If a callback is provided, none.
#### Examples
```js
// Default: buf contains a PNG-encoded image
const buf = canvas.toBuffer()
// PNG-encoded, zlib compression level 3 for faster compression but bigger files, no filtering
const buf2 = canvas.toBuffer('image/png', { compressionLevel: 3, filters: canvas.PNG_FILTER_NONE })
// JPEG-encoded, 50% quality
const buf3 = canvas.toBuffer('image/jpeg', { quality: 0.5 })
// Asynchronous PNG
canvas.toBuffer((err, buf) => {
if (err) throw err // encoding failed
// buf is PNG-encoded image
})
canvas.toBuffer((err, buf) => {
if (err) throw err // encoding failed
// buf is JPEG-encoded image at 95% quality
}, 'image/jpeg', { quality: 0.95 })
// BGRA pixel values, native-endian
const buf4 = canvas.toBuffer('raw')
const { stride, width } = canvas
// In memory, this is `canvas.height * canvas.stride` bytes long.
// The top row of pixels, in BGRA order on little-endian hardware,
// left-to-right, is:
const topPixelsBGRALeftToRight = buf4.slice(0, width * 4)
// And the third row is:
const row3 = buf4.slice(2 * stride, 2 * stride + width * 4)
// SVG and PDF canvases
const myCanvas = createCanvas(w, h, 'pdf')
myCanvas.toBuffer() // returns a buffer containing a PDF-encoded canvas
// With optional metadata:
myCanvas.toBuffer('application/pdf', {
title: 'my picture',
keywords: 'node.js demo cairo',
creationDate: new Date()
})
```
### Canvas#createPNGStream()
> ```ts
> canvas.createPNGStream(config?: any) => ReadableStream
> ```
Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits PNG-encoded data.
* `config` An object specifying the ZLIB compression level (between 0 and 9), the compression filter(s), the palette (indexed PNGs only) and/or the background palette index (indexed PNGs only): `{compressionLevel: 6, filters: canvas.PNG_ALL_FILTERS, palette: undefined, backgroundIndex: 0, resolution: undefined}`. All properties are optional.
#### Examples
```javascript
const fs = require('fs')
const out = fs.createWriteStream(__dirname + '/test.png')
const stream = canvas.createPNGStream()
stream.pipe(out)
out.on('finish', () => console.log('The PNG file was created.'))
```
To encode indexed PNGs from canvases with `pixelFormat: 'A8'` or `'A1'`, provide an options object:
```js
const palette = new Uint8ClampedArray([
//r g b a
0, 50, 50, 255, // index 1
10, 90, 90, 255, // index 2
127, 127, 255, 255
// ...
])
canvas.createPNGStream({
palette: palette,
backgroundIndex: 0 // optional, defaults to 0
})
```
### Canvas#createJPEGStream()
> ```ts
> canvas.createJPEGStream(config?: any) => ReadableStream
> ```
Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits JPEG-encoded data.
*Note: At the moment, `createJPEGStream()` is synchronous under the hood. That is, it runs in the main thread, not in the libuv threadpool.*
* `config` an object specifying the quality (0 to 1), if progressive compression should be used and/or if chroma subsampling should be used: `{quality: 0.75, progressive: false, chromaSubsampling: true}`. All properties are optional.
#### Examples
```javascript
const fs = require('fs')
const out = fs.createWriteStream(__dirname + '/test.jpeg')
const stream = canvas.createJPEGStream()
stream.pipe(out)
out.on('finish', () => console.log('The JPEG file was created.'))
// Disable 2x2 chromaSubsampling for deeper colors and use a higher quality
const stream = canvas.createJPEGStream({
quality: 0.95,
chromaSubsampling: false
})
```
### Canvas#createPDFStream()
> ```ts
> canvas.createPDFStream(config?: any) => ReadableStream
> ```
* `config` an object specifying optional document metadata: `{title: string, author: string, subject: string, keywords: string, creator: string, creationDate: Date, modDate: Date}`. See `toBuffer()` for more information. *Adding metadata requires Cairo 1.16.0 or later.*
Applies to PDF canvases only. Creates a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable) that emits the encoded PDF. `canvas.toBuffer()` also produces an encoded PDF, but `createPDFStream()` can be used to reduce memory usage.
### Canvas#toDataURL()
This is a standard API, but several non-standard calls are supported. The full list of supported calls is:
```js
dataUrl = canvas.toDataURL() // defaults to PNG
dataUrl = canvas.toDataURL('image/png')
dataUrl = canvas.toDataURL('image/jpeg')
dataUrl = canvas.toDataURL('image/jpeg', quality) // quality from 0 to 1
canvas.toDataURL((err, png) => { }) // defaults to PNG
canvas.toDataURL('image/png', (err, png) => { })
canvas.toDataURL('image/jpeg', (err, jpeg) => { }) // sync JPEG is not supported
canvas.toDataURL('image/jpeg', {...opts}, (err, jpeg) => { }) // see Canvas#createJPEGStream for valid options
canvas.toDataURL('image/jpeg', quality, (err, jpeg) => { }) // spec-following; quality from 0 to 1
```
### CanvasRenderingContext2D#patternQuality
> ```ts
> context.patternQuality: 'fast'|'good'|'best'|'nearest'|'bilinear'
> ```
Defaults to `'good'`. Affects pattern (gradient, image, etc.) rendering quality.
### CanvasRenderingContext2D#quality
> ```ts
> context.quality: 'fast'|'good'|'best'|'nearest'|'bilinear'
> ```
Defaults to `'good'`. Like `patternQuality`, but applies to transformations affecting more than just patterns.
### CanvasRenderingContext2D#textDrawingMode
> ```ts
> context.textDrawingMode: 'path'|'glyph'
> ```
Defaults to `'path'`. The effect depends on the canvas type:
* **Standard (image)** `glyph` and `path` both result in rasterized text. Glyph mode is faster than `path`, but may result in lower-quality text, especially when rotated or translated.
* **PDF** `glyph` will embed text instead of paths into the PDF. This is faster to encode, faster to open with PDF viewers, yields a smaller file size and makes the text selectable. The subset of the font needed to render the glyphs will be embedded in the PDF. This is usually the mode you want to use with PDF canvases.
* **SVG** `glyph` does *not* cause `<text>` elements to be produced as one might expect ([cairo bug](https://gitlab.freedesktop.org/cairo/cairo/issues/253)). Rather, `glyph` will create a `<defs>` section with a `<symbol>` for each glyph, then those glyphs be reused via `<use>` elements. `path` mode creates a `<path>` element for each text string. `glyph` mode is faster and yields a smaller file size.
In `glyph` mode, `ctx.strokeText()` and `ctx.fillText()` behave the same (aside from using the stroke and fill style, respectively).
This property is tracked as part of the canvas state in save/restore.
### CanvasRenderingContext2D#globalCompositeOperation = 'saturate'
In addition to all of the standard global composite operations defined by the Canvas specification, the ['saturate'](https://www.cairographics.org/operators/#saturate) operation is also available.
### CanvasRenderingContext2D#antialias
> ```ts
> context.antialias: 'default'|'none'|'gray'|'subpixel'
> ```
Sets the anti-aliasing mode.
## PDF Output Support
node-canvas can create PDF documents instead of images. The canvas type must be set when creating the canvas as follows:
```js
const canvas = createCanvas(200, 500, 'pdf')
```
An additional method `.addPage()` is then available to create multiple page PDFs:
```js
// On first page
ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)
ctx.addPage()
// Now on second page
ctx.font = '22px Helvetica'
ctx.fillText('Hello World 2', 50, 80)
canvas.toBuffer() // returns a PDF file
canvas.createPDFStream() // returns a ReadableStream that emits a PDF
// With optional document metadata (requires Cairo 1.16.0):
canvas.toBuffer('application/pdf', {
title: 'my picture',
keywords: 'node.js demo cairo',
creationDate: new Date()
})
```
It is also possible to create pages with different sizes by passing `width` and `height` to the `.addPage()` method:
```js
ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)
ctx.addPage(400, 800)
ctx.fillText('Hello World 2', 50, 80)
```
It is possible to add hyperlinks using `.beginTag()` and `.endTag()`:
```js
ctx.beginTag('Link', "uri='https://google.com'")
ctx.font = '22px Helvetica'
ctx.fillText('Hello World', 50, 80)
ctx.endTag('Link')
```
Or with a defined rectangle:
```js
ctx.beginTag('Link', "uri='https://google.com' rect=[50 80 100 20]")
ctx.endTag('Link')
```
Note that the syntax for attributes is unique to Cairo. See [cairo_tag_begin](https://www.cairographics.org/manual/cairo-Tags-and-Links.html#cairo-tag-begin) for the full documentation.
You can create areas on the canvas using the "cairo.dest" tag, and then link to them using the "Link" tag with the `dest=` attribute. You can also define PDF structure for accessibility by using tag names like "P", "H1", and "TABLE". The standard tags are defined in §14.8.4 of the [PDF 1.7](https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf) specification.
See also:
* [Image#dataMode](#imagedatamode) for embedding JPEGs in PDFs
* [Canvas#createPDFStream()](#canvascreatepdfstream) for creating PDF streams
* [CanvasRenderingContext2D#textDrawingMode](#canvasrenderingcontext2dtextdrawingmode)
for embedding text instead of paths
## SVG Output Support
node-canvas can create SVG documents instead of images. The canvas type must be set when creating the canvas as follows:
```js
const canvas = createCanvas(200, 500, 'svg')
// Use the normal primitives.
fs.writeFileSync('out.svg', canvas.toBuffer())
```
## SVG Image Support
If librsvg is available when node-canvas is installed, node-canvas can render SVG images to your canvas context. This currently works by rasterizing the SVG image (i.e. drawing an SVG image to an SVG canvas will not preserve the SVG data).
```js
const img = new Image()
img.onload = () => ctx.drawImage(img, 0, 0)
img.onerror = err => { throw err }
img.src = './example.svg'
```
## Image pixel formats (experimental)
node-canvas has experimental support for additional pixel formats, roughly following the [Canvas color space proposal](https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md).
```js
const canvas = createCanvas(200, 200)
const ctx = canvas.getContext('2d', { pixelFormat: 'A8' })
```
By default, canvases are created in the `RGBA32` format, which corresponds to the native HTML Canvas behavior. Each pixel is 32 bits. The JavaScript APIs that involve pixel data (`getImageData`, `putImageData`) store the colors in the order {red, green, blue, alpha} without alpha pre-multiplication. (The C++ API stores the colors in the order {alpha, red, green, blue} in native-[endian](https://en.wikipedia.org/wiki/Endianness) ordering, with alpha pre-multiplication.)
These additional pixel formats have experimental support:
* `RGB24` Like `RGBA32`, but the 8 alpha bits are always opaque. This format is always used if the `alpha` context attribute is set to false (i.e. `canvas.getContext('2d', {alpha: false})`). This format can be faster than `RGBA32` because transparency does not need to be calculated.
* `A8` Each pixel is 8 bits. This format can either be used for creating grayscale images (treating each byte as an alpha value), or for creating indexed PNGs (treating each byte as a palette index) (see [the example using alpha values with `fillStyle`](examples/indexed-png-alpha.js) and [the example using `imageData`](examples/indexed-png-image-data.js)).
* `RGB16_565` Each pixel is 16 bits, with red in the upper 5 bits, green in the middle 6 bits, and blue in the lower 5 bits, in native platform endianness. Some hardware devices and frame buffers use this format. Note that PNG does not support this format; when creating a PNG, the image will be converted to 24-bit RGB. This format is thus suboptimal for generating PNGs. `ImageData` instances for this mode use a `Uint16Array` instead of a `Uint8ClampedArray`.
* `A1` Each pixel is 1 bit, and pixels are packed together into 32-bit quantities. The ordering of the bits matches the endianness of the
platform: on a little-endian machine, the first pixel is the least-significant bit. This format can be used for creating single-color images. *Support for this format is incomplete, see note below.*
* `RGB30` Each pixel is 30 bits, with red in the upper 10, green in the middle 10, and blue in the lower 10. (Requires Cairo 1.12 or later.) *Support for this format is incomplete, see note below.*
Notes and caveats:
* Using a non-default format can affect the behavior of APIs that involve pixel data:
* `context2d.createImageData` The size of the array returned depends on the number of bit per pixel for the underlying image data format, per the above descriptions.
* `context2d.getImageData` The format of the array returned depends on the underlying image mode, per the above descriptions. Be aware of platform endianness, which can be determined using node.js's [`os.endianness()`](https://nodejs.org/api/os.html#os_os_endianness)
function.
* `context2d.putImageData` As above.
* `A1` and `RGB30` do not yet support `getImageData` or `putImageData`. Have a use case and/or opinion on working with these formats? Open an issue and let us know! (See #935.)
* `A1`, `A8`, `RGB30` and `RGB16_565` with shadow blurs may crash or not render properly.
* The `ImageData(width, height)` and `ImageData(Uint8ClampedArray, width)` constructors assume 4 bytes per pixel. To create an `ImageData` instance with a different number of bytes per pixel, use `new ImageData(new Uint8ClampedArray(size), width, height)` or `new ImageData(new Uint16ClampedArray(size), width, height)`.
## Testing
First make sure you've built the latest version. Get all the deps you need (see [compiling](#compiling) above), and run:
```
npm install --build-from-source
```
For visual tests: `npm run test-server` and point your browser to http://localhost:4000.
For unit tests: `npm run test`.
## Benchmarks
Benchmarks live in the `benchmarks` directory.
## Examples
Examples line in the `examples` directory. Most produce a png image of the same name, and others such as *live-clock.js* launch an HTTP server to be viewed in the browser.
## Original Authors
- TJ Holowaychuk ([tj](http://github.com/tj))
- Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate))
- Rod Vagg ([rvagg](http://github.com/rvagg))
- Juriy Zaytsev ([kangax](http://github.com/kangax))
## License
### node-canvas
(The MIT License)
Copyright (c) 2010 LearnBoost, and contributors &lt;dev@learnboost.com&gt;
Copyright (c) 2014 Automattic, Inc and contributors &lt;dev@automattic.com&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the 'Software'), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### BMP parser
See [license](src/bmp/LICENSE.md)

234
node_modules/loupedeck/node_modules/canvas/binding.gyp generated vendored Normal file
View File

@@ -0,0 +1,234 @@
{
'conditions': [
['OS=="win"', {
'variables': {
'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle
'with_jpeg%': 'false',
'with_gif%': 'false',
'with_rsvg%': 'false',
'variables': { # Nest jpeg_root to evaluate it before with_jpeg
'jpeg_root%': '<!(node ./util/win_jpeg_lookup)'
},
'jpeg_root%': '<(jpeg_root)', # Take value of nested variable
'conditions': [
['jpeg_root==""', {
'with_jpeg%': 'false'
}, {
'with_jpeg%': 'true'
}]
]
}
}, { # 'OS!="win"'
'variables': {
'with_jpeg%': '<!(node ./util/has_lib.js jpeg)',
'with_gif%': '<!(node ./util/has_lib.js gif)',
'with_rsvg%': '<!(node ./util/has_lib.js rsvg)'
}
}]
],
'targets': [
{
'target_name': 'canvas-postbuild',
'dependencies': ['canvas'],
'conditions': [
['OS=="win"', {
'copies': [{
'destination': '<(PRODUCT_DIR)',
'files': [
'<(GTK_Root)/bin/zlib1.dll',
'<(GTK_Root)/bin/libintl-8.dll',
'<(GTK_Root)/bin/libpng14-14.dll',
'<(GTK_Root)/bin/libpangocairo-1.0-0.dll',
'<(GTK_Root)/bin/libpango-1.0-0.dll',
'<(GTK_Root)/bin/libpangoft2-1.0-0.dll',
'<(GTK_Root)/bin/libpangowin32-1.0-0.dll',
'<(GTK_Root)/bin/libcairo-2.dll',
'<(GTK_Root)/bin/libfontconfig-1.dll',
'<(GTK_Root)/bin/libfreetype-6.dll',
'<(GTK_Root)/bin/libglib-2.0-0.dll',
'<(GTK_Root)/bin/libgobject-2.0-0.dll',
'<(GTK_Root)/bin/libgmodule-2.0-0.dll',
'<(GTK_Root)/bin/libgthread-2.0-0.dll',
'<(GTK_Root)/bin/libexpat-1.dll'
]
}]
}]
]
},
{
'target_name': 'canvas',
'include_dirs': ["<!(node -p \"require('node-addon-api').include_dir\")"],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS', 'NODE_ADDON_API_ENABLE_MAYBE' ],
'sources': [
'src/backend/Backend.cc',
'src/backend/ImageBackend.cc',
'src/backend/PdfBackend.cc',
'src/backend/SvgBackend.cc',
'src/bmp/BMPParser.cc',
'src/Backends.cc',
'src/Canvas.cc',
'src/CanvasGradient.cc',
'src/CanvasPattern.cc',
'src/CanvasRenderingContext2d.cc',
'src/closure.cc',
'src/color.cc',
'src/Image.cc',
'src/ImageData.cc',
'src/init.cc',
'src/register_font.cc',
'src/FontParser.cc'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/cairo.lib',
'-l<(GTK_Root)/lib/libpng.lib',
'-l<(GTK_Root)/lib/pangocairo-1.0.lib',
'-l<(GTK_Root)/lib/pango-1.0.lib',
'-l<(GTK_Root)/lib/freetype.lib',
'-l<(GTK_Root)/lib/glib-2.0.lib',
'-l<(GTK_Root)/lib/gobject-2.0.lib'
],
'include_dirs': [
'<(GTK_Root)/include',
'<(GTK_Root)/include/cairo',
'<(GTK_Root)/include/pango-1.0',
'<(GTK_Root)/include/glib-2.0',
'<(GTK_Root)/include/freetype2',
'<(GTK_Root)/lib/glib-2.0/include'
],
'defines': [
'_USE_MATH_DEFINES', # for M_PI
'NOMINMAX' # allow std::min/max to work
],
'configurations': {
'Debug': {
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': 4,
'ExceptionHandling': 1,
'DisableSpecificWarnings': [
4100, 4611
]
}
}
},
'Release': {
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': 4,
'ExceptionHandling': 1,
'DisableSpecificWarnings': [
4100, 4611
]
}
}
}
}
}, { # 'OS!="win"'
'libraries': [
'<!@(pkg-config pixman-1 --libs)',
'<!@(pkg-config cairo --libs)',
'<!@(pkg-config libpng --libs)',
'<!@(pkg-config pangocairo --libs)',
'<!@(pkg-config freetype2 --libs)'
],
'include_dirs': [
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)',
'<!@(pkg-config libpng --cflags-only-I | sed s/-I//g)',
'<!@(pkg-config pangocairo --cflags-only-I | sed s/-I//g)',
'<!@(pkg-config freetype2 --cflags-only-I | sed s/-I//g)'
],
'cflags': ['-Wno-cast-function-type'],
'cflags!': ['-fno-exceptions'],
'cflags_cc!': ['-fno-exceptions']
}],
['OS=="mac"', {
'cflags+': ['-fvisibility=hidden'],
'xcode_settings': {
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
}
}],
['with_jpeg=="true"', {
'defines': [
'HAVE_JPEG'
],
'conditions': [
['OS=="win"', {
'copies': [{
'destination': '<(PRODUCT_DIR)',
'files': [
'<(jpeg_root)/bin/jpeg62.dll',
]
}],
'include_dirs': [
'<(jpeg_root)/include'
],
'libraries': [
'-l<(jpeg_root)/lib/jpeg.lib',
]
}, {
'include_dirs': [
'<!@(pkg-config libjpeg --cflags-only-I | sed s/-I//g)'
],
'libraries': [
'<!@(pkg-config libjpeg --libs)'
]
}]
]
}],
['with_gif=="true"', {
'defines': [
'HAVE_GIF'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/gif.lib'
]
}, {
'include_dirs': [
'/opt/homebrew/include'
],
'libraries': [
'-L/opt/homebrew/lib',
'-lgif'
]
}]
]
}],
['with_rsvg=="true"', {
'defines': [
'HAVE_RSVG'
],
'conditions': [
['OS=="win"', {
'copies': [{
'destination': '<(PRODUCT_DIR)',
'files': [
'<(GTK_Root)/bin/librsvg-2-2.dll',
'<(GTK_Root)/bin/libgdk_pixbuf-2.0-0.dll',
'<(GTK_Root)/bin/libgio-2.0-0.dll',
'<(GTK_Root)/bin/libcroco-0.6-3.dll',
'<(GTK_Root)/bin/libgsf-1-114.dll',
'<(GTK_Root)/bin/libxml2-2.dll'
]
}],
'libraries': [
'-l<(GTK_Root)/lib/librsvg-2-2.lib'
]
}, {
'include_dirs': [
'<!@(pkg-config librsvg-2.0 --cflags-only-I | sed s/-I//g)'
],
'libraries': [
'<!@(pkg-config librsvg-2.0 --libs)'
]
}]
]
}]
]
}
]
}

31
node_modules/loupedeck/node_modules/canvas/browser.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
/* globals document, ImageData */
exports.createCanvas = function (width, height) {
return Object.assign(document.createElement('canvas'), { width: width, height: height })
}
exports.createImageData = function (array, width, height) {
// Browser implementation of ImageData looks at the number of arguments passed
switch (arguments.length) {
case 0: return new ImageData()
case 1: return new ImageData(array)
case 2: return new ImageData(array, width)
default: return new ImageData(array, width, height)
}
}
exports.loadImage = function (src, options) {
return new Promise(function (resolve, reject) {
const image = Object.assign(document.createElement('img'), options)
function cleanup () {
image.onload = null
image.onerror = null
}
image.onload = function () { cleanup(); resolve(image) }
image.onerror = function () { cleanup(); reject(new Error('Failed to load the image "' + src + '"')) }
image.src = src
})
}

View File

@@ -0,0 +1,354 @@
# We borrow heavily from the kernel build setup, though we are simpler since
# we don't have Kconfig tweaking settings on us.
# The implicit make rules have it looking for RCS files, among other things.
# We instead explicitly write all the rules we care about.
# It's even quicker (saves ~200ms) to pass -r on the command line.
MAKEFLAGS=-r
# The source directory tree.
srcdir := ..
abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= .
# The V=1 flag on command line makes us verbosely print command lines.
ifdef V
quiet=
else
quiet=quiet_
endif
# Specify BUILDTYPE=Release on the command line for a release build.
BUILDTYPE ?= Release
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
# as they reach into the src/ directory for data with relative paths.
builddir ?= $(builddir_name)/$(BUILDTYPE)
abs_builddir := $(abspath $(builddir))
depsdir := $(builddir)/.deps
# Object output directory.
obj := $(builddir)/obj
abs_obj := $(abspath $(obj))
# We build up a list of every single one of the targets so we can slurp in the
# generated dependency rule Makefiles in one pass.
all_deps :=
CC.target ?= $(CC)
CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
CXX.target ?= $(CXX)
CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
LINK.target ?= $(LINK)
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
PLI.target ?= pli
# C++ apps need to be linked with g++.
LINK ?= $(CXX.target)
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= gcc
CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
CXX.host ?= g++
CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
LINK.host ?= $(CXX.host)
LDFLAGS.host ?= $(LDFLAGS_host)
AR.host ?= ar
PLI.host ?= pli
# Define a dir function that can handle spaces.
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
# "leading spaces cannot appear in the text of the first argument as written.
# These characters can be put into the argument value by variable substitution."
empty :=
space := $(empty) $(empty)
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
replace_spaces = $(subst $(space),?,$1)
unreplace_spaces = $(subst ?,$(space),$1)
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
# Flags to make gcc output dependency info. Note that you need to be
# careful here to use the flags that ccache and distcc can understand.
# We write to a dep file on the side first and then rename at the end
# so we can't end up with a broken dep file.
depfile = $(depsdir)/$(call replace_spaces,$@).d
DEPFLAGS = -MMD -MF $(depfile).raw
# We have to fixup the deps output in a few ways.
# (1) the file output should mention the proper .o file.
# ccache or distcc lose the path to the target, so we convert a rule of
# the form:
# foobar.o: DEP1 DEP2
# into
# path/to/foobar.o: DEP1 DEP2
# (2) we want missing files not to cause us to fail to build.
# We want to rewrite
# foobar.o: DEP1 DEP2 \
# DEP3
# to
# DEP1:
# DEP2:
# DEP3:
# so if the files are missing, they're just considered phony rules.
# We have to do some pretty insane escaping to get those backslashes
# and dollar signs past make, the shell, and sed at the same time.
# Doesn't work with spaces, but that's fine: .d files have spaces in
# their names replaced with other characters.
define fixup_dep
# The depfile may not exist if the input file didn't have any #includes.
touch $(depfile).raw
# Fixup path as in (1).
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
# Add extra rules as in (2).
# We remove slashes and replace spaces with new lines;
# remove blank lines;
# delete the first line and append a colon to the remaining lines.
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
grep -v '^$$' |\
sed -e 1d -e 's|$$|:|' \
>> $(depfile)
rm $(depfile).raw
endef
# Command definitions:
# - cmd_foo is the actual command to run;
# - quiet_cmd_foo is the brief-output summary of the command.
quiet_cmd_cc = CC($(TOOLSET)) $@
cmd_cc = $(CC.$(TOOLSET)) -o $@ $< $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c
quiet_cmd_cxx = CXX($(TOOLSET)) $@
cmd_cxx = $(CXX.$(TOOLSET)) -o $@ $< $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
quiet_cmd_copy = COPY $@
# send stderr to /dev/null to ignore messages when linking directories.
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
quiet_cmd_symlink = SYMLINK $@
cmd_symlink = ln -sf "$<" "$@"
quiet_cmd_alink = AR($(TOOLSET)) $@
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
# Due to circular dependencies between libraries :(, we wrap the
# special "figure out circular dependencies" flags around the entire
# input list during linking.
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) -o $@ $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group
# Note: this does not handle spaces in paths
define xargs
$(1) $(word 1,$(2))
$(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2))))
endef
define write-to-file
@: >$(1)
$(call xargs,@printf "%s\n" >>$(1),$(2))
endef
OBJ_FILE_LIST := ar-file-list
define create_archive
rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
$(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
$(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST)
endef
define create_thin_archive
rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
$(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
$(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST)
endef
# We support two kinds of shared objects (.so):
# 1) shared_library, which is just bundling together many dependent libraries
# into a link line.
# 2) loadable_module, which is generating a module intended for dlopen().
#
# They differ only slightly:
# In the former case, we want to package all dependent code into the .so.
# In the latter case, we want to package just the API exposed by the
# outermost module.
# This means shared_library uses --whole-archive, while loadable_module doesn't.
# (Note that --whole-archive is incompatible with the --start-group used in
# normal linking.)
# Other shared-object link notes:
# - Set SONAME to the library filename so our binaries don't reference
# the local, absolute paths used on the link command-line.
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
# Define an escape_quotes function to escape single quotes.
# This allows us to handle quotes properly as long as we always use
# use single quotes and escape_quotes.
escape_quotes = $(subst ','\'',$(1))
# This comment is here just to include a ' to unconfuse syntax highlighting.
# Define an escape_vars function to escape '$' variable syntax.
# This allows us to read/write command lines with shell variables (e.g.
# $LD_LIBRARY_PATH), without triggering make substitution.
escape_vars = $(subst $$,$$$$,$(1))
# Helper that expands to a shell command to echo a string exactly as it is in
# make. This uses printf instead of echo because printf's behaviour with respect
# to escape sequences is more portable than echo's across different shells
# (e.g., dash, bash).
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
# Helper to compare the command we're about to run against the command
# we logged the last time we ran the command. Produces an empty
# string (false) when the commands match.
# Tricky point: Make has no string-equality test function.
# The kernel uses the following, but it seems like it would have false
# positives, where one string reordered its arguments.
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
# $(filter-out $(cmd_$@), $(cmd_$(1))))
# We instead substitute each for the empty string into the other, and
# say they're equal if both substitutions produce the empty string.
# .d files contain ? instead of spaces, take that into account.
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
# Helper that is non-empty when a prerequisite changes.
# Normally make does this implicitly, but we force rules to always run
# so we can check their command lines.
# $? -- new prerequisites
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
# Helper that executes all postbuilds until one fails.
define do_postbuilds
@E=0;\
for p in $(POSTBUILDS); do\
eval $$p;\
E=$$?;\
if [ $$E -ne 0 ]; then\
break;\
fi;\
done;\
if [ $$E -ne 0 ]; then\
rm -rf "$@";\
exit $$E;\
fi
endef
# do_cmd: run a command via the above cmd_foo names, if necessary.
# Should always run for a given target to handle command-line changes.
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
# Third argument, if non-zero, makes it do POSTBUILDS processing.
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
# spaces already and dirx strips the ? characters.
define do_cmd
$(if $(or $(command_changed),$(prereq_changed)),
@$(call exact_echo, $($(quiet)cmd_$(1)))
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
$(if $(findstring flock,$(word 1,$(cmd_$1))),
@$(cmd_$(1))
@echo " $(quiet_cmd_$(1)): Finished",
@$(cmd_$(1))
)
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
@$(if $(2),$(fixup_dep))
$(if $(and $(3), $(POSTBUILDS)),
$(call do_postbuilds)
)
)
endef
# Declare the "all" target first so it is the default,
# even though we don't have the deps yet.
.PHONY: all
all:
# make looks for ways to re-generate included makefiles, but in our case, we
# don't have a direct way. Explicitly telling make that it has nothing to do
# for them makes it go faster.
%.d: ;
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
# do_cmd.
.PHONY: FORCE_DO_CMD
FORCE_DO_CMD:
TOOLSET := target
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
$(findstring $(join ^,$(prefix)),\
$(join ^,canvas.target.mk)))),)
include canvas.target.mk
endif
quiet_cmd_regen_makefile = ACTION Regenerating $@
cmd_regen_makefile = cd $(srcdir); /__t/node/21.7.3/x64/lib/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/github/home/.cache/node-gyp/21.7.3" "-Dnode_gyp_dir=/__t/node/21.7.3/x64/lib/node_modules/node-gyp" "-Dnode_lib_file=/github/home/.cache/node-gyp/21.7.3/<(target_arch)/node.lib" "-Dmodule_root_dir=/__w/node-canvas/node-canvas" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/__w/node-canvas/node-canvas/build/config.gypi -I/__t/node/21.7.3/x64/lib/node_modules/node-gyp/addon.gypi -I/github/home/.cache/node-gyp/21.7.3/include/node/common.gypi "--toplevel-dir=." binding.gyp
Makefile: $(srcdir)/../../../__t/node/21.7.3/x64/lib/node_modules/node-gyp/addon.gypi $(srcdir)/../../../github/home/.cache/node-gyp/21.7.3/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi
$(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
# sub-makefiles. This is just here to clarify.
all:
# Add in dependency-tracking rules. $(all_deps) is the list of every single
# target in our tree. Only consider the ones with .d (dependency) info:
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
ifneq ($(d_files),)
include $(d_files)
endif

View File

@@ -0,0 +1 @@
x64--119

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# This file is generated by gyp; do not edit.
export builddir_name ?= ./build/.
.PHONY: all
all:
$(MAKE) canvas

View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2015
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "canvas", "canvas.vcxproj", "{90D75E7A-41A0-8814-61A2-B5859FC0E033}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{90D75E7A-41A0-8814-61A2-B5859FC0E033}.Debug|x64.ActiveCfg = Debug|x64
{90D75E7A-41A0-8814-61A2-B5859FC0E033}.Debug|x64.Build.0 = Debug|x64
{90D75E7A-41A0-8814-61A2-B5859FC0E033}.Release|x64.ActiveCfg = Release|x64
{90D75E7A-41A0-8814-61A2-B5859FC0E033}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,223 @@
# This file is generated by gyp; do not edit.
TOOLSET := target
TARGET := canvas
DEFS_Debug := \
'-DNODE_GYP_MODULE_NAME=canvas' \
'-DUSING_UV_SHARED=1' \
'-DUSING_V8_SHARED=1' \
'-DV8_DEPRECATION_WARNINGS=1' \
'-D_GLIBCXX_USE_CXX11_ABI=1' \
'-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D__STDC_FORMAT_MACROS' \
'-DOPENSSL_NO_PINSHARED' \
'-DOPENSSL_THREADS' \
'-DHAVE_GIF' \
'-DHAVE_JPEG' \
'-DHAVE_RSVG' \
'-DNAPI_DISABLE_CPP_EXCEPTIONS' \
'-DNODE_ADDON_API_ENABLE_MAYBE' \
'-DBUILDING_NODE_EXTENSION' \
'-DDEBUG' \
'-D_DEBUG'
# Flags passed to all source files.
CFLAGS_Debug := \
-fPIC \
-pthread \
-Wall \
-Wextra \
-Wno-unused-parameter \
-m64 \
-g \
-O0
# Flags passed to only C files.
CFLAGS_C_Debug :=
# Flags passed to only C++ files.
CFLAGS_CC_Debug := \
-fno-rtti \
-std=gnu++17
INCS_Debug := \
-I/github/home/.cache/node-gyp/21.7.3/include/node \
-I/github/home/.cache/node-gyp/21.7.3/src \
-I/github/home/.cache/node-gyp/21.7.3/deps/openssl/config \
-I/github/home/.cache/node-gyp/21.7.3/deps/openssl/openssl/include \
-I/github/home/.cache/node-gyp/21.7.3/deps/uv/include \
-I/github/home/.cache/node-gyp/21.7.3/deps/zlib \
-I/github/home/.cache/node-gyp/21.7.3/deps/v8/include \
-I$(srcdir)/node_modules/node-addon-api \
-I/usr/local/include/cairo \
-I/usr/local/include \
-I/usr/local/include/glib-2.0 \
-I/usr/local/lib/glib-2.0/include \
-I/usr/local/include/pixman-1 \
-I/usr/local/include/freetype2 \
-I/usr/local/include/libpng16 \
-I/usr/local/include/pango-1.0 \
-I/usr/local/include/fribidi \
-I/usr/local/include/harfbuzz \
-I/usr/local/include/librsvg-2.0 \
-I/usr/local/include/gdk-pixbuf-2.0
DEFS_Release := \
'-DNODE_GYP_MODULE_NAME=canvas' \
'-DUSING_UV_SHARED=1' \
'-DUSING_V8_SHARED=1' \
'-DV8_DEPRECATION_WARNINGS=1' \
'-D_GLIBCXX_USE_CXX11_ABI=1' \
'-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D__STDC_FORMAT_MACROS' \
'-DOPENSSL_NO_PINSHARED' \
'-DOPENSSL_THREADS' \
'-DHAVE_GIF' \
'-DHAVE_JPEG' \
'-DHAVE_RSVG' \
'-DNAPI_DISABLE_CPP_EXCEPTIONS' \
'-DNODE_ADDON_API_ENABLE_MAYBE' \
'-DBUILDING_NODE_EXTENSION'
# Flags passed to all source files.
CFLAGS_Release := \
-fPIC \
-pthread \
-Wall \
-Wextra \
-Wno-unused-parameter \
-m64 \
-O3 \
-fno-omit-frame-pointer
# Flags passed to only C files.
CFLAGS_C_Release :=
# Flags passed to only C++ files.
CFLAGS_CC_Release := \
-fno-rtti \
-std=gnu++17
INCS_Release := \
-I/github/home/.cache/node-gyp/21.7.3/include/node \
-I/github/home/.cache/node-gyp/21.7.3/src \
-I/github/home/.cache/node-gyp/21.7.3/deps/openssl/config \
-I/github/home/.cache/node-gyp/21.7.3/deps/openssl/openssl/include \
-I/github/home/.cache/node-gyp/21.7.3/deps/uv/include \
-I/github/home/.cache/node-gyp/21.7.3/deps/zlib \
-I/github/home/.cache/node-gyp/21.7.3/deps/v8/include \
-I$(srcdir)/node_modules/node-addon-api \
-I/usr/local/include/cairo \
-I/usr/local/include \
-I/usr/local/include/glib-2.0 \
-I/usr/local/lib/glib-2.0/include \
-I/usr/local/include/pixman-1 \
-I/usr/local/include/freetype2 \
-I/usr/local/include/libpng16 \
-I/usr/local/include/pango-1.0 \
-I/usr/local/include/fribidi \
-I/usr/local/include/harfbuzz \
-I/usr/local/include/librsvg-2.0 \
-I/usr/local/include/gdk-pixbuf-2.0
OBJS := \
$(obj).target/$(TARGET)/src/backend/Backend.o \
$(obj).target/$(TARGET)/src/backend/ImageBackend.o \
$(obj).target/$(TARGET)/src/backend/PdfBackend.o \
$(obj).target/$(TARGET)/src/backend/SvgBackend.o \
$(obj).target/$(TARGET)/src/bmp/BMPParser.o \
$(obj).target/$(TARGET)/src/Backends.o \
$(obj).target/$(TARGET)/src/Canvas.o \
$(obj).target/$(TARGET)/src/CanvasGradient.o \
$(obj).target/$(TARGET)/src/CanvasPattern.o \
$(obj).target/$(TARGET)/src/CanvasRenderingContext2d.o \
$(obj).target/$(TARGET)/src/closure.o \
$(obj).target/$(TARGET)/src/color.o \
$(obj).target/$(TARGET)/src/Image.o \
$(obj).target/$(TARGET)/src/ImageData.o \
$(obj).target/$(TARGET)/src/init.o \
$(obj).target/$(TARGET)/src/register_font.o \
$(obj).target/$(TARGET)/src/FontParser.o
# Add to the list of files we specially track dependencies for.
all_deps += $(OBJS)
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := \
-pthread \
-rdynamic \
-Wl,-rpath '-Wl,$$ORIGIN' \
-m64
LDFLAGS_Release := \
-pthread \
-rdynamic \
-Wl,-rpath '-Wl,$$ORIGIN' \
-m64
LIBS := \
-L/usr/local/lib \
-lpixman-1 \
-lcairo \
-lpng16 \
-lz \
-lpangocairo-1.0 \
-lpango-1.0 \
-lgobject-2.0 \
-lglib-2.0 \
-lharfbuzz \
-lfreetype \
-lrsvg-2 \
-lm \
-lgio-2.0 \
-lgdk_pixbuf-2.0 \
-ljpeg \
-lgif
$(obj).target/canvas.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(obj).target/canvas.node: LIBS := $(LIBS)
$(obj).target/canvas.node: TOOLSET := $(TOOLSET)
$(obj).target/canvas.node: $(OBJS) FORCE_DO_CMD
$(call do_cmd,solink_module)
all_deps += $(obj).target/canvas.node
# Add target alias
.PHONY: canvas
canvas: $(builddir)/canvas.node
# Copy this to the executable output path.
$(builddir)/canvas.node: TOOLSET := $(TOOLSET)
$(builddir)/canvas.node: $(obj).target/canvas.node FORCE_DO_CMD
$(call do_cmd,copy)
all_deps += $(builddir)/canvas.node
# Short alias for building this executable.
.PHONY: canvas.node
canvas.node: $(obj).target/canvas.node $(builddir)/canvas.node
# Add executable to "all" target.
.PHONY: all
all: $(builddir)/canvas.node

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{90D75E7A-41A0-8814-61A2-B5859FC0E033}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>canvas</RootNamespace>
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<PropertyGroup Label="Locals">
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props"/>
<ImportGroup Label="ExtensionSettings"/>
<ImportGroup Label="PropertySheets">
<Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
</ImportGroup>
<PropertyGroup Label="UserMacros"/>
<PropertyGroup>
<ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\</ExecutablePath>
<IgnoreImportLibrary>true</IgnoreImportLibrary>
<IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
<TargetName>$(ProjectName)</TargetName>
<TargetPath>$(OutDir)\$(ProjectName).node</TargetPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\include\node;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\src;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\config;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\openssl\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\uv\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\zlib;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\v8\include;..\node_modules\node-addon-api;D:\a\_temp\msys64\ucrt64\include;D:\a\_temp\msys64\ucrt64\include\harfbuzz;D:\a\_temp\msys64\ucrt64\include\pango-1.0;D:\a\_temp\msys64\ucrt64\include\cairo;D:\a\_temp\msys64\ucrt64\include\libpng16;D:\a\_temp\msys64\ucrt64\include\glib-2.0;D:\a\_temp\msys64\ucrt64\lib\glib-2.0\include;D:\a\_temp\msys64\ucrt64\include\pixman-1;D:\a\_temp\msys64\ucrt64\include\freetype2;D:\a\_temp\msys64\ucrt64\include\fontconfig;D:\a\_temp\msys64\ucrt64\include\librsvg-2.0;D:\a\_temp\msys64\ucrt64\include\gdk-pixbuf-2.0;D:\a\_temp\msys64\ucrt64\include\libgsf-1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/Zc:__cplusplus -std:c++17 %(AdditionalOptions)</AdditionalOptions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4201;4244;4267;4506;4611;4714;4512;4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>Sync</ExceptionHandling>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>false</OmitFramePointers>
<Optimization>Disabled</Optimization>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=canvas;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;HAVE_GIF;HAVE_JPEG;HAVE_RSVG;HAVE_BOOLEAN;_USE_MATH_DEFINES;NOMINMAX;NAPI_DISABLE_CPP_EXCEPTIONS;NODE_ADDON_API_ENABLE_MAYBE;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StringPooling>true</StringPooling>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TreatWarningAsError>false</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<Lib>
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
</Lib>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\\Users\\runneradmin\\AppData\\Local\\node-gyp\\Cache\\21.7.3\\x64\\node.lib&quot;;D:\a\_temp\msys64\ucrt64\lib\libcairo-2.lib;D:\a\_temp\msys64\ucrt64\lib\libpng16-16.lib;D:\a\_temp\msys64\ucrt64\lib\libjpeg-8.lib;D:\a\_temp\msys64\ucrt64\lib\libpango-1.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libpangocairo-1.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libgobject-2.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libglib-2.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libturbojpeg.lib;D:\a\_temp\msys64\ucrt64\lib\libgif-7.lib;D:\a\_temp\msys64\ucrt64\lib\libfreetype-6.lib;D:\a\_temp\msys64\ucrt64\lib\librsvg-2-2.lib</AdditionalDependencies>
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetExt>.node</TargetExt>
<TargetMachine>MachineX64</TargetMachine>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\include\node;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\src;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\config;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\openssl\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\uv\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\zlib;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\v8\include;..\node_modules\node-addon-api;D:\a\_temp\msys64\ucrt64\include;D:\a\_temp\msys64\ucrt64\include\harfbuzz;D:\a\_temp\msys64\ucrt64\include\pango-1.0;D:\a\_temp\msys64\ucrt64\include\cairo;D:\a\_temp\msys64\ucrt64\include\libpng16;D:\a\_temp\msys64\ucrt64\include\glib-2.0;D:\a\_temp\msys64\ucrt64\lib\glib-2.0\include;D:\a\_temp\msys64\ucrt64\include\pixman-1;D:\a\_temp\msys64\ucrt64\include\freetype2;D:\a\_temp\msys64\ucrt64\include\fontconfig;D:\a\_temp\msys64\ucrt64\include\librsvg-2.0;D:\a\_temp\msys64\ucrt64\include\gdk-pixbuf-2.0;D:\a\_temp\msys64\ucrt64\include\libgsf-1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=canvas;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;HAVE_GIF;HAVE_JPEG;HAVE_RSVG;HAVE_BOOLEAN;_USE_MATH_DEFINES;NOMINMAX;NAPI_DISABLE_CPP_EXCEPTIONS;NODE_ADDON_API_ENABLE_MAYBE;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\include\node;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\src;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\config;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\openssl\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\uv\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\zlib;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\v8\include;..\node_modules\node-addon-api;D:\a\_temp\msys64\ucrt64\include;D:\a\_temp\msys64\ucrt64\include\harfbuzz;D:\a\_temp\msys64\ucrt64\include\pango-1.0;D:\a\_temp\msys64\ucrt64\include\cairo;D:\a\_temp\msys64\ucrt64\include\libpng16;D:\a\_temp\msys64\ucrt64\include\glib-2.0;D:\a\_temp\msys64\ucrt64\lib\glib-2.0\include;D:\a\_temp\msys64\ucrt64\include\pixman-1;D:\a\_temp\msys64\ucrt64\include\freetype2;D:\a\_temp\msys64\ucrt64\include\fontconfig;D:\a\_temp\msys64\ucrt64\include\librsvg-2.0;D:\a\_temp\msys64\ucrt64\include\gdk-pixbuf-2.0;D:\a\_temp\msys64\ucrt64\include\libgsf-1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/Zc:__cplusplus -std:c++17 %(AdditionalOptions)</AdditionalOptions>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4201;4244;4267;4506;4611;4714;4512;4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>Sync</ExceptionHandling>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<FunctionLevelLinking>true</FunctionLevelLinking>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<Optimization>Full</Optimization>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=canvas;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;HAVE_GIF;HAVE_JPEG;HAVE_RSVG;HAVE_BOOLEAN;_USE_MATH_DEFINES;NOMINMAX;NAPI_DISABLE_CPP_EXCEPTIONS;NODE_ADDON_API_ENABLE_MAYBE;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<StringPooling>true</StringPooling>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TreatWarningAsError>false</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<Lib>
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
</Lib>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\\Users\\runneradmin\\AppData\\Local\\node-gyp\\Cache\\21.7.3\\x64\\node.lib&quot;;D:\a\_temp\msys64\ucrt64\lib\libcairo-2.lib;D:\a\_temp\msys64\ucrt64\lib\libpng16-16.lib;D:\a\_temp\msys64\ucrt64\lib\libjpeg-8.lib;D:\a\_temp\msys64\ucrt64\lib\libpango-1.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libpangocairo-1.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libgobject-2.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libglib-2.0-0.lib;D:\a\_temp\msys64\ucrt64\lib\libturbojpeg.lib;D:\a\_temp\msys64\ucrt64\lib\libgif-7.lib;D:\a\_temp\msys64\ucrt64\lib\libfreetype-6.lib;D:\a\_temp\msys64\ucrt64\lib\librsvg-2-2.lib</AdditionalDependencies>
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetExt>.node</TargetExt>
<TargetMachine>MachineX64</TargetMachine>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\include\node;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\src;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\config;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\openssl\openssl\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\uv\include;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\zlib;C:\Users\runneradmin\AppData\Local\node-gyp\Cache\21.7.3\deps\v8\include;..\node_modules\node-addon-api;D:\a\_temp\msys64\ucrt64\include;D:\a\_temp\msys64\ucrt64\include\harfbuzz;D:\a\_temp\msys64\ucrt64\include\pango-1.0;D:\a\_temp\msys64\ucrt64\include\cairo;D:\a\_temp\msys64\ucrt64\include\libpng16;D:\a\_temp\msys64\ucrt64\include\glib-2.0;D:\a\_temp\msys64\ucrt64\lib\glib-2.0\include;D:\a\_temp\msys64\ucrt64\include\pixman-1;D:\a\_temp\msys64\ucrt64\include\freetype2;D:\a\_temp\msys64\ucrt64\include\fontconfig;D:\a\_temp\msys64\ucrt64\include\librsvg-2.0;D:\a\_temp\msys64\ucrt64\include\gdk-pixbuf-2.0;D:\a\_temp\msys64\ucrt64\include\libgsf-1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=canvas;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;HAVE_GIF;HAVE_JPEG;HAVE_RSVG;HAVE_BOOLEAN;_USE_MATH_DEFINES;NOMINMAX;NAPI_DISABLE_CPP_EXCEPTIONS;NODE_ADDON_API_ENABLE_MAYBE;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="..\binding.gyp"/>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\backend\Backend.cc">
<ObjectFileName>$(IntDir)\src\backend\Backend.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\backend\ImageBackend.cc">
<ObjectFileName>$(IntDir)\src\backend\ImageBackend.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\backend\PdfBackend.cc">
<ObjectFileName>$(IntDir)\src\backend\PdfBackend.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\backend\SvgBackend.cc">
<ObjectFileName>$(IntDir)\src\backend\SvgBackend.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\bmp\BMPParser.cc">
<ObjectFileName>$(IntDir)\src\bmp\BMPParser.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\Backends.cc">
<ObjectFileName>$(IntDir)\src\Backends.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\Canvas.cc">
<ObjectFileName>$(IntDir)\src\Canvas.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\CanvasGradient.cc">
<ObjectFileName>$(IntDir)\src\CanvasGradient.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\CanvasPattern.cc">
<ObjectFileName>$(IntDir)\src\CanvasPattern.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\CanvasRenderingContext2d.cc">
<ObjectFileName>$(IntDir)\src\CanvasRenderingContext2d.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\closure.cc">
<ObjectFileName>$(IntDir)\src\closure.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\color.cc">
<ObjectFileName>$(IntDir)\src\color.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\Image.cc">
<ObjectFileName>$(IntDir)\src\Image.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\ImageData.cc">
<ObjectFileName>$(IntDir)\src\ImageData.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\init.cc">
<ObjectFileName>$(IntDir)\src\init.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\register_font.cc">
<ObjectFileName>$(IntDir)\src\register_font.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\src\FontParser.cc">
<ObjectFileName>$(IntDir)\src\FontParser.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.cc"/>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets"/>
<ImportGroup Label="ExtensionTargets"/>
</Project>

View File

@@ -0,0 +1,217 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..\src\backend">
<UniqueIdentifier>{0601BD18-2FE3-2D4A-0C05-611A0F36D709}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..\src\backend">
<UniqueIdentifier>{0601BD18-2FE3-2D4A-0C05-611A0F36D709}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..\src\backend">
<UniqueIdentifier>{0601BD18-2FE3-2D4A-0C05-611A0F36D709}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..\src\backend">
<UniqueIdentifier>{0601BD18-2FE3-2D4A-0C05-611A0F36D709}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..\src\bmp">
<UniqueIdentifier>{C08C95BF-9646-DB44-5C81-9CB5B5F652A5}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
<Filter Include="..\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="C:">
<UniqueIdentifier>{7B735499-E5DD-1C2B-6C26-70023832A1CF}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache">
<UniqueIdentifier>{296B63E6-8BC4-B79B-77CC-9C615B0D2B0F}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows">
<UniqueIdentifier>{C1450D01-C033-76F3-3763-6DE88AF48A77}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node">
<UniqueIdentifier>{A49AD564-6B22-6A46-08E5-B5A7F4427839}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3">
<UniqueIdentifier>{1C63F1C8-0353-A369-E968-394FCDA23886}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64">
<UniqueIdentifier>{E075064C-529C-A4E7-0810-FB88D599C3BE}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules">
<UniqueIdentifier>{56DF7A98-063D-FB9D-485C-089023B4C16A}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm">
<UniqueIdentifier>{741E0E76-39B2-B1AB-9FA1-F1A20B16F295}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules">
<UniqueIdentifier>{56DF7A98-063D-FB9D-485C-089023B4C16A}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules\node-gyp">
<UniqueIdentifier>{77348C0E-2034-7791-74D5-63C077DF5A3B}</UniqueIdentifier>
</Filter>
<Filter Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules\node-gyp\src">
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
</Filter>
<Filter Include="..">
<UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\backend\Backend.cc">
<Filter>..\src\backend</Filter>
</ClCompile>
<ClCompile Include="..\src\backend\ImageBackend.cc">
<Filter>..\src\backend</Filter>
</ClCompile>
<ClCompile Include="..\src\backend\PdfBackend.cc">
<Filter>..\src\backend</Filter>
</ClCompile>
<ClCompile Include="..\src\backend\SvgBackend.cc">
<Filter>..\src\backend</Filter>
</ClCompile>
<ClCompile Include="..\src\bmp\BMPParser.cc">
<Filter>..\src\bmp</Filter>
</ClCompile>
<ClCompile Include="..\src\Backends.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\Canvas.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\CanvasGradient.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\CanvasPattern.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\CanvasRenderingContext2d.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\closure.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\color.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\Image.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\ImageData.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\init.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\register_font.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="..\src\FontParser.cc">
<Filter>..\src</Filter>
</ClCompile>
<ClCompile Include="C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.cc">
<Filter>C:\hostedtoolcache\windows\node\21.7.3\x64\node_modules\npm\node_modules\node-gyp\src</Filter>
</ClCompile>
<None Include="..\binding.gyp">
<Filter>..</Filter>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,420 @@
# Do not edit. File was generated by node-gyp's "configure" step
{
"target_defaults": {
"cflags": [],
"default_configuration": "Release",
"defines": [],
"include_dirs": [],
"libraries": []
},
"variables": {
"asan": 0,
"coverage": "false",
"dcheck_always_on": 0,
"debug_nghttp2": "false",
"debug_node": "false",
"enable_lto": "false",
"enable_pgo_generate": "false",
"enable_pgo_use": "false",
"error_on_warn": "false",
"force_dynamic_crt": 0,
"gas_version": "2.35",
"host_arch": "x64",
"icu_data_in": "../../deps/icu-tmp/icudt74l.dat",
"icu_endianness": "l",
"icu_gyp_path": "tools/icu/icu-generic.gyp",
"icu_path": "deps/icu-small",
"icu_small": "false",
"icu_ver_major": "74",
"is_debug": 0,
"libdir": "lib",
"llvm_version": "0.0",
"napi_build_version": "9",
"node_builtin_shareable_builtins": [
"deps/cjs-module-lexer/lexer.js",
"deps/cjs-module-lexer/dist/lexer.js",
"deps/undici/undici.js"
],
"node_byteorder": "little",
"node_debug_lib": "false",
"node_enable_d8": "false",
"node_enable_v8_vtunejit": "false",
"node_fipsinstall": "false",
"node_install_corepack": "true",
"node_install_npm": "true",
"node_library_files": [
"lib/_http_agent.js",
"lib/_http_client.js",
"lib/_http_common.js",
"lib/_http_incoming.js",
"lib/_http_outgoing.js",
"lib/_http_server.js",
"lib/_stream_duplex.js",
"lib/_stream_passthrough.js",
"lib/_stream_readable.js",
"lib/_stream_transform.js",
"lib/_stream_wrap.js",
"lib/_stream_writable.js",
"lib/_tls_common.js",
"lib/_tls_wrap.js",
"lib/assert.js",
"lib/assert/strict.js",
"lib/async_hooks.js",
"lib/buffer.js",
"lib/child_process.js",
"lib/cluster.js",
"lib/console.js",
"lib/constants.js",
"lib/crypto.js",
"lib/dgram.js",
"lib/diagnostics_channel.js",
"lib/dns.js",
"lib/dns/promises.js",
"lib/domain.js",
"lib/events.js",
"lib/fs.js",
"lib/fs/promises.js",
"lib/http.js",
"lib/http2.js",
"lib/https.js",
"lib/inspector.js",
"lib/inspector/promises.js",
"lib/internal/abort_controller.js",
"lib/internal/assert.js",
"lib/internal/assert/assertion_error.js",
"lib/internal/assert/calltracker.js",
"lib/internal/async_hooks.js",
"lib/internal/blob.js",
"lib/internal/blocklist.js",
"lib/internal/bootstrap/node.js",
"lib/internal/bootstrap/realm.js",
"lib/internal/bootstrap/shadow_realm.js",
"lib/internal/bootstrap/switches/does_not_own_process_state.js",
"lib/internal/bootstrap/switches/does_own_process_state.js",
"lib/internal/bootstrap/switches/is_main_thread.js",
"lib/internal/bootstrap/switches/is_not_main_thread.js",
"lib/internal/bootstrap/web/exposed-wildcard.js",
"lib/internal/bootstrap/web/exposed-window-or-worker.js",
"lib/internal/buffer.js",
"lib/internal/child_process.js",
"lib/internal/child_process/serialization.js",
"lib/internal/cli_table.js",
"lib/internal/cluster/child.js",
"lib/internal/cluster/primary.js",
"lib/internal/cluster/round_robin_handle.js",
"lib/internal/cluster/shared_handle.js",
"lib/internal/cluster/utils.js",
"lib/internal/cluster/worker.js",
"lib/internal/console/constructor.js",
"lib/internal/console/global.js",
"lib/internal/constants.js",
"lib/internal/crypto/aes.js",
"lib/internal/crypto/certificate.js",
"lib/internal/crypto/cfrg.js",
"lib/internal/crypto/cipher.js",
"lib/internal/crypto/diffiehellman.js",
"lib/internal/crypto/ec.js",
"lib/internal/crypto/hash.js",
"lib/internal/crypto/hashnames.js",
"lib/internal/crypto/hkdf.js",
"lib/internal/crypto/keygen.js",
"lib/internal/crypto/keys.js",
"lib/internal/crypto/mac.js",
"lib/internal/crypto/pbkdf2.js",
"lib/internal/crypto/random.js",
"lib/internal/crypto/rsa.js",
"lib/internal/crypto/scrypt.js",
"lib/internal/crypto/sig.js",
"lib/internal/crypto/util.js",
"lib/internal/crypto/webcrypto.js",
"lib/internal/crypto/webidl.js",
"lib/internal/crypto/x509.js",
"lib/internal/debugger/inspect.js",
"lib/internal/debugger/inspect_client.js",
"lib/internal/debugger/inspect_repl.js",
"lib/internal/dgram.js",
"lib/internal/dns/callback_resolver.js",
"lib/internal/dns/promises.js",
"lib/internal/dns/utils.js",
"lib/internal/encoding.js",
"lib/internal/error_serdes.js",
"lib/internal/errors.js",
"lib/internal/event_target.js",
"lib/internal/events/symbols.js",
"lib/internal/file.js",
"lib/internal/fixed_queue.js",
"lib/internal/freelist.js",
"lib/internal/freeze_intrinsics.js",
"lib/internal/fs/cp/cp-sync.js",
"lib/internal/fs/cp/cp.js",
"lib/internal/fs/dir.js",
"lib/internal/fs/glob.js",
"lib/internal/fs/promises.js",
"lib/internal/fs/read/context.js",
"lib/internal/fs/recursive_watch.js",
"lib/internal/fs/rimraf.js",
"lib/internal/fs/streams.js",
"lib/internal/fs/sync_write_stream.js",
"lib/internal/fs/utils.js",
"lib/internal/fs/watchers.js",
"lib/internal/heap_utils.js",
"lib/internal/histogram.js",
"lib/internal/http.js",
"lib/internal/http2/compat.js",
"lib/internal/http2/core.js",
"lib/internal/http2/util.js",
"lib/internal/idna.js",
"lib/internal/inspector_async_hook.js",
"lib/internal/js_stream_socket.js",
"lib/internal/legacy/processbinding.js",
"lib/internal/linkedlist.js",
"lib/internal/main/check_syntax.js",
"lib/internal/main/embedding.js",
"lib/internal/main/eval_stdin.js",
"lib/internal/main/eval_string.js",
"lib/internal/main/inspect.js",
"lib/internal/main/mksnapshot.js",
"lib/internal/main/print_help.js",
"lib/internal/main/prof_process.js",
"lib/internal/main/repl.js",
"lib/internal/main/run_main_module.js",
"lib/internal/main/test_runner.js",
"lib/internal/main/watch_mode.js",
"lib/internal/main/worker_thread.js",
"lib/internal/mime.js",
"lib/internal/modules/cjs/loader.js",
"lib/internal/modules/esm/assert.js",
"lib/internal/modules/esm/create_dynamic_module.js",
"lib/internal/modules/esm/fetch_module.js",
"lib/internal/modules/esm/formats.js",
"lib/internal/modules/esm/get_format.js",
"lib/internal/modules/esm/handle_process_exit.js",
"lib/internal/modules/esm/hooks.js",
"lib/internal/modules/esm/initialize_import_meta.js",
"lib/internal/modules/esm/load.js",
"lib/internal/modules/esm/loader.js",
"lib/internal/modules/esm/module_job.js",
"lib/internal/modules/esm/module_map.js",
"lib/internal/modules/esm/resolve.js",
"lib/internal/modules/esm/shared_constants.js",
"lib/internal/modules/esm/translators.js",
"lib/internal/modules/esm/utils.js",
"lib/internal/modules/esm/worker.js",
"lib/internal/modules/helpers.js",
"lib/internal/modules/package_json_reader.js",
"lib/internal/modules/run_main.js",
"lib/internal/navigator.js",
"lib/internal/net.js",
"lib/internal/options.js",
"lib/internal/per_context/domexception.js",
"lib/internal/per_context/messageport.js",
"lib/internal/per_context/primordials.js",
"lib/internal/perf/event_loop_delay.js",
"lib/internal/perf/event_loop_utilization.js",
"lib/internal/perf/nodetiming.js",
"lib/internal/perf/observe.js",
"lib/internal/perf/performance.js",
"lib/internal/perf/performance_entry.js",
"lib/internal/perf/resource_timing.js",
"lib/internal/perf/timerify.js",
"lib/internal/perf/usertiming.js",
"lib/internal/perf/utils.js",
"lib/internal/policy/manifest.js",
"lib/internal/policy/sri.js",
"lib/internal/priority_queue.js",
"lib/internal/process/esm_loader.js",
"lib/internal/process/execution.js",
"lib/internal/process/per_thread.js",
"lib/internal/process/permission.js",
"lib/internal/process/policy.js",
"lib/internal/process/pre_execution.js",
"lib/internal/process/promises.js",
"lib/internal/process/report.js",
"lib/internal/process/signal.js",
"lib/internal/process/task_queues.js",
"lib/internal/process/warning.js",
"lib/internal/process/worker_thread_only.js",
"lib/internal/promise_hooks.js",
"lib/internal/querystring.js",
"lib/internal/readline/callbacks.js",
"lib/internal/readline/emitKeypressEvents.js",
"lib/internal/readline/interface.js",
"lib/internal/readline/promises.js",
"lib/internal/readline/utils.js",
"lib/internal/repl.js",
"lib/internal/repl/await.js",
"lib/internal/repl/history.js",
"lib/internal/repl/utils.js",
"lib/internal/socket_list.js",
"lib/internal/socketaddress.js",
"lib/internal/source_map/prepare_stack_trace.js",
"lib/internal/source_map/source_map.js",
"lib/internal/source_map/source_map_cache.js",
"lib/internal/stream_base_commons.js",
"lib/internal/streams/add-abort-signal.js",
"lib/internal/streams/compose.js",
"lib/internal/streams/destroy.js",
"lib/internal/streams/duplex.js",
"lib/internal/streams/duplexify.js",
"lib/internal/streams/end-of-stream.js",
"lib/internal/streams/from.js",
"lib/internal/streams/lazy_transform.js",
"lib/internal/streams/legacy.js",
"lib/internal/streams/operators.js",
"lib/internal/streams/passthrough.js",
"lib/internal/streams/pipeline.js",
"lib/internal/streams/readable.js",
"lib/internal/streams/state.js",
"lib/internal/streams/transform.js",
"lib/internal/streams/utils.js",
"lib/internal/streams/writable.js",
"lib/internal/test/binding.js",
"lib/internal/test/transfer.js",
"lib/internal/test_runner/coverage.js",
"lib/internal/test_runner/harness.js",
"lib/internal/test_runner/mock/mock.js",
"lib/internal/test_runner/mock/mock_timers.js",
"lib/internal/test_runner/reporter/dot.js",
"lib/internal/test_runner/reporter/junit.js",
"lib/internal/test_runner/reporter/lcov.js",
"lib/internal/test_runner/reporter/spec.js",
"lib/internal/test_runner/reporter/tap.js",
"lib/internal/test_runner/reporter/v8-serializer.js",
"lib/internal/test_runner/runner.js",
"lib/internal/test_runner/test.js",
"lib/internal/test_runner/tests_stream.js",
"lib/internal/test_runner/utils.js",
"lib/internal/timers.js",
"lib/internal/tls/secure-context.js",
"lib/internal/tls/secure-pair.js",
"lib/internal/trace_events_async_hooks.js",
"lib/internal/tty.js",
"lib/internal/url.js",
"lib/internal/util.js",
"lib/internal/util/colors.js",
"lib/internal/util/comparisons.js",
"lib/internal/util/debuglog.js",
"lib/internal/util/embedding.js",
"lib/internal/util/inspect.js",
"lib/internal/util/inspector.js",
"lib/internal/util/iterable_weak_map.js",
"lib/internal/util/parse_args/parse_args.js",
"lib/internal/util/parse_args/utils.js",
"lib/internal/util/types.js",
"lib/internal/v8/startup_snapshot.js",
"lib/internal/v8_prof_polyfill.js",
"lib/internal/v8_prof_processor.js",
"lib/internal/validators.js",
"lib/internal/vm.js",
"lib/internal/vm/module.js",
"lib/internal/wasm_web_api.js",
"lib/internal/watch_mode/files_watcher.js",
"lib/internal/watchdog.js",
"lib/internal/webidl.js",
"lib/internal/webstreams/adapters.js",
"lib/internal/webstreams/compression.js",
"lib/internal/webstreams/encoding.js",
"lib/internal/webstreams/queuingstrategies.js",
"lib/internal/webstreams/readablestream.js",
"lib/internal/webstreams/transfer.js",
"lib/internal/webstreams/transformstream.js",
"lib/internal/webstreams/util.js",
"lib/internal/webstreams/writablestream.js",
"lib/internal/worker.js",
"lib/internal/worker/io.js",
"lib/internal/worker/js_transferable.js",
"lib/module.js",
"lib/net.js",
"lib/os.js",
"lib/path.js",
"lib/path/posix.js",
"lib/path/win32.js",
"lib/perf_hooks.js",
"lib/process.js",
"lib/punycode.js",
"lib/querystring.js",
"lib/readline.js",
"lib/readline/promises.js",
"lib/repl.js",
"lib/sea.js",
"lib/stream.js",
"lib/stream/consumers.js",
"lib/stream/promises.js",
"lib/stream/web.js",
"lib/string_decoder.js",
"lib/sys.js",
"lib/test.js",
"lib/test/reporters.js",
"lib/timers.js",
"lib/timers/promises.js",
"lib/tls.js",
"lib/trace_events.js",
"lib/tty.js",
"lib/url.js",
"lib/util.js",
"lib/util/types.js",
"lib/v8.js",
"lib/vm.js",
"lib/wasi.js",
"lib/worker_threads.js",
"lib/zlib.js"
],
"node_module_version": 120,
"node_no_browser_globals": "false",
"node_prefix": "/",
"node_release_urlbase": "https://nodejs.org/download/release/",
"node_section_ordering_info": "",
"node_shared": "false",
"node_shared_brotli": "false",
"node_shared_cares": "false",
"node_shared_http_parser": "false",
"node_shared_libuv": "false",
"node_shared_nghttp2": "false",
"node_shared_nghttp3": "false",
"node_shared_ngtcp2": "false",
"node_shared_openssl": "false",
"node_shared_zlib": "false",
"node_tag": "",
"node_target_type": "executable",
"node_use_bundled_v8": "true",
"node_use_node_code_cache": "true",
"node_use_node_snapshot": "true",
"node_use_openssl": "true",
"node_use_v8_platform": "true",
"node_with_ltcg": "false",
"node_without_node_options": "false",
"node_write_snapshot_as_array_literals": "false",
"openssl_is_fips": "false",
"openssl_quic": "true",
"ossfuzz": "false",
"shlib_suffix": "so.120",
"single_executable_application": "true",
"target_arch": "x64",
"use_prefix_to_find_headers": "false",
"v8_enable_31bit_smis_on_64bit_arch": 0,
"v8_enable_extensible_ro_snapshot": 0,
"v8_enable_gdbjit": 0,
"v8_enable_hugepage": 0,
"v8_enable_i18n_support": 1,
"v8_enable_inspector": 1,
"v8_enable_javascript_promise_hooks": 1,
"v8_enable_lite_mode": 0,
"v8_enable_maglev": 0,
"v8_enable_object_print": 1,
"v8_enable_pointer_compression": 0,
"v8_enable_shared_ro_heap": 1,
"v8_enable_short_builtin_calls": 1,
"v8_enable_v8_checks": 0,
"v8_enable_webassembly": 1,
"v8_no_strict_aliasing": 1,
"v8_optimized_debug": 1,
"v8_promise_internal_field_count": 1,
"v8_random_seed": 0,
"v8_trace_maps": 0,
"v8_use_siphash": 1,
"want_separate_host_toolset": 0,
"nodedir": "/github/home/.cache/node-gyp/21.7.3",
"python": "/usr/local/bin/python3",
"standalone_static_library": 1
}
}

507
node_modules/loupedeck/node_modules/canvas/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,507 @@
// TypeScript Version: 3.0
import { Readable } from 'stream'
export interface PngConfig {
/** Specifies the ZLIB compression level. Defaults to 6. */
compressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
/**
* Any bitwise combination of `PNG_FILTER_NONE`, `PNG_FILTER_SUB`,
* `PNG_FILTER_UP`, `PNG_FILTER_AVG` and `PNG_FILTER_PATETH`; or one of
* `PNG_ALL_FILTERS` or `PNG_NO_FILTERS` (all are properties of the canvas
* instance). These specify which filters *may* be used by libpng. During
* encoding, libpng will select the best filter from this list of allowed
* filters. Defaults to `canvas.PNG_ALL_FILTERS`.
*/
filters?: number
/**
* _For creating indexed PNGs._ The palette of colors. Entries should be in
* RGBA order.
*/
palette?: Uint8ClampedArray
/**
* _For creating indexed PNGs._ The index of the background color. Defaults
* to 0.
*/
backgroundIndex?: number
/** pixels per inch */
resolution?: number
}
export interface JpegConfig {
/** Specifies the quality, between 0 and 1. Defaults to 0.75. */
quality?: number
/** Enables progressive encoding. Defaults to `false`. */
progressive?: boolean
/** Enables 2x2 chroma subsampling. Defaults to `true`. */
chromaSubsampling?: boolean
}
export interface PdfConfig {
title?: string
author?: string
subject?: string
keywords?: string
creator?: string
creationDate?: Date
modDate?: Date
}
export interface NodeCanvasRenderingContext2DSettings {
alpha?: boolean
pixelFormat?: 'RGBA32' | 'RGB24' | 'A8' | 'RGB16_565' | 'A1' | 'RGB30'
}
export class Canvas {
width: number
height: number
/** _Non standard._ The type of the canvas. */
readonly type: 'image'|'pdf'|'svg'
/** _Non standard._ Getter. The stride used by the canvas. */
readonly stride: number;
/** Constant used in PNG encoding methods. */
static readonly PNG_NO_FILTERS: number
/** Constant used in PNG encoding methods. */
static readonly PNG_ALL_FILTERS: number
/** Constant used in PNG encoding methods. */
static readonly PNG_FILTER_NONE: number
/** Constant used in PNG encoding methods. */
static readonly PNG_FILTER_SUB: number
/** Constant used in PNG encoding methods. */
static readonly PNG_FILTER_UP: number
/** Constant used in PNG encoding methods. */
static readonly PNG_FILTER_AVG: number
/** Constant used in PNG encoding methods. */
static readonly PNG_FILTER_PAETH: number
constructor(width: number, height: number, type?: 'image'|'pdf'|'svg')
getContext(contextId: '2d', contextAttributes?: NodeCanvasRenderingContext2DSettings): CanvasRenderingContext2D
/**
* For image canvases, encodes the canvas as a PNG. For PDF canvases,
* encodes the canvas as a PDF. For SVG canvases, encodes the canvas as an
* SVG.
*/
toBuffer(cb: (err: Error|null, result: Buffer) => void): void
toBuffer(cb: (err: Error|null, result: Buffer) => void, mimeType: 'image/png', config?: PngConfig): void
toBuffer(cb: (err: Error|null, result: Buffer) => void, mimeType: 'image/jpeg', config?: JpegConfig): void
/**
* For image canvases, encodes the canvas as a PNG. For PDF canvases,
* encodes the canvas as a PDF. For SVG canvases, encodes the canvas as an
* SVG.
*/
toBuffer(): Buffer
toBuffer(mimeType: 'image/png', config?: PngConfig): Buffer
toBuffer(mimeType: 'image/jpeg', config?: JpegConfig): Buffer
toBuffer(mimeType: 'application/pdf', config?: PdfConfig): Buffer
/**
* Returns the unencoded pixel data, top-to-bottom. On little-endian (most)
* systems, the array will be ordered BGRA; on big-endian systems, it will
* be ARGB.
*/
toBuffer(mimeType: 'raw'): Buffer
createPNGStream(config?: PngConfig): PNGStream
createJPEGStream(config?: JpegConfig): JPEGStream
createPDFStream(config?: PdfConfig): PDFStream
/** Defaults to PNG image. */
toDataURL(): string
toDataURL(mimeType: 'image/png'): string
toDataURL(mimeType: 'image/jpeg', quality?: number): string
/** _Non-standard._ Defaults to PNG image. */
toDataURL(cb: (err: Error|null, result: string) => void): void
/** _Non-standard._ */
toDataURL(mimeType: 'image/png', cb: (err: Error|null, result: string) => void): void
/** _Non-standard._ */
toDataURL(mimeType: 'image/jpeg', cb: (err: Error|null, result: string) => void): void
/** _Non-standard._ */
toDataURL(mimeType: 'image/jpeg', config: JpegConfig, cb: (err: Error|null, result: string) => void): void
/** _Non-standard._ */
toDataURL(mimeType: 'image/jpeg', quality: number, cb: (err: Error|null, result: string) => void): void
}
export interface TextMetrics {
readonly alphabeticBaseline: number;
readonly actualBoundingBoxAscent: number;
readonly actualBoundingBoxDescent: number;
readonly actualBoundingBoxLeft: number;
readonly actualBoundingBoxRight: number;
readonly emHeightAscent: number;
readonly emHeightDescent: number;
readonly fontBoundingBoxAscent: number;
readonly fontBoundingBoxDescent: number;
readonly width: number;
}
export type CanvasFillRule = 'evenodd' | 'nonzero';
export type GlobalCompositeOperation =
| 'clear'
| 'copy'
| 'destination'
| 'source-over'
| 'destination-over'
| 'source-in'
| 'destination-in'
| 'source-out'
| 'destination-out'
| 'source-atop'
| 'destination-atop'
| 'xor'
| 'lighter'
| 'normal'
| 'multiply'
| 'screen'
| 'overlay'
| 'darken'
| 'lighten'
| 'color-dodge'
| 'color-burn'
| 'hard-light'
| 'soft-light'
| 'difference'
| 'exclusion'
| 'hue'
| 'saturation'
| 'color'
| 'luminosity'
| 'saturate';
export type CanvasLineCap = 'butt' | 'round' | 'square';
export type CanvasLineJoin = 'bevel' | 'miter' | 'round';
export type CanvasTextBaseline = 'alphabetic' | 'bottom' | 'hanging' | 'ideographic' | 'middle' | 'top';
export type CanvasTextAlign = 'center' | 'end' | 'left' | 'right' | 'start';
export class CanvasRenderingContext2D {
drawImage(image: Canvas|Image, dx: number, dy: number): void
drawImage(image: Canvas|Image, dx: number, dy: number, dw: number, dh: number): void
drawImage(image: Canvas|Image, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void
putImageData(imagedata: ImageData, dx: number, dy: number): void;
putImageData(imagedata: ImageData, dx: number, dy: number, dirtyX: number, dirtyY: number, dirtyWidth: number, dirtyHeight: number): void;
getImageData(sx: number, sy: number, sw: number, sh: number): ImageData;
createImageData(sw: number, sh: number): ImageData;
createImageData(imagedata: ImageData): ImageData;
/**
* For PDF canvases, adds another page. If width and/or height are omitted,
* the canvas's initial size is used.
*/
addPage(width?: number, height?: number): void
save(): void;
restore(): void;
rotate(angle: number): void;
translate(x: number, y: number): void;
transform(a: number, b: number, c: number, d: number, e: number, f: number): void;
getTransform(): DOMMatrix;
resetTransform(): void;
setTransform(transform?: DOMMatrix): void;
setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void;
isPointInPath(x: number, y: number, fillRule?: CanvasFillRule): boolean;
scale(x: number, y: number): void;
clip(fillRule?: CanvasFillRule): void;
fill(fillRule?: CanvasFillRule): void;
stroke(): void;
fillText(text: string, x: number, y: number, maxWidth?: number): void;
strokeText(text: string, x: number, y: number, maxWidth?: number): void;
fillRect(x: number, y: number, w: number, h: number): void;
strokeRect(x: number, y: number, w: number, h: number): void;
clearRect(x: number, y: number, w: number, h: number): void;
rect(x: number, y: number, w: number, h: number): void;
roundRect(x: number, y: number, w: number, h: number, radii?: number | number[]): void;
measureText(text: string): TextMetrics;
moveTo(x: number, y: number): void;
lineTo(x: number, y: number): void;
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
beginPath(): void;
closePath(): void;
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void;
ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
setLineDash(segments: number[]): void;
getLineDash(): number[];
createPattern(image: Canvas|Image, repetition: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' | '' | null): CanvasPattern
createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradient;
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient;
beginTag(tagName: string, attributes?: string): void;
endTag(tagName: string): void;
/**
* _Non-standard_. Defaults to 'good'. Affects pattern (gradient, image,
* etc.) rendering quality.
*/
patternQuality: 'fast' | 'good' | 'best' | 'nearest' | 'bilinear'
imageSmoothingEnabled: boolean;
globalCompositeOperation: GlobalCompositeOperation;
globalAlpha: number;
shadowColor: string;
miterLimit: number;
lineWidth: number;
lineCap: CanvasLineCap;
lineJoin: CanvasLineJoin;
lineDashOffset: number;
shadowOffsetX: number;
shadowOffsetY: number;
shadowBlur: number;
/** _Non-standard_. Sets the antialiasing mode. */
antialias: 'default' | 'gray' | 'none' | 'subpixel'
/**
* Defaults to 'path'. The effect depends on the canvas type:
*
* * **Standard (image)** `'glyph'` and `'path'` both result in rasterized
* text. Glyph mode is faster than path, but may result in lower-quality
* text, especially when rotated or translated.
*
* * **PDF** `'glyph'` will embed text instead of paths into the PDF. This
* is faster to encode, faster to open with PDF viewers, yields a smaller
* file size and makes the text selectable. The subset of the font needed
* to render the glyphs will be embedded in the PDF. This is usually the
* mode you want to use with PDF canvases.
*
* * **SVG** glyph does not cause `<text>` elements to be produced as one
* might expect ([cairo bug](https://gitlab.freedesktop.org/cairo/cairo/issues/253)).
* Rather, glyph will create a `<defs>` section with a `<symbol>` for each
* glyph, then those glyphs be reused via `<use>` elements. `'path'` mode
* creates a `<path>` element for each text string. glyph mode is faster
* and yields a smaller file size.
*
* In glyph mode, `ctx.strokeText()` and `ctx.fillText()` behave the same
* (aside from using the stroke and fill style, respectively).
*/
textDrawingMode: 'path' | 'glyph'
/**
* _Non-standard_. Defaults to 'good'. Like `patternQuality`, but applies to
* transformations affecting more than just patterns.
*/
quality: 'fast' | 'good' | 'best' | 'nearest' | 'bilinear'
/** Returns or sets a `DOMMatrix` for the current transformation matrix. */
currentTransform: DOMMatrix
fillStyle: string | CanvasGradient | CanvasPattern;
strokeStyle: string | CanvasGradient | CanvasPattern;
font: string;
textBaseline: CanvasTextBaseline;
textAlign: CanvasTextAlign;
canvas: Canvas;
direction: 'ltr' | 'rtl';
lang: string;
}
export class CanvasGradient {
addColorStop(offset: number, color: string): void;
}
export class CanvasPattern {
setTransform(transform?: DOMMatrix): void;
}
// This does not extend HTMLImageElement because there are dozens of inherited
// methods and properties that we do not provide.
export class Image {
/** Track image data */
static readonly MODE_IMAGE: number
/** Track MIME data */
static readonly MODE_MIME: number
/**
* The URL, `data:` URI or local file path of the image to be loaded, or a
* Buffer instance containing an encoded image.
*/
src: string | Buffer
/** Retrieves whether the object is fully loaded. */
readonly complete: boolean
/** Sets or retrieves the height of the image. */
height: number
/** Sets or retrieves the width of the image. */
width: number
/** The original height of the image resource before sizing. */
readonly naturalHeight: number
/** The original width of the image resource before sizing. */
readonly naturalWidth: number
/**
* Applies to JPEG images drawn to PDF canvases only. Setting
* `img.dataMode = Image.MODE_MIME` or `Image.MODE_MIME|Image.MODE_IMAGE`
* enables image MIME data tracking. When MIME data is tracked, PDF canvases
* can embed JPEGs directly into the output, rather than re-encoding into
* PNG. This can drastically reduce filesize and speed up rendering.
*/
dataMode: number
onload: (() => void) | null;
onerror: ((err: Error) => void) | null;
}
/**
* Creates a Canvas instance. This function works in both Node.js and Web
* browsers, where there is no Canvas constructor.
* @param type Optionally specify to create a PDF or SVG canvas. Defaults to an
* image canvas.
*/
export function createCanvas(width: number, height: number, type?: 'pdf'|'svg'): Canvas
/**
* Creates an ImageData instance. This function works in both Node.js and Web
* browsers.
* @param data An array containing the pixel representation of the image.
* @param height If omitted, the height is calculated based on the array's size
* and `width`.
*/
export function createImageData(data: Uint8ClampedArray, width: number, height?: number): ImageData
/**
* _Non-standard._ Creates an ImageData instance for an alternative pixel
* format, such as RGB16_565
* @param data An array containing the pixel representation of the image.
* @param height If omitted, the height is calculated based on the array's size
* and `width`.
*/
export function createImageData(data: Uint16Array, width: number, height?: number): ImageData
/**
* Creates an ImageData instance. This function works in both Node.js and Web
* browsers.
*/
export function createImageData(width: number, height: number): ImageData
/**
* Convenience function for loading an image with a Promise interface. This
* function works in both Node.js and Web browsers; however, the `src` must be
* a string in Web browsers (it can only be a Buffer in Node.js).
* @param src URL, `data: ` URI or (Node.js only) a local file path or Buffer
* instance.
*/
export function loadImage(src: string|Buffer, options?: any): Promise<Image>
/**
* Registers a font that is not installed as a system font. This must be used
* before creating Canvas instances.
* @param path Path to local font file.
* @param fontFace Description of the font face, corresponding to CSS properties
* used in `@font-face` rules.
*/
export function registerFont(path: string, fontFace: {family: string, weight?: string, style?: string}): void
/**
* Unloads all fonts
*/
export function deregisterAllFonts(): void;
/** This class must not be constructed directly; use `canvas.createPNGStream()`. */
export class PNGStream extends Readable {}
/** This class must not be constructed directly; use `canvas.createJPEGStream()`. */
export class JPEGStream extends Readable {}
/** This class must not be constructed directly; use `canvas.createPDFStream()`. */
export class PDFStream extends Readable {}
// TODO: this is wrong. See matrixTransform in lib/DOMMatrix.js
type DOMMatrixInit = DOMMatrix | string | number[];
interface DOMPointInit {
w?: number;
x?: number;
y?: number;
z?: number;
}
export class DOMPoint {
w: number;
x: number;
y: number;
z: number;
matrixTransform(matrix?: DOMMatrixInit): DOMPoint;
toJSON(): any;
static fromPoint(other?: DOMPointInit): DOMPoint;
}
export class DOMMatrix {
constructor(init?: string | number[]);
toString(): string;
multiply(other?: DOMMatrix): DOMMatrix;
multiplySelf(other?: DOMMatrix): DOMMatrix;
preMultiplySelf(other?: DOMMatrix): DOMMatrix;
translate(tx?: number, ty?: number, tz?: number): DOMMatrix;
translateSelf(tx?: number, ty?: number, tz?: number): DOMMatrix;
scale(scaleX?: number, scaleY?: number, scaleZ?: number, originX?: number, originY?: number, originZ?: number): DOMMatrix;
scale3d(scale?: number, originX?: number, originY?: number, originZ?: number): DOMMatrix;
scale3dSelf(scale?: number, originX?: number, originY?: number, originZ?: number): DOMMatrix;
scaleSelf(scaleX?: number, scaleY?: number, scaleZ?: number, originX?: number, originY?: number, originZ?: number): DOMMatrix;
/**
* @deprecated
*/
scaleNonUniform(scaleX?: number, scaleY?: number): DOMMatrix;
rotateFromVector(x?: number, y?: number): DOMMatrix;
rotateFromVectorSelf(x?: number, y?: number): DOMMatrix;
rotate(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix;
rotateSelf(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix;
rotateAxisAngle(x?: number, y?: number, z?: number, angle?: number): DOMMatrix;
rotateAxisAngleSelf(x?: number, y?: number, z?: number, angle?: number): DOMMatrix;
skewX(sx?: number): DOMMatrix;
skewXSelf(sx?: number): DOMMatrix;
skewY(sy?: number): DOMMatrix;
skewYSelf(sy?: number): DOMMatrix;
flipX(): DOMMatrix;
flipY(): DOMMatrix;
inverse(): DOMMatrix;
invertSelf(): DOMMatrix;
setMatrixValue(transformList: string): DOMMatrix;
transformPoint(point?: DOMPoint): DOMPoint;
toJSON(): any;
toFloat32Array(): Float32Array;
toFloat64Array(): Float64Array;
readonly is2D: boolean;
readonly isIdentity: boolean;
a: number;
b: number;
c: number;
d: number;
e: number;
f: number;
m11: number;
m12: number;
m13: number;
m14: number;
m21: number;
m22: number;
m23: number;
m24: number;
m31: number;
m32: number;
m33: number;
m34: number;
m41: number;
m42: number;
m43: number;
m44: number;
static fromMatrix(other: DOMMatrix): DOMMatrix;
static fromFloat32Array(a: Float32Array): DOMMatrix;
static fromFloat64Array(a: Float64Array): DOMMatrix;
}
export class ImageData {
constructor(sw: number, sh: number);
constructor(data: Uint8ClampedArray, sw: number, sh?: number);
readonly data: Uint8ClampedArray;
readonly height: number;
readonly width: number;
}
// Not documented: backends
/** Library version. */
export const version: string
/** Cairo version. */
export const cairoVersion: string
/** jpeglib version, if built with JPEG support. */
export const jpegVersion: string | undefined
/** giflib version, if built with GIF support. */
export const gifVersion: string | undefined
/** freetype version. */
export const freetypeVersion: string
/** rsvg version. */
export const rsvgVersion: string | undefined

94
node_modules/loupedeck/node_modules/canvas/index.js generated vendored Normal file
View File

@@ -0,0 +1,94 @@
const Canvas = require('./lib/canvas')
const Image = require('./lib/image')
const CanvasRenderingContext2D = require('./lib/context2d')
const CanvasPattern = require('./lib/pattern')
const packageJson = require('./package.json')
const bindings = require('./lib/bindings')
const fs = require('fs')
const PNGStream = require('./lib/pngstream')
const PDFStream = require('./lib/pdfstream')
const JPEGStream = require('./lib/jpegstream')
const { DOMPoint, DOMMatrix } = require('./lib/DOMMatrix')
bindings.setDOMMatrix(DOMMatrix)
function createCanvas (width, height, type) {
return new Canvas(width, height, type)
}
function createImageData (array, width, height) {
return new bindings.ImageData(array, width, height)
}
function loadImage (src) {
return new Promise((resolve, reject) => {
const image = new Image()
function cleanup () {
image.onload = null
image.onerror = null
}
image.onload = () => { cleanup(); resolve(image) }
image.onerror = (err) => { cleanup(); reject(err) }
image.src = src
})
}
/**
* Resolve paths for registerFont. Must be called *before* creating a Canvas
* instance.
* @param src {string} Path to font file.
* @param fontFace {{family: string, weight?: string, style?: string}} Object
* specifying font information. `weight` and `style` default to `"normal"`.
*/
function registerFont (src, fontFace) {
// TODO this doesn't need to be on Canvas; it should just be a static method
// of `bindings`.
return Canvas._registerFont(fs.realpathSync(src), fontFace)
}
/**
* Unload all fonts from pango to free up memory
*/
function deregisterAllFonts () {
return Canvas._deregisterAllFonts()
}
exports.Canvas = Canvas
exports.Context2d = CanvasRenderingContext2D // Legacy/compat export
exports.CanvasRenderingContext2D = CanvasRenderingContext2D
exports.CanvasGradient = bindings.CanvasGradient
exports.CanvasPattern = CanvasPattern
exports.Image = Image
exports.ImageData = bindings.ImageData
exports.PNGStream = PNGStream
exports.PDFStream = PDFStream
exports.JPEGStream = JPEGStream
exports.DOMMatrix = DOMMatrix
exports.DOMPoint = DOMPoint
exports.registerFont = registerFont
exports.deregisterAllFonts = deregisterAllFonts
exports.createCanvas = createCanvas
exports.createImageData = createImageData
exports.loadImage = loadImage
exports.backends = bindings.Backends
/** Library version. */
exports.version = packageJson.version
/** Cairo version. */
exports.cairoVersion = bindings.cairoVersion
/** jpeglib version. */
exports.jpegVersion = bindings.jpegVersion
/** gif_lib version. */
exports.gifVersion = bindings.gifVersion ? bindings.gifVersion.replace(/[^.\d]/g, '') : undefined
/** freetype version. */
exports.freetypeVersion = bindings.freetypeVersion
/** rsvg version. */
exports.rsvgVersion = bindings.rsvgVersion
/** pango version. */
exports.pangoVersion = bindings.pangoVersion

View File

@@ -0,0 +1,678 @@
'use strict'
const util = require('util')
// DOMMatrix per https://drafts.fxtf.org/geometry/#DOMMatrix
class DOMPoint {
constructor (x, y, z, w) {
if (typeof x === 'object' && x !== null) {
w = x.w
z = x.z
y = x.y
x = x.x
}
this.x = typeof x === 'number' ? x : 0
this.y = typeof y === 'number' ? y : 0
this.z = typeof z === 'number' ? z : 0
this.w = typeof w === 'number' ? w : 1
}
matrixTransform(init) {
// TODO: this next line is wrong. matrixTransform is supposed to only take
// an object with the DOMMatrix properties called DOMMatrixInit
const m = init instanceof DOMMatrix ? init : new DOMMatrix(init)
return m.transformPoint(this)
}
toJSON() {
return {
x: this.x,
y: this.y,
z: this.z,
w: this.w
}
}
static fromPoint(other) {
return new this(other.x, other.y, other.z, other.w)
}
}
// Constants to index into _values (col-major)
const M11 = 0; const M12 = 1; const M13 = 2; const M14 = 3
const M21 = 4; const M22 = 5; const M23 = 6; const M24 = 7
const M31 = 8; const M32 = 9; const M33 = 10; const M34 = 11
const M41 = 12; const M42 = 13; const M43 = 14; const M44 = 15
const DEGREE_PER_RAD = 180 / Math.PI
const RAD_PER_DEGREE = Math.PI / 180
function parseMatrix (init) {
let parsed = init.replace('matrix(', '')
parsed = parsed.split(',', 7) // 6 + 1 to handle too many params
if (parsed.length !== 6) throw new Error(`Failed to parse ${init}`)
parsed = parsed.map(parseFloat)
return [
parsed[0], parsed[1], 0, 0,
parsed[2], parsed[3], 0, 0,
0, 0, 1, 0,
parsed[4], parsed[5], 0, 1
]
}
function parseMatrix3d (init) {
let parsed = init.replace('matrix3d(', '')
parsed = parsed.split(',', 17) // 16 + 1 to handle too many params
if (parsed.length !== 16) throw new Error(`Failed to parse ${init}`)
return parsed.map(parseFloat)
}
function parseTransform (tform) {
const type = tform.split('(', 1)[0]
switch (type) {
case 'matrix':
return parseMatrix(tform)
case 'matrix3d':
return parseMatrix3d(tform)
// TODO This is supposed to support any CSS transform value.
default:
throw new Error(`${type} parsing not implemented`)
}
}
class DOMMatrix {
constructor (init) {
this._is2D = true
this._values = new Float64Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
])
let i
if (typeof init === 'string') { // parse CSS transformList
if (init === '') return // default identity matrix
const tforms = init.split(/\)\s+/, 20).map(parseTransform)
if (tforms.length === 0) return
init = tforms[0]
for (i = 1; i < tforms.length; i++) init = multiply(tforms[i], init)
}
i = 0
if (init && init.length === 6) {
setNumber2D(this, M11, init[i++])
setNumber2D(this, M12, init[i++])
setNumber2D(this, M21, init[i++])
setNumber2D(this, M22, init[i++])
setNumber2D(this, M41, init[i++])
setNumber2D(this, M42, init[i++])
} else if (init && init.length === 16) {
setNumber2D(this, M11, init[i++])
setNumber2D(this, M12, init[i++])
setNumber3D(this, M13, init[i++])
setNumber3D(this, M14, init[i++])
setNumber2D(this, M21, init[i++])
setNumber2D(this, M22, init[i++])
setNumber3D(this, M23, init[i++])
setNumber3D(this, M24, init[i++])
setNumber3D(this, M31, init[i++])
setNumber3D(this, M32, init[i++])
setNumber3D(this, M33, init[i++])
setNumber3D(this, M34, init[i++])
setNumber2D(this, M41, init[i++])
setNumber2D(this, M42, init[i++])
setNumber3D(this, M43, init[i++])
setNumber3D(this, M44, init[i])
} else if (init !== undefined) {
throw new TypeError('Expected string or array.')
}
}
toString () {
return this.is2D
? `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`
: `matrix3d(${this._values.join(', ')})`
}
multiply (other) {
return newInstance(this._values).multiplySelf(other)
}
multiplySelf (other) {
this._values = multiply(other._values, this._values)
if (!other.is2D) this._is2D = false
return this
}
preMultiplySelf (other) {
this._values = multiply(this._values, other._values)
if (!other.is2D) this._is2D = false
return this
}
translate (tx, ty, tz) {
return newInstance(this._values).translateSelf(tx, ty, tz)
}
translateSelf (tx, ty, tz) {
if (typeof tx !== 'number') tx = 0
if (typeof ty !== 'number') ty = 0
if (typeof tz !== 'number') tz = 0
this._values = multiply([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
tx, ty, tz, 1
], this._values)
if (tz !== 0) this._is2D = false
return this
}
scale (scaleX, scaleY, scaleZ, originX, originY, originZ) {
return newInstance(this._values).scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
}
scale3d (scale, originX, originY, originZ) {
return newInstance(this._values).scale3dSelf(scale, originX, originY, originZ)
}
scale3dSelf (scale, originX, originY, originZ) {
return this.scaleSelf(scale, scale, scale, originX, originY, originZ)
}
/**
* @deprecated
*/
scaleNonUniform(scaleX, scaleY) {
return this.scale(scaleX, scaleY)
}
scaleSelf (scaleX, scaleY, scaleZ, originX, originY, originZ) {
// Not redundant with translate's checks because we need to negate the values later.
if (typeof originX !== 'number') originX = 0
if (typeof originY !== 'number') originY = 0
if (typeof originZ !== 'number') originZ = 0
this.translateSelf(originX, originY, originZ)
if (typeof scaleX !== 'number') scaleX = 1
if (typeof scaleY !== 'number') scaleY = scaleX
if (typeof scaleZ !== 'number') scaleZ = 1
this._values = multiply([
scaleX, 0, 0, 0,
0, scaleY, 0, 0,
0, 0, scaleZ, 0,
0, 0, 0, 1
], this._values)
this.translateSelf(-originX, -originY, -originZ)
if (scaleZ !== 1 || originZ !== 0) this._is2D = false
return this
}
rotateFromVector (x, y) {
return newInstance(this._values).rotateFromVectorSelf(x, y)
}
rotateFromVectorSelf (x, y) {
if (typeof x !== 'number') x = 0
if (typeof y !== 'number') y = 0
const theta = (x === 0 && y === 0) ? 0 : Math.atan2(y, x) * DEGREE_PER_RAD
return this.rotateSelf(theta)
}
rotate (rotX, rotY, rotZ) {
return newInstance(this._values).rotateSelf(rotX, rotY, rotZ)
}
rotateSelf (rotX, rotY, rotZ) {
if (rotY === undefined && rotZ === undefined) {
rotZ = rotX
rotX = rotY = 0
}
if (typeof rotY !== 'number') rotY = 0
if (typeof rotZ !== 'number') rotZ = 0
if (rotX !== 0 || rotY !== 0) this._is2D = false
rotX *= RAD_PER_DEGREE
rotY *= RAD_PER_DEGREE
rotZ *= RAD_PER_DEGREE
let c, s
c = Math.cos(rotZ)
s = Math.sin(rotZ)
this._values = multiply([
c, s, 0, 0,
-s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], this._values)
c = Math.cos(rotY)
s = Math.sin(rotY)
this._values = multiply([
c, 0, -s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1
], this._values)
c = Math.cos(rotX)
s = Math.sin(rotX)
this._values = multiply([
1, 0, 0, 0,
0, c, s, 0,
0, -s, c, 0,
0, 0, 0, 1
], this._values)
return this
}
rotateAxisAngle (x, y, z, angle) {
return newInstance(this._values).rotateAxisAngleSelf(x, y, z, angle)
}
rotateAxisAngleSelf (x, y, z, angle) {
if (typeof x !== 'number') x = 0
if (typeof y !== 'number') y = 0
if (typeof z !== 'number') z = 0
// Normalize axis
const length = Math.sqrt(x * x + y * y + z * z)
if (length === 0) return this
if (length !== 1) {
x /= length
y /= length
z /= length
}
angle *= RAD_PER_DEGREE
const c = Math.cos(angle)
const s = Math.sin(angle)
const t = 1 - c
const tx = t * x
const ty = t * y
// NB: This is the generic transform. If the axis is a major axis, there are
// faster transforms.
this._values = multiply([
tx * x + c, tx * y + s * z, tx * z - s * y, 0,
tx * y - s * z, ty * y + c, ty * z + s * x, 0,
tx * z + s * y, ty * z - s * x, t * z * z + c, 0,
0, 0, 0, 1
], this._values)
if (x !== 0 || y !== 0) this._is2D = false
return this
}
skewX (sx) {
return newInstance(this._values).skewXSelf(sx)
}
skewXSelf (sx) {
if (typeof sx !== 'number') return this
const t = Math.tan(sx * RAD_PER_DEGREE)
this._values = multiply([
1, 0, 0, 0,
t, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], this._values)
return this
}
skewY (sy) {
return newInstance(this._values).skewYSelf(sy)
}
skewYSelf (sy) {
if (typeof sy !== 'number') return this
const t = Math.tan(sy * RAD_PER_DEGREE)
this._values = multiply([
1, t, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], this._values)
return this
}
flipX () {
return newInstance(multiply([
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], this._values))
}
flipY () {
return newInstance(multiply([
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], this._values))
}
inverse () {
return newInstance(this._values).invertSelf()
}
invertSelf () {
const m = this._values
const inv = m.map(v => 0)
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10]
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10]
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9]
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9]
// If the determinant is zero, this matrix cannot be inverted, and all
// values should be set to NaN, with the is2D flag set to false.
const det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]
if (det === 0) {
this._values = m.map(v => NaN)
this._is2D = false
return this
}
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10]
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10]
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9]
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9]
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6]
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6]
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5]
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5]
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6]
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6]
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5]
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5]
inv.forEach((v, i) => { inv[i] = v / det })
this._values = inv
return this
}
setMatrixValue (transformList) {
const temp = new DOMMatrix(transformList)
this._values = temp._values
this._is2D = temp._is2D
return this
}
transformPoint (point) {
point = new DOMPoint(point)
const x = point.x
const y = point.y
const z = point.z
const w = point.w
const values = this._values
const nx = values[M11] * x + values[M21] * y + values[M31] * z + values[M41] * w
const ny = values[M12] * x + values[M22] * y + values[M32] * z + values[M42] * w
const nz = values[M13] * x + values[M23] * y + values[M33] * z + values[M43] * w
const nw = values[M14] * x + values[M24] * y + values[M34] * z + values[M44] * w
return new DOMPoint(nx, ny, nz, nw)
}
toFloat32Array () {
return Float32Array.from(this._values)
}
toFloat64Array () {
return this._values.slice(0)
}
static fromMatrix (init) {
if (!(init instanceof DOMMatrix)) throw new TypeError('Expected DOMMatrix')
return new DOMMatrix(init._values)
}
static fromFloat32Array (init) {
if (!(init instanceof Float32Array)) throw new TypeError('Expected Float32Array')
return new DOMMatrix(init)
}
static fromFloat64Array (init) {
if (!(init instanceof Float64Array)) throw new TypeError('Expected Float64Array')
return new DOMMatrix(init)
}
[util.inspect.custom || 'inspect'] (depth, options) {
if (depth < 0) return '[DOMMatrix]'
return `DOMMatrix [
a: ${this.a}
b: ${this.b}
c: ${this.c}
d: ${this.d}
e: ${this.e}
f: ${this.f}
m11: ${this.m11}
m12: ${this.m12}
m13: ${this.m13}
m14: ${this.m14}
m21: ${this.m21}
m22: ${this.m22}
m23: ${this.m23}
m23: ${this.m23}
m31: ${this.m31}
m32: ${this.m32}
m33: ${this.m33}
m34: ${this.m34}
m41: ${this.m41}
m42: ${this.m42}
m43: ${this.m43}
m44: ${this.m44}
is2D: ${this.is2D}
isIdentity: ${this.isIdentity} ]`
}
}
/**
* Checks that `value` is a number and sets the value.
*/
function setNumber2D (receiver, index, value) {
if (typeof value !== 'number') throw new TypeError('Expected number')
return (receiver._values[index] = value)
}
/**
* Checks that `value` is a number, sets `_is2D = false` if necessary and sets
* the value.
*/
function setNumber3D (receiver, index, value) {
if (typeof value !== 'number') throw new TypeError('Expected number')
if (index === M33 || index === M44) {
if (value !== 1) receiver._is2D = false
} else if (value !== 0) receiver._is2D = false
return (receiver._values[index] = value)
}
Object.defineProperties(DOMMatrix.prototype, {
m11: { get () { return this._values[M11] }, set (v) { return setNumber2D(this, M11, v) } },
m12: { get () { return this._values[M12] }, set (v) { return setNumber2D(this, M12, v) } },
m13: { get () { return this._values[M13] }, set (v) { return setNumber3D(this, M13, v) } },
m14: { get () { return this._values[M14] }, set (v) { return setNumber3D(this, M14, v) } },
m21: { get () { return this._values[M21] }, set (v) { return setNumber2D(this, M21, v) } },
m22: { get () { return this._values[M22] }, set (v) { return setNumber2D(this, M22, v) } },
m23: { get () { return this._values[M23] }, set (v) { return setNumber3D(this, M23, v) } },
m24: { get () { return this._values[M24] }, set (v) { return setNumber3D(this, M24, v) } },
m31: { get () { return this._values[M31] }, set (v) { return setNumber3D(this, M31, v) } },
m32: { get () { return this._values[M32] }, set (v) { return setNumber3D(this, M32, v) } },
m33: { get () { return this._values[M33] }, set (v) { return setNumber3D(this, M33, v) } },
m34: { get () { return this._values[M34] }, set (v) { return setNumber3D(this, M34, v) } },
m41: { get () { return this._values[M41] }, set (v) { return setNumber2D(this, M41, v) } },
m42: { get () { return this._values[M42] }, set (v) { return setNumber2D(this, M42, v) } },
m43: { get () { return this._values[M43] }, set (v) { return setNumber3D(this, M43, v) } },
m44: { get () { return this._values[M44] }, set (v) { return setNumber3D(this, M44, v) } },
a: { get () { return this.m11 }, set (v) { return (this.m11 = v) } },
b: { get () { return this.m12 }, set (v) { return (this.m12 = v) } },
c: { get () { return this.m21 }, set (v) { return (this.m21 = v) } },
d: { get () { return this.m22 }, set (v) { return (this.m22 = v) } },
e: { get () { return this.m41 }, set (v) { return (this.m41 = v) } },
f: { get () { return this.m42 }, set (v) { return (this.m42 = v) } },
is2D: { get () { return this._is2D } }, // read-only
isIdentity: {
get () {
const values = this._values
return (values[M11] === 1 && values[M12] === 0 && values[M13] === 0 && values[M14] === 0 &&
values[M21] === 0 && values[M22] === 1 && values[M23] === 0 && values[M24] === 0 &&
values[M31] === 0 && values[M32] === 0 && values[M33] === 1 && values[M34] === 0 &&
values[M41] === 0 && values[M42] === 0 && values[M43] === 0 && values[M44] === 1)
}
},
toJSON: {
value() {
return {
a: this.a,
b: this.b,
c: this.c,
d: this.d,
e: this.e,
f: this.f,
m11: this.m11,
m12: this.m12,
m13: this.m13,
m14: this.m14,
m21: this.m21,
m22: this.m22,
m23: this.m23,
m23: this.m23,
m31: this.m31,
m32: this.m32,
m33: this.m33,
m34: this.m34,
m41: this.m41,
m42: this.m42,
m43: this.m43,
m44: this.m44,
is2D: this.is2D,
isIdentity: this.isIdentity,
}
}
}
})
/**
* Instantiates a DOMMatrix, bypassing the constructor.
* @param {Float64Array} values Value to assign to `_values`. This is assigned
* without copying (okay because all usages are followed by a multiply).
*/
function newInstance (values) {
const instance = Object.create(DOMMatrix.prototype)
instance.constructor = DOMMatrix
instance._is2D = true
instance._values = values
return instance
}
function multiply (A, B) {
const dest = new Float64Array(16)
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
let sum = 0
for (let k = 0; k < 4; k++) {
sum += A[i * 4 + k] * B[k * 4 + j]
}
dest[i * 4 + j] = sum
}
}
return dest
}
module.exports = { DOMMatrix, DOMPoint }

View File

@@ -0,0 +1,43 @@
'use strict'
const bindings = require('../build/Release/canvas.node')
module.exports = bindings
Object.defineProperty(bindings.Canvas.prototype, Symbol.toStringTag, {
value: 'HTMLCanvasElement',
configurable: true
})
Object.defineProperty(bindings.Image.prototype, Symbol.toStringTag, {
value: 'HTMLImageElement',
configurable: true
})
bindings.ImageData.prototype.toString = function () {
return '[object ImageData]'
}
Object.defineProperty(bindings.ImageData.prototype, Symbol.toStringTag, {
value: 'ImageData',
configurable: true
})
bindings.CanvasGradient.prototype.toString = function () {
return '[object CanvasGradient]'
}
Object.defineProperty(bindings.CanvasGradient.prototype, Symbol.toStringTag, {
value: 'CanvasGradient',
configurable: true
})
Object.defineProperty(bindings.CanvasPattern.prototype, Symbol.toStringTag, {
value: 'CanvasPattern',
configurable: true
})
Object.defineProperty(bindings.CanvasRenderingContext2d.prototype, Symbol.toStringTag, {
value: 'CanvasRenderingContext2d',
configurable: true
})

View File

@@ -0,0 +1,113 @@
'use strict'
/*!
* Canvas
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
const bindings = require('./bindings')
const Canvas = module.exports = bindings.Canvas
const Context2d = require('./context2d')
const PNGStream = require('./pngstream')
const PDFStream = require('./pdfstream')
const JPEGStream = require('./jpegstream')
const FORMATS = ['image/png', 'image/jpeg']
const util = require('util')
// TODO || is for Node.js pre-v6.6.0
Canvas.prototype[util.inspect.custom || 'inspect'] = function () {
return `[Canvas ${this.width}x${this.height}]`
}
Canvas.prototype.getContext = function (contextType, contextAttributes) {
if (contextType == '2d') {
const ctx = this._context2d || (this._context2d = new Context2d(this, contextAttributes))
this.context = ctx
ctx.canvas = this
return ctx
}
}
Canvas.prototype.pngStream =
Canvas.prototype.createPNGStream = function (options) {
return new PNGStream(this, options)
}
Canvas.prototype.pdfStream =
Canvas.prototype.createPDFStream = function (options) {
return new PDFStream(this, options)
}
Canvas.prototype.jpegStream =
Canvas.prototype.createJPEGStream = function (options) {
return new JPEGStream(this, options)
}
Canvas.prototype.toDataURL = function (a1, a2, a3) {
// valid arg patterns (args -> [type, opts, fn]):
// [] -> ['image/png', null, null]
// [qual] -> ['image/png', null, null]
// [undefined] -> ['image/png', null, null]
// ['image/png'] -> ['image/png', null, null]
// ['image/png', qual] -> ['image/png', null, null]
// [fn] -> ['image/png', null, fn]
// [type, fn] -> [type, null, fn]
// [undefined, fn] -> ['image/png', null, fn]
// ['image/png', qual, fn] -> ['image/png', null, fn]
// ['image/jpeg', fn] -> ['image/jpeg', null, fn]
// ['image/jpeg', opts, fn] -> ['image/jpeg', opts, fn]
// ['image/jpeg', qual, fn] -> ['image/jpeg', {quality: qual}, fn]
// ['image/jpeg', undefined, fn] -> ['image/jpeg', null, fn]
// ['image/jpeg'] -> ['image/jpeg', null, fn]
// ['image/jpeg', opts] -> ['image/jpeg', opts, fn]
// ['image/jpeg', qual] -> ['image/jpeg', {quality: qual}, fn]
let type = 'image/png'
let opts = {}
let fn
if (typeof a1 === 'function') {
fn = a1
} else {
if (typeof a1 === 'string' && FORMATS.includes(a1.toLowerCase())) {
type = a1.toLowerCase()
}
if (typeof a2 === 'function') {
fn = a2
} else {
if (typeof a2 === 'object') {
opts = a2
} else if (typeof a2 === 'number') {
opts = { quality: Math.max(0, Math.min(1, a2)) }
}
if (typeof a3 === 'function') {
fn = a3
} else if (undefined !== a3) {
throw new TypeError(`${typeof a3} is not a function`)
}
}
}
if (this.width === 0 || this.height === 0) {
// Per spec, if the bitmap has no pixels, return this string:
const str = 'data:,'
if (fn) {
setTimeout(() => fn(null, str))
return
} else {
return str
}
}
if (fn) {
this.toBuffer((err, buf) => {
if (err) return fn(err)
fn(null, `data:${type};base64,${buf.toString('base64')}`)
}, type, opts)
} else {
return `data:${type};base64,${this.toBuffer(type, opts).toString('base64')}`
}
}

View File

@@ -0,0 +1,11 @@
'use strict'
/*!
* Canvas - Context2d
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
const bindings = require('./bindings')
module.exports = bindings.CanvasRenderingContext2d

View File

@@ -0,0 +1,97 @@
'use strict'
/*!
* Canvas - Image
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
const bindings = require('./bindings')
const Image = module.exports = bindings.Image
const util = require('util')
const { GetSource, SetSource } = bindings
Object.defineProperty(Image.prototype, 'src', {
/**
* src setter. Valid values:
* * `data:` URI
* * Local file path
* * HTTP or HTTPS URL
* * Buffer containing image data (i.e. not a `data:` URI stored in a Buffer)
*
* @param {String|Buffer} val filename, buffer, data URI, URL
* @api public
*/
set (val) {
if (typeof val === 'string') {
if (/^\s*data:/.test(val)) { // data: URI
const commaI = val.indexOf(',')
// 'base64' must come before the comma
const isBase64 = val.lastIndexOf('base64', commaI) !== -1
const content = val.slice(commaI + 1)
setSource(this, Buffer.from(content, isBase64 ? 'base64' : 'utf8'), val)
} else if (/^\s*https?:\/\//.test(val)) { // remote URL
const onerror = err => {
if (typeof this.onerror === 'function') {
this.onerror(err)
} else {
throw err
}
}
fetch(val, {
method: 'GET',
headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36' }
})
.then(res => {
if (!res.ok) {
throw new Error(`Server responded with ${res.status}`)
}
return res.arrayBuffer()
})
.then(data => {
setSource(this, Buffer.from(data))
})
.catch(onerror)
} else { // local file path assumed
setSource(this, val)
}
} else if (Buffer.isBuffer(val)) {
setSource(this, val)
} else {
const err = new Error("Invalid image source")
if (typeof this.onerror === 'function') this.onerror(err)
else throw err
}
},
get () {
// TODO https://github.com/Automattic/node-canvas/issues/118
return getSource(this)
},
configurable: true
})
// TODO || is for Node.js pre-v6.6.0
Image.prototype[util.inspect.custom || 'inspect'] = function () {
return '[Image' +
(this.complete ? ':' + this.width + 'x' + this.height : '') +
(this.src ? ' ' + this.src : '') +
(this.complete ? ' complete' : '') +
']'
}
function getSource (img) {
return img._originalSource || GetSource.call(img)
}
function setSource (img, src, origSrc) {
SetSource.call(img, src)
img._originalSource = origSrc
}

View File

@@ -0,0 +1,41 @@
'use strict'
/*!
* Canvas - JPEGStream
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
const { Readable } = require('stream')
function noop () {}
class JPEGStream extends Readable {
constructor (canvas, options) {
super()
if (canvas.streamJPEGSync === undefined) {
throw new Error('node-canvas was built without JPEG support.')
}
this.options = options
this.canvas = canvas
}
_read () {
// For now we're not controlling the c++ code's data emission, so we only
// call canvas.streamJPEGSync once and let it emit data at will.
this._read = noop
this.canvas.streamJPEGSync(this.options, (err, chunk) => {
if (err) {
this.emit('error', err)
} else if (chunk) {
this.push(chunk)
} else {
this.push(null)
}
})
}
};
module.exports = JPEGStream

View File

@@ -0,0 +1,15 @@
'use strict'
/*!
* Canvas - CanvasPattern
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
const bindings = require('./bindings')
module.exports = bindings.CanvasPattern
bindings.CanvasPattern.prototype.toString = function () {
return '[object CanvasPattern]'
}

View File

@@ -0,0 +1,35 @@
'use strict'
/*!
* Canvas - PDFStream
*/
const { Readable } = require('stream')
function noop () {}
class PDFStream extends Readable {
constructor (canvas, options) {
super()
this.canvas = canvas
this.options = options
}
_read () {
// For now we're not controlling the c++ code's data emission, so we only
// call canvas.streamPDFSync once and let it emit data at will.
this._read = noop
this.canvas.streamPDFSync((err, chunk, len) => {
if (err) {
this.emit('error', err)
} else if (len) {
this.push(chunk)
} else {
this.push(null)
}
}, this.options)
}
}
module.exports = PDFStream

Some files were not shown because too many files have changed in this diff Show More