Skip to content

Implement Readable instead of Stream #740

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

Merged
merged 1 commit into from
May 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 30 additions & 15 deletions lib/jpegstream.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
* Module dependencies.
*/

var Stream = require('stream').Stream;
var Readable = require('stream').Readable;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should depend from readable-stream, it is better practice and yields more stability across node versions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does require pulling in another dependency though...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the fact that most of the stream utilities depends on readable-stream, it's not really problematic (the users will do depend on it anyway). The only issue might be in the browser, but I don't think this can be used there.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(in browserify the stream module is based on readable-stream so it's no big deal)

var util = require('util');

/**
* Initialize a `JPEGStream` with the given `canvas`.
Expand All @@ -30,33 +31,47 @@ var Stream = require('stream').Stream;
*/

var JPEGStream = module.exports = function JPEGStream(canvas, options, sync) {
var self = this
, method = sync
if (!(this instanceof JPEGStream)) {
throw new TypeError("Class constructors cannot be invoked without 'new'");
}

Readable.call(this);

var self = this;
var method = sync
? 'streamJPEGSync'
: 'streamJPEG';
this.options = options;
this.sync = sync;
this.canvas = canvas;
this.readable = true;

// TODO: implement async
if ('streamJPEG' == method) method = 'streamJPEGSync';
this.method = method;
};

util.inherits(JPEGStream, Readable);

function noop() {}

JPEGStream.prototype._read = function _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;
var self = this;
var method = this.method;
var bufsize = this.options.bufsize;
var quality = this.options.quality;
var progressive = this.options.progressive;
process.nextTick(function(){
canvas[method](options.bufsize, options.quality, options.progressive, function(err, chunk){
self.canvas[method](bufsize, quality, progressive, function(err, chunk){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (chunk) {
self.emit('data', chunk);
self.push(chunk);
} else {
self.emit('end');
self.readable = false;
self.push(null);
}
});
});
};

/**
* Inherit from `EventEmitter`.
*/

JPEGStream.prototype.__proto__ = Stream.prototype;
37 changes: 24 additions & 13 deletions lib/pdfstream.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
* Module dependencies.
*/

var Stream = require('stream').Stream;
var Readable = require('stream').Readable;
var util = require('util');

/**
* Initialize a `PDFStream` with the given `canvas`.
Expand All @@ -28,32 +29,42 @@ var Stream = require('stream').Stream;
*/

var PDFStream = module.exports = function PDFStream(canvas, sync) {
if (!(this instanceof PDFStream)) {
throw new TypeError("Class constructors cannot be invoked without 'new'");
}

Readable.call(this);

var self = this
, method = sync
? 'streamPDFSync'
: 'streamPDF';
this.sync = sync;
this.canvas = canvas;
this.readable = true;

// TODO: implement async
if ('streamPDF' == method) method = 'streamPDFSync';
this.method = method;
};

util.inherits(PDFStream, Readable);

function noop() {}

PDFStream.prototype._read = function _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;
var self = this;
process.nextTick(function(){
canvas[method](function(err, chunk, len){
self.canvas[self.method](function(err, chunk, len){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (len) {
self.emit('data', chunk, len);
self.push(chunk);
} else {
self.emit('end');
self.readable = false;
self.push(null);
}
});
});
};

/**
* Inherit from `EventEmitter`.
*/

PDFStream.prototype.__proto__ = Stream.prototype;
60 changes: 44 additions & 16 deletions lib/pngstream.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
* Module dependencies.
*/

var Stream = require('stream').Stream;
var Readable = require('stream').Readable;
var util = require('util');

/**
* Initialize a `PNGStream` with the given `canvas`.
Expand All @@ -30,32 +31,59 @@ var Stream = require('stream').Stream;
*/

var PNGStream = module.exports = function PNGStream(canvas, sync) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a:

if (!(this instanceof PNGStream)) {
  return new PNGStream(canvas, sync)
}

To avoid pollution of the global namespace if invoked without new.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer throwing an error since this is the default behaviour with ES6 classes which we probably will want to upgrade the code base to at some point. Also, you can always stop throwing an exception without a major bump but going the other way is more complicated.

This is the exact error the Node throws:

throw new TypeError("Class constructors cannot be invoked without 'new'")

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Addressed. GitHub isn't hiding this because the diff is below the comment.)

var self = this
, method = sync
if (!(this instanceof PNGStream)) {
throw new TypeError("Class constructors cannot be invoked without 'new'");
}

Readable.call(this);

var self = this;
var method = sync
? 'streamPNGSync'
: 'streamPNG';
this.sync = sync;
this.canvas = canvas;

// TODO: implement async
if ('streamPNG' === method) method = 'streamPNGSync';
this.method = method;
};

util.inherits(PNGStream, Readable);

var PNGStream = module.exports = function PNGStream(canvas, sync) {
Readable.call(this);

var self = this;
var method = sync
? 'streamPNGSync'
: 'streamPNG';
this.sync = sync;
this.canvas = canvas;
this.readable = true;

// TODO: implement async
if ('streamPNG' == method) method = 'streamPNGSync';
if ('streamPNG' === method) method = 'streamPNGSync';
this.method = method;
};

util.inherits(PNGStream, Readable);

function noop() {}

PNGStream.prototype._read = function _read() {
// For now we're not controlling the c++ code's data emission, so we only
// call canvas.streamPNGSync once and let it emit data at will.
this._read = noop;
var self = this;
process.nextTick(function(){
canvas[method](function(err, chunk, len){
self.canvas[self.method](function(err, chunk, len){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (len) {
self.emit('data', chunk, len);
self.push(chunk);
} else {
self.emit('end');
self.readable = false;
self.push(null);
}
});
});
};

/**
* Inherit from `EventEmitter`.
*/

PNGStream.prototype.__proto__ = Stream.prototype;
2 changes: 1 addition & 1 deletion src/Canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ NAN_METHOD(Canvas::StreamPNGSync) {
Nan::Null()
, Nan::Null()
, Nan::New<Uint32>(0) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 3, argv);
}
return;
}
Expand Down
6 changes: 5 additions & 1 deletion test/canvas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ var Canvas = require('../')
, assert = require('assert')
, parseFont = Canvas.Context2d.parseFont
, fs = require('fs')
, os = require('os');
, os = require('os')
, Readable = require('stream').Readable;

console.log();
console.log(' canvas: %s', Canvas.version);
Expand Down Expand Up @@ -878,6 +879,7 @@ describe('Canvas', function () {
it('Canvas#createSyncPNGStream()', function (done) {
var canvas = new Canvas(20, 20);
var stream = canvas.createSyncPNGStream();
assert(stream instanceof Readable);
var firstChunk = true;
stream.on('data', function(chunk){
if (firstChunk) {
Expand All @@ -896,6 +898,7 @@ describe('Canvas', function () {
it('Canvas#createSyncPDFStream()', function (done) {
var canvas = new Canvas(20, 20, 'pdf');
var stream = canvas.createSyncPDFStream();
assert(stream instanceof Readable);
var firstChunk = true;
stream.on('data', function (chunk) {
if (firstChunk) {
Expand All @@ -914,6 +917,7 @@ describe('Canvas', function () {
it('Canvas#jpegStream()', function (done) {
var canvas = new Canvas(640, 480);
var stream = canvas.jpegStream();
assert(stream instanceof Readable);
var firstChunk = true;
var bytes = 0;
stream.on('data', function(chunk){
Expand Down