@duetds/date-picker
Version:
Duet Date Picker is an open source version of Duet Design System’s accessible date picker.
1,924 lines (1,558 loc) • 465 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.png = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (Buffer){
'use strict';
var interlaceUtils = require('./interlace');
var pixelBppMapper = [
// 0 - dummy entry
function() {},
// 1 - L
// 0: 0, 1: 0, 2: 0, 3: 0xff
function(pxData, data, pxPos, rawPos) {
if (rawPos === data.length) {
throw new Error('Ran out of data');
}
var pixel = data[rawPos];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = 0xff;
},
// 2 - LA
// 0: 0, 1: 0, 2: 0, 3: 1
function(pxData, data, pxPos, rawPos) {
if (rawPos + 1 >= data.length) {
throw new Error('Ran out of data');
}
var pixel = data[rawPos];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = data[rawPos + 1];
},
// 3 - RGB
// 0: 0, 1: 1, 2: 2, 3: 0xff
function(pxData, data, pxPos, rawPos) {
if (rawPos + 2 >= data.length) {
throw new Error('Ran out of data');
}
pxData[pxPos] = data[rawPos];
pxData[pxPos + 1] = data[rawPos + 1];
pxData[pxPos + 2] = data[rawPos + 2];
pxData[pxPos + 3] = 0xff;
},
// 4 - RGBA
// 0: 0, 1: 1, 2: 2, 3: 3
function(pxData, data, pxPos, rawPos) {
if (rawPos + 3 >= data.length) {
throw new Error('Ran out of data');
}
pxData[pxPos] = data[rawPos];
pxData[pxPos + 1] = data[rawPos + 1];
pxData[pxPos + 2] = data[rawPos + 2];
pxData[pxPos + 3] = data[rawPos + 3];
}
];
var pixelBppCustomMapper = [
// 0 - dummy entry
function() {},
// 1 - L
// 0: 0, 1: 0, 2: 0, 3: 0xff
function(pxData, pixelData, pxPos, maxBit) {
var pixel = pixelData[0];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = maxBit;
},
// 2 - LA
// 0: 0, 1: 0, 2: 0, 3: 1
function(pxData, pixelData, pxPos) {
var pixel = pixelData[0];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = pixelData[1];
},
// 3 - RGB
// 0: 0, 1: 1, 2: 2, 3: 0xff
function(pxData, pixelData, pxPos, maxBit) {
pxData[pxPos] = pixelData[0];
pxData[pxPos + 1] = pixelData[1];
pxData[pxPos + 2] = pixelData[2];
pxData[pxPos + 3] = maxBit;
},
// 4 - RGBA
// 0: 0, 1: 1, 2: 2, 3: 3
function(pxData, pixelData, pxPos) {
pxData[pxPos] = pixelData[0];
pxData[pxPos + 1] = pixelData[1];
pxData[pxPos + 2] = pixelData[2];
pxData[pxPos + 3] = pixelData[3];
}
];
function bitRetriever(data, depth) {
var leftOver = [];
var i = 0;
function split() {
if (i === data.length) {
throw new Error('Ran out of data');
}
var byte = data[i];
i++;
var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1;
switch (depth) {
default:
throw new Error('unrecognised depth');
case 16:
byte2 = data[i];
i++;
leftOver.push(((byte << 8) + byte2));
break;
case 4:
byte2 = byte & 0x0f;
byte1 = byte >> 4;
leftOver.push(byte1, byte2);
break;
case 2:
byte4 = byte & 3;
byte3 = byte >> 2 & 3;
byte2 = byte >> 4 & 3;
byte1 = byte >> 6 & 3;
leftOver.push(byte1, byte2, byte3, byte4);
break;
case 1:
byte8 = byte & 1;
byte7 = byte >> 1 & 1;
byte6 = byte >> 2 & 1;
byte5 = byte >> 3 & 1;
byte4 = byte >> 4 & 1;
byte3 = byte >> 5 & 1;
byte2 = byte >> 6 & 1;
byte1 = byte >> 7 & 1;
leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
break;
}
}
return {
get: function(count) {
while (leftOver.length < count) {
split();
}
var returner = leftOver.slice(0, count);
leftOver = leftOver.slice(count);
return returner;
},
resetAfterLine: function() {
leftOver.length = 0;
},
end: function() {
if (i !== data.length) {
throw new Error('extra data found');
}
}
};
}
function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-disable-line max-params
var imageWidth = image.width;
var imageHeight = image.height;
var imagePass = image.index;
for (var y = 0; y < imageHeight; y++) {
for (var x = 0; x < imageWidth; x++) {
var pxPos = getPxPos(x, y, imagePass);
pixelBppMapper[bpp](pxData, data, pxPos, rawPos);
rawPos += bpp; //eslint-disable-line no-param-reassign
}
}
return rawPos;
}
function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { // eslint-disable-line max-params
var imageWidth = image.width;
var imageHeight = image.height;
var imagePass = image.index;
for (var y = 0; y < imageHeight; y++) {
for (var x = 0; x < imageWidth; x++) {
var pixelData = bits.get(bpp);
var pxPos = getPxPos(x, y, imagePass);
pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit);
}
bits.resetAfterLine();
}
}
exports.dataToBitMap = function(data, bitmapInfo) {
var width = bitmapInfo.width;
var height = bitmapInfo.height;
var depth = bitmapInfo.depth;
var bpp = bitmapInfo.bpp;
var interlace = bitmapInfo.interlace;
if (depth !== 8) {
var bits = bitRetriever(data, depth);
}
var pxData;
if (depth <= 8) {
pxData = new Buffer(width * height * 4);
}
else {
pxData = new Uint16Array(width * height * 4);
}
var maxBit = Math.pow(2, depth) - 1;
var rawPos = 0;
var images;
var getPxPos;
if (interlace) {
images = interlaceUtils.getImagePasses(width, height);
getPxPos = interlaceUtils.getInterlaceIterator(width, height);
}
else {
var nonInterlacedPxPos = 0;
getPxPos = function() {
var returner = nonInterlacedPxPos;
nonInterlacedPxPos += 4;
return returner;
};
images = [{ width: width, height: height }];
}
for (var imageIndex = 0; imageIndex < images.length; imageIndex++) {
if (depth === 8) {
rawPos = mapImage8Bit(images[imageIndex], pxData, getPxPos, bpp, data, rawPos);
}
else {
mapImageCustomBit(images[imageIndex], pxData, getPxPos, bpp, bits, maxBit);
}
}
if (depth === 8) {
if (rawPos !== data.length) {
throw new Error('extra data found');
}
}
else {
bits.end();
}
return pxData;
};
}).call(this,require("buffer").Buffer)
},{"./interlace":11,"buffer":32}],2:[function(require,module,exports){
(function (Buffer){
'use strict';
var constants = require('./constants');
module.exports = function(dataIn, width, height, options) {
var outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(options.colorType) !== -1;
if (options.colorType === options.inputColorType) {
var bigEndian = (function() {
var buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] !== 256;
})();
// If no need to convert to grayscale and alpha is present/absent in both, take a fast route
if (options.bitDepth === 8 || (options.bitDepth === 16 && bigEndian)) {
return dataIn;
}
}
// map to a UInt16 array if data is 16bit, fix endianness below
var data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer);
var maxValue = 255;
var inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType];
if (inBpp === 4 && !options.inputHasAlpha) {
inBpp = 3;
}
var outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType];
if (options.bitDepth === 16) {
maxValue = 65535;
outBpp *= 2;
}
var outData = new Buffer(width * height * outBpp);
var inIndex = 0;
var outIndex = 0;
var bgColor = options.bgColor || {};
if (bgColor.red === undefined) {
bgColor.red = maxValue;
}
if (bgColor.green === undefined) {
bgColor.green = maxValue;
}
if (bgColor.blue === undefined) {
bgColor.blue = maxValue;
}
function getRGBA() {
var red;
var green;
var blue;
var alpha = maxValue;
switch (options.inputColorType) {
case constants.COLORTYPE_COLOR_ALPHA:
alpha = data[inIndex + 3];
red = data[inIndex];
green = data[inIndex + 1];
blue = data[inIndex + 2];
break;
case constants.COLORTYPE_COLOR:
red = data[inIndex];
green = data[inIndex + 1];
blue = data[inIndex + 2];
break;
case constants.COLORTYPE_ALPHA:
alpha = data[inIndex + 1];
red = data[inIndex];
green = red;
blue = red;
break;
case constants.COLORTYPE_GRAYSCALE:
red = data[inIndex];
green = red;
blue = red;
break;
default:
throw new Error('input color type:' + options.inputColorType + ' is not supported at present');
}
if (options.inputHasAlpha) {
if (!outHasAlpha) {
alpha /= maxValue;
red = Math.min(Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0), maxValue);
green = Math.min(Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0), maxValue);
blue = Math.min(Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0), maxValue);
}
}
return { red: red, green: green, blue: blue, alpha: alpha };
}
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var rgba = getRGBA(data, inIndex);
switch (options.colorType) {
case constants.COLORTYPE_COLOR_ALPHA:
case constants.COLORTYPE_COLOR:
if (options.bitDepth === 8) {
outData[outIndex] = rgba.red;
outData[outIndex + 1] = rgba.green;
outData[outIndex + 2] = rgba.blue;
if (outHasAlpha) {
outData[outIndex + 3] = rgba.alpha;
}
}
else {
outData.writeUInt16BE(rgba.red, outIndex);
outData.writeUInt16BE(rgba.green, outIndex + 2);
outData.writeUInt16BE(rgba.blue, outIndex + 4);
if (outHasAlpha) {
outData.writeUInt16BE(rgba.alpha, outIndex + 6);
}
}
break;
case constants.COLORTYPE_ALPHA:
case constants.COLORTYPE_GRAYSCALE:
// Convert to grayscale and alpha
var grayscale = (rgba.red + rgba.green + rgba.blue) / 3;
if (options.bitDepth === 8) {
outData[outIndex] = grayscale;
if (outHasAlpha) {
outData[outIndex + 1] = rgba.alpha;
}
}
else {
outData.writeUInt16BE(grayscale, outIndex);
if (outHasAlpha) {
outData.writeUInt16BE(rgba.alpha, outIndex + 2);
}
}
break;
default:
throw new Error('unrecognised color Type ' + options.colorType);
}
inIndex += inBpp;
outIndex += outBpp;
}
}
return outData;
};
}).call(this,require("buffer").Buffer)
},{"./constants":4,"buffer":32}],3:[function(require,module,exports){
(function (process,Buffer){
'use strict';
var util = require('util');
var Stream = require('stream');
var ChunkStream = module.exports = function() {
Stream.call(this);
this._buffers = [];
this._buffered = 0;
this._reads = [];
this._paused = false;
this._encoding = 'utf8';
this.writable = true;
};
util.inherits(ChunkStream, Stream);
ChunkStream.prototype.read = function(length, callback) {
this._reads.push({
length: Math.abs(length), // if length < 0 then at most this length
allowLess: length < 0,
func: callback
});
process.nextTick(function() {
this._process();
// its paused and there is not enought data then ask for more
if (this._paused && this._reads.length > 0) {
this._paused = false;
this.emit('drain');
}
}.bind(this));
};
ChunkStream.prototype.write = function(data, encoding) {
if (!this.writable) {
this.emit('error', new Error('Stream not writable'));
return false;
}
var dataBuffer;
if (Buffer.isBuffer(data)) {
dataBuffer = data;
}
else {
dataBuffer = new Buffer(data, encoding || this._encoding);
}
this._buffers.push(dataBuffer);
this._buffered += dataBuffer.length;
this._process();
// ok if there are no more read requests
if (this._reads && this._reads.length === 0) {
this._paused = true;
}
return this.writable && !this._paused;
};
ChunkStream.prototype.end = function(data, encoding) {
if (data) {
this.write(data, encoding);
}
this.writable = false;
// already destroyed
if (!this._buffers) {
return;
}
// enqueue or handle end
if (this._buffers.length === 0) {
this._end();
}
else {
this._buffers.push(null);
this._process();
}
};
ChunkStream.prototype.destroySoon = ChunkStream.prototype.end;
ChunkStream.prototype._end = function() {
if (this._reads.length > 0) {
this.emit('error',
new Error('Unexpected end of input')
);
}
this.destroy();
};
ChunkStream.prototype.destroy = function() {
if (!this._buffers) {
return;
}
this.writable = false;
this._reads = null;
this._buffers = null;
this.emit('close');
};
ChunkStream.prototype._processReadAllowingLess = function(read) {
// ok there is any data so that we can satisfy this request
this._reads.shift(); // == read
// first we need to peek into first buffer
var smallerBuf = this._buffers[0];
// ok there is more data than we need
if (smallerBuf.length > read.length) {
this._buffered -= read.length;
this._buffers[0] = smallerBuf.slice(read.length);
read.func.call(this, smallerBuf.slice(0, read.length));
}
else {
// ok this is less than maximum length so use it all
this._buffered -= smallerBuf.length;
this._buffers.shift(); // == smallerBuf
read.func.call(this, smallerBuf);
}
};
ChunkStream.prototype._processRead = function(read) {
this._reads.shift(); // == read
var pos = 0;
var count = 0;
var data = new Buffer(read.length);
// create buffer for all data
while (pos < read.length) {
var buf = this._buffers[count++];
var 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._buffered -= read.length;
read.func.call(this, data);
};
ChunkStream.prototype._process = function() {
try {
// as long as there is any data and read requests
while (this._buffered > 0 && this._reads && this._reads.length > 0) {
var read = this._reads[0];
// read any data (but no more than length)
if (read.allowLess) {
this._processReadAllowingLess(read);
}
else if (this._buffered >= read.length) {
// ok we can meet some expectations
this._processRead(read);
}
else {
// not enought data to satisfy first request in queue
// so we need to wait for more
break;
}
}
if (this._buffers && !this.writable) {
this._end();
}
}
catch (ex) {
this.emit('error', ex);
}
};
}).call(this,require('_process'),require("buffer").Buffer)
},{"_process":51,"buffer":32,"stream":64,"util":69}],4:[function(require,module,exports){
'use strict';
module.exports = {
PNG_SIGNATURE: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
TYPE_IHDR: 0x49484452,
TYPE_IEND: 0x49454e44,
TYPE_IDAT: 0x49444154,
TYPE_PLTE: 0x504c5445,
TYPE_tRNS: 0x74524e53, // eslint-disable-line camelcase
TYPE_gAMA: 0x67414d41, // eslint-disable-line camelcase
// color-type bits
COLORTYPE_GRAYSCALE: 0,
COLORTYPE_PALETTE: 1,
COLORTYPE_COLOR: 2,
COLORTYPE_ALPHA: 4, // e.g. grayscale and alpha
// color-type combinations
COLORTYPE_PALETTE_COLOR: 3,
COLORTYPE_COLOR_ALPHA: 6,
COLORTYPE_TO_BPP_MAP: {
0: 1,
2: 3,
3: 1,
4: 2,
6: 4
},
GAMMA_DIVISION: 100000
};
},{}],5:[function(require,module,exports){
'use strict';
var crcTable = [];
(function() {
for (var i = 0; i < 256; i++) {
var currentCrc = i;
for (var j = 0; j < 8; j++) {
if (currentCrc & 1) {
currentCrc = 0xedb88320 ^ (currentCrc >>> 1);
}
else {
currentCrc = currentCrc >>> 1;
}
}
crcTable[i] = currentCrc;
}
}());
var CrcCalculator = module.exports = function() {
this._crc = -1;
};
CrcCalculator.prototype.write = function(data) {
for (var i = 0; i < data.length; i++) {
this._crc = crcTable[(this._crc ^ data[i]) & 0xff] ^ (this._crc >>> 8);
}
return true;
};
CrcCalculator.prototype.crc32 = function() {
return this._crc ^ -1;
};
CrcCalculator.crc32 = function(buf) {
var crc = -1;
for (var i = 0; i < buf.length; i++) {
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
}
return crc ^ -1;
};
},{}],6:[function(require,module,exports){
(function (Buffer){
'use strict';
var paethPredictor = require('./paeth-predictor');
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
for (var x = 0; x < byteWidth; x++) {
rawData[rawPos + x] = pxData[pxPos + x];
}
}
function filterSumNone(pxData, pxPos, byteWidth) {
var sum = 0;
var length = pxPos + byteWidth;
for (var i = pxPos; i < length; i++) {
sum += Math.abs(pxData[i]);
}
return sum;
}
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var val = pxData[pxPos + x] - left;
rawData[rawPos + x] = val;
}
}
function filterSumSub(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var val = pxData[pxPos + x] - left;
sum += Math.abs(val);
}
return sum;
}
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
for (var x = 0; x < byteWidth; x++) {
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - up;
rawData[rawPos + x] = val;
}
}
function filterSumUp(pxData, pxPos, byteWidth) {
var sum = 0;
var length = pxPos + byteWidth;
for (var x = pxPos; x < length; x++) {
var up = pxPos > 0 ? pxData[x - byteWidth] : 0;
var val = pxData[x] - up;
sum += Math.abs(val);
}
return sum;
}
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - ((left + up) >> 1);
rawData[rawPos + x] = val;
}
}
function filterSumAvg(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var val = pxData[pxPos + x] - ((left + up) >> 1);
sum += Math.abs(val);
}
return sum;
}
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
rawData[rawPos + x] = val;
}
}
function filterSumPaeth(pxData, pxPos, byteWidth, bpp) {
var sum = 0;
for (var x = 0; x < byteWidth; x++) {
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
var upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
sum += Math.abs(val);
}
return sum;
}
var filters = {
0: filterNone,
1: filterSub,
2: filterUp,
3: filterAvg,
4: filterPaeth
};
var filterSums = {
0: filterSumNone,
1: filterSumSub,
2: filterSumUp,
3: filterSumAvg,
4: filterSumPaeth
};
module.exports = function(pxData, width, height, options, bpp) {
var filterTypes;
if (!('filterType' in options) || options.filterType === -1) {
filterTypes = [0, 1, 2, 3, 4];
}
else if (typeof options.filterType === 'number') {
filterTypes = [options.filterType];
}
else {
throw new Error('unrecognised filter types');
}
if (options.bitDepth === 16) {
bpp *= 2;
}
var byteWidth = width * bpp;
var rawPos = 0;
var pxPos = 0;
var rawData = new Buffer((byteWidth + 1) * height);
var sel = filterTypes[0];
for (var y = 0; y < height; y++) {
if (filterTypes.length > 1) {
// find best filter for this line (with lowest sum of values)
var min = Infinity;
for (var i = 0; i < filterTypes.length; i++) {
var sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
if (sum < min) {
sel = filterTypes[i];
min = sum;
}
}
}
rawData[rawPos] = sel;
rawPos++;
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
rawPos += byteWidth;
pxPos += byteWidth;
}
return rawData;
};
}).call(this,require("buffer").Buffer)
},{"./paeth-predictor":15,"buffer":32}],7:[function(require,module,exports){
(function (Buffer){
'use strict';
var util = require('util');
var ChunkStream = require('./chunkstream');
var Filter = require('./filter-parse');
var FilterAsync = module.exports = function(bitmapInfo) {
ChunkStream.call(this);
var buffers = [];
var that = this;
this._filter = new Filter(bitmapInfo, {
read: this.read.bind(this),
write: function(buffer) {
buffers.push(buffer);
},
complete: function() {
that.emit('complete', Buffer.concat(buffers));
}
});
this._filter.start();
};
util.inherits(FilterAsync, ChunkStream);
}).call(this,require("buffer").Buffer)
},{"./chunkstream":3,"./filter-parse":9,"buffer":32,"util":69}],8:[function(require,module,exports){
(function (Buffer){
'use strict';
var SyncReader = require('./sync-reader');
var Filter = require('./filter-parse');
exports.process = function(inBuffer, bitmapInfo) {
var outBuffers = [];
var reader = new SyncReader(inBuffer);
var filter = new Filter(bitmapInfo, {
read: reader.read.bind(reader),
write: function(bufferPart) {
outBuffers.push(bufferPart);
},
complete: function() {
}
});
filter.start();
reader.process();
return Buffer.concat(outBuffers);
};
}).call(this,require("buffer").Buffer)
},{"./filter-parse":9,"./sync-reader":22,"buffer":32}],9:[function(require,module,exports){
(function (Buffer){
'use strict';
var interlaceUtils = require('./interlace');
var paethPredictor = require('./paeth-predictor');
function getByteWidth(width, bpp, depth) {
var byteWidth = width * bpp;
if (depth !== 8) {
byteWidth = Math.ceil(byteWidth / (8 / depth));
}
return byteWidth;
}
var Filter = module.exports = function(bitmapInfo, dependencies) {
var width = bitmapInfo.width;
var height = bitmapInfo.height;
var interlace = bitmapInfo.interlace;
var bpp = bitmapInfo.bpp;
var depth = bitmapInfo.depth;
this.read = dependencies.read;
this.write = dependencies.write;
this.complete = dependencies.complete;
this._imageIndex = 0;
this._images = [];
if (interlace) {
var passes = interlaceUtils.getImagePasses(width, height);
for (var i = 0; i < passes.length; i++) {
this._images.push({
byteWidth: getByteWidth(passes[i].width, bpp, depth),
height: passes[i].height,
lineIndex: 0
});
}
}
else {
this._images.push({
byteWidth: getByteWidth(width, bpp, depth),
height: height,
lineIndex: 0
});
}
// when filtering the line we look at the pixel to the left
// the spec also says it is done on a byte level regardless of the number of pixels
// so if the depth is byte compatible (8 or 16) we subtract the bpp in order to compare back
// a pixel rather than just a different byte part. However if we are sub byte, we ignore.
if (depth === 8) {
this._xComparison = bpp;
}
else if (depth === 16) {
this._xComparison = bpp * 2;
}
else {
this._xComparison = 1;
}
};
Filter.prototype.start = function() {
this.read(this._images[this._imageIndex].byteWidth + 1, this._reverseFilterLine.bind(this));
};
Filter.prototype._unFilterType1 = function(rawData, unfilteredLine, byteWidth) {
var xComparison = this._xComparison;
var xBiggerThan = xComparison - 1;
for (var x = 0; x < byteWidth; x++) {
var rawByte = rawData[1 + x];
var f1Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
unfilteredLine[x] = rawByte + f1Left;
}
};
Filter.prototype._unFilterType2 = function(rawData, unfilteredLine, byteWidth) {
var lastLine = this._lastLine;
for (var x = 0; x < byteWidth; x++) {
var rawByte = rawData[1 + x];
var f2Up = lastLine ? lastLine[x] : 0;
unfilteredLine[x] = rawByte + f2Up;
}
};
Filter.prototype._unFilterType3 = function(rawData, unfilteredLine, byteWidth) {
var xComparison = this._xComparison;
var xBiggerThan = xComparison - 1;
var lastLine = this._lastLine;
for (var x = 0; x < byteWidth; x++) {
var rawByte = rawData[1 + x];
var f3Up = lastLine ? lastLine[x] : 0;
var f3Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
var f3Add = Math.floor((f3Left + f3Up) / 2);
unfilteredLine[x] = rawByte + f3Add;
}
};
Filter.prototype._unFilterType4 = function(rawData, unfilteredLine, byteWidth) {
var xComparison = this._xComparison;
var xBiggerThan = xComparison - 1;
var lastLine = this._lastLine;
for (var x = 0; x < byteWidth; x++) {
var rawByte = rawData[1 + x];
var f4Up = lastLine ? lastLine[x] : 0;
var f4Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
var f4UpLeft = x > xBiggerThan && lastLine ? lastLine[x - xComparison] : 0;
var f4Add = paethPredictor(f4Left, f4Up, f4UpLeft);
unfilteredLine[x] = rawByte + f4Add;
}
};
Filter.prototype._reverseFilterLine = function(rawData) {
var filter = rawData[0];
var unfilteredLine;
var currentImage = this._images[this._imageIndex];
var byteWidth = currentImage.byteWidth;
if (filter === 0) {
unfilteredLine = rawData.slice(1, byteWidth + 1);
}
else {
unfilteredLine = new Buffer(byteWidth);
switch (filter) {
case 1:
this._unFilterType1(rawData, unfilteredLine, byteWidth);
break;
case 2:
this._unFilterType2(rawData, unfilteredLine, byteWidth);
break;
case 3:
this._unFilterType3(rawData, unfilteredLine, byteWidth);
break;
case 4:
this._unFilterType4(rawData, unfilteredLine, byteWidth);
break;
default:
throw new Error('Unrecognised filter type - ' + filter);
}
}
this.write(unfilteredLine);
currentImage.lineIndex++;
if (currentImage.lineIndex >= currentImage.height) {
this._lastLine = null;
this._imageIndex++;
currentImage = this._images[this._imageIndex];
}
else {
this._lastLine = unfilteredLine;
}
if (currentImage) {
// read, using the byte width that may be from the new current image
this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this));
}
else {
this._lastLine = null;
this.complete();
}
};
}).call(this,require("buffer").Buffer)
},{"./interlace":11,"./paeth-predictor":15,"buffer":32}],10:[function(require,module,exports){
(function (Buffer){
'use strict';
function dePalette(indata, outdata, width, height, palette) {
var pxPos = 0;
// use values from palette
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var color = palette[indata[pxPos]];
if (!color) {
throw new Error('index ' + indata[pxPos] + ' not in palette');
}
for (var i = 0; i < 4; i++) {
outdata[pxPos + i] = color[i];
}
pxPos += 4;
}
}
}
function replaceTransparentColor(indata, outdata, width, height, transColor) {
var pxPos = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var makeTrans = false;
if (transColor.length === 1) {
if (transColor[0] === indata[pxPos]) {
makeTrans = true;
}
}
else if (transColor[0] === indata[pxPos] && transColor[1] === indata[pxPos + 1] && transColor[2] === indata[pxPos + 2]) {
makeTrans = true;
}
if (makeTrans) {
for (var i = 0; i < 4; i++) {
outdata[pxPos + i] = 0;
}
}
pxPos += 4;
}
}
}
function scaleDepth(indata, outdata, width, height, depth) {
var maxOutSample = 255;
var maxInSample = Math.pow(2, depth) - 1;
var pxPos = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
for (var i = 0; i < 4; i++) {
outdata[pxPos + i] = Math.floor((indata[pxPos + i] * maxOutSample) / maxInSample + 0.5);
}
pxPos += 4;
}
}
}
module.exports = function(indata, imageData) {
var depth = imageData.depth;
var width = imageData.width;
var height = imageData.height;
var colorType = imageData.colorType;
var transColor = imageData.transColor;
var palette = imageData.palette;
var outdata = indata; // only different for 16 bits
if (colorType === 3) { // paletted
dePalette(indata, outdata, width, height, palette);
}
else {
if (transColor) {
replaceTransparentColor(indata, outdata, width, height, transColor);
}
// if it needs scaling
if (depth !== 8) {
// if we need to change the buffer size
if (depth === 16) {
outdata = new Buffer(width * height * 4);
}
scaleDepth(indata, outdata, width, height, depth);
}
}
return outdata;
};
}).call(this,require("buffer").Buffer)
},{"buffer":32}],11:[function(require,module,exports){
'use strict';
// Adam 7
// 0 1 2 3 4 5 6 7
// 0 x 6 4 6 x 6 4 6
// 1 7 7 7 7 7 7 7 7
// 2 5 6 5 6 5 6 5 6
// 3 7 7 7 7 7 7 7 7
// 4 3 6 4 6 3 6 4 6
// 5 7 7 7 7 7 7 7 7
// 6 5 6 5 6 5 6 5 6
// 7 7 7 7 7 7 7 7 7
var imagePasses = [
{ // pass 1 - 1px
x: [0],
y: [0]
},
{ // pass 2 - 1px
x: [4],
y: [0]
},
{ // pass 3 - 2px
x: [0, 4],
y: [4]
},
{ // pass 4 - 4px
x: [2, 6],
y: [0, 4]
},
{ // pass 5 - 8px
x: [0, 2, 4, 6],
y: [2, 6]
},
{ // pass 6 - 16px
x: [1, 3, 5, 7],
y: [0, 2, 4, 6]
},
{ // pass 7 - 32px
x: [0, 1, 2, 3, 4, 5, 6, 7],
y: [1, 3, 5, 7]
}
];
exports.getImagePasses = function(width, height) {
var images = [];
var xLeftOver = width % 8;
var yLeftOver = height % 8;
var xRepeats = (width - xLeftOver) / 8;
var yRepeats = (height - yLeftOver) / 8;
for (var i = 0; i < imagePasses.length; i++) {
var pass = imagePasses[i];
var passWidth = xRepeats * pass.x.length;
var passHeight = yRepeats * pass.y.length;
for (var j = 0; j < pass.x.length; j++) {
if (pass.x[j] < xLeftOver) {
passWidth++;
}
else {
break;
}
}
for (j = 0; j < pass.y.length; j++) {
if (pass.y[j] < yLeftOver) {
passHeight++;
}
else {
break;
}
}
if (passWidth > 0 && passHeight > 0) {
images.push({ width: passWidth, height: passHeight, index: i });
}
}
return images;
};
exports.getInterlaceIterator = function(width) {
return function(x, y, pass) {
var outerXLeftOver = x % imagePasses[pass].x.length;
var outerX = (((x - outerXLeftOver) / imagePasses[pass].x.length) * 8) + imagePasses[pass].x[outerXLeftOver];
var outerYLeftOver = y % imagePasses[pass].y.length;
var outerY = (((y - outerYLeftOver) / imagePasses[pass].y.length) * 8) + imagePasses[pass].y[outerYLeftOver];
return (outerX * 4) + (outerY * width * 4);
};
};
},{}],12:[function(require,module,exports){
(function (Buffer){
'use strict';
var util = require('util');
var Stream = require('stream');
var constants = require('./constants');
var Packer = require('./packer');
var PackerAsync = module.exports = function(opt) {
Stream.call(this);
var options = opt || {};
this._packer = new Packer(options);
this._deflate = this._packer.createDeflate();
this.readable = true;
};
util.inherits(PackerAsync, Stream);
PackerAsync.prototype.pack = function(data, width, height, gamma) {
// Signature
this.emit('data', new Buffer(constants.PNG_SIGNATURE));
this.emit('data', this._packer.packIHDR(width, height));
if (gamma) {
this.emit('data', this._packer.packGAMA(gamma));
}
var filteredData = this._packer.filterData(data, width, height);
// compress it
this._deflate.on('error', this.emit.bind(this, 'error'));
this._deflate.on('data', function(compressedData) {
this.emit('data', this._packer.packIDAT(compressedData));
}.bind(this));
this._deflate.on('end', function() {
this.emit('data', this._packer.packIEND());
this.emit('end');
}.bind(this));
this._deflate.end(filteredData);
};
}).call(this,require("buffer").Buffer)
},{"./constants":4,"./packer":14,"buffer":32,"stream":64,"util":69}],13:[function(require,module,exports){
(function (Buffer){
'use strict';
var hasSyncZlib = true;
var zlib = require('zlib');
if (!zlib.deflateSync) {
hasSyncZlib = false;
}
var constants = require('./constants');
var Packer = require('./packer');
module.exports = function(metaData, opt) {
if (!hasSyncZlib) {
throw new Error('To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0');
}
var options = opt || {};
var packer = new Packer(options);
var chunks = [];
// Signature
chunks.push(new Buffer(constants.PNG_SIGNATURE));
// Header
chunks.push(packer.packIHDR(metaData.width, metaData.height));
if (metaData.gamma) {
chunks.push(packer.packGAMA(metaData.gamma));
}
var filteredData = packer.filterData(metaData.data, metaData.width, metaData.height);
// compress it
var compressedData = zlib.deflateSync(filteredData, packer.getDeflateOptions());
filteredData = null;
if (!compressedData || !compressedData.length) {
throw new Error('bad png - invalid compressed data response');
}
chunks.push(packer.packIDAT(compressedData));
// End
chunks.push(packer.packIEND());
return Buffer.concat(chunks);
};
}).call(this,require("buffer").Buffer)
},{"./constants":4,"./packer":14,"buffer":32,"zlib":30}],14:[function(require,module,exports){
(function (Buffer){
'use strict';
var constants = require('./constants');
var CrcStream = require('./crc');
var bitPacker = require('./bitpacker');
var filter = require('./filter-pack');
var zlib = require('zlib');
var Packer = module.exports = function(options) {
this._options = options;
options.deflateChunkSize = options.deflateChunkSize || 32 * 1024;
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
options.inputHasAlpha = options.inputHasAlpha != null ? options.inputHasAlpha : true;
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
options.bitDepth = options.bitDepth || 8;
// This is outputColorType
options.colorType = (typeof options.colorType === 'number') ? options.colorType : constants.COLORTYPE_COLOR_ALPHA;
options.inputColorType = (typeof options.inputColorType === 'number') ? options.inputColorType : constants.COLORTYPE_COLOR_ALPHA;
if ([
constants.COLORTYPE_GRAYSCALE,
constants.COLORTYPE_COLOR,
constants.COLORTYPE_COLOR_ALPHA,
constants.COLORTYPE_ALPHA
].indexOf(options.colorType) === -1) {
throw new Error('option color type:' + options.colorType + ' is not supported at present');
}
if ([
constants.COLORTYPE_GRAYSCALE,
constants.COLORTYPE_COLOR,
constants.COLORTYPE_COLOR_ALPHA,
constants.COLORTYPE_ALPHA
].indexOf(options.inputColorType) === -1) {
throw new Error('option input color type:' + options.inputColorType + ' is not supported at present');
}
if (options.bitDepth !== 8 && options.bitDepth !== 16) {
throw new Error('option bit depth:' + options.bitDepth + ' is not supported at present');
}
};
Packer.prototype.getDeflateOptions = function() {
return {
chunkSize: this._options.deflateChunkSize,
level: this._options.deflateLevel,
strategy: this._options.deflateStrategy
};
};
Packer.prototype.createDeflate = function() {
return this._options.deflateFactory(this.getDeflateOptions());
};
Packer.prototype.filterData = function(data, width, height) {
// convert to correct format for filtering (e.g. right bpp and bit depth)
var packedData = bitPacker(data, width, height, this._options);
// filter pixel data
var bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType];
var filteredData = filter(packedData, width, height, this._options, bpp);
return filteredData;
};
Packer.prototype._packChunk = function(type, data) {
var len = (data ? data.length : 0);
var buf = new Buffer(len + 12);
buf.writeUInt32BE(len, 0);
buf.writeUInt32BE(type, 4);
if (data) {
data.copy(buf, 8);
}
buf.writeInt32BE(CrcStream.crc32(buf.slice(4, buf.length - 4)), buf.length - 4);
return buf;
};
Packer.prototype.packGAMA = function(gamma) {
var buf = new Buffer(4);
buf.writeUInt32BE(Math.floor(gamma * constants.GAMMA_DIVISION), 0);
return this._packChunk(constants.TYPE_gAMA, buf);
};
Packer.prototype.packIHDR = function(width, height) {
var buf = new Buffer(13);
buf.writeUInt32BE(width, 0);
buf.writeUInt32BE(height, 4);
buf[8] = this._options.bitDepth; // Bit depth
buf[9] = this._options.colorType; // colorType
buf[10] = 0; // compression
buf[11] = 0; // filter
buf[12] = 0; // interlace
return this._packChunk(constants.TYPE_IHDR, buf);
};
Packer.prototype.packIDAT = function(data) {
return this._packChunk(constants.TYPE_IDAT, data);
};
Packer.prototype.packIEND = function() {
return this._packChunk(constants.TYPE_IEND, null);
};
}).call(this,require("buffer").Buffer)
},{"./bitpacker":2,"./constants":4,"./crc":5,"./filter-pack":6,"buffer":32,"zlib":30}],15:[function(require,module,exports){
'use strict';
module.exports = function paethPredictor(left, above, upLeft) {
var paeth = left + above - upLeft;
var pLeft = Math.abs(paeth - left);
var pAbove = Math.abs(paeth - above);
var pUpLeft = Math.abs(paeth - upLeft);
if (pLeft <= pAbove && pLeft <= pUpLeft) {
return left;
}
if (pAbove <= pUpLeft) {
return above;
}
return upLeft;
};
},{}],16:[function(require,module,exports){
'use strict';
var util = require('util');
var zlib = require('zlib');
var ChunkStream = require('./chunkstream');
var FilterAsync = require('./filter-parse-async');
var Parser = require('./parser');
var bitmapper = require('./bitmapper');
var formatNormaliser = require('./format-normaliser');
var ParserAsync = module.exports = function(options) {
ChunkStream.call(this);
this._parser = new Parser(options, {
read: this.read.bind(this),
error: this._handleError.bind(this),
metadata: this._handleMetaData.bind(this),
gamma: this.emit.bind(this, 'gamma'),
palette: this._handlePalette.bind(this),
transColor: this._handleTransColor.bind(this),
finished: this._finished.bind(this),
inflateData: this._inflateData.bind(this),
simpleTransparency: this._simpleTransparency.bind(this),
headersFinished: this._headersFinished.bind(this)
});
this._options = options;
this.writable = true;
this._parser.start();
};
util.inherits(ParserAsync, ChunkStream);
ParserAsync.prototype._handleError = function(err) {
this.emit('error', err);
this.writable = false;
this.destroy();
if (this._inflate && this._inflate.destroy) {
this._inflate.destroy();
}
if (this._filter) {
this._filter.destroy();
// For backward compatibility with Node 7 and below.
// Suppress errors due to _inflate calling write() even after
// it's destroy()'ed.
this._filter.on('error', function() {});
}
this.errord = true;
};
ParserAsync.prototype._inflateData = function(data) {
if (!this._inflate) {
if (this._bitmapInfo.interlace) {
this._inflate = zlib.createInflate();
this._inflate.on('error', this.emit.bind(this, 'error'));
this._filter.on('complete', this._complete.bind(this));
this._inflate.pipe(this._filter);
}
else {
var rowSize = ((this._bitmapInfo.width * this._bitmapInfo.bpp * this._bitmapInfo.depth + 7) >> 3) + 1;
var imageSize = rowSize * this._bitmapInfo.height;
var chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK);
this._inflate = zlib.createInflate({ chunkSize: chunkSize });
var leftToInflate = imageSize;
var emitError = this.emit.bind(this, 'error');
this._inflate.on('error', function(err) {
if (!leftToInflate) {
return;
}
emitError(err);
});
this._filter.on('complete', this._complete.bind(this));
var filterWrite = this._filter.write.bind(this._filter);
this._inflate.on('data', function(chunk) {
if (!leftToInflate) {
return;
}
if (chunk.length > leftToInflate) {
chunk = chunk.slice(0, leftToInflate);
}
leftToInflate -= chunk.length;
filterWrite(chunk);
});
this._inflate.on('end', this._filter.end.bind(this._filter));
}
}
this._inflate.write(data);
};
ParserAsync.prototype._handleMetaData = function(metaData) {
this._metaData = metaData;
this._bitmapInfo = Object.create(metaData);
this._filter = new FilterAsync(this._bitmapInfo);
};
ParserAsync.prototype._handleTransColor = function(transColor) {
this._bitmapInfo.transColor = transColor;
};
ParserAsync.prototype._handlePalette = function(palette) {
this._bitmapInfo.palette = palette;
};
ParserAsync.prototype._simpleTransparency = function() {
this._metaData.alpha = true;
};
ParserAsync.prototype._headersFinished = function() {
// Up until this point, we don't know if we have a tRNS chunk (alpha)
// so we can't emit metadata any earlier
this.emit('metadata', this._metaData);
};
ParserAsync.prototype._finished = function() {
if (this.errord) {
return;
}
if (!this._inflate) {
this.emit('error', 'No Inflate block');
}
else {
// no more data to inflate
this._inflate.end();
}
this.destroySoon();
};
ParserAsync.prototype._complete = function(filteredData) {
if (this.errord) {
return;
}
try {
var bitmapData = bitmapper.dataToBitMap(filteredData, this._bitmapInfo);
var normalisedBitmapData = formatNormaliser(bitmapData, this._bitmapInfo);
bitmapData = null;
}
catch (ex) {
this._handleError(ex);
return;
}
this.emit('parsed', normalisedBitmapData);
};
},{"./bitmapper":1,"./chunkstream":3,"./filter-parse-async":7,"./format-normaliser":10,"./parser":18,"util":69,"zlib":30}],17:[function(require,module,exports){
(function (Buffer){
'use strict';
var hasSyncZlib = true;
var zlib = require('zlib');
var inflateSync = require('./sync-inflate');
if (!zlib.deflateSync) {
hasSyncZlib = false;
}
var SyncReader = require('./sync-reader');
var FilterSync = require('./filter-parse-sync');
var Parser = require('./parser');
var bitmapper = require('./bitmapper');
var formatNormaliser = require('./format-normaliser');
module.exports = function(buffer, options) {
if (!hasSyncZlib) {
throw new Error('To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0');
}
var err;
function handleError(_err_) {
err = _err_;
}
var metaData;
function handleMetaData(_metaData_) {
metaData = _metaData_;
}
function handleTransColor(transColor) {
metaData.transColor = transColor;
}
function handlePalette(palette) {
metaData.palette = palette;
}
function handleSimpleTransparency() {
metaData.alpha = true;
}
var gamma;
function handleGamma(_gamma_) {
gamma = _gamma_;
}
var inflateDataList = [];
function handleInflateData(inflatedData) {
inflateDataList.push(inflatedData);
}
var reader = new SyncReader(buffer);
var parser = new Parser(options, {
read: reader.read.bind(reader),
error: handleError,
metadata: handleMetaData,
gamma: handleGamma,
palette: handlePalette,
transColor: handleTransColor,
inflateData: handleInflateData,
simpleTransparency: handleSimpleTransparency
});
parser.start();
reader.process();
if (err) {
throw err;
}
//join together the inflate datas
var inflateData = Buffer.concat(inflateDataList);
inflateDataList.length = 0;
var inflatedData;
if (metaData.interlace) {
inflatedData = zlib.inflateSync(inflateData);
}
else {
var rowSize = ((metaData.width * metaData.bpp * metaData.depth + 7) >> 3) + 1;
var imageSize = rowSize * metaData.height;
inflatedData = inflateSync(inflateData, { chunkSize: imageSize, maxLength: imageSize });
}
inflateData = null;
if (!inflatedData || !inflatedData.length) {
throw new Error('bad png - invalid inflate data response');
}
var unfilteredData = FilterSync.process(inflatedData, metaData);
inflateData = null;
var bitmapData = bitmapper.dataToBitMap(unfilteredData, metaData);
unfilteredData = null;
var normalisedBitmapData = formatNormaliser(bitmapData, metaData);
metaData.data = normalisedBitmapData;
metaData.gamma = gamma || 0;
return metaData;
};
}).call(this,require("buffer").Buffer)
},{"./bitmapper":1,"./filter-parse-sync":8,"./format-normaliser":10,"./parser":18,"./sync-inflate":21,"./sync-reader":22,"buffer":32,"zlib":30}],18:[function(require,module,exports){
(function (Buffer){
'use strict';
var constants = require('./constants');
var CrcCalculator = require('./crc');
var Parser = module.exports = function(options, dependencies) {
this._options = options;
options.checkCRC = options.checkCRC !== false;
this._hasIHDR = false;
this._hasIEND = false;
this._emittedHeadersFinished = false;
// input flags/metadata
this._palette = [];
this._colorType = 0;
this._chunks = {};
this._chunks[constants.TYPE_IHDR] = this._handleIHDR.bind(this);
this._chunks[constants.TYPE_IEND] = this._handleIEND.bind(this);
this._chunks[constants.TYPE_IDAT] = this._handleIDAT.bind(this);
this._chunks[constants.TYPE_PLTE] = this._handlePLTE.bind(this);
this._chunks[constants.TYPE_tRNS] = this._handleTRNS.bind(this);
this._chunks[constants.TYPE_gAMA] = this._handleGAMA.bind(this);
this.read = dependencies.read;
this.error = dependencies.error;
this.metadata = dependencies.metadata;
this.gamma = dependencies.gamma;
this.transColor = dependencies.transColor;
this.palette = dependencies.palette;
this.parsed = dependencies.parsed;
this.inflateData = dependencies.inflateData;
this.finished = dependencies.finished;
this.simpleTransparency = dependencies.simpleTransparency;
this.headersFinished = dependencies.headersFinished || function() {};
};
Parser.prototype.start = function() {
this.read(constants.PNG_SIGNATURE.length,
this._parseSignature.bind(this)
);
};
Parser.prototype._parseSignature = function(data) {
var signature = constants.PNG_SIGNATURE;
for (var i = 0; i < signature.length; i++) {
if (data[i] !== signature[i]) {
this.error(new Error('Invalid file signature'));
return;
}
}
this.read(8, this._parseChunkBegin.bind(this));
};
Parser.prototype._parseChunkBegin = function(data) {
// chunk content length
var length = data.readUInt32BE(0);
// chunk type
var type = data.readUInt32BE(4);
var name = '';
for (var i = 4; i < 8; i++) {
name += String.fromCharCode(data[i]);
}
//console.log('chunk ', name, length);
// chunk flags
var ancillary = Boolean(data[4] & 0x20); // or critical
// priv = Boolean(data[5] & 0x20), // or public
// safeToCopy = Boolean(data[7] & 0x20); // or unsafe
if (!this._hasIHDR && type !== constants.TYPE_IHDR) {
this.error(new Error('Expected IHDR on beggining'));
return;
}
this._crc = new CrcCalculator();
this._crc.write(new Buffer(name));
if (this._chunks[type]) {
return this._chunks[type](length);
}
if (!ancillary) {
this.error(new Error('Unsupported critical chunk type ' + name));
return;
}
this.read(length + 4, this._skipChunk.bind(this));
};
Parser.prototype._skipChunk = function(/*data*/) {
this.read(8, this._parseChunkBegin.bind(this));
};
Parser.prototype._handleChunkEnd = function() {
this.read(4, this._parseChunkEnd.bind(this));
};
Parser.prototype._parseChunkEnd = function(data) {
var