configure the rest of eslint.

This commit is contained in:
Luke Page 2015-08-04 21:32:22 +01:00
parent 8155d300f0
commit bf5ae3c54e
16 changed files with 737 additions and 713 deletions

136
.eslintrc
View file

@ -2,10 +2,10 @@
"ecmaFeatures": {}, "ecmaFeatures": {},
"rules": { "rules": {
"no-alert": 2, "no-alert": 2,
"no-array-constructor": 1, "no-array-constructor": 0,
"no-bitwise": 0, "no-bitwise": 0,
"no-caller": 2, "no-caller": 2,
"no-catch-shadow": 1, "no-catch-shadow": 2,
"no-class-assign": 2, "no-class-assign": 2,
"no-cond-assign": 2, "no-cond-assign": 2,
"no-console": 2, "no-console": 2,
@ -26,15 +26,15 @@
"no-eq-null": 0, "no-eq-null": 0,
"no-eval": 2, "no-eval": 2,
"no-ex-assign": 2, "no-ex-assign": 2,
"no-extend-native": 0, "no-extend-native": 2,
"no-extra-bind": 1, "no-extra-bind": 1,
"no-extra-boolean-cast": 2, "no-extra-boolean-cast": 2,
"no-extra-parens": 0, "no-extra-parens": 0,
"no-extra-semi": 2, "no-extra-semi": 2,
"no-fallthrough": 2, "no-fallthrough": 2,
"no-floating-decimal": 0, "no-floating-decimal": 1,
"no-func-assign": 2, "no-func-assign": 2,
"no-implicit-coercion": 0, "no-implicit-coercion": 1,
"no-implied-eval": 1, "no-implied-eval": 1,
"no-inline-comments": 0, "no-inline-comments": 0,
"no-inner-declarations": [2, "functions"], "no-inner-declarations": [2, "functions"],
@ -45,26 +45,26 @@
"no-label-var": 1, "no-label-var": 1,
"no-labels": 1, "no-labels": 1,
"no-lone-blocks": 1, "no-lone-blocks": 1,
"no-lonely-if": 0, "no-lonely-if": 1,
"no-loop-func": 1, "no-loop-func": 1,
"no-mixed-requires": [0, false], "no-mixed-requires": [1, false],
"no-mixed-spaces-and-tabs": [2, false], "no-mixed-spaces-and-tabs": [2, false],
"linebreak-style": [0, "unix"], "linebreak-style": [0, "unix"],
"no-multi-spaces": 1, "no-multi-spaces": 1,
"no-multi-str": 0, "no-multi-str": 0,
"no-multiple-empty-lines": [0, {"max": 2}], "no-multiple-empty-lines": [1, {"max": 2}],
"no-native-reassign": 0, "no-native-reassign": 2,
"no-negated-in-lhs": 2, "no-negated-in-lhs": 2,
"no-nested-ternary": 0, "no-nested-ternary": 1,
"no-new": 0, "no-new": 1,
"no-new-func": 0, "no-new-func": 1,
"no-new-object": 0, "no-new-object": 1,
"no-new-require": 0, "no-new-require": 1,
"no-new-wrappers": 0, "no-new-wrappers": 1,
"no-obj-calls": 2, "no-obj-calls": 2,
"no-octal": 2, "no-octal": 2,
"no-octal-escape": 0, "no-octal-escape": 0,
"no-param-reassign": 0, "no-param-reassign": 1,
"no-path-concat": 0, "no-path-concat": 0,
"no-plusplus": 0, "no-plusplus": 0,
"no-process-env": 0, "no-process-env": 0,
@ -73,23 +73,23 @@
"no-redeclare": 2, "no-redeclare": 2,
"no-regex-spaces": 2, "no-regex-spaces": 2,
"no-restricted-modules": 0, "no-restricted-modules": 0,
"no-return-assign": 0, "no-return-assign": 1,
"no-script-url": 0, "no-script-url": 0,
"no-self-compare": 0, "no-self-compare": 1,
"no-sequences": 0, "no-sequences": 1,
"no-shadow": 1, "no-shadow": 1,
"no-shadow-restricted-names": 0, "no-shadow-restricted-names": 1,
"no-spaced-func": 1, "no-spaced-func": 1,
"no-sparse-arrays": 2, "no-sparse-arrays": 2,
"no-sync": 0, "no-sync": 0,
"no-ternary": 0, "no-ternary": 0,
"no-trailing-spaces": 1, "no-trailing-spaces": 1,
"no-this-before-super": 0, "no-this-before-super": 1,
"no-throw-literal": 0, "no-throw-literal": 1,
"no-undef": 2, "no-undef": 2,
"no-undef-init": 0, "no-undef-init": 1,
"no-undefined": 0, "no-undefined": 0,
"no-unexpected-multiline": 0, "no-unexpected-multiline": 1,
"no-underscore-dangle": 0, "no-underscore-dangle": 0,
"no-unneeded-ternary": 0, "no-unneeded-ternary": 0,
"no-unreachable": 2, "no-unreachable": 2,
@ -99,73 +99,75 @@
"no-useless-call": 2, "no-useless-call": 2,
"no-void": 0, "no-void": 0,
"no-var": 0, "no-var": 0,
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }], "no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
"no-with": 0, "no-with": 1,
"array-bracket-spacing": [0, "never"], "array-bracket-spacing": [1, "never"],
"arrow-parens": 0, "arrow-parens": 1,
"arrow-spacing": 0, "arrow-spacing": 1,
"accessor-pairs": 0, "accessor-pairs": 1,
"block-scoped-var": 0, "block-scoped-var": 0,
"brace-style": [0, "1tbs"], "brace-style": [1, "1tbs"],
"callback-return": 0, "callback-return": [2, ["callback", "cb", "next"]],
"camelcase": 0, "camelcase": [2, {"properties": "always"}],
"comma-dangle": [2, "never"], "comma-dangle": [2, "never"],
"comma-spacing": 0, "comma-spacing": 2,
"comma-style": 0, "comma-style": 1,
"complexity": [0, 11], "complexity": [1, 10],
"computed-property-spacing": [0, "never"], "computed-property-spacing": [0, "never"],
"consistent-return": 0, "consistent-return": 0,
"consistent-this": [0, "that"], "consistent-this": [0, "that"],
"constructor-super": 0, "constructor-super": 1,
"curly": [0, "all"], "curly": [1, "all"],
"default-case": 0, "default-case": 1,
"dot-location": 0, "dot-location": [1, "property"],
"dot-notation": [0, { "allowKeywords": true }], "dot-notation": [1, { "allowKeywords": true }],
"eol-last": 0, "eol-last": 0,
"eqeqeq": 0, "eqeqeq": 1,
"func-names": 0, "func-names": 0,
"func-style": [0, "declaration"], "func-style": [0, "declaration"],
"generator-star-spacing": 0, "generator-star-spacing": 0,
"guard-for-in": 0, "guard-for-in": 1,
"handle-callback-err": 0, "handle-callback-err": 2,
"id-length": 0, "id-length": [2, {"min": 3, "max": 20, "exceptions":["x", "y", "i", "j"]}],
"indent": 0, "indent": [1, 2, {"SwitchCase": 1}],
"init-declarations": 0, "init-declarations": 0,
"key-spacing": [0, { "beforeColon": false, "afterColon": true }], "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
"lines-around-comment": 0, "lines-around-comment": 0,
"max-depth": [0, 4], "max-depth": [1, 4],
"max-len": [0, 80, 4], "max-len": [1, 160, 2],
"max-nested-callbacks": [0, 2], "max-nested-callbacks": [1, 2],
"max-params": [0, 3], "max-params": [1, 5],
"max-statements": [0, 10], "max-statements": [1, 30],
"new-cap": 0, "new-cap": 1,
"new-parens": 0, "new-parens": 1,
"newline-after-var": 0, "newline-after-var": 0,
"object-curly-spacing": [0, "never"], "object-curly-spacing": [1, "always"],
"object-shorthand": 0, "object-shorthand": 0,
"one-var": 0, "one-var": [1, {
"initialized": "never"
}],
"operator-assignment": [0, "always"], "operator-assignment": [0, "always"],
"operator-linebreak": 0, "operator-linebreak": [1, "after"],
"padded-blocks": 0, "padded-blocks": 0,
"prefer-const": 0, "prefer-const": 0,
"prefer-spread": 0, "prefer-spread": 0,
"prefer-reflect": 0, "prefer-reflect": 0,
"quote-props": 0, "quote-props": 0,
"quotes": [0, "double"], "quotes": [1, "single"],
"radix": 0, "radix": 0,
"id-match": 0, "id-match": 0,
"require-yield": 0, "require-yield": 0,
"semi": 0, "semi": [1, "always"],
"semi-spacing": [0, {"before": false, "after": true}], "semi-spacing": [1, {"before": false, "after": true}],
"sort-vars": 0, "sort-vars": 0,
"space-after-keywords": [0, "always"], "space-after-keywords": [1, "always"],
"space-before-blocks": [0, "always"], "space-before-blocks": [1, "always"],
"space-before-function-paren": [0, "always"], "space-before-function-paren": [1, "never"],
"space-in-parens": [0, "never"], "space-in-parens": [1, "never"],
"space-infix-ops": 0, "space-infix-ops": 1,
"space-return-throw-case": 0, "space-return-throw-case": 1,
"space-unary-ops": [0, { "words": true, "nonwords": false }], "space-unary-ops": [1, { "words": true, "nonwords": false }],
"spaced-comment": 0, "spaced-comment": 0,
"strict": [2, "global"], "strict": [2, "global"],
"use-isnan": 2, "use-isnan": 2,

View file

@ -33,16 +33,17 @@ function bitRetriever(data, depth) {
var leftOver = []; var leftOver = [];
var i = 0; var i = 0;
function split() { function split() {
if (i === data.length) { if (i === data.length) {
throw new Error("Ran out of data"); throw new Error('Ran out of data');
} }
var byte = data[i]; var byte = data[i];
i++; i++;
var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1 var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1;
switch(depth) { switch (depth) {
default: default:
throw new Error("unrecognised depth"); throw new Error('unrecognised depth');
case 16: case 16:
byte2 = data[i]; byte2 = data[i];
i++; i++;
@ -73,9 +74,10 @@ function bitRetriever(data, depth) {
break; break;
} }
} }
return { return {
get: function(count) { get: function(count) {
while(leftOver.length < count) { while (leftOver.length < count) {
split(); split();
} }
var returner = leftOver.slice(0, count); var returner = leftOver.slice(0, count);
@ -87,7 +89,8 @@ function bitRetriever(data, depth) {
}, },
end: function() { end: function() {
if (i !== data.length) { if (i !== data.length) {
throw new Error("extra data found"); // todo these exceptions should be emitting errors
throw new Error('extra data found');
} }
} }
}; };
@ -120,10 +123,10 @@ exports.dataToBitMap = function(data, width, height, bpp, depth, interlace) {
nonInterlacedPxPos += 4; nonInterlacedPxPos += 4;
return returner; return returner;
}; };
images = [{width: width, height: height}]; images = [{ width: width, height: height }];
} }
for(var imageIndex = 0; imageIndex < images.length; imageIndex++) { for (var imageIndex = 0; imageIndex < images.length; imageIndex++) {
var imageWidth = images[imageIndex].width; var imageWidth = images[imageIndex].width;
var imageHeight = images[imageIndex].height; var imageHeight = images[imageIndex].height;
var imagePass = images[imageIndex].index; var imagePass = images[imageIndex].index;
@ -138,7 +141,7 @@ exports.dataToBitMap = function(data, width, height, bpp, depth, interlace) {
var idx = pixelBppMap[bpp][i]; var idx = pixelBppMap[bpp][i];
if (depth === 8) { if (depth === 8) {
if (i === data.length) { if (i === data.length) {
throw new Error("Ran out of data"); throw new Error('Ran out of data');
} }
pxData[pxPos + i] = idx !== 0xff ? data[idx + rawPos] : maxBit; pxData[pxPos + i] = idx !== 0xff ? data[idx + rawPos] : maxBit;
} else { } else {
@ -155,7 +158,7 @@ exports.dataToBitMap = function(data, width, height, bpp, depth, interlace) {
} }
if (depth === 8) { if (depth === 8) {
if (rawPos !== data.length) { if (rawPos !== data.length) {
throw new Error("extra data found"); throw new Error('extra data found');
} }
} else { } else {
bits.end(); bits.end();

View file

@ -21,180 +21,189 @@
'use strict'; 'use strict';
var util = require('util'), var util = require('util');
Stream = require('stream'); var Stream = require('stream');
var ChunkStream = module.exports = function() { var ChunkStream = module.exports = function() {
Stream.call(this); Stream.call(this);
this._buffers = []; this._buffers = [];
this._buffered = 0; this._buffered = 0;
this._reads = []; this._reads = [];
this._paused = false; this._paused = false;
this._encoding = 'utf8'; this._encoding = 'utf8';
this.writable = true; this.writable = true;
}; };
util.inherits(ChunkStream, Stream); util.inherits(ChunkStream, Stream);
ChunkStream.prototype.read = function(length, callback) { ChunkStream.prototype.read = function(length, callback) {
this._reads.push({ this._reads.push({
length: Math.abs(length), // if length < 0 then at most this length length: Math.abs(length), // if length < 0 then at most this length
allowLess: length < 0, allowLess: length < 0,
func: callback func: callback
}); });
process.nextTick(function() { process.nextTick(function() {
this._process(); this._process();
// its paused and there is not enought data then ask for more // its paused and there is not enought data then ask for more
if (this._paused && this._reads.length > 0) { if (this._paused && this._reads.length > 0) {
this._paused = false; this._paused = false;
this.emit('drain'); this.emit('drain');
} }
}.bind(this)); }.bind(this));
}; };
ChunkStream.prototype.write = function(data, encoding) { ChunkStream.prototype.write = function(data, encoding) {
if (!this.writable) { if (!this.writable) {
this.emit('error', new Error('Stream not writable')); this.emit('error', new Error('Stream not writable'));
return false; return false;
} }
if (!Buffer.isBuffer(data)) var dataBuffer;
data = new Buffer(data, encoding || this._encoding); if (Buffer.isBuffer(data)) {
dataBuffer = data;
} else {
dataBuffer = new Buffer(data, encoding || this._encoding);
}
this._buffers.push(data); this._buffers.push(dataBuffer);
this._buffered += data.length; this._buffered += dataBuffer.length;
this._process(); this._process();
// ok if there are no more read requests // ok if there are no more read requests
if (this._reads && this._reads.length == 0) if (this._reads && this._reads.length == 0) {
this._paused = true; this._paused = true;
}
return this.writable && !this._paused; return this.writable && !this._paused;
}; };
ChunkStream.prototype.end = function(data, encoding) { ChunkStream.prototype.end = function(data, encoding) {
if (data) this.write(data, encoding); if (data) {
this.write(data, encoding);
}
this.writable = false; this.writable = false;
// already destroyed // already destroyed
if (!this._buffers) return; if (!this._buffers) return;
// enqueue or handle end // enqueue or handle end
if (this._buffers.length == 0) { if (this._buffers.length == 0) {
this._end(); this._end();
} else { } else {
this._buffers.push(null); this._buffers.push(null);
this._process(); this._process();
} }
}; };
ChunkStream.prototype.destroySoon = ChunkStream.prototype.end; ChunkStream.prototype.destroySoon = ChunkStream.prototype.end;
ChunkStream.prototype._end = function() { ChunkStream.prototype._end = function() {
if (this._reads.length > 0) { if (this._reads.length > 0) {
this.emit('error', this.emit('error',
new Error('There are some read requests waitng on finished stream') new Error('There are some read requests waitng on finished stream')
); );
} }
this.destroy(); this.destroy();
}; };
ChunkStream.prototype.destroy = function() { ChunkStream.prototype.destroy = function() {
if (!this._buffers) return; if (!this._buffers) {
return;
}
this.writable = false; this.writable = false;
this._reads = null; this._reads = null;
this._buffers = null; this._buffers = null;
this.emit('close'); this.emit('close');
}; };
ChunkStream.prototype._process = function() { ChunkStream.prototype._process = function() {
// as long as there is any data and read requests // as long as there is any data and read requests
while (this._buffered > 0 && this._reads && this._reads.length > 0) { while (this._buffered > 0 && this._reads && this._reads.length > 0) {
var read = this._reads[0]; var read = this._reads[0];
// read any data (but no more than length) // read any data (but no more than length)
if (read.allowLess) { if (read.allowLess) {
// ok there is any data so that we can satisfy this request // ok there is any data so that we can satisfy this request
this._reads.shift(); // == read this._reads.shift(); // == read
// first we need to peek into first buffer // first we need to peek into first buffer
var smallerBuf = this._buffers[0]; var smallerBuf = this._buffers[0];
// ok there is more data than we need // ok there is more data than we need
if (smallerBuf.length > read.length) { if (smallerBuf.length > read.length) {
this._buffered -= read.length; this._buffered -= read.length;
this._buffers[0] = smallerBuf.slice(read.length); this._buffers[0] = smallerBuf.slice(read.length);
read.func.call(this, smallerBuf.slice(0, read.length)); read.func.call(this, smallerBuf.slice(0, read.length));
} else { } else {
// ok this is less than maximum length so use it all // ok this is less than maximum length so use it all
this._buffered -= smallerBuf.length; this._buffered -= smallerBuf.length;
this._buffers.shift(); // == smallerBuf this._buffers.shift(); // == smallerBuf
read.func.call(this, smallerBuf); read.func.call(this, smallerBuf);
} }
} else if (this._buffered >= read.length) { } else if (this._buffered >= read.length) {
// ok we can meet some expectations // ok we can meet some expectations
this._reads.shift(); // == read this._reads.shift(); // == read
var pos = 0, var pos = 0;
count = 0, var count = 0;
data = new Buffer(read.length); var data = new Buffer(read.length);
// create buffer for all data // create buffer for all data
while (pos < read.length) { while (pos < read.length) {
var buf = this._buffers[count++], var buf = this._buffers[count++];
len = Math.min(buf.length, read.length - pos); var len = Math.min(buf.length, read.length - pos);
buf.copy(data, pos, 0, len); buf.copy(data, pos, 0, len);
pos += len; pos += len;
// last buffer wasn't used all so just slice it and leave // last buffer wasn't used all so just slice it and leave
if (len != buf.length) if (len != buf.length)
this._buffers[--count] = buf.slice(len); this._buffers[--count] = buf.slice(len);
} }
// remove all used buffers // remove all used buffers
if (count > 0) if (count > 0)
this._buffers.splice(0, count); this._buffers.splice(0, count);
this._buffered -= read.length; this._buffered -= read.length;
read.func.call(this, data); read.func.call(this, data);
} else { } else {
// not enought data to satisfy first request in queue // not enought data to satisfy first request in queue
// so we need to wait for more // so we need to wait for more
break; break;
}
} }
}
if (this._buffers && this._buffers.length > 0 && this._buffers[0] == null) { if (this._buffers && this._buffers.length > 0 && this._buffers[0] == null) {
this._end(); this._end();
} }
}; };

View file

@ -23,16 +23,18 @@
module.exports = { module.exports = {
PNG_SIGNATURE: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], PNG_SIGNATURE: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
TYPE_IHDR: 0x49484452, TYPE_IHDR: 0x49484452,
TYPE_IEND: 0x49454e44, TYPE_IEND: 0x49454e44,
TYPE_IDAT: 0x49444154, TYPE_IDAT: 0x49444154,
TYPE_PLTE: 0x504c5445, TYPE_PLTE: 0x504c5445,
TYPE_tRNS: 0x74524e53, /*eslint camelcase: 0*/
TYPE_gAMA: 0x67414d41, TYPE_tRNS: 0x74524e53,
TYPE_gAMA: 0x67414d41,
/*eslint camelcase: 1*/
COLOR_PALETTE: 1, COLOR_PALETTE: 1,
COLOR_COLOR: 2, COLOR_COLOR: 2,
COLOR_ALPHA: 4 COLOR_ALPHA: 4
}; };

View file

@ -23,41 +23,41 @@
var crcTable = []; var crcTable = [];
(function() { (function() {
for (var i = 0; i < 256; i++) { for (var i = 0; i < 256; i++) {
var c = i; var currentCrc = i;
for (var j = 0; j < 8; j++) { for (var j = 0; j < 8; j++) {
if (c & 1) { if (currentCrc & 1) {
c = 0xedb88320 ^ (c >>> 1); currentCrc = 0xedb88320 ^ (currentCrc >>> 1);
} else { } else {
c = c >>> 1; currentCrc = currentCrc >>> 1;
} }
}
crcTable[i] = c;
} }
crcTable[i] = currentCrc;
}
}()); }());
var CrcCalculator = module.exports = function() { var CrcCalculator = module.exports = function() {
this._crc = -1; this._crc = -1;
}; };
CrcCalculator.prototype.write = function(data) { CrcCalculator.prototype.write = function(data) {
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
this._crc = crcTable[(this._crc ^ data[i]) & 0xff] ^ (this._crc >>> 8); this._crc = crcTable[(this._crc ^ data[i]) & 0xff] ^ (this._crc >>> 8);
} }
return true; return true;
}; };
CrcCalculator.prototype.crc32 = function() { CrcCalculator.prototype.crc32 = function() {
return this._crc ^ -1; return this._crc ^ -1;
}; };
CrcCalculator.crc32 = function(buf) { CrcCalculator.crc32 = function(buf) {
var crc = -1; var crc = -1;
for (var i = 0; i < buf.length; i++) { for (var i = 0; i < buf.length; i++) {
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8); crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
} }
return crc ^ -1; return crc ^ -1;
}; };

View file

@ -20,26 +20,26 @@
'use strict'; 'use strict';
var util = require('util'), var util = require('util');
ChunkStream = require('./chunkstream'), var ChunkStream = require('./chunkstream');
Filter = require('./filter'); var Filter = require('./filter');
var FilterAsync = module.exports = function(width, height, Bpp, depth, interlace, options) { var FilterAsync = module.exports = function(width, height, Bpp, depth, interlace, options) {
ChunkStream.call(this); ChunkStream.call(this);
var buffers = []; var buffers = [];
var that = this; var that = this;
this._filter = new Filter(width, height, Bpp, depth, interlace, options, { this._filter = new Filter(width, height, Bpp, depth, interlace, options, {
read: this.read.bind(this), read: this.read.bind(this),
complete: function() { complete: function() {
that.emit('complete', Buffer.concat(buffers), width, height) that.emit('complete', Buffer.concat(buffers), width, height)
}, },
write: function(buffer) { write: function(buffer) {
buffers.push(buffer); buffers.push(buffer);
} }
}); });
this._filter.start(); this._filter.start();
}; };
util.inherits(FilterAsync, ChunkStream); util.inherits(FilterAsync, ChunkStream);

View file

@ -20,24 +20,25 @@
'use strict'; 'use strict';
var SyncReader = require('./sync-reader'), var SyncReader = require('./sync-reader');
Filter = require('./filter'); var Filter = require('./filter');
exports.process = function(inBuffer, width, height, Bpp, depth, interlace, options) { exports.process = function(inBuffer, width, height, Bpp, depth, interlace, options) {
var outBuffers = []; var outBuffers = [];
var reader = new SyncReader(inBuffer); var reader = new SyncReader(inBuffer);
var filter = new Filter(width, height, Bpp, depth, interlace, options, { var filter = new Filter(width, height, Bpp, depth, interlace, options, {
read: reader.read.bind(reader), read: reader.read.bind(reader),
write: function(bufferPart) { write: function(bufferPart) {
outBuffers.push(bufferPart); outBuffers.push(bufferPart);
}, },
complete: function(){} complete: function() {
}); }
});
filter.start(); filter.start();
reader.process(); reader.process();
return Buffer.concat(outBuffers); return Buffer.concat(outBuffers);
}; };

View file

@ -23,265 +23,265 @@
var interlaceUtils = require('./interlace'); var interlaceUtils = require('./interlace');
function getByteWidth(width, bpp, depth) { function getByteWidth(width, bpp, depth) {
var byteWidth = width * bpp; var byteWidth = width * bpp;
if (depth !== 8) { if (depth !== 8) {
byteWidth = Math.ceil(byteWidth / (8 / depth)); byteWidth = Math.ceil(byteWidth / (8 / depth));
} }
return byteWidth; return byteWidth;
} }
function PaethPredictor(left, above, upLeft) { function PaethPredictor(left, above, upLeft) {
var p = left + above - upLeft, var p = left + above - upLeft,
pLeft = Math.abs(p - left), pLeft = Math.abs(p - left),
pAbove = Math.abs(p - above), pAbove = Math.abs(p - above),
pUpLeft = Math.abs(p - upLeft); pUpLeft = Math.abs(p - upLeft);
if (pLeft <= pAbove && pLeft <= pUpLeft) { if (pLeft <= pAbove && pLeft <= pUpLeft) {
return left; return left;
} }
if (pAbove <= pUpLeft) { if (pAbove <= pUpLeft) {
return above; return above;
} }
return upLeft; return upLeft;
} }
var Filter = module.exports = function(width, height, Bpp, depth, interlace, options, dependencies) { var Filter = module.exports = function(width, height, Bpp, depth, interlace, options, dependencies) {
this._width = width; this._width = width;
this._height = height; this._height = height;
this._Bpp = Bpp; this._Bpp = Bpp;
this._depth = depth; this._depth = depth;
this._options = options; this._options = options;
if (!('filterType' in options) || options.filterType == -1) { if (!('filterType' in options) || options.filterType == -1) {
options.filterType = [0, 1, 2, 3, 4]; options.filterType = [0, 1, 2, 3, 4];
} else if (typeof options.filterType == 'number') { } else if (typeof options.filterType == 'number') {
options.filterType = [options.filterType]; options.filterType = [options.filterType];
} }
this._filters = { this._filters = {
0: this._filterNone.bind(this), 0: this._filterNone.bind(this),
1: this._filterSub.bind(this), 1: this._filterSub.bind(this),
2: this._filterUp.bind(this), 2: this._filterUp.bind(this),
3: this._filterAvg.bind(this), 3: this._filterAvg.bind(this),
4: this._filterPaeth.bind(this) 4: this._filterPaeth.bind(this)
}; };
this.read = dependencies.read; this.read = dependencies.read;
this.write = dependencies.write; this.write = dependencies.write;
this.complete = dependencies.complete; this.complete = dependencies.complete;
this._imageIndex = 0; this._imageIndex = 0;
this._images = []; this._images = [];
if (interlace) { if (interlace) {
var passes = interlaceUtils.getImagePasses(width, height); var passes = interlaceUtils.getImagePasses(width, height);
for(var i = 0; i < passes.length; i++) { for (var i = 0; i < passes.length; i++) {
this._images.push({ this._images.push({
byteWidth: getByteWidth(passes[i].width, Bpp, depth), byteWidth: getByteWidth(passes[i].width, Bpp, depth),
height: passes[i].height, height: passes[i].height,
lineIndex: 0 lineIndex: 0
}); });
}
} else {
this._images.push({
byteWidth: getByteWidth(width, Bpp, depth),
height: height,
lineIndex: 0
});
} }
} else {
this._images.push({
byteWidth: getByteWidth(width, Bpp, depth),
height: height,
lineIndex: 0
});
}
}; };
Filter.prototype.start = function() { Filter.prototype.start = function() {
this.read(this._images[this._imageIndex].byteWidth + 1, this._reverseFilterLine.bind(this)); this.read(this._images[this._imageIndex].byteWidth + 1, this._reverseFilterLine.bind(this));
}; };
Filter.prototype._reverseFilterLine = function(rawData) { Filter.prototype._reverseFilterLine = function(rawData) {
var currentImage = this._images[this._imageIndex]; var currentImage = this._images[this._imageIndex];
var line = new Buffer(currentImage.byteWidth); var line = new Buffer(currentImage.byteWidth);
var filter = rawData[0]; var filter = rawData[0];
var xComparison = this._depth >= 8 ? ((this._depth === 16) ? this._Bpp * 2 : this._Bpp) : 1; var xComparison = this._depth >= 8 ? ((this._depth === 16) ? this._Bpp * 2 : this._Bpp) : 1;
var xBiggerThan = xComparison - 1; var xBiggerThan = xComparison - 1;
for (var x = 0; x < currentImage.byteWidth; x++) { for (var x = 0; x < currentImage.byteWidth; x++) {
var rawByte = rawData[1 + x]; var rawByte = rawData[1 + x];
switch(filter) { switch (filter) {
case 0: case 0:
line[x] = rawByte; line[x] = rawByte;
break; break;
case 1: case 1:
var f1_left = x > xBiggerThan ? line[x - xComparison] : 0; var f1_left = x > xBiggerThan ? line[x - xComparison] : 0;
line[x] = rawByte + f1_left; line[x] = rawByte + f1_left;
break; break;
case 2: case 2:
var f2_up = this._lastLine ? this._lastLine[x] : 0; var f2_up = this._lastLine ? this._lastLine[x] : 0;
line[x] = rawByte + f2_up; line[x] = rawByte + f2_up;
break; break;
case 3: case 3:
var f3_up = this._lastLine ? this._lastLine[x] : 0; var f3_up = this._lastLine ? this._lastLine[x] : 0;
var f3_left = x > xBiggerThan ? line[x - xComparison] : 0; var f3_left = x > xBiggerThan ? line[x - xComparison] : 0;
var f3_add = Math.floor((f3_left + f3_up) / 2); var f3_add = Math.floor((f3_left + f3_up) / 2);
line[x] = rawByte + f3_add; line[x] = rawByte + f3_add;
break; break;
case 4: case 4:
var f4_up = this._lastLine ? this._lastLine[x] : 0; var f4_up = this._lastLine ? this._lastLine[x] : 0;
var f4_left = x > xBiggerThan ? line[x - xComparison] : 0; var f4_left = x > xBiggerThan ? line[x - xComparison] : 0;
var f4_upLeft = x > xBiggerThan && this._lastLine var f4_upLeft = x > xBiggerThan && this._lastLine
? this._lastLine[x - xComparison] : 0; ? this._lastLine[x - xComparison] : 0;
var f4_add = PaethPredictor(f4_left, f4_up, f4_upLeft); var f4_add = PaethPredictor(f4_left, f4_up, f4_upLeft);
line[x] = rawByte + f4_add; line[x] = rawByte + f4_add;
break; break;
}
//if (x === 5) {
// console.log("R", line[3], "G", line[4], "B", line[5]);
//}
} }
this.write(line); //if (x === 5) {
// console.log("R", line[3], "G", line[4], "B", line[5]);
//}
}
currentImage.lineIndex++; this.write(line);
if (currentImage.lineIndex >= currentImage.height) {
this._lastLine = null;
this._imageIndex++;
currentImage = this._images[this._imageIndex];
} else {
this._lastLine = line;
}
if (currentImage) { currentImage.lineIndex++;
this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this)); if (currentImage.lineIndex >= currentImage.height) {
} else { this._lastLine = null;
this.complete(this._width, this._height); this._imageIndex++;
} currentImage = this._images[this._imageIndex];
} else {
this._lastLine = line;
}
if (currentImage) {
this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this));
} else {
this.complete(this._width, this._height);
}
}; };
Filter.prototype.filter = function(pxData) { Filter.prototype.filter = function(pxData) {
var rawData = new Buffer(((this._width << 2) + 1) * this._height); var rawData = new Buffer(((this._width << 2) + 1) * this._height);
for (var y = 0; y < this._height; y++) { for (var y = 0; y < this._height; y++) {
// find best filter for this line (with lowest sum of values) // find best filter for this line (with lowest sum of values)
var filterTypes = this._options.filterType, var filterTypes = this._options.filterType,
min = Infinity, min = Infinity,
sel = 0; sel = 0;
for (var i = 0; i < filterTypes.length; i++) { for (var i = 0; i < filterTypes.length; i++) {
var sum = this._filters[filterTypes[i]](pxData, y, null); var sum = this._filters[filterTypes[i]](pxData, y, null);
if (sum < min) { if (sum < min) {
sel = filterTypes[i]; sel = filterTypes[i];
min = sum; min = sum;
} }
}
this._filters[sel](pxData, y, rawData);
} }
return rawData;
this._filters[sel](pxData, y, rawData);
}
return rawData;
}; };
Filter.prototype._filterNone = function(pxData, y, rawData) { Filter.prototype._filterNone = function(pxData, y, rawData) {
var pxRowLength = this._width << 2, var pxRowLength = this._width << 2,
rawRowLength = pxRowLength + 1, rawRowLength = pxRowLength + 1,
sum = 0; sum = 0;
if (!rawData) { if (!rawData) {
for (var x = 0; x < pxRowLength; x++) for (var x = 0; x < pxRowLength; x++)
sum += Math.abs(pxData[y * pxRowLength + x]); sum += Math.abs(pxData[y * pxRowLength + x]);
} else { } else {
rawData[y * rawRowLength] = 0; rawData[y * rawRowLength] = 0;
pxData.copy(rawData, rawRowLength * y + 1, pxRowLength * y, pxRowLength * (y + 1)); pxData.copy(rawData, rawRowLength * y + 1, pxRowLength * y, pxRowLength * (y + 1));
} }
return sum; return sum;
}; };
Filter.prototype._filterSub = function(pxData, y, rawData) { Filter.prototype._filterSub = function(pxData, y, rawData) {
var pxRowLength = this._width << 2, var pxRowLength = this._width << 2,
rawRowLength = pxRowLength + 1, rawRowLength = pxRowLength + 1,
sum = 0; sum = 0;
if (rawData) if (rawData)
rawData[y * rawRowLength] = 1; rawData[y * rawRowLength] = 1;
for (var x = 0; x < pxRowLength; x++) { for (var x = 0; x < pxRowLength; x++) {
var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0, var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0,
val = pxData[y * pxRowLength + x] - left; val = pxData[y * pxRowLength + x] - left;
if (!rawData) sum += Math.abs(val); if (!rawData) sum += Math.abs(val);
else rawData[y * rawRowLength + 1 + x] = val; else rawData[y * rawRowLength + 1 + x] = val;
} }
return sum; return sum;
}; };
Filter.prototype._filterUp = function(pxData, y, rawData) { Filter.prototype._filterUp = function(pxData, y, rawData) {
var pxRowLength = this._width << 2, var pxRowLength = this._width << 2,
rawRowLength = pxRowLength + 1, rawRowLength = pxRowLength + 1,
sum = 0; sum = 0;
if (rawData) if (rawData)
rawData[y * rawRowLength] = 2; rawData[y * rawRowLength] = 2;
for (var x = 0; x < pxRowLength; x++) { for (var x = 0; x < pxRowLength; x++) {
var up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0, var up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0,
val = pxData[y * pxRowLength + x] - up; val = pxData[y * pxRowLength + x] - up;
if (!rawData) sum += Math.abs(val); if (!rawData) sum += Math.abs(val);
else rawData[y * rawRowLength + 1 + x] = val; else rawData[y * rawRowLength + 1 + x] = val;
} }
return sum; return sum;
}; };
Filter.prototype._filterAvg = function(pxData, y, rawData) { Filter.prototype._filterAvg = function(pxData, y, rawData) {
var pxRowLength = this._width << 2, var pxRowLength = this._width << 2,
rawRowLength = pxRowLength + 1, rawRowLength = pxRowLength + 1,
sum = 0; sum = 0;
if (rawData) if (rawData)
rawData[y * rawRowLength] = 3; rawData[y * rawRowLength] = 3;
for (var x = 0; x < pxRowLength; x++) { for (var x = 0; x < pxRowLength; x++) {
var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0, var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0,
up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0, up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0,
val = pxData[y * pxRowLength + x] - ((left + up) >> 1); val = pxData[y * pxRowLength + x] - ((left + up) >> 1);
if (!rawData) sum += Math.abs(val); if (!rawData) sum += Math.abs(val);
else rawData[y * rawRowLength + 1 + x] = val; else rawData[y * rawRowLength + 1 + x] = val;
} }
return sum; return sum;
}; };
Filter.prototype._filterPaeth = function(pxData, y, rawData) { Filter.prototype._filterPaeth = function(pxData, y, rawData) {
var pxRowLength = this._width << 2, var pxRowLength = this._width << 2,
rawRowLength = pxRowLength + 1, rawRowLength = pxRowLength + 1,
sum = 0; sum = 0;
if (rawData) if (rawData)
rawData[y * rawRowLength] = 4; rawData[y * rawRowLength] = 4;
for (var x = 0; x < pxRowLength; x++) { for (var x = 0; x < pxRowLength; x++) {
var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0, var left = x >= 4 ? pxData[y * pxRowLength + x - 4] : 0,
up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0, up = y > 0 ? pxData[(y - 1) * pxRowLength + x] : 0,
upLeft = x >= 4 && y > 0 ? pxData[(y - 1) * pxRowLength + x - 4] : 0, upLeft = x >= 4 && y > 0 ? pxData[(y - 1) * pxRowLength + x - 4] : 0,
val = pxData[y * pxRowLength + x] - PaethPredictor(left, up, upLeft); val = pxData[y * pxRowLength + x] - PaethPredictor(left, up, upLeft);
if (!rawData) sum += Math.abs(val); if (!rawData) sum += Math.abs(val);
else rawData[y * rawRowLength + 1 + x] = val; else rawData[y * rawRowLength + 1 + x] = val;
} }
return sum; return sum;
}; };

View file

@ -49,11 +49,11 @@ exports.getImagePasses = function(width, height) {
var yLeftOver = height % 8; var yLeftOver = height % 8;
var xRepeats = (width - xLeftOver) / 8; var xRepeats = (width - xLeftOver) / 8;
var yRepeats = (width - yLeftOver) / 8; var yRepeats = (width - yLeftOver) / 8;
for(var i = 0; i < imagePasses.length; i++) { for (var i = 0; i < imagePasses.length; i++) {
var pass = imagePasses[i]; var pass = imagePasses[i];
var passWidth = xRepeats * pass.x.length; var passWidth = xRepeats * pass.x.length;
var passHeight = yRepeats * pass.y.length; var passHeight = yRepeats * pass.y.length;
for(var j = 0; j < pass.x.length; j++) { for (var j = 0; j < pass.x.length; j++) {
if (pass.x[j] < xLeftOver) { if (pass.x[j] < xLeftOver) {
passWidth++; passWidth++;
} }
@ -61,7 +61,7 @@ exports.getImagePasses = function(width, height) {
break; break;
} }
} }
for(j = 0; j < pass.y.length; j++) { for (j = 0; j < pass.y.length; j++) {
if (pass.y[j] < yLeftOver) { if (pass.y[j] < yLeftOver) {
passHeight++; passHeight++;
} }
@ -70,7 +70,7 @@ exports.getImagePasses = function(width, height) {
} }
} }
if (passWidth > 0 && passHeight > 0) { if (passWidth > 0 && passHeight > 0) {
images.push({ width: passWidth, height: passHeight, index: i}); images.push({width: passWidth, height: passHeight, index: i});
} }
} }
return images; return images;
@ -79,7 +79,7 @@ exports.getImagePasses = function(width, height) {
exports.getInterlaceIterator = function(width) { exports.getInterlaceIterator = function(width) {
return function(x, y, pass) { return function(x, y, pass) {
var outerXLeftOver = x % imagePasses[pass].x.length; var outerXLeftOver = x % imagePasses[pass].x.length;
var outerX = (((x - outerXLeftOver)/ imagePasses[pass].x.length) * 8) + imagePasses[pass].x[outerXLeftOver]; var outerX = (((x - outerXLeftOver) / imagePasses[pass].x.length) * 8) + imagePasses[pass].x[outerXLeftOver];
var outerYLeftOver = y % imagePasses[pass].y.length; var outerYLeftOver = y % imagePasses[pass].y.length;
var outerY = (((y - outerYLeftOver) / imagePasses[pass].y.length) * 8) + imagePasses[pass].y[outerYLeftOver]; var outerY = (((y - outerYLeftOver) / imagePasses[pass].y.length) * 8) + imagePasses[pass].y[outerYLeftOver];
return (outerX * 4) + (outerY * width * 4); return (outerX * 4) + (outerY * width * 4);

View file

@ -21,91 +21,91 @@
'use strict'; 'use strict';
var util = require('util'), var util = require('util');
Stream = require('stream'), var Stream = require('stream');
zlib = require('zlib'), var zlib = require('zlib');
Filter = require('./filter'), var Filter = require('./filter');
CrcStream = require('./crc'), var CrcStream = require('./crc');
constants = require('./constants'); var constants = require('./constants');
var Packer = module.exports = function(options) { var Packer = module.exports = function(options) {
Stream.call(this); Stream.call(this);
this._options = options; this._options = options;
options.deflateChunkSize = options.deflateChunkSize || 32 * 1024; options.deflateChunkSize = options.deflateChunkSize || 32 * 1024;
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9; options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3; options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
this.readable = true; this.readable = true;
}; };
util.inherits(Packer, Stream); util.inherits(Packer, Stream);
Packer.prototype.pack = function(data, width, height) { Packer.prototype.pack = function(data, width, height) {
// Signature // Signature
this.emit('data', new Buffer(constants.PNG_SIGNATURE)); this.emit('data', new Buffer(constants.PNG_SIGNATURE));
this.emit('data', this._packIHDR(width, height)); this.emit('data', this._packIHDR(width, height));
// filter pixel data // filter pixel data
//TODO {} //TODO {}
var filter = new Filter(width, height, 4, 8, false, this._options, {}); var filter = new Filter(width, height, 4, 8, false, this._options, {});
var filteredData = filter.filter(data); var filteredData = filter.filter(data);
// compress it // compress it
var deflate = zlib.createDeflate({ var deflate = zlib.createDeflate({
chunkSize: this._options.deflateChunkSize, chunkSize: this._options.deflateChunkSize,
level: this._options.deflateLevel, level: this._options.deflateLevel,
strategy: this._options.deflateStrategy strategy: this._options.deflateStrategy
}); });
deflate.on('error', this.emit.bind(this, 'error')); deflate.on('error', this.emit.bind(this, 'error'));
deflate.on('data', function(compressedData) { deflate.on('data', function(compressedData) {
this.emit('data', this._packIDAT(compressedData)); this.emit('data', this._packIDAT(compressedData));
}.bind(this)); }.bind(this));
deflate.on('end', function() { deflate.on('end', function() {
this.emit('data', this._packIEND()); this.emit('data', this._packIEND());
this.emit('end'); this.emit('end');
}.bind(this)); }.bind(this));
deflate.end(filteredData); deflate.end(filteredData);
}; };
Packer.prototype._packChunk = function(type, data) { Packer.prototype._packChunk = function(type, data) {
var len = (data ? data.length : 0), var len = (data ? data.length : 0),
buf = new Buffer(len + 12); buf = new Buffer(len + 12);
buf.writeUInt32BE(len, 0); buf.writeUInt32BE(len, 0);
buf.writeUInt32BE(type, 4); buf.writeUInt32BE(type, 4);
if (data) data.copy(buf, 8); if (data) data.copy(buf, 8);
buf.writeInt32BE(CrcStream.crc32(buf.slice(4, buf.length - 4)), buf.length - 4); buf.writeInt32BE(CrcStream.crc32(buf.slice(4, buf.length - 4)), buf.length - 4);
return buf; return buf;
}; };
Packer.prototype._packIHDR = function(width, height) { Packer.prototype._packIHDR = function(width, height) {
var buf = new Buffer(13); var buf = new Buffer(13);
buf.writeUInt32BE(width, 0); buf.writeUInt32BE(width, 0);
buf.writeUInt32BE(height, 4); buf.writeUInt32BE(height, 4);
buf[8] = 8; buf[8] = 8;
buf[9] = 6; // colorType buf[9] = 6; // colorType
buf[10] = 0; // compression buf[10] = 0; // compression
buf[11] = 0; // filter buf[11] = 0; // filter
buf[12] = 0; // interlace buf[12] = 0; // interlace
return this._packChunk(constants.TYPE_IHDR, buf); return this._packChunk(constants.TYPE_IHDR, buf);
}; };
Packer.prototype._packIDAT = function(data) { Packer.prototype._packIDAT = function(data) {
return this._packChunk(constants.TYPE_IDAT, data); return this._packChunk(constants.TYPE_IDAT, data);
}; };
Packer.prototype._packIEND = function() { Packer.prototype._packIEND = function() {
return this._packChunk(constants.TYPE_IEND, null); return this._packChunk(constants.TYPE_IEND, null);
}; };

View file

@ -21,108 +21,108 @@
'use strict'; 'use strict';
var util = require('util'), var util = require('util');
zlib = require('zlib'), var zlib = require('zlib');
ChunkStream = require('./chunkstream'), var ChunkStream = require('./chunkstream');
FilterAsync = require('./filter-async'), var FilterAsync = require('./filter-async');
Parser = require('./parser'), var Parser = require('./parser');
bitmapper = require('./bitmapper'); var bitmapper = require('./bitmapper');
var ParserAsync = module.exports = function(options) { var ParserAsync = module.exports = function(options) {
ChunkStream.call(this); ChunkStream.call(this);
this._parser = new Parser(options, { this._parser = new Parser(options, {
read: this.read.bind(this), read: this.read.bind(this),
error: this._handleError.bind(this), error: this._handleError.bind(this),
metadata: this.emit.bind(this, "metadata"), metadata: this.emit.bind(this, "metadata"),
gamma: this.emit.bind(this, "gamma"), gamma: this.emit.bind(this, "gamma"),
finished: this._finished.bind(this), finished: this._finished.bind(this),
inflateData: this._inflateData.bind(this), inflateData: this._inflateData.bind(this),
createData: this._createData.bind(this) createData: this._createData.bind(this)
}); });
this._options = options; this._options = options;
this.writable = true; this.writable = true;
this._parser.start(); this._parser.start();
}; };
util.inherits(ParserAsync, ChunkStream); util.inherits(ParserAsync, ChunkStream);
ParserAsync.prototype._handleError = function(err) { ParserAsync.prototype._handleError = function(err) {
this.emit('error', err); this.emit('error', err);
this.writable = false; this.writable = false;
this.destroy(); this.destroy();
if (this._inflate && this._inflate.destroy) { if (this._inflate && this._inflate.destroy) {
this._inflate.destroy(); this._inflate.destroy();
} }
this.errord = true; this.errord = true;
}; };
ParserAsync.prototype._inflateData = function(data) { ParserAsync.prototype._inflateData = function(data) {
if (!this._inflate) { if (!this._inflate) {
this._inflate = zlib.createInflate(); this._inflate = zlib.createInflate();
this._inflate.on('error', this.emit.bind(this, 'error')); this._inflate.on('error', this.emit.bind(this, 'error'));
this._filter.on('complete', this._complete.bind(this)); this._filter.on('complete', this._complete.bind(this));
this._inflate.pipe(this._filter); this._inflate.pipe(this._filter);
} }
this._inflate.write(data); this._inflate.write(data);
}; };
ParserAsync.prototype._createData = function(width, height, bpp, depth, interlace) { ParserAsync.prototype._createData = function(width, height, bpp, depth, interlace) {
this._bpp = bpp; this._bpp = bpp;
this._depth = depth; this._depth = depth;
this._interlace = interlace; this._interlace = interlace;
this._filter = new FilterAsync( this._filter = new FilterAsync(
width, height, width, height,
bpp, bpp,
depth, depth,
interlace, interlace,
this._options this._options
); );
}; };
ParserAsync.prototype._finished = function() { ParserAsync.prototype._finished = function() {
if (this.errord) { if (this.errord) {
return; return;
} }
if (!this._inflate) { if (!this._inflate) {
this.emit('error', 'No Inflate block'); this.emit('error', 'No Inflate block');
} else { } else {
// no more data to inflate // no more data to inflate
this._inflate.end(); this._inflate.end();
} }
this.destroySoon(); this.destroySoon();
}; };
ParserAsync.prototype._complete = function(data, width, height) { ParserAsync.prototype._complete = function(data, width, height) {
if (this.errord) { if (this.errord) {
return; return;
} }
try { try {
data = bitmapper.dataToBitMap(data, width, height, data = bitmapper.dataToBitMap(data, width, height,
this._bpp, this._bpp,
this._depth, this._depth,
this._interlace); this._interlace);
data = this._parser.reverseFiltered(data, this._depth, width, height); data = this._parser.reverseFiltered(data, this._depth, width, height);
} }
catch(e) { catch (e) {
this._handleError(); this._handleError();
return; return;
} }
this.emit('parsed', data); this.emit('parsed', data);
}; };

View file

@ -21,76 +21,77 @@
'use strict'; 'use strict';
var zlib = require('zlib'), var zlib = require('zlib');
SyncReader = require('./sync-reader'), var SyncReader = require('./sync-reader');
FilterSync = require('./filter-sync'), var FilterSync = require('./filter-sync');
Parser = require('./parser'), var Parser = require('./parser');
bitmapper = require('./bitmapper'); var bitmapper = require('./bitmapper');
var ParserSync = module.exports = function(buffer, options) { var ParserSync = module.exports = function(buffer, options) {
var reader = new SyncReader(buffer); var reader = new SyncReader(buffer);
this._inflateDataList = []; this._inflateDataList = [];
this._parser = new Parser(options, { this._parser = new Parser(options, {
read: reader.read.bind(reader), read: reader.read.bind(reader),
error: this._handleError.bind(this), error: this._handleError.bind(this),
metadata: this._metaData.bind(this), metadata: this._metaData.bind(this),
gamma: this._gamma.bind(this), gamma: this._gamma.bind(this),
finished: function() {}, finished: function() {
inflateData: this._inflateData.bind(this), },
createData: this._createData.bind(this) inflateData: this._inflateData.bind(this),
}); createData: this._createData.bind(this)
this._options = options; });
this._options = options;
this._parser.start(); this._parser.start();
reader.process(); reader.process();
//join together the inflate datas //join together the inflate datas
var inflateData = Buffer.concat(this._inflateDataList); var inflateData = Buffer.concat(this._inflateDataList);
var data = zlib.inflateSync(inflateData); var data = zlib.inflateSync(inflateData);
data = FilterSync.process( data = FilterSync.process(
data, data,
this._width, this._height, this._width, this._height,
this._bpp, this._bpp,
this._depth, this._depth,
this._interlace, this._interlace,
this._options this._options
); );
this._data = bitmapper.dataToBitMap(data, this._width, this._height, this._data = bitmapper.dataToBitMap(data, this._width, this._height,
this._bpp, this._bpp,
this._depth, this._depth,
this._interlace); this._interlace);
// todo yuck // todo yuck
this.data = this._parser.reverseFiltered(this._data, this._depth, this._width, this._height); this.data = this._parser.reverseFiltered(this._data, this._depth, this._width, this._height);
}; };
ParserSync.prototype._handleError = function(err) { ParserSync.prototype._handleError = function(err) {
this.err = err; this.err = err;
}; };
ParserSync.prototype._metaData = function(metaData) { ParserSync.prototype._metaData = function(metaData) {
this.metaData = metaData; this.metaData = metaData;
}; };
ParserSync.prototype._gamma = function(gamma) { ParserSync.prototype._gamma = function(gamma) {
this.gamma = gamma; this.gamma = gamma;
}; };
ParserSync.prototype._inflateData = function(data) { ParserSync.prototype._inflateData = function(data) {
this._inflateDataList.push(data); this._inflateDataList.push(data);
}; };
ParserSync.prototype._createData = function(width, height, bpp, depth, interlace) { ParserSync.prototype._createData = function(width, height, bpp, depth, interlace) {
this._data = new Buffer(width * height * 4); this._data = new Buffer(width * height * 4);
this._bpp = bpp; this._bpp = bpp;
this._width = width; this._width = width;
this._height = height; this._height = height;
this._depth = depth; this._depth = depth;
this._interlace = interlace; this._interlace = interlace;
return this._data; return this._data;
}; };

View file

@ -21,8 +21,8 @@
'use strict'; 'use strict';
var constants = require('./constants'), var constants = require('./constants');
CrcCalculator = require('./crc'); var CrcCalculator = require('./crc');
var Parser = module.exports = function(options, dependencies) { var Parser = module.exports = function(options, dependencies) {
@ -52,7 +52,7 @@ var Parser = module.exports = function(options, dependencies) {
this.parsed = dependencies.parsed; this.parsed = dependencies.parsed;
this.createData = dependencies.createData; this.createData = dependencies.createData;
this.inflateData = dependencies.inflateData; this.inflateData = dependencies.inflateData;
this.finished = dependencies.finished; this.finished = dependencies.finished;
}; };
var colorTypeToBppMap = { var colorTypeToBppMap = {
@ -221,7 +221,7 @@ Parser.prototype._parsePLTE = function(data) {
this._palette.push([ this._palette.push([
data[i * 3], data[i * 3],
data[i * 3 + 1], data[i * 3 + 1],
data[i * 3 + 2 ], data[i * 3 + 2],
0xff 0xff
]); ]);
} }

View file

@ -26,17 +26,16 @@ var Parser = require('./parser-sync');
exports.read = function(buffer, options) { exports.read = function(buffer, options) {
options = options || {}; var parser = new Parser(buffer, options || {});
var parser = new Parser(buffer, options);
if (parser.err) { if (parser.err) {
throw parser.err; throw parser.err;
} }
return { return {
data: parser.data, data: parser.data,
width: parser._width, width: parser._width,
height: parser._height, height: parser._height,
gamma: parser.gamma || 0 gamma: parser.gamma || 0
}; };
}; };

View file

@ -21,47 +21,47 @@
'use strict'; 'use strict';
var util = require('util'), var util = require('util');
Stream = require('stream'), var Stream = require('stream');
Parser = require('./parser-async'), var Parser = require('./parser-async');
Packer = require('./packer'), var Packer = require('./packer');
PNGSync = require('./png-sync'); var PNGSync = require('./png-sync');
var PNG = exports.PNG = function(options) { var PNG = exports.PNG = function(options) {
Stream.call(this); Stream.call(this);
options = options || {}; options = options || {}; // eslint-disable-line no-param-reassign
this.width = options.width || 0; this.width = options.width || 0;
this.height = options.height || 0; this.height = options.height || 0;
this.data = this.width > 0 && this.height > 0 this.data = this.width > 0 && this.height > 0
? new Buffer(4 * this.width * this.height) : null; ? new Buffer(4 * this.width * this.height) : null;
if(options.fill && this.data){ if (options.fill && this.data) {
this.data.fill(0); this.data.fill(0);
} }
this.gamma = 0; this.gamma = 0;
this.readable = this.writable = true; this.readable = this.writable = true;
this._parser = new Parser(options || {}); this._parser = new Parser(options || {});
this._parser.on('error', this.emit.bind(this, 'error')); this._parser.on('error', this.emit.bind(this, 'error'));
this._parser.on('close', this._handleClose.bind(this)); this._parser.on('close', this._handleClose.bind(this));
this._parser.on('metadata', this._metadata.bind(this)); this._parser.on('metadata', this._metadata.bind(this));
this._parser.on('gamma', this._gamma.bind(this)); this._parser.on('gamma', this._gamma.bind(this));
this._parser.on('parsed', function(data) { this._parser.on('parsed', function(data) {
this.data = data; this.data = data;
this.emit('parsed', data); this.emit('parsed', data);
}.bind(this)); }.bind(this));
this._packer = new Packer(options); this._packer = new Packer(options);
this._packer.on('data', this.emit.bind(this, 'data')); this._packer.on('data', this.emit.bind(this, 'data'));
this._packer.on('end', this.emit.bind(this, 'end')); this._packer.on('end', this.emit.bind(this, 'end'));
this._parser.on('close', this._handleClose.bind(this)); this._parser.on('close', this._handleClose.bind(this));
this._packer.on('error', this.emit.bind(this, 'error')); this._packer.on('error', this.emit.bind(this, 'error'));
}; };
util.inherits(PNG, Stream); util.inherits(PNG, Stream);
@ -70,103 +70,110 @@ PNG.sync = PNGSync;
PNG.prototype.pack = function() { PNG.prototype.pack = function() {
process.nextTick(function() { process.nextTick(function() {
this._packer.pack(this.data, this.width, this.height); this._packer.pack(this.data, this.width, this.height);
}.bind(this)); }.bind(this));
return this; return this;
}; };
PNG.prototype.parse = function(data, callback) { PNG.prototype.parse = function(data, callback) {
if (callback) { if (callback) {
var onParsed = null, onError = null; var onParsed, onError;
this.once('parsed', onParsed = function(parsedData) { onParsed = function(parsedData) {
this.removeListener('error', onError); this.removeListener('error', onError);
this.data = parsedData; this.data = parsedData;
callback(null, this); callback(null, this);
}.bind(this);
}.bind(this)); onError = function(err) {
this.removeListener('parsed', onParsed);
this.once('error', onError = function(err) { callback(err, null);
this.removeListener('parsed', onParsed); }.bind(this);
callback(err, null); this.once('parsed', onParsed);
}.bind(this)); this.once('error', onError);
} }
this.end(data); this.end(data);
return this; return this;
}; };
PNG.prototype.write = function(data) { PNG.prototype.write = function(data) {
this._parser.write(data); this._parser.write(data);
return true; return true;
}; };
PNG.prototype.end = function(data) { PNG.prototype.end = function(data) {
this._parser.end(data); this._parser.end(data);
}; };
PNG.prototype._metadata = function(metadata) { PNG.prototype._metadata = function(metadata) {
this.width = metadata.width; this.width = metadata.width;
this.height = metadata.height; this.height = metadata.height;
this.emit('metadata', metadata); this.emit('metadata', metadata);
}; };
PNG.prototype._gamma = function(gamma) { PNG.prototype._gamma = function(gamma) {
this.gamma = gamma; this.gamma = gamma;
}; };
PNG.prototype._handleClose = function() { PNG.prototype._handleClose = function() {
if (!this._parser.writable && !this._packer.readable) if (!this._parser.writable && !this._packer.readable) {
this.emit('close'); this.emit('close');
}; }
PNG.bitblt = function(src, dst, sx, sy, w, h, dx, dy) {
if (sx > src.width || sy > src.height
|| sx + w > src.width || sy + h > src.height)
throw new Error('bitblt reading outside image');
if (dx > dst.width || dy > dst.height
|| dx + w > dst.width || dy + h > dst.height)
throw new Error('bitblt writing outside image');
for (var y = 0; y < h; y++) {
src.data.copy(dst.data,
((dy + y) * dst.width + dx) << 2,
((sy + y) * src.width + sx) << 2,
((sy + y) * src.width + sx + w) << 2
);
}
}; };
PNG.prototype.bitblt = function(dst, sx, sy, w, h, dx, dy) { PNG.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) { // eslint-disable-line max-params
PNG.bitblt(this, dst, sx, sy, w, h, dx, dy); if (srcX > src.width || srcY > src.height || srcX + width > src.width || srcY + height > src.height) {
return this; throw new Error('bitblt reading outside image');
}
if (deltaX > dst.width || deltaY > dst.height || deltaX + width > dst.width || deltaY + height > dst.height) {
throw new Error('bitblt writing outside image');
}
for (var y = 0; y < height; y++) {
src.data.copy(dst.data,
((deltaY + y) * dst.width + deltaX) << 2,
((srcY + y) * src.width + srcX) << 2,
((srcY + y) * src.width + srcX + width) << 2
);
}
};
PNG.prototype.bitblt = function(src, dst, srcX, srcY, width, height, deltaX, deltaY) { // eslint-disable-line max-params
PNG.bitblt(this, dst, srcX, srcY, width, height, deltaX, deltaY);
return this;
}; };
PNG.adjustGamma = function(src) { PNG.adjustGamma = function(src) {
if (src.gamma) { if (src.gamma) {
for (var y = 0; y < src.height; y++) { for (var y = 0; y < src.height; y++) {
for (var x = 0; x < src.width; x++) { for (var x = 0; x < src.width; x++) {
var idx = (src.width * y + x) << 2; var idx = (src.width * y + x) << 2;
for (var i = 0; i < 3; i++) { for (var i = 0; i < 3; i++) {
var sample = src.data[idx + i] / 255; var sample = src.data[idx + i] / 255;
sample = Math.pow(sample, 1 / 2.2 / src.gamma); sample = Math.pow(sample, 1 / 2.2 / src.gamma);
src.data[idx + i] = Math.round(sample * 255); src.data[idx + i] = Math.round(sample * 255);
}
}
} }
src.gamma = 0; }
} }
src.gamma = 0;
}
}; };
PNG.prototype.adjustGamma = function() { PNG.adjustGamma(this); }; PNG.prototype.adjustGamma = function() {
PNG.adjustGamma(this);
};

View file

@ -20,13 +20,13 @@
'use strict'; 'use strict';
var SyncReader = module.exports = function (buffer) { var SyncReader = module.exports = function(buffer) {
this._buffer = buffer; this._buffer = buffer;
this._reads = []; this._reads = [];
}; };
SyncReader.prototype.read = function (length, callback) { SyncReader.prototype.read = function(length, callback) {
this._reads.push({ this._reads.push({
length: Math.abs(length), // if length < 0 then at most this length length: Math.abs(length), // if length < 0 then at most this length
@ -35,7 +35,7 @@ SyncReader.prototype.read = function (length, callback) {
}); });
}; };
SyncReader.prototype.process = function () { SyncReader.prototype.process = function() {
// as long as there is any data and read requests // as long as there is any data and read requests
while (this._reads.length > 0 && this._buffer.length) { while (this._reads.length > 0 && this._buffer.length) {
@ -54,13 +54,13 @@ SyncReader.prototype.process = function () {
read.func.call(this, buf.slice(0, read.length)); read.func.call(this, buf.slice(0, read.length));
} else { } else {
break; break;
} }
} }
if (this._reads.length > 0) { if (this._reads.length > 0) {
return new Error('There are some read requests waitng on finished stream'); return new Error('There are some read requests waitng on finished stream');
} }
if (this._buffer.length > 0) { if (this._buffer.length > 0) {