fsk-imgoptimize
Version:
144 lines (128 loc) • 3.88 kB
JavaScript
'use strict';
var Stream = require('stream');
var Readable = Stream.Readable;
var Writable = Stream.Writable;
var util = require('util');
var PNG_CONSTANTS = require('./constants.js').png;
util.inherits(ImageStream, Readable);
var keys = Object.keys(Writable.prototype);
for (var v = 0; v < keys.length; v++) {
var method = keys[v];
if (!ImageStream.prototype[method])
ImageStream.prototype[method] = Writable.prototype[method];
}
function ImageStream(path, options) {
options = options || {};
Stream.call(this, options);
Readable.call(this, options);
console.log('111')
console.dir(this._readableState )
this.writable = true;
this.pos = options.hasOwnProperty('pos') ? options.pos : 0;
this.buffers = [];
this.buffer_length = 0;
this._queue = [];
this._chunks = {};
this.content = [];
this.readSignature();
}
ImageStream.prototype._read = function() {
this.push();
};
ImageStream.prototype.write = function(data, encoding) {
if (!this.writable) {
this.emit('error', new Error('Stream not writable'));
return;
}
if (!util.isBuffer(data)) {
data = new Buffer(data, encoding, this._encoding);
}
this.buffers.push(data);
this.buffer_length += data.length;
this._parseTrunk();
};
ImageStream.prototype.readSignature = function() {
this._queue.push({
length: 8,
callback: this.parseSignature.bind(this)
});
this._parseTrunk();
};
ImageStream.prototype.parseSignature = function(data) {
if (PNG_CONSTANTS.PNG_SIGNATURE.every(function(o, n) {
return o === data[n];
})) {
this.content.push(data);
this.push(data);
this.readTrunkStart();
} else {
this.emit('error', 'Invalid file signature');
}
};
ImageStream.prototype.readTrunkStart = function() {
this._queue.push({
length: 8,
callback: this.parseTrunkStart.bind(this)
});
this._parseTrunk();
};
ImageStream.prototype.parseTrunkStart = function(data) {
var length = data.readUInt32BE(0);
var type = data.readUInt32BE(4);
var name = data.slice(4).toString();
var self = this;
if (this._chunks[type]) {
this.content.push(data);
this.push(data);
this._queue.push({
length: length + 4,
callback: function(content) {
self.content.push(content);
this.push(content);
self.readTrunkStart();
}
})
} else {
this._queue.push({
length: length + 4,
callback: self.readTrunkStart.bind(self)
});
}
};
ImageStream.prototype.end = function(data, cb) {
console.log(this.content);
}
ImageStream.prototype._parseTrunk = function() {
console.log('start', this._queue[0] , this.buffers)
while (this.buffer_length > 0 && this._queue && this._queue.length > 0) {
var read = this._queue[0];
if (this.buffer_length >= read.length) {
// ok we can meet some expectations
this._queue.shift(); // == read
var pos = 0,
count = 0,
data = new Buffer(read.length);
// create buffer for all data
while (pos < read.length) {
var buf = this.buffers[count++],
len = Math.min(buf.length, read.length - pos);
buf.copy(data, pos, 0, len);
pos += len;
// last buffer wasn't used all so just slice it and leave
if (len != buf.length)
this.buffers[--count] = buf.slice(len);
}
// remove all used buffers
if (count > 0)
this.buffers.splice(0, count);
this.buffer_length -= read.length;
read.callback.call(this, data);
} else {
// not enought data to satisfy first request in queue
// so we need to wait for more
break;
}
}
}
var fs = require('fs');
fs.createReadStream('iBtn.png').pipe(new ImageStream()).pipe(fs.createWriteStream('test.png'));