Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FbDev #1541

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open

FbDev #1541

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ad0a41f
Extracted code for FbDev support from #571 to make it easier to revie…
piranna Nov 19, 2018
3a1d55d
Fix linting
piranna Nov 20, 2018
9c8a13d
Merge branch 'linting' into framebuffer
piranna Nov 20, 2018
9ebb624
Move `getFormat()` implementation out of header file
piranna Nov 20, 2018
b37d648
Added `Backend::setFormat()` method
piranna Nov 20, 2018
2aa765c
Added `FBDevBackend::setFormat()` method
piranna Nov 20, 2018
2e60f78
[FBDevBackend] Get `width` and `height` in constructor
piranna Nov 20, 2018
c29ef89
[FBDevBackend] Set `format` in constructor
piranna Nov 20, 2018
851ffb2
[FBDevBackend][fix] Wrongly copy&pasted variable
piranna Nov 20, 2018
4940a7b
Merge branch 'master' of github.com:ventrata/node-canvas into framebu…
piranna Nov 28, 2018
ad2ddc0
[FbDev] Set default FbDev device as constant
piranna Nov 28, 2018
3e4f681
[FbDev] Move initialization of framebuffer device to `initFbDev()` me…
piranna Nov 28, 2018
cf99d46
[FbDev] Allow to define framebuffer device from `Canvas` constructor
piranna Nov 28, 2018
5cc8631
[FbDev] Don't regenerate surface on creation for non-standard color m…
piranna Nov 28, 2018
9a583f3
[FbDev] Don't regenerate surface on creation to define the width and …
piranna Nov 28, 2018
5838252
[FbDev][fix] Set framebuffer dimensions if specified
piranna Nov 28, 2018
848ab2e
[Backend] Use default arguments to remove duplicated constructor
piranna Dec 1, 2018
0e8be22
clean-up
piranna Dec 7, 2018
81fa69f
[FbDev] Show used pixel format in `simple_fbdev` example
piranna Dec 7, 2018
a0fd140
Merge remote-tracking branch 'Automattic/master' into FbDev
piranna Dec 24, 2018
6a22cb2
Fixed documentation
piranna Dec 24, 2018
ff8b503
Merge remote-tracking branch 'Automattic/master' into FbDev
piranna Mar 21, 2020
bfb4f1d
Fixes after merge
piranna Mar 21, 2020
b5f5dd0
Fixed linting
piranna Mar 21, 2020
64fb2e5
Isolated `lint` script
piranna Mar 21, 2020
45021a7
Throw exception for unknown canvas type instead create `Image` by def…
piranna Mar 21, 2020
601a415
Updated dependencies
piranna Mar 21, 2020
fdf14bc
Remove unmaintained Node.js v6 and v8
piranna Mar 22, 2020
6fb4bb4
Merge remote-tracking branch 'Automattic/master' into FbDev
piranna Oct 17, 2020
0688eff
Update `devDependencies` to fix linting errors
piranna Oct 17, 2020
6f7876a
Enable FbDev backend only on Linux
piranna Oct 17, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ This project is an implementation of the Web Canvas API and implements that API
### createCanvas()

> ```ts
> createCanvas(width: number, height: number, type?: 'PDF'|'SVG') => Canvas
> createCanvas(width: number, height: number, type?: 'fbdev'|'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.)
Expand Down
10 changes: 9 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
}
}],
['OS=="linux" and has_FBDev=="true"',
{
'defines': ['HAS_FBDEV'],
'sources': ['src/backend/FBDevBackend.cc']
}],
['with_jpeg=="true"', {
'defines': [
'HAVE_JPEG'
Expand Down Expand Up @@ -216,7 +221,10 @@
}]
]
}]
]
],
'variables': {
'has_FBDev%': 'true',
}
}
]
}
40 changes: 40 additions & 0 deletions examples/simple_fbdev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

const fs = require('fs')
const { join } = require('path')

const { backends: { FBDevBackend }, Canvas } = require('..')

const squareSize = 100

var device = process.argv[2]

var backend = new FBDevBackend(device)
var canvas = new Canvas(backend)
var ctx = canvas.getContext('2d')

var offsetX = canvas.width - squareSize
var offsetY = canvas.height - squareSize

ctx.fillStyle = '#FF0000'
ctx.fillRect(0, 0, squareSize, squareSize)

ctx.fillStyle = '#00FF00'
ctx.fillRect(offsetX, 0, squareSize, squareSize)

ctx.fillStyle = '#0000FF'
ctx.fillRect(0, offsetY, squareSize, squareSize)

ctx.fillStyle = '#FFFFFF'
ctx.fillRect(offsetX, offsetY, squareSize, squareSize)

console.log('Width: ' + canvas.width + ', Height: ' + canvas.height +
'Pixel format: ' + ctx.pixelFormat)

var outPath = join(__dirname, 'rectangle.png')

canvas.createPNGStream().pipe(fs.createWriteStream(outPath))
90 changes: 45 additions & 45 deletions lib/DOMMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const util = require('util')

// DOMMatrix per https://drafts.fxtf.org/geometry/#DOMMatrix

function DOMPoint(x, y, z, w) {
function DOMPoint (x, y, z, w) {
if (!(this instanceof DOMPoint)) {
throw new TypeError("Class constructors cannot be invoked without 'new'")
}
Expand All @@ -22,15 +22,15 @@ function DOMPoint(x, y, z, w) {
}

// Constants to index into _values (col-major)
const M11 = 0, M12 = 1, M13 = 2, M14 = 3
const M21 = 4, M22 = 5, M23 = 6, M24 = 7
const M31 = 8, M32 = 9, M33 = 10, M34 = 11
const M41 = 12, M42 = 13, M43 = 14, M44 = 15
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) {
function parseMatrix (init) {
var 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}`)
Expand All @@ -43,14 +43,14 @@ function parseMatrix(init) {
]
}

function parseMatrix3d(init) {
function parseMatrix3d (init) {
var 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) {
function parseTransform (tform) {
var type = tform.split(/\(/, 1)[0]
switch (type) {
case 'matrix':
Expand Down Expand Up @@ -161,15 +161,15 @@ DOMMatrix.prototype[util.inspect.custom || 'inspect'] = function (depth, options
}

DOMMatrix.prototype.toString = function () {
return this.is2D ?
`matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})` :
`matrix3d(${this._values.join(', ')})`
return this.is2D
? `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`
: `matrix3d(${this._values.join(', ')})`
}

/**
* Checks that `value` is a number and sets the value.
*/
function setNumber2D(receiver, index, value) {
function setNumber2D (receiver, index, value) {
if (typeof value !== 'number') throw new TypeError('Expected number')
return receiver._values[index] = value
}
Expand All @@ -178,7 +178,7 @@ function setNumber2D(receiver, index, value) {
* Checks that `value` is a number, sets `_is2D = false` if necessary and sets
* the value.
*/
function setNumber3D(receiver, index, 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
Expand All @@ -187,31 +187,31 @@ function setNumber3D(receiver, index, value) {
}

Object.defineProperties(DOMMatrix.prototype, {
m11: {get: function () { return this._values[M11] }, set: function (v) { return setNumber2D(this, M11, v) }},
m12: {get: function () { return this._values[M12] }, set: function (v) { return setNumber2D(this, M12, v) }},
m13: {get: function () { return this._values[M13] }, set: function (v) { return setNumber3D(this, M13, v) }},
m14: {get: function () { return this._values[M14] }, set: function (v) { return setNumber3D(this, M14, v) }},
m21: {get: function () { return this._values[M21] }, set: function (v) { return setNumber2D(this, M21, v) }},
m22: {get: function () { return this._values[M22] }, set: function (v) { return setNumber2D(this, M22, v) }},
m23: {get: function () { return this._values[M23] }, set: function (v) { return setNumber3D(this, M23, v) }},
m24: {get: function () { return this._values[M24] }, set: function (v) { return setNumber3D(this, M24, v) }},
m31: {get: function () { return this._values[M31] }, set: function (v) { return setNumber3D(this, M31, v) }},
m32: {get: function () { return this._values[M32] }, set: function (v) { return setNumber3D(this, M32, v) }},
m33: {get: function () { return this._values[M33] }, set: function (v) { return setNumber3D(this, M33, v) }},
m34: {get: function () { return this._values[M34] }, set: function (v) { return setNumber3D(this, M34, v) }},
m41: {get: function () { return this._values[M41] }, set: function (v) { return setNumber2D(this, M41, v) }},
m42: {get: function () { return this._values[M42] }, set: function (v) { return setNumber2D(this, M42, v) }},
m43: {get: function () { return this._values[M43] }, set: function (v) { return setNumber3D(this, M43, v) }},
m44: {get: function () { return this._values[M44] }, set: function (v) { return setNumber3D(this, M44, v) }},

a: {get: function () { return this.m11 }, set: function (v) { return this.m11 = v }},
b: {get: function () { return this.m12 }, set: function (v) { return this.m12 = v }},
c: {get: function () { return this.m21 }, set: function (v) { return this.m21 = v }},
d: {get: function () { return this.m22 }, set: function (v) { return this.m22 = v }},
e: {get: function () { return this.m41 }, set: function (v) { return this.m41 = v }},
f: {get: function () { return this.m42 }, set: function (v) { return this.m42 = v }},

is2D: {get: function () { return this._is2D }}, // read-only
m11: { get: function () { return this._values[M11] }, set: function (v) { return setNumber2D(this, M11, v) } },
m12: { get: function () { return this._values[M12] }, set: function (v) { return setNumber2D(this, M12, v) } },
m13: { get: function () { return this._values[M13] }, set: function (v) { return setNumber3D(this, M13, v) } },
m14: { get: function () { return this._values[M14] }, set: function (v) { return setNumber3D(this, M14, v) } },
m21: { get: function () { return this._values[M21] }, set: function (v) { return setNumber2D(this, M21, v) } },
m22: { get: function () { return this._values[M22] }, set: function (v) { return setNumber2D(this, M22, v) } },
m23: { get: function () { return this._values[M23] }, set: function (v) { return setNumber3D(this, M23, v) } },
m24: { get: function () { return this._values[M24] }, set: function (v) { return setNumber3D(this, M24, v) } },
m31: { get: function () { return this._values[M31] }, set: function (v) { return setNumber3D(this, M31, v) } },
m32: { get: function () { return this._values[M32] }, set: function (v) { return setNumber3D(this, M32, v) } },
m33: { get: function () { return this._values[M33] }, set: function (v) { return setNumber3D(this, M33, v) } },
m34: { get: function () { return this._values[M34] }, set: function (v) { return setNumber3D(this, M34, v) } },
m41: { get: function () { return this._values[M41] }, set: function (v) { return setNumber2D(this, M41, v) } },
m42: { get: function () { return this._values[M42] }, set: function (v) { return setNumber2D(this, M42, v) } },
m43: { get: function () { return this._values[M43] }, set: function (v) { return setNumber3D(this, M43, v) } },
m44: { get: function () { return this._values[M44] }, set: function (v) { return setNumber3D(this, M44, v) } },

a: { get: function () { return this.m11 }, set: function (v) { return this.m11 = v } },
b: { get: function () { return this.m12 }, set: function (v) { return this.m12 = v } },
c: { get: function () { return this.m21 }, set: function (v) { return this.m21 = v } },
d: { get: function () { return this.m22 }, set: function (v) { return this.m22 = v } },
e: { get: function () { return this.m41 }, set: function (v) { return this.m41 = v } },
f: { get: function () { return this.m42 }, set: function (v) { return this.m42 = v } },

is2D: { get: function () { return this._is2D } }, // read-only

isIdentity: {
get: function () {
Expand All @@ -229,15 +229,15 @@ Object.defineProperties(DOMMatrix.prototype, {
* @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) {
function newInstance (values) {
var instance = Object.create(DOMMatrix.prototype)
instance.constructor = DOMMatrix
instance._is2D = true
instance._values = values
return instance
}

function multiply(A, B) {
function multiply (A, B) {
var dest = new Float64Array(16)
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
Expand Down Expand Up @@ -386,10 +386,10 @@ DOMMatrix.prototype.rotateAxisAngleSelf = function (x, y, z, angle) {
// 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
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
Expand Down Expand Up @@ -606,4 +606,4 @@ DOMMatrix.prototype.toFloat64Array = function () {
return this._values.slice(0)
}

module.exports = {DOMMatrix, DOMPoint}
module.exports = { DOMMatrix, DOMPoint }
4 changes: 2 additions & 2 deletions lib/bindings.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
'use strict';
'use strict'

module.exports = require('../build/Release/canvas.node');
module.exports = require('../build/Release/canvas.node')
72 changes: 36 additions & 36 deletions lib/canvas.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict';
'use strict'

/*!
* Canvas
Expand All @@ -21,28 +21,28 @@ Canvas.prototype[util.inspect.custom || 'inspect'] = function () {
}

Canvas.prototype.getContext = function (contextType, contextAttributes) {
if ('2d' == contextType) {
var ctx = this._context2d || (this._context2d = new Context2d(this, contextAttributes));
this.context = ctx;
ctx.canvas = this;
return ctx;
if (contextType == '2d') {
var 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.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.createJPEGStream = function (options) {
return new JPEGStream(this, options)
}

Canvas.prototype.toDataURL = function(a1, a2, a3){
// valid arg patterns (args -> [type, opts, fn]):
Expand All @@ -63,51 +63,51 @@ Canvas.prototype.toDataURL = function(a1, a2, a3){
// ['image/jpeg', opts] -> ['image/jpeg', opts, fn]
// ['image/jpeg', qual] -> ['image/jpeg', {quality: qual}, fn]

var type = 'image/png';
var opts = {};
var fn;
var type = 'image/png'
var opts = {}
var fn

if ('function' === typeof a1) {
fn = a1;
if (typeof a1 === 'function') {
fn = a1
} else {
if ('string' === typeof a1 && FORMATS.includes(a1.toLowerCase())) {
type = a1.toLowerCase();
if (typeof a1 === 'string' && FORMATS.includes(a1.toLowerCase())) {
type = a1.toLowerCase()
}

if ('function' === typeof a2) {
fn = a2;
if (typeof a2 === 'function') {
fn = a2
} else {
if ('object' === typeof a2) {
opts = a2;
} else if ('number' === typeof a2) {
opts = {quality: Math.max(0, Math.min(1, a2))};
if (typeof a2 === 'object') {
opts = a2
} else if (typeof a2 === 'number') {
opts = { quality: Math.max(0, Math.min(1, a2)) }
}

if ('function' === typeof a3) {
fn = a3;
if (typeof a3 === 'function') {
fn = a3
} else if (undefined !== a3) {
throw new TypeError(typeof a3 + ' is not a function');
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:
var str = "data:,";
var str = 'data:,'
if (fn) {
setTimeout(() => fn(null, str));
return;
setTimeout(() => fn(null, str))
return
} else {
return str;
return str
}
}

if (fn) {
this.toBuffer((err, buf) => {
if (err) return fn(err);
fn(null, `data:${type};base64,${buf.toString('base64')}`);
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')}`
}
};
}
Loading