From 43a7c3dc4ebfc1f9d21546aec19dfa8fc13dd8db Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Wed, 22 Aug 2012 11:30:12 +0200 Subject: [PATCH] new experimental streams --- lib/compress.js | 94 --------- lib/constants.js | 38 ++++ lib/helpers.js | 45 ++++ lib/packer.js | 98 +++++++++ lib/parser.js | 516 ++++++++++++++++++++++------------------------ lib/readstream.js | 55 +++++ 6 files changed, 484 insertions(+), 362 deletions(-) delete mode 100644 lib/compress.js create mode 100644 lib/constants.js create mode 100644 lib/helpers.js create mode 100644 lib/packer.js create mode 100644 lib/readstream.js diff --git a/lib/compress.js b/lib/compress.js deleted file mode 100644 index f110de6..0000000 --- a/lib/compress.js +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2012 Kuba Niegowski -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -'use strict'; - -var util = require('util'), - zlib = require('zlib'), - events = require('events'); - - -var Compress = module.exports = function(options) { - events.EventEmitter.call(this); - - this._options = options; - options.deflateChunkSize = options.deflateChunkSize || 32 * 1024; - options.deflateLevel = options.deflateLevel || 9; - - this._inflate = null; -}; -util.inherits(Compress, events.EventEmitter); - - -Compress.prototype.prepareInflate = function(type) { - - if (type != 0) - throw new Error('Unsupported compression method'); - - this._inflate = zlib.createInflate(); - - bufferStream(this._inflate, function(data) { - this._inflate = null; - this.emit('inflated', data); - }.bind(this)); - - this._inflate.on('error', this.emit.bind(this, 'error')); -}; - -Compress.prototype.writeInflate = function(data) { - this._inflate.write(data); -}; - -Compress.prototype.endInflate = function() { - this._inflate.end(); -}; - -Compress.prototype.deflate = function(data) { - - var deflate = zlib.createDeflate({ - chunkSize: this._options.deflateChunkSize, - level: this._options.deflateLevel - }); - - bufferStream(deflate, function(data) { - this.emit('deflated', data); - }.bind(this)); - - deflate.on('error', this.emit.bind(this, 'error')); - - deflate.end(data); -}; - -function bufferStream(stream, callback) { - - var buffers = [], - length = 0; - - stream.on('data', function(data) { - buffers.push(data); - length += data.length; - }); - - stream.on('end', function() { - callback(Buffer.concat(buffers, length)); - }); - - return stream; -}; diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 0000000..1e74b79 --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,38 @@ +// Copyright (c) 2012 Kuba Niegowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +'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, + TYPE_gAMA: 0x67414d41, + + COLOR_PALETTE: 1, + COLOR_COLOR: 2, + COLOR_ALPHA: 4 +}; diff --git a/lib/helpers.js b/lib/helpers.js new file mode 100644 index 0000000..4634bf5 --- /dev/null +++ b/lib/helpers.js @@ -0,0 +1,45 @@ +// Copyright (c) 2012 Kuba Niegowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +'use strict'; + + +var crcTable = []; + +for (var i = 0; i < 256; i++) { + var c = i; + for (var j = 0; j < 8; j++) { + if (c & 1) { + c = 0xedb88320 ^ (c >>> 1); + } else { + c = c >>> 1; + } + } + crcTable[i] = c; +} + +exports.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; +}; diff --git a/lib/packer.js b/lib/packer.js new file mode 100644 index 0000000..9d39d5d --- /dev/null +++ b/lib/packer.js @@ -0,0 +1,98 @@ +// Copyright (c) 2012 Kuba Niegowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +'use strict'; + + +var util = require('util'), + Stream = require('stream'), + Compress = require('./compress'), + Filter = require('./filter'); + + +var Parser = module.exports = function(options) { + Stream.call(this); + + this._options = options; + + // this._compress = new Compress(options); + // this._compress.on('error', this.emit.bind(this, 'error')); + // this._compress.on('deflated', this._packData.bind(this)); +}; +util.inherits(Parser, Stream); + + +Parser.prototype._pack = function(width, height, data) { + + // Signature + this.emit('data', new Buffer(signature)); + this.emit('data', this._packIHDR(width, height)); + + // filter pixel data + var data = this._filter.filter(data, width, height); + + // compress it + this._compress.deflate(data); +}; + +Parser.prototype._packData = function(data) { + + // console.log('deflate', data.length); + + this.emit('data', this._packIDAT(data)); + this.emit('data', this._packIEND()); + this.emit('end'); +}; + +Parser.prototype._packChunk = function(type, data) { + + var len = (data ? data.length : 0), + buf = new Buffer(len + 12); + + buf.writeUInt32BE(len, 0); + buf.writeUInt32BE(type, 4); + + if (data) data.copy(buf, 8); + + buf.writeInt32BE(crc32(buf.slice(4, buf.length - 4)), buf.length - 4); + return buf; +}; + +Parser.prototype._packIHDR = function(width, height) { + + var buf = new Buffer(13); + buf.writeUInt32BE(width, 0); + buf.writeUInt32BE(height, 4); + buf[8] = 8; + buf[9] = 6; // colorType + buf[10] = 0; // compression + buf[11] = 0; // filter + buf[12] = 0; // interlace + + return this._packChunk(TYPE_IHDR, buf); +}; + +Parser.prototype._packIDAT = function(data) { + return this._packChunk(TYPE_IDAT, data); +}; + +Parser.prototype._packIEND = function() { + return this._packChunk(TYPE_IEND, null); +}; diff --git a/lib/parser.js b/lib/parser.js index 08117d7..f64e716 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -23,24 +23,12 @@ var util = require('util'), Stream = require('stream'), - Compress = require('./compress'), + zlib = require('zlib'), + helpers = require('./helpers'), + constants = require('./constants'), Filter = require('./filter'); -var signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]; - -var TYPE_IHDR = 0x49484452; -var TYPE_IEND = 0x49454e44; -var TYPE_IDAT = 0x49444154; -var TYPE_PLTE = 0x504c5445; -var TYPE_tRNS = 0x74524e53; -var TYPE_gAMA = 0x67414d41; - -var COLOR_PALETTE = 1; -var COLOR_COLOR = 2; -var COLOR_ALPHA = 4; - - var Parser = module.exports = function(options) { Stream.call(this); @@ -50,79 +38,277 @@ var Parser = module.exports = function(options) { this._hasIHDR = false; this._hasIEND = false; - // input flags + this._stream = new ReadStream(); + this._inflate = null; + + // input flags/metadata this._palette = []; this._colorType = 0; + this._width = 0; + this._height = 0; this._chunks = {}; - this._chunks[TYPE_IHDR] = this._parseIHDR.bind(this); - this._chunks[TYPE_IEND] = this._parseIEND.bind(this); - this._chunks[TYPE_IDAT] = this._parseIDAT.bind(this); - this._chunks[TYPE_PLTE] = this._parsePLTE.bind(this); - this._chunks[TYPE_tRNS] = this._parseTRNS.bind(this); - this._chunks[TYPE_gAMA] = this._parseGAMA.bind(this); + 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._compress = new Compress(options); - this._filter = new Filter(options); + this.writable = true; - this._initCompress(); + this.on('error', this._handleError.bind(this)); + + this._handleSignature(); }; util.inherits(Parser, Stream); -Parser.prototype._initCompress = function() { - this._compress.on('error', this.emit.bind(this, 'error')); - - this._compress.on('deflated', this._packData.bind(this)); - this._compress.on('inflated', this._unfilter.bind(this)); +Parser.prototype.write = function(data) { + this._stream.write(data); }; -Parser.prototype._parse = function(data) { +Parser.prototype.end = function(data) { + this._stream.end(data); +}; - var idx = 0; +Parser.prototype._handleError = function() { - try { - // check PNG file signature - while (idx < signature.length) { - if (data[idx] != signature[idx]) { - throw new Error('Invalid file signature'); - } - idx++; - } - //console.log('Signature is ok'); + this.writable = false; + this._stream.destroy(); - // iterate chunks - while (idx < data.length) { - idx = this._parseChunk(data, idx); + if (this._inflate) + this._inflate.destroy(); +}; + +Parser.prototype._handleSignature = function() { + this._stream.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.emit('error', new Error('Invalid file signature')); + return; } } - catch(err) { - this.emit('error', err); + this._stream.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), + name = ''; + for (var i = 4; i < 8; i++) + name += String.fromCharCode(data[i]); + + // chunk flags + var ancillary = !!(data[4] & 0x20), // or critical + priv = !!(data[5] & 0x20), // or public + safeToCopy = !!(data[7] & 0x20); // or unsafe + + if (!this._hasIHDR && type != constants.TYPE_IHDR) { + this.emit('error', new Error('Expected IHDR on beggining')); + return; + } + + if (this._chunks[type]) { + return this._chunks[type](length); + + } else if (!ancillary) { + this.emit('error', new Error('Unsupported critical chunk type ' + name)); + return; } }; -Parser.prototype._pack = function(width, height, data) { - - // Signature - this.emit('data', new Buffer(signature)); - this.emit('data', this._packIHDR(width, height)); - - // filter pixel data - var data = this._filter.filter(data, width, height); - - // compress it - this._compress.deflate(data); +Parser.prototype._handleChunkEnd = function() { + this._stream.read(4, this._parseChunkEnd.bind(this)); }; -Parser.prototype._packData = function(data) { +Parser.prototype._parseChunkEnd = function(data) { - // console.log('deflate', data.length); + var fileCrc = data.readInt32BE(0); - this.emit('data', this._packIDAT(data)); - this.emit('data', this._packIEND()); - this.emit('end'); +// // calc CRC (of chunk type and content) +// var calcCrc = helpers.crc32(data.slice(idx - 4, idx + length)), +// content = data.slice(idx, idx + length); +// idx += length; + +// // read CRC +// var fileCrc = data.readInt32BE(idx); +// idx += 4; + +// // and check CRC +// if (this._options.checkCRC && calcCrc != fileCrc) +// throw new Error('Crc error'); + + // TODO: calc crc on stream + + if (this._hasIEND) { + this._stream.destroy(); + + } else { + this._stream.read(8, this._parseChunkBegin.bind(this)); + } }; + +Parser.prototype._handleIHDR = function(length) { + this._stream.read(length, this._parseIHDR.bind(this)); +}; +Parser.prototype._parseIHDR = function(data) { + + var width = data.readUInt32BE(0), + height = data.readUInt32BE(4), + depth = data[8], + colorType = data[9], // bits: 1 palette, 2 color, 4 alpha + compr = data[10], + filter = data[11], + interlace = data[12]; + + console.log(' width', width, 'height', height, + 'depth', depth, 'colorType', colorType, + 'compr', compr, 'filter', filter, 'interlace', interlace + ); + + if (depth != 8) { + this.emit('error', new Error('Unsupported bit depth ' + depth)); + return; + } + if (compr != 0) { + this.emit('error', new Error('Unsupported compression method')); + return; + } + if (filter != 0) { + this.emit('error', new Error('Unsupported filter method')); + return; + } + if (interlace != 0) { + this.emit('error', new Error('Unsupported interlace method')); + return; + } + + this._colorType = colorType; + this._width = width; + this._height = height; + this._hasIHDR = true; + + this.emit('metadata', { + width: width, + height: height, + palette: !!(colorType & constants.COLOR_PALETTE), + color: !!(colorType & constants.COLOR_COLOR), + alpha: !!(colorType & constants.COLOR_ALPHA) + }); + + this._handleChunkEnd(); +}; + + +Parser.prototype._handlePLTE = function(length) { + this._stream.read(length, this._parsePLTE.bind(this)); +}; +Parser.prototype._parsePLTE = function(data) { + + var entries = Math.floor(data.length / 3); + console.log('Palette:', entries); + + for (var i = 0; i < entries; i++) { + this._palette.push([ + data.readUInt8(i * 3), + data.readUInt8(i * 3 + 1), + data.readUInt8(i * 3 + 2 ), + 0xff + ]); + } + + this._handleChunkEnd(); +}; + +Parser.prototype._handleTRNS = function(length) { + this._stream.read(length, this._parseTRNS.bind(this)); +}; +Parser.prototype._parseTRNS = function(data) { + + // palette + if (this._colorType == 3) { + if (this._palette.length == 0) { + this.emit('error', new Error('Transparency chunk must be after palette')); + return; + } + if (data.length > this._palette.length) { + this.emit('error', new Error('More transparent colors than palette size')); + return; + } + for (var i = 0; i < this._palette.length; i++) { + this._palette[i][3] = i < data.length ? data.readUInt8(i) : 0xff; + } + } + + // for colorType 0 (grayscale) and 2 (rgb) + // there might be one gray/color defined as transparent + + this._handleChunkEnd(); +}; + +Parser.prototype._handleGAMA = function(length) { + this._stream.read(length, this._parseGAMA.bind(this)); +}; +Parser.prototype._parseGAMA = function(data) { + + this.emit('gamma', data.readUInt32BE(0) / 100000); + + this._handleChunkEnd(); +}; + +Parser.prototype._handleIDAT = function(length) { + this._stream.read(-length, this._parseIDAT.bind(this, length)); +}; +Parser.prototype._parseIDAT = function(lenght, data) { + + if (this._colorType == 3 && this._palette.length == 0) + throw new Error('Expected palette not found'); + + if (!this._inflate) { + this._inflate = zlib.createInflate(); + + this._inflate.on('error', this.emit.bind(this, 'error')); + //this._inflate.pipe(filter); + } + + this._inflate.write(data); + length -= data.length; + + if (length > 0) + this._handleIDAT(length); + else + this._handleChunkEnd(); +}; + + +Parser.prototype._handleIEND = function(length) { + this._stream.read(length, this._parseIEND.bind(this)); +}; +Parser.prototype._parseIEND = function(data) { + + // no more data to inflate + this._inflate.end(); + + this._hasIEND = true; + this._handleChunkEnd(); +}; + + + Parser.prototype._unfilter = function(data) { // expand data to 32 bit depending on colorType @@ -160,209 +346,3 @@ Parser.prototype._unfilter = function(data) { this.emit('parsed', data); }; - - - - -Parser.prototype._parseChunk = function(data, idx) { - - if (this._hasIEND) - throw new Error('Not expected chunk after IEND'); - - // chunk size (only content) - var length = data.readUInt32BE(idx); - idx += 4; - - // chunk type - var type = data.readUInt32BE(idx), - ancillary = !!(data[idx] & 0x20), // or critical - priv = !!(data[idx+1] & 0x20), // or public - safeToCopy = !!(data[idx+3] & 0x20), // or unsafe - name = ''; - for (var i = 0; i < 4; i++) - name += String.fromCharCode(data[idx+i]); - idx += 4; - - // console.log('chunk ', name, length); - - // calc CRC (of chunk type and content) - var calcCrc = crc32(data.slice(idx - 4, idx + length)), - content = data.slice(idx, idx + length); - idx += length; - - // read CRC - var fileCrc = data.readInt32BE(idx); - idx += 4; - - // and check CRC - if (this._options.checkCRC && calcCrc != fileCrc) - throw new Error('Crc error'); - - - if (!this._hasIHDR && type != TYPE_IHDR) - throw new Error('Expected IHDR on beggining'); - - if (this._chunks[type]) { - this._chunks[type](content); - - } else if (!ancillary) - throw new Error('Unsupported critical chunk type ' + name); - // else - // console.log('Ignoring chunk', name, type.toString(16)); - - return idx; -}; - -Parser.prototype._packChunk = function(type, data) { - - var len = (data ? data.length : 0), - buf = new Buffer(len + 12); - - buf.writeUInt32BE(len, 0); - buf.writeUInt32BE(type, 4); - - if (data) data.copy(buf, 8); - - buf.writeInt32BE(crc32(buf.slice(4, buf.length - 4)), buf.length - 4); - return buf; -}; - - -Parser.prototype._parseIHDR = function(data) { - - var width = data.readUInt32BE(0), - height = data.readUInt32BE(4), - depth = data[8], - colorType = data[9], // 1 palette, 2 color, 4 alpha - compr = data[10], - filter = data[11], - interlace = data[12]; - - // console.log(' width', width, 'height', height, - // 'depth', depth, 'colorType', colorType, - // 'compr', compr, 'filter', filter, 'interlace', interlace - // ); - - if (depth != 8) - throw new Error('Unsupported bit depth ' + depth); - if (interlace != 0) - throw new Error('Unsupported interlace method'); - - this._colorType = colorType; - - this._compress.prepareInflate(compr); - this._filter.prepare(width, height, filter); - - this._hasIHDR = true; - - this.emit('metadata', width, height); -}; - -Parser.prototype._packIHDR = function(width, height) { - - var buf = new Buffer(13); - buf.writeUInt32BE(width, 0); - buf.writeUInt32BE(height, 4); - buf[8] = 8; - buf[9] = 6; // colorType - buf[10] = 0; // compression - buf[11] = 0; // filter - buf[12] = 0; // interlace - - return this._packChunk(TYPE_IHDR, buf); -}; - - -Parser.prototype._parsePLTE = function(data) { - - var entries = Math.floor(data.length / 3); - // console.log('Palette:', entries); - - for (var i = 0; i < entries; i++) { - this._palette.push([ - data.readUInt8(i * 3), - data.readUInt8(i * 3 + 1), - data.readUInt8(i * 3 + 2 ), - 0xff - ]); - } -}; - -Parser.prototype._parseTRNS = function(data) { - - // palette - if (this._colorType == 3) { - if (this._palette.length == 0) - throw new Error('Transparency chunk must be after palette'); - - if (data.length > this._palette.length) - throw new Error('More transparent colors than palette size'); - - for (var i = 0; i < this._palette.length; i++) - this._palette[i][3] = i < data.length ? data.readUInt8(i) : 0xff; - } - - // for colorType 0 (grayscale) and 2 (rgb) - // there might be one gray/color defined as transparent -}; - -Parser.prototype._parseGAMA = function(data) { - this.emit('gamma', data.readUInt32BE(0) / 100000); -}; - -Parser.prototype._parseIDAT = function(data) { - - if (this._colorType == 3 && this._palette.length == 0) - throw new Error('Expected palette not found'); - - this._compress.writeInflate(data); -}; - -Parser.prototype._packIDAT = function(data) { - return this._packChunk(TYPE_IDAT, data); -}; - - -Parser.prototype._parseIEND = function(data) { - - // no more data to inflate - this._compress.endInflate(); - - this._hasIEND = true; -}; - -Parser.prototype._packIEND = function() { - return this._packChunk(TYPE_IEND, null); -}; - - - - - - - - -// prepare crc table as in PNG Specification -var crcTable = []; - -for (var i = 0; i < 256; i++) { - var c = i; - for (var j = 0; j < 8; j++) { - if (c & 1) { - c = 0xedb88320 ^ (c >>> 1); - } else { - c = c >>> 1; - } - } - crcTable[i] = c; -} - -function crc32(buf) { - - var crc = -1; - for (var i = 0; i < buf.length; i++) { - crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8); - } - return crc ^ -1; -} - diff --git a/lib/readstream.js b/lib/readstream.js new file mode 100644 index 0000000..83f5aab --- /dev/null +++ b/lib/readstream.js @@ -0,0 +1,55 @@ +// Copyright (c) 2012 Kuba Niegowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +'use strict'; + + +var util = require('util'), + Stream = require('stream'); + + +var ReadStream = module.exports = function() { + Stream.call(this); + + + + this.writeable = true; +}; +util.inherits(ReadStream, Stream); + + +// length < 0 -> at most this length +ReadStream.prototype.read = function(length, callback) { + +}; + +ReadStream.prototype.destroy = function() { + +}; + + +ReadStream.prototype.write = function(data) { + +}; + +ReadStream.prototype.end = function(data) { + +}; +