canvas-to-buffer
Advanced tools
Comparing version 3.0.1 to 3.1.0
{ | ||
"name": "canvas-to-buffer", | ||
"version": "3.0.1", | ||
"version": "3.1.0", | ||
"description": "Converts a Canvas graphic into a Buffer, as fast as possible and without a copy.", | ||
"source": "index.js", | ||
"main": "dist/canvas-to-buffer.js", | ||
"type": "module", | ||
"source": "src/index.js", | ||
"exports": { | ||
"require": "./dist/canvas-to-buffer.cjs", | ||
"default": "./dist/canvas-to-buffer.modern.js" | ||
}, | ||
"main": "dist/canvas-to-buffer.cjs", | ||
"module": "dist/canvas-to-buffer.mjs", | ||
"unpkg": "dist/canvas-to-buffer.umd.js", | ||
"scripts": { | ||
"lint": "standard src", | ||
"lint:fix": "standard --fix src", | ||
"lint": "eslint --color ./src ./test", | ||
"lint:fix": "npm --silent run lint -- --fix", | ||
"build": "microbundle src", | ||
"test": "tape test/*.js" | ||
"test": "tape test/*.js", | ||
"prettier": "prettier --check ./src ./test", | ||
"prettier:fix": "prettier --write ./src ./test " | ||
}, | ||
@@ -34,5 +41,6 @@ "author": { | ||
"engines": { | ||
"node": ">=18.12.1", | ||
"npm": ">=8.19.2" | ||
"node": "^20.12.2", | ||
"npm": "^10.5.0" | ||
}, | ||
"prettier": "./prettier.config.cjs", | ||
"dependencies": { | ||
@@ -43,7 +51,10 @@ "atob": "2.1.2", | ||
"devDependencies": { | ||
"canvas": "2.11.0", | ||
"canvas": "2.11.2", | ||
"eslint": "8.57.0", | ||
"eslint-config-prettier": "9.1.0", | ||
"eslint-plugin-import": "2.29.1", | ||
"microbundle": "0.15.1", | ||
"standard": "17.0.0", | ||
"tape": "5.6.3" | ||
"prettier": "3.3.3", | ||
"tape": "5.8.1" | ||
} | ||
} |
@@ -23,12 +23,12 @@ # canvas-to-buffer | ||
// I call it a Frame but you can go with i.E. CanvasConverter, whatever | ||
var Frame = require("canvas-to-buffer"); | ||
import Frame from "canvas-to-buffer"; | ||
// Drop in any canvas, i.E. from a webcam | ||
var frame = new Frame(canvas); | ||
const frame = new Frame(canvas); | ||
// Automatically detects image type and does the conversion | ||
var buffer = frame.toBuffer(); | ||
const buffer = frame.toBuffer(); | ||
// Returns the chosen image type, could be `'image/png'` | ||
var imageType = frame.getImageType(); | ||
const imageType = frame.getImageType(); | ||
``` | ||
@@ -39,4 +39,4 @@ | ||
```js | ||
var Frame = require("canvas-to-buffer"); | ||
var frame = new Frame(canvas, { | ||
import Frame from "canvas-to-buffer"; | ||
const frame = new Frame(canvas, { | ||
quality: 0.4, | ||
@@ -43,0 +43,0 @@ image: { |
192
src/index.js
@@ -1,84 +0,84 @@ | ||
const toBuffer = require('typedarray-to-buffer') | ||
const atob = require('atob') | ||
import toBuffer from "typedarray-to-buffer"; | ||
import atob from "atob"; | ||
const isBrowser = | ||
typeof document !== 'undefined' && typeof document.createElement === 'function' | ||
typeof document !== "undefined" && typeof document.createElement === "function"; | ||
// cached, used only once for browser environments | ||
let verifiedImageType | ||
let verifiedImageType; | ||
module.exports = function (canvas, options = {}) { | ||
const self = this | ||
const Frame = function (canvas, options = {}) { | ||
const self = this; | ||
options.image = options.image ? options.image : {} | ||
options.image.types = options.image.types ? options.image.types : [] | ||
options.image = options.image ? options.image : {}; | ||
options.image.types = options.image.types ? options.image.types : []; | ||
// validate some options this class needs | ||
if (options.image.types.length > 2) { | ||
throw new Error('Too many image types are specified!') | ||
throw new Error("Too many image types are specified!"); | ||
} else if (options.image.types.length < 1) { | ||
// Set a default image type, just to be robust | ||
options.image.types = isBrowser ? ['webp', 'jpeg'] : ['png'] | ||
options.image.types = isBrowser ? ["webp", "jpeg"] : ["png"]; | ||
} | ||
if (!options.image.quality) { | ||
options.image.quality = 0.5 // default | ||
options.image.quality = 0.5; // default | ||
} | ||
const quality = parseFloat(options.image.quality) | ||
const quality = parseFloat(options.image.quality); | ||
function composeImageType (index) { | ||
let imageType | ||
function composeImageType(index) { | ||
let imageType; | ||
if (options.image.types[index]) { | ||
imageType = 'image/' + options.image.types[index] | ||
imageType = "image/" + options.image.types[index]; | ||
} | ||
return imageType | ||
return imageType; | ||
} | ||
function isMatch (uri, imageType) { | ||
const match = uri && uri.match(imageType) | ||
function isMatch(uri, imageType) { | ||
const match = uri && uri.match(imageType); | ||
match && options.debug && options.debug('Image type %s verified', imageType) | ||
match && options.debug && options.debug("Image type %s verified", imageType); | ||
return match | ||
return match; | ||
} | ||
// Performance tweak, we do not need a big canvas for finding out the supported image type | ||
function getTestCanvas () { | ||
let testCanvas | ||
function getTestCanvas() { | ||
let testCanvas; | ||
if (isBrowser) { | ||
testCanvas = document.createElement('canvas') | ||
testCanvas.width = testCanvas.height = 1 | ||
testCanvas = document.createElement("canvas"); | ||
testCanvas.width = testCanvas.height = 1; | ||
} else { | ||
testCanvas = canvas | ||
testCanvas = canvas; | ||
} | ||
return testCanvas | ||
return testCanvas; | ||
} | ||
function canvasSupportsImageTypeAsync (imageType, cb) { | ||
function canvasSupportsImageTypeAsync(imageType, cb) { | ||
try { | ||
const testCanvas = getTestCanvas() | ||
const testCanvas = getTestCanvas(); | ||
testCanvas.toDataURL(imageType, function (err, uri) { | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else { | ||
cb(null, isMatch(uri, imageType)) | ||
cb(null, isMatch(uri, imageType)); | ||
} | ||
}) | ||
}); | ||
} catch (exc) { | ||
cb(null, false) | ||
cb(null, false); | ||
} | ||
} | ||
function canvasSupportsImageTypeSync (imageType) { | ||
let match | ||
function canvasSupportsImageTypeSync(imageType) { | ||
let match; | ||
try { | ||
const testCanvas = getTestCanvas() | ||
const uri = testCanvas.toDataURL && testCanvas.toDataURL(imageType) | ||
const testCanvas = getTestCanvas(); | ||
const uri = testCanvas.toDataURL && testCanvas.toDataURL(imageType); | ||
match = isMatch(uri, imageType) | ||
match = isMatch(uri, imageType); | ||
} catch (exc) { | ||
@@ -88,58 +88,58 @@ // Can happen when i.E. a spider is coming. Just be robust here and continue. | ||
options.logger.debug( | ||
'Failed to call toDataURL() on canvas for image type %s', | ||
imageType | ||
) | ||
"Failed to call toDataURL() on canvas for image type %s", | ||
imageType, | ||
); | ||
} | ||
return match | ||
return match; | ||
} | ||
function verifyImageTypeAsync (imageType, cb) { | ||
function verifyImageTypeAsync(imageType, cb) { | ||
canvasSupportsImageTypeAsync(imageType, function (err, match) { | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else { | ||
if (match) { | ||
cb(null, imageType) | ||
cb(null, imageType); | ||
} else { | ||
imageType = composeImageType(1) | ||
imageType = composeImageType(1); | ||
canvasSupportsImageTypeAsync(imageType, function (err, match) { | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else { | ||
cb(null, match ? imageType : null) | ||
cb(null, match ? imageType : null); | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}) | ||
}); | ||
} | ||
function verifyImageTypeSync (imageType) { | ||
function verifyImageTypeSync(imageType) { | ||
if (!canvasSupportsImageTypeSync(imageType)) { | ||
if (options.image.types[1]) { | ||
imageType = composeImageType(1) | ||
imageType = composeImageType(1); | ||
if (!canvasSupportsImageTypeSync(imageType)) { | ||
imageType = null | ||
imageType = null; | ||
} | ||
} else { | ||
imageType = null | ||
imageType = null; | ||
} | ||
} | ||
!imageType && options.debug && options.logger.debug('Unable to verify image type') | ||
!imageType && options.debug && options.logger.debug("Unable to verify image type"); | ||
return imageType | ||
return imageType; | ||
} | ||
// callbacks are needed for server side tests | ||
function verifyImageType (cb) { | ||
const imageType = composeImageType(0) | ||
function verifyImageType(cb) { | ||
const imageType = composeImageType(0); | ||
if (cb) { | ||
verifyImageTypeAsync(imageType, cb) | ||
verifyImageTypeAsync(imageType, cb); | ||
} else { | ||
return verifyImageTypeSync(imageType) | ||
return verifyImageTypeSync(imageType); | ||
} | ||
@@ -150,53 +150,53 @@ } | ||
// http://jsperf.com/data-uri-to-buffer-performance/3 | ||
function uriToBuffer (uri) { | ||
const uriSplitted = uri.split(',')[1] | ||
let bytes | ||
function uriToBuffer(uri) { | ||
const uriSplitted = uri.split(",")[1]; | ||
let bytes; | ||
// Beware that the atob function might be a static one for server side tests | ||
if (typeof atob === 'function') { | ||
bytes = atob(uriSplitted) | ||
} else if (typeof self.constructor.atob === 'function') { | ||
bytes = self.constructor.atob(uriSplitted) | ||
if (typeof atob === "function") { | ||
bytes = atob(uriSplitted); | ||
} else if (typeof self.constructor.atob === "function") { | ||
bytes = self.constructor.atob(uriSplitted); | ||
} else { | ||
throw new Error('atob function is missing') | ||
throw new Error("atob function is missing"); | ||
} | ||
const arr = new Uint8Array(bytes.length) | ||
const arr = new Uint8Array(bytes.length); | ||
// http://mrale.ph/blog/2014/12/24/array-length-caching.html | ||
for (let i = 0, l = bytes.length; i < l; i++) { | ||
arr[i] = bytes.charCodeAt(i) | ||
arr[i] = bytes.charCodeAt(i); | ||
} | ||
return toBuffer(arr) | ||
return toBuffer(arr); | ||
} | ||
function toBufferSync () { | ||
const imageType = self.getImageType() | ||
let buffer | ||
function toBufferSync() { | ||
const imageType = self.getImageType(); | ||
let buffer; | ||
if (imageType) { | ||
const uri = canvas.toDataURL(imageType, quality) | ||
buffer = uriToBuffer(uri) | ||
const uri = canvas.toDataURL(imageType, quality); | ||
buffer = uriToBuffer(uri); | ||
} | ||
return buffer | ||
return buffer; | ||
} | ||
function toBufferAsync (cb) { | ||
function toBufferAsync(cb) { | ||
self.getImageType(function (err, imageType) { | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else if (!imageType) { | ||
cb() | ||
cb(); | ||
} else { | ||
canvas.toDataURL(imageType, function (err, uri) { | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else { | ||
cb(null, uriToBuffer(uri)) | ||
cb(null, uriToBuffer(uri)); | ||
} | ||
}) | ||
}); | ||
} | ||
}) | ||
}); | ||
} | ||
@@ -206,7 +206,7 @@ | ||
if (cb) { | ||
toBufferAsync(cb) | ||
toBufferAsync(cb); | ||
} else { | ||
return toBufferSync() | ||
return toBufferSync(); | ||
} | ||
} | ||
}; | ||
@@ -221,10 +221,10 @@ // browsers do not need a callback, but tests do | ||
if (err) { | ||
cb(err) | ||
cb(err); | ||
} else { | ||
verifiedImageType = newVerifiedImageType | ||
cb(null, verifiedImageType) | ||
verifiedImageType = newVerifiedImageType; | ||
cb(null, verifiedImageType); | ||
} | ||
}) | ||
}); | ||
} else { | ||
cb(null, verifiedImageType) | ||
cb(null, verifiedImageType); | ||
} | ||
@@ -234,8 +234,10 @@ } else { | ||
if (!verifiedImageType || !isBrowser) { | ||
verifiedImageType = verifyImageType() | ||
verifiedImageType = verifyImageType(); | ||
} | ||
return verifiedImageType | ||
return verifiedImageType; | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
export default Frame; |
@@ -1,35 +0,35 @@ | ||
const test = require('tape') | ||
const { createCanvas } = require('canvas') | ||
const atob = require('atob') | ||
import test from "tape"; | ||
import { createCanvas } from "canvas"; | ||
import atob from "atob"; | ||
const Frame = require('./../src/index') | ||
import Frame from "./../src/index.js"; | ||
// Add missing function because atob only exists on the browser | ||
Frame.atob = atob | ||
Frame.atob = atob; | ||
test('frame:', function (t) { | ||
t.test('arguments', function (tt) { | ||
tt.test('missing options are fine', function (tt) { | ||
tt.plan(1) | ||
test("frame:", function (t) { | ||
t.test("arguments", function (tt) { | ||
tt.test("missing options are fine", function (tt) { | ||
tt.plan(1); | ||
tt.doesNotThrow(function () { | ||
return new Frame() | ||
}) | ||
}) | ||
return new Frame(); | ||
}); | ||
}); | ||
tt.test('invalid image type', function (tt) { | ||
tt.plan(2) | ||
tt.test("invalid image type", function (tt) { | ||
tt.plan(2); | ||
new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: ['bad image type'] | ||
} | ||
types: ["bad image type"], | ||
}, | ||
}).getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, undefined) | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, undefined); | ||
}); | ||
}); | ||
tt.test('too many image types', function (tt) { | ||
tt.plan(1) | ||
tt.test("too many image types", function (tt) { | ||
tt.plan(1); | ||
@@ -39,46 +39,46 @@ tt.throws(function () { | ||
image: { | ||
types: ['too', 'many', 'image', 'types'] | ||
} | ||
}) | ||
}) | ||
}) | ||
types: ["too", "many", "image", "types"], | ||
}, | ||
}); | ||
}); | ||
}); | ||
tt.test('missing image type sets default one', function (tt) { | ||
tt.plan(8) | ||
tt.test("missing image type sets default one", function (tt) { | ||
tt.plan(8); | ||
new Frame(createCanvas(1, 1)).getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
new Frame(createCanvas(1, 1), { | ||
image: {} | ||
image: {}, | ||
}).getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: null | ||
} | ||
types: null, | ||
}, | ||
}).getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: [] | ||
} | ||
types: [], | ||
}, | ||
}).getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
}); | ||
tt.test('one valid image type', function (tt) { | ||
tt.plan(3) | ||
tt.test("one valid image type", function (tt) { | ||
tt.plan(3); | ||
var frame | ||
var frame; | ||
@@ -88,75 +88,75 @@ tt.doesNotThrow(function () { | ||
image: { | ||
types: ['png'] | ||
} | ||
}) | ||
}) | ||
types: ["png"], | ||
}, | ||
}); | ||
}); | ||
frame.getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
}); | ||
tt.test('first image type is invalid, second image type is valid', function (tt) { | ||
tt.plan(2) | ||
tt.test("first image type is invalid, second image type is valid", function (tt) { | ||
tt.plan(2); | ||
var frame = new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: ['bad image type', 'png'] | ||
} | ||
}) | ||
types: ["bad image type", "png"], | ||
}, | ||
}); | ||
frame.getImageType(function (err, imageType) { | ||
tt.equal(err, null) | ||
tt.equal(imageType, 'image/png') | ||
}) | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(imageType, "image/png"); | ||
}); | ||
}); | ||
}); | ||
t.test('toBuffer', function (tt) { | ||
tt.test('fails without valid image type', function (tt) { | ||
tt.plan(1) | ||
t.test("toBuffer", function (tt) { | ||
tt.test("fails without valid image type", function (tt) { | ||
tt.plan(1); | ||
var frame = new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: ['bad image type'] | ||
} | ||
}) | ||
types: ["bad image type"], | ||
}, | ||
}); | ||
var buffer = frame.toBuffer() | ||
tt.equal(buffer, undefined) | ||
}) | ||
var buffer = frame.toBuffer(); | ||
tt.equal(buffer, undefined); | ||
}); | ||
tt.test('buffer from small canvas has correct contents', function (tt) { | ||
tt.plan(3) | ||
tt.test("buffer from small canvas has correct contents", function (tt) { | ||
tt.plan(3); | ||
var frame = new Frame(createCanvas(1, 1), { | ||
image: { | ||
types: ['png'] | ||
} | ||
}) | ||
types: ["png"], | ||
}, | ||
}); | ||
frame.toBuffer(function (err, buffer) { | ||
tt.equal(err, null) | ||
tt.equal(buffer.length >= 86, true) // cos on travis it's 88 due to different OS | ||
tt.equal(buffer.toString().indexOf('PNG') > -1, true) | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(buffer.length >= 86, true); // cos on travis it's 88 due to different OS | ||
tt.equal(buffer.toString().indexOf("PNG") > -1, true); | ||
}); | ||
}); | ||
tt.test('buffer from large canvas has correct PNG contents', function (tt) { | ||
tt.plan(3) | ||
tt.test("buffer from large canvas has correct PNG contents", function (tt) { | ||
tt.plan(3); | ||
var frame = new Frame(createCanvas(1000, 1000), { | ||
image: { | ||
types: ['png'] | ||
} | ||
}) | ||
types: ["png"], | ||
}, | ||
}); | ||
frame.toBuffer(function (err, buffer) { | ||
tt.equal(err, null) | ||
tt.equal(buffer.length, 3975) | ||
tt.equal(buffer.toString().indexOf('PNG') > -1, true) | ||
}) | ||
}) | ||
}) | ||
}) | ||
tt.equal(err, null); | ||
tt.equal(buffer.length, 3975); | ||
tt.equal(buffer.toString().indexOf("PNG") > -1, true); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1
Yes
16450
7
9
345
1