mirror of
https://github.com/danbulant/pngjs
synced 2026-07-05 19:20:38 +00:00
Support for 1,2,4 bits PNG
This commit is contained in:
parent
807ffcd66f
commit
d601f60c79
10 changed files with 278 additions and 154 deletions
120
lib/bitmapper.js
Normal file
120
lib/bitmapper.js
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
function bitRetriever(data, depth) {
|
||||||
|
|
||||||
|
var leftOver = [];
|
||||||
|
var i = 0;
|
||||||
|
function split() {
|
||||||
|
var byte = data[i];
|
||||||
|
i++;
|
||||||
|
switch(depth) {
|
||||||
|
default:
|
||||||
|
throw new Error("unrecognised depth");
|
||||||
|
break;
|
||||||
|
/* case 8:
|
||||||
|
leftOver.push(byte);
|
||||||
|
break;*/
|
||||||
|
case 4:
|
||||||
|
var byte2 = byte & 0x0f;
|
||||||
|
var byte1 = byte >> 4;
|
||||||
|
leftOver.push(byte1, byte2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
var byte4 = byte & 3;
|
||||||
|
var byte3 = byte >> 2 & 3;
|
||||||
|
var byte2 = byte >> 4 & 3;
|
||||||
|
var byte1 = byte >> 6 & 3;
|
||||||
|
leftOver.push(byte1, byte2, byte3, byte4);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var byte8 = byte & 1;
|
||||||
|
var byte7 = byte >> 1 & 1;
|
||||||
|
var byte6 = byte >> 2 & 1;
|
||||||
|
var byte5 = byte >> 3 & 1;
|
||||||
|
var byte4 = byte >> 4 & 1;
|
||||||
|
var byte3 = byte >> 5 & 1;
|
||||||
|
var byte2 = byte >> 6 & 1;
|
||||||
|
var byte1 = byte >> 7 & 1;
|
||||||
|
leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
get: function(count) {
|
||||||
|
var returner;
|
||||||
|
if (depth === 8) {
|
||||||
|
returner = data.slice(i, i + count);
|
||||||
|
i += count;
|
||||||
|
return returner;
|
||||||
|
}
|
||||||
|
while(leftOver.length < count) {
|
||||||
|
split();
|
||||||
|
}
|
||||||
|
returner = leftOver.slice(0, count);
|
||||||
|
leftOver = leftOver.slice(count);
|
||||||
|
return returner;
|
||||||
|
},
|
||||||
|
resetAfterLine: function() {
|
||||||
|
leftOver.length = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.dataToBitMap = function(data, width, height, bpp, depth) {
|
||||||
|
if (depth !== 8) {
|
||||||
|
var bits = bitRetriever(data, depth);
|
||||||
|
}
|
||||||
|
var pxData = new Buffer(width * height * 4);
|
||||||
|
var pxPos = 0;
|
||||||
|
var maxBit = Math.pow(2, depth) - 1;
|
||||||
|
var rawPos = 0;
|
||||||
|
var pixelData;
|
||||||
|
|
||||||
|
for(var y = 0; y < height; y++) {
|
||||||
|
for(var x = 0; x < width; x++) {
|
||||||
|
if (depth !== 8) {
|
||||||
|
pixelData = bits.get(bpp);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
var idx = pixelBppMap[bpp][i];
|
||||||
|
if (depth === 8) {
|
||||||
|
pxData[pxPos] = idx !== 0xff ? data[idx + rawPos] : maxBit;
|
||||||
|
} else {
|
||||||
|
pxData[pxPos] = idx !== 0xff ? pixelData[idx] : maxBit;
|
||||||
|
}
|
||||||
|
pxPos++;
|
||||||
|
}
|
||||||
|
rawPos += bpp;
|
||||||
|
}
|
||||||
|
if (depth !== 8) {
|
||||||
|
bits.resetAfterLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pxData;
|
||||||
|
};
|
||||||
|
|
||||||
|
var pixelBppMap = {
|
||||||
|
1: { // L
|
||||||
|
0: 0,
|
||||||
|
1: 0,
|
||||||
|
2: 0,
|
||||||
|
3: 0xff
|
||||||
|
},
|
||||||
|
2: { // LA
|
||||||
|
0: 0,
|
||||||
|
1: 0,
|
||||||
|
2: 0,
|
||||||
|
3: 1
|
||||||
|
},
|
||||||
|
3: { // RGB
|
||||||
|
0: 0,
|
||||||
|
1: 1,
|
||||||
|
2: 2,
|
||||||
|
3: 0xff
|
||||||
|
},
|
||||||
|
4: { // RGBA
|
||||||
|
0: 0,
|
||||||
|
1: 1,
|
||||||
|
2: 2,
|
||||||
|
3: 3
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -25,12 +25,19 @@ var util = require('util'),
|
||||||
Filter = require('./filter');
|
Filter = require('./filter');
|
||||||
|
|
||||||
|
|
||||||
var FilterAsync = module.exports = function(width, height, Bpp, data, options) {
|
var FilterAsync = module.exports = function(width, height, Bpp, depth, options) {
|
||||||
ChunkStream.call(this);
|
ChunkStream.call(this);
|
||||||
|
|
||||||
this._filter = new Filter(width, height, Bpp, data, options, {
|
var buffers = [];
|
||||||
|
var that = this;
|
||||||
|
this._filter = new Filter(width, height, Bpp, depth, options, {
|
||||||
read: this.read.bind(this),
|
read: this.read.bind(this),
|
||||||
complete: this.emit.bind(this, 'complete')
|
complete: function(width, height) {
|
||||||
|
that.emit('complete', Buffer.concat(buffers), width, height)
|
||||||
|
},
|
||||||
|
write: function(buffer) {
|
||||||
|
buffers.push(buffer);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._filter.start();
|
this._filter.start();
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,20 @@ var SyncReader = require('./sync-reader'),
|
||||||
Filter = require('./filter');
|
Filter = require('./filter');
|
||||||
|
|
||||||
|
|
||||||
exports.process = function(buffer, width, height, Bpp, outData, options) {
|
exports.process = function(buffer, width, height, Bpp, depth, options) {
|
||||||
|
|
||||||
|
var buffers = [];
|
||||||
var reader = new SyncReader(buffer);
|
var reader = new SyncReader(buffer);
|
||||||
var filter = new Filter(width, height, Bpp, outData, options, {
|
var filter = new Filter(width, height, Bpp, depth, options, {
|
||||||
read: reader.read.bind(reader),
|
read: reader.read.bind(reader),
|
||||||
|
write: function(buffer) {
|
||||||
|
buffers.push(buffer);
|
||||||
|
},
|
||||||
complete: function(){}
|
complete: function(){}
|
||||||
});
|
});
|
||||||
|
|
||||||
filter.start();
|
filter.start();
|
||||||
reader.process();
|
reader.process();
|
||||||
|
|
||||||
|
return Buffer.concat(buffers);
|
||||||
};
|
};
|
||||||
170
lib/filter.js
170
lib/filter.js
|
|
@ -20,16 +20,15 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var util = require('util'),
|
var util = require('util');
|
||||||
ChunkStream = require('./chunkstream');
|
|
||||||
|
|
||||||
|
|
||||||
var Filter = module.exports = function(width, height, Bpp, data, options, dependencies) {
|
var Filter = module.exports = function(width, height, Bpp, depth, options, dependencies) {
|
||||||
|
|
||||||
this._width = width;
|
this._width = width;
|
||||||
this._height = height;
|
this._height = height;
|
||||||
this._Bpp = Bpp;
|
this._Bpp = Bpp;
|
||||||
this._data = data;
|
this._depth = depth;
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
|
||||||
this._line = 0;
|
this._line = 0;
|
||||||
|
|
@ -49,135 +48,80 @@ var Filter = module.exports = function(width, height, Bpp, data, options, depend
|
||||||
};
|
};
|
||||||
|
|
||||||
this.read = dependencies.read;
|
this.read = dependencies.read;
|
||||||
|
this.write = dependencies.write;
|
||||||
this.complete = dependencies.complete;
|
this.complete = dependencies.complete;
|
||||||
|
|
||||||
|
var byteWidth = this._width * this._Bpp;
|
||||||
|
if (this._depth !== 8) {
|
||||||
|
byteWidth = Math.ceil(byteWidth / (8 / this._depth));
|
||||||
|
}
|
||||||
|
this._byteWidth = byteWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
Filter.prototype.start = function() {
|
Filter.prototype.start = function() {
|
||||||
this.read(this._width * this._Bpp + 1, this._reverseFilterLine.bind(this));
|
this.read(this._byteWidth + 1, this._reverseFilterLine.bind(this));
|
||||||
};
|
|
||||||
|
|
||||||
var pixelBppMap = {
|
|
||||||
1: { // L
|
|
||||||
0: 0,
|
|
||||||
1: 0,
|
|
||||||
2: 0,
|
|
||||||
3: 0xff
|
|
||||||
},
|
|
||||||
2: { // LA
|
|
||||||
0: 0,
|
|
||||||
1: 0,
|
|
||||||
2: 0,
|
|
||||||
3: 1
|
|
||||||
},
|
|
||||||
3: { // RGB
|
|
||||||
0: 0,
|
|
||||||
1: 1,
|
|
||||||
2: 2,
|
|
||||||
3: 0xff
|
|
||||||
},
|
|
||||||
4: { // RGBA
|
|
||||||
0: 0,
|
|
||||||
1: 1,
|
|
||||||
2: 2,
|
|
||||||
3: 3
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Filter.prototype._reverseFilterLine = function(rawData) {
|
Filter.prototype._reverseFilterLine = function(rawData) {
|
||||||
|
|
||||||
var pxData = this._data,
|
var line = new Buffer(this._byteWidth);
|
||||||
pxLineLength = this._width << 2,
|
|
||||||
pxRowPos = this._line * pxLineLength,
|
|
||||||
filter = rawData[0];
|
|
||||||
|
|
||||||
if (filter == 0) {
|
var filter = rawData[0];
|
||||||
for (var x = 0; x < this._width; x++) {
|
|
||||||
var pxPos = pxRowPos + (x << 2),
|
|
||||||
rawPos = 1 + x * this._Bpp;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++) {
|
var xComparison = this._depth === 8 ? this._Bpp : 1;
|
||||||
var idx = pixelBppMap[this._Bpp][i];
|
var xBiggerThan = xComparison - 1;
|
||||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] : 0xff;
|
|
||||||
}
|
for (var x = 0; x < this._byteWidth; x++) {
|
||||||
|
var rawByte = rawData[1 + x];
|
||||||
|
switch(filter) {
|
||||||
|
case 0:
|
||||||
|
line[x] = rawByte;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||||
|
line[x] = rawByte + left;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||||
|
line[x] = rawByte + up;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||||
|
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||||
|
var add = Math.floor((left + up) / 2);
|
||||||
|
line[x] = rawByte + add;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||||
|
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||||
|
var upLeft = x > xBiggerThan && this._lastLine
|
||||||
|
? this._lastLine[x - xComparison] : 0;
|
||||||
|
var add = PaethPredictor(left, up, upLeft);
|
||||||
|
line[x] = rawByte + add;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (filter == 1) {
|
//if (x === 5) {
|
||||||
for (var x = 0; x < this._width; x++) {
|
// console.log("R", line[3], "G", line[4], "B", line[5]);
|
||||||
var pxPos = pxRowPos + (x << 2),
|
//}
|
||||||
rawPos = 1 + x * this._Bpp;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
var idx = pixelBppMap[this._Bpp][i],
|
|
||||||
left = x > 0 ? pxData[pxPos + i - 4] : 0;
|
|
||||||
|
|
||||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + left : 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (filter == 2) {
|
|
||||||
for (var x = 0; x < this._width; x++) {
|
|
||||||
var pxPos = pxRowPos + (x << 2),
|
|
||||||
rawPos = 1 + x * this._Bpp;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
var idx = pixelBppMap[this._Bpp][i],
|
|
||||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0;
|
|
||||||
|
|
||||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + up : 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (filter == 3) {
|
|
||||||
for (var x = 0; x < this._width; x++) {
|
|
||||||
var pxPos = pxRowPos + (x << 2),
|
|
||||||
rawPos = 1 + x * this._Bpp;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
var idx = pixelBppMap[this._Bpp][i],
|
|
||||||
left = x > 0 ? pxData[pxPos + i - 4] : 0,
|
|
||||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0,
|
|
||||||
add = Math.floor((left + up) / 2);
|
|
||||||
|
|
||||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + add : 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (filter == 4) {
|
|
||||||
for (var x = 0; x < this._width; x++) {
|
|
||||||
var pxPos = pxRowPos + (x << 2),
|
|
||||||
rawPos = 1 + x * this._Bpp;
|
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
var idx = pixelBppMap[this._Bpp][i],
|
|
||||||
left = x > 0 ? pxData[pxPos + i - 4] : 0,
|
|
||||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0,
|
|
||||||
upLeft = x > 0 && this._line > 0
|
|
||||||
? pxData[pxPos - pxLineLength + i - 4] : 0,
|
|
||||||
add = PaethPredictor(left, up, upLeft);
|
|
||||||
|
|
||||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + add : 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this._line++;
|
this._line++;
|
||||||
|
this._lastLine = line;
|
||||||
|
this.write(line);
|
||||||
|
|
||||||
if (this._line < this._height)
|
if (this._line < this._height) {
|
||||||
this.read(this._width * this._Bpp + 1, this._reverseFilterLine.bind(this));
|
this.read(this._byteWidth + 1, this._reverseFilterLine.bind(this));
|
||||||
else
|
} else {
|
||||||
this.complete(this._data, this._width, this._height);
|
this._lastLine = null;
|
||||||
|
this.complete(this._width, this._height);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Filter.prototype.filter = function(pxData) {
|
||||||
|
|
||||||
|
var rawData = new Buffer(((this._width << 2) + 1) * this._height);
|
||||||
Filter.prototype.filter = function() {
|
|
||||||
|
|
||||||
var pxData = this._data,
|
|
||||||
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++) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,9 @@ Packer.prototype.pack = function(data, width, height) {
|
||||||
this.emit('data', this._packIHDR(width, height));
|
this.emit('data', this._packIHDR(width, height));
|
||||||
|
|
||||||
// filter pixel data
|
// filter pixel data
|
||||||
var filter = new Filter(width, height, 4, data, this._options, {});
|
//TODO {}
|
||||||
var data = filter.filter();
|
var filter = new Filter(width, height, 4, 8, this._options, {});
|
||||||
|
var data = filter.filter(data);
|
||||||
|
|
||||||
// compress it
|
// compress it
|
||||||
var deflate = zlib.createDeflate({
|
var deflate = zlib.createDeflate({
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ var util = require('util'),
|
||||||
zlib = require('zlib'),
|
zlib = require('zlib'),
|
||||||
ChunkStream = require('./chunkstream'),
|
ChunkStream = require('./chunkstream'),
|
||||||
FilterAsync = require('./filter-async'),
|
FilterAsync = require('./filter-async'),
|
||||||
Parser = require('./parser');
|
Parser = require('./parser'),
|
||||||
|
bitmapper = require('./bitmapper');
|
||||||
|
|
||||||
|
|
||||||
var ParserAsync = module.exports = function(options) {
|
var ParserAsync = module.exports = function(options) {
|
||||||
|
|
@ -72,26 +73,36 @@ ParserAsync.prototype._inflateData = function(data) {
|
||||||
this._inflate.write(data);
|
this._inflate.write(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
ParserAsync.prototype._createData = function(width, height, bpp) {
|
ParserAsync.prototype._createData = function(width, height, bpp, depth) {
|
||||||
this._data = new Buffer(width * height * 4);
|
|
||||||
|
this._bpp = bpp;
|
||||||
|
this._depth = depth;
|
||||||
|
|
||||||
this._filter = new FilterAsync(
|
this._filter = new FilterAsync(
|
||||||
width, height,
|
width, height,
|
||||||
bpp,
|
bpp,
|
||||||
this._data,
|
depth,
|
||||||
this._options
|
this._options
|
||||||
);
|
);
|
||||||
return this._data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ParserAsync.prototype._finished = function(data) {
|
ParserAsync.prototype._finished = function(data) {
|
||||||
// no more data to inflate
|
if (!this._inflate) {
|
||||||
this._inflate.end();
|
this.emit('error', 'No Inflate block');
|
||||||
|
} else {
|
||||||
|
// no more data to inflate
|
||||||
|
this._inflate.end();
|
||||||
|
}
|
||||||
this.destroySoon();
|
this.destroySoon();
|
||||||
};
|
};
|
||||||
|
|
||||||
ParserAsync.prototype._complete = function(data, width, height) {
|
ParserAsync.prototype._complete = function(data, width, height) {
|
||||||
|
|
||||||
data = this._parser.reverseFiltered(data, width, height);
|
data = bitmapper.dataToBitMap(data, width, height,
|
||||||
|
this._bpp,
|
||||||
|
this._depth);
|
||||||
|
|
||||||
|
data = this._parser.reverseFiltered(data, this._depth, width, height);
|
||||||
|
|
||||||
this.emit('parsed', data);
|
this.emit('parsed', data);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@
|
||||||
var zlib = require('zlib'),
|
var zlib = require('zlib'),
|
||||||
SyncReader = require('./sync-reader'),
|
SyncReader = require('./sync-reader'),
|
||||||
FilterSync = require('./filter-sync'),
|
FilterSync = require('./filter-sync'),
|
||||||
Parser = require('./parser');
|
Parser = require('./parser'),
|
||||||
|
bitmapper = require('./bitmapper');
|
||||||
|
|
||||||
|
|
||||||
var ParserSync = module.exports = function(buffer, options) {
|
var ParserSync = module.exports = function(buffer, options) {
|
||||||
|
|
@ -51,15 +52,19 @@ var ParserSync = module.exports = function(buffer, options) {
|
||||||
|
|
||||||
var data = zlib.inflateSync(inflateData);
|
var data = zlib.inflateSync(inflateData);
|
||||||
|
|
||||||
FilterSync.process(
|
data = FilterSync.process(
|
||||||
data,
|
data,
|
||||||
this._width, this._height,
|
this._width, this._height,
|
||||||
this._bpp,
|
this._bpp,
|
||||||
this._data,
|
this._depth,
|
||||||
this._options
|
this._options
|
||||||
);
|
);
|
||||||
|
|
||||||
this.data = this._parser.reverseFiltered(this._data, this._width, this._height);
|
this._data = bitmapper.dataToBitMap(data, this._width, this._height,
|
||||||
|
this._bpp,
|
||||||
|
this._depth);
|
||||||
|
// todo yuck
|
||||||
|
this.data = this._parser.reverseFiltered(this._data, this._depth, this._width, this._height);
|
||||||
};
|
};
|
||||||
|
|
||||||
ParserSync.prototype._handleError = function(err) {
|
ParserSync.prototype._handleError = function(err) {
|
||||||
|
|
@ -78,10 +83,11 @@ ParserSync.prototype._inflateData = function(data) {
|
||||||
this._inflateDataList.push(data);
|
this._inflateDataList.push(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
ParserSync.prototype._createData = function(width, height, bpp) {
|
ParserSync.prototype._createData = function(width, height, bpp, depth) {
|
||||||
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;
|
||||||
return this._data;
|
return this._data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ Parser.prototype._parseIHDR = function(data) {
|
||||||
// 'compr', compr, 'filter', filter, 'interlace', interlace
|
// 'compr', compr, 'filter', filter, 'interlace', interlace
|
||||||
// );
|
// );
|
||||||
|
|
||||||
if (depth != 8) {
|
if (depth !== 8 && depth !== 4 && depth !== 2 && depth !== 1) {
|
||||||
this.error(new Error('Unsupported bit depth ' + depth));
|
this.error(new Error('Unsupported bit depth ' + depth));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -187,17 +187,17 @@ Parser.prototype._parseIHDR = function(data) {
|
||||||
|
|
||||||
this._colorType = colorType;
|
this._colorType = colorType;
|
||||||
|
|
||||||
this._data = this.createData(width, height, colorTypeToBppMap[this._colorType]);
|
this.createData(width, height, colorTypeToBppMap[this._colorType], depth);
|
||||||
|
|
||||||
this._hasIHDR = true;
|
this._hasIHDR = true;
|
||||||
|
|
||||||
this.metadata({
|
this.metadata({
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
|
depth: depth,
|
||||||
palette: !!(colorType & constants.COLOR_PALETTE),
|
palette: !!(colorType & constants.COLOR_PALETTE),
|
||||||
color: !!(colorType & constants.COLOR_COLOR),
|
color: !!(colorType & constants.COLOR_COLOR),
|
||||||
alpha: !!(colorType & constants.COLOR_ALPHA),
|
alpha: !!(colorType & constants.COLOR_ALPHA)
|
||||||
data: this._data
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._handleChunkEnd();
|
this._handleChunkEnd();
|
||||||
|
|
@ -298,10 +298,10 @@ Parser.prototype._parseIEND = function(data) {
|
||||||
this.finished();
|
this.finished();
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser.prototype.reverseFiltered = function(data, width, height) {
|
Parser.prototype.reverseFiltered = function(data, depth, width, height) {
|
||||||
|
|
||||||
if (this._colorType == 3) { // paletted
|
if (this._colorType == 3) { // paletted
|
||||||
|
//console.log("paletted");
|
||||||
// use values from palette
|
// use values from palette
|
||||||
var pxLineLength = width << 2;
|
var pxLineLength = width << 2;
|
||||||
|
|
||||||
|
|
@ -312,10 +312,31 @@ Parser.prototype.reverseFiltered = function(data, width, height) {
|
||||||
var pxPos = pxRowPos + (x << 2),
|
var pxPos = pxRowPos + (x << 2),
|
||||||
color = this._palette[data[pxPos]];
|
color = this._palette[data[pxPos]];
|
||||||
|
|
||||||
|
if (!color) {
|
||||||
|
console.error("data - " + data[pxPos] + " got no colour");
|
||||||
|
console.log("depth is ", depth);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < 4; i++)
|
for (var i = 0; i < 4; i++)
|
||||||
data[pxPos + i] = color[i];
|
data[pxPos + i] = color[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (depth !== 8) {
|
||||||
|
//console.log("adjusting");
|
||||||
|
var pxLineLength = width << 2;
|
||||||
|
var maxOutSample = 255;
|
||||||
|
var maxInSample = Math.pow(2, depth) - 1;
|
||||||
|
|
||||||
|
for (var y = 0; y < height; y++) {
|
||||||
|
var pxRowPos = y * pxLineLength;
|
||||||
|
|
||||||
|
for (var x = 0; x < width; x++) {
|
||||||
|
var pxPos = pxRowPos + (x << 2);
|
||||||
|
for (var i = 0; i < 4; i++)
|
||||||
|
data[pxPos + i] = Math.floor((data[pxPos + i] * maxOutSample) / maxInSample + 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,7 @@ PNG.prototype.end = function(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.data = metadata.data;
|
|
||||||
|
|
||||||
delete metadata.data;
|
|
||||||
this.emit('metadata', metadata);
|
this.emit('metadata', metadata);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
36
test/test.js
36
test/test.js
|
|
@ -12,26 +12,36 @@ fs.readdir(__dirname + '/in/', function(err, files) {
|
||||||
|
|
||||||
var expectedError = false;
|
var expectedError = false;
|
||||||
if (file.match(/^x/) ||
|
if (file.match(/^x/) ||
|
||||||
file.match(/^...i/) || // interlace
|
file.match(/^...i/) ||// interlace
|
||||||
file.match(/^......(01|02|04|16)/) || // 1/2/4/16 bit
|
file.match(/^......(16)/) // 1/2/4/16 bit
|
||||||
file.match(/^basn3p(01|02|04)/) // 2/4/16 colour palette
|
|
||||||
) {
|
) {
|
||||||
expectedError = true;
|
expectedError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expectedError) {
|
var data = fs.readFileSync(__dirname + '/in/' + file);
|
||||||
var data = fs.readFileSync(__dirname + '/in/' + file);
|
try {
|
||||||
|
console.log("Sync: parsing..", file);
|
||||||
var png = PNG.sync.read(data);
|
var png = PNG.sync.read(data);
|
||||||
|
} catch (e) {
|
||||||
var outpng = new PNG();
|
if (!expectedError) {
|
||||||
PNG.adjustGamma(png);
|
console.log(e);
|
||||||
outpng.data = png.data;
|
console.log(e.stack);
|
||||||
outpng.width = png.width;
|
}
|
||||||
outpng.height = png.height;
|
return;
|
||||||
outpng.pack()
|
|
||||||
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expectedError) {
|
||||||
|
console.log("Error expected, parsed fine", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
var outpng = new PNG();
|
||||||
|
PNG.adjustGamma(png);
|
||||||
|
outpng.data = png.data;
|
||||||
|
outpng.width = png.width;
|
||||||
|
outpng.height = png.height;
|
||||||
|
outpng.pack()
|
||||||
|
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file));
|
||||||
|
|
||||||
fs.createReadStream(__dirname + '/in/' + file)
|
fs.createReadStream(__dirname + '/in/' + file)
|
||||||
.pipe(new PNG())
|
.pipe(new PNG())
|
||||||
.on('error', function(err) {
|
.on('error', function(err) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue