mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -05:00
156 lines
6.1 KiB
JavaScript
156 lines
6.1 KiB
JavaScript
/*
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
|
* http://paperjs.org/
|
|
*
|
|
* Copyright (c) 2011 - 2019, Juerg Lehni & Jonathan Puckey
|
|
* http://scratchdisk.com/ & https://puckey.studio/
|
|
*
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
*
|
|
* All rights reserved.
|
|
*/
|
|
|
|
var fs = require('fs'),
|
|
path = require('path');
|
|
|
|
module.exports = function(paper) {
|
|
if (paper.PaperScript) {
|
|
var sourceMapSupport = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n',
|
|
sourceMaps = {};
|
|
|
|
paper.PaperScript.sourceMapSupport = {
|
|
retrieveSourceMap: function(source) {
|
|
var map = sourceMaps[source];
|
|
return map ? { url: source, map: map } : null;
|
|
}
|
|
};
|
|
|
|
// Register the .pjs extension for automatic compilation as PaperScript
|
|
require.extensions['.pjs'] = function(module, filename) {
|
|
// Requiring a PaperScript on Node.js returns an initialize method which
|
|
// needs to receive a Canvas object when called and returns the
|
|
// PaperScope.
|
|
module.exports = function(canvas) {
|
|
var source = fs.readFileSync(filename, 'utf8'),
|
|
code = sourceMapSupport + source,
|
|
compiled = paper.PaperScript.compile(code, {
|
|
url: filename,
|
|
source: source,
|
|
sourceMaps: true,
|
|
offset: -1 // remove sourceMapSupport...
|
|
}),
|
|
scope = new paper.PaperScope();
|
|
// Keep track of sourceMaps so retrieveSourceMap() can link them up
|
|
scope.setup(canvas);
|
|
scope.__filename = filename;
|
|
scope.__dirname = path.dirname(filename);
|
|
// Expose core methods and values
|
|
scope.require = require;
|
|
scope.console = console;
|
|
sourceMaps[filename] = compiled.map;
|
|
paper.PaperScript.execute(compiled, scope);
|
|
return scope;
|
|
};
|
|
};
|
|
}
|
|
|
|
paper.PaperScope.inject({
|
|
createCanvas: function(width, height, type) {
|
|
// Do not use CanvasProvider.getCanvas(), since we may be changing
|
|
// the underlying node-canvas when requesting PDF support, and don't
|
|
// want to release it after back into the pool.
|
|
var canvas = paper.document.createElement('canvas');
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
canvas.type = type;
|
|
return canvas;
|
|
},
|
|
|
|
/**
|
|
* @deprecated, use use {@link #createCanvas(width, height)} instead.
|
|
*/
|
|
Canvas: '#createCanvas'
|
|
});
|
|
|
|
// Override requestAnimationFrame() to avoid setInterval() timers.
|
|
// NOTE: In Node.js, we only support manual updating for now, but
|
|
// View#exportFrames() below offers a way to emulate animations by exporting
|
|
// them frame by frame at the given frame-rate.
|
|
paper.DomEvent.requestAnimationFrame = function(callback) {
|
|
};
|
|
|
|
// Node.js based image exporting code.
|
|
paper.CanvasView.inject({
|
|
// DOCS: CanvasView#exportFrames(options);
|
|
exportFrames: function(options) {
|
|
options = paper.Base.set({
|
|
fps: 30,
|
|
prefix: 'frame-',
|
|
amount: 1,
|
|
format: 'png' // Supported: 'png' or 'jpeg'
|
|
}, options);
|
|
if (!options.directory)
|
|
throw new Error('Missing options.directory');
|
|
if (options.format && !/^(jpeg|png)$/.test(options.format))
|
|
throw new Error('Unsupported format. Use "png" or "jpeg"');
|
|
var view = this,
|
|
count = 0,
|
|
frameDuration = 1 / options.fps,
|
|
startTime = Date.now(),
|
|
lastTime = startTime,
|
|
padding = options.padding || ((options.amount - 1) + '').length,
|
|
paddedStr = Array(padding + 1).join('0');
|
|
|
|
// Start exporting frames by exporting the first frame:
|
|
exportFrame(options);
|
|
|
|
function exportFrame() {
|
|
// Convert to a Base object, for #toString()
|
|
view.emit('frame', new paper.Base({
|
|
delta: frameDuration,
|
|
time: frameDuration * count,
|
|
count: count
|
|
}));
|
|
var file = path.join(options.directory,
|
|
options.prefix + (paddedStr + count).slice(-padding)
|
|
+ '.' + options.format);
|
|
var out = view.exportImage(file, function() {
|
|
// Once the file has been closed, export the next fame:
|
|
var then = Date.now();
|
|
if (options.onProgress) {
|
|
options.onProgress({
|
|
count: count,
|
|
amount: options.amount,
|
|
percentage: Math.round((count + 1) / options.amount
|
|
* 10000) / 100,
|
|
time: then - startTime,
|
|
delta: then - lastTime
|
|
});
|
|
}
|
|
lastTime = then;
|
|
if (++count < options.amount) {
|
|
exportFrame();
|
|
} else {
|
|
// Call onComplete handler when finished:
|
|
if (options.onComplete) {
|
|
options.onComplete();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// DOCS: CanvasView#exportImage(path, callback);
|
|
exportImage: function(path, callback) {
|
|
this.update();
|
|
var out = fs.createWriteStream(path),
|
|
format = /\.jp(e?)g$/.test(path) ? 'jpeg' : 'png',
|
|
stream = this._element[format + 'Stream']();
|
|
stream.pipe(out);
|
|
if (callback) {
|
|
out.on('close', callback);
|
|
}
|
|
return out;
|
|
}
|
|
});
|
|
};
|