Pull out format normaliser. Fix #18

This commit is contained in:
Luke Page 2015-08-05 23:21:28 +01:00
parent 8cf14b9ca2
commit 71a371d6cd
7 changed files with 131 additions and 93 deletions

View file

@ -129,7 +129,7 @@
"generator-star-spacing": 0,
"guard-for-in": 1,
"handle-callback-err": 2,
"id-length": [2, {"min": 3, "max": 20, "exceptions":["x", "y", "i", "j", "ex", "up"]}],
"id-length": [2, {"min": 3, "max": 25, "exceptions":["x", "y", "i", "j", "ex", "up"]}],
"indent": [1, 2, {"SwitchCase": 1}],
"init-declarations": 0,
"key-spacing": [1, { "beforeColon": false, "afterColon": true }],

89
lib/format-normaliser.js Normal file
View file

@ -0,0 +1,89 @@
'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;
};

View file

@ -1,13 +1,12 @@
'use strict';
var util = require('util');
var zlib = require('zlib');
var ChunkStream = require('./chunkstream');
var FilterAsync = require('./filter-async');
var Parser = require('./parser');
var bitmapper = require('./bitmapper');
var formatNormaliser = require('./format-normaliser');
var ParserAsync = module.exports = function(options) {
ChunkStream.call(this);
@ -98,7 +97,14 @@ ParserAsync.prototype._complete = function(filteredData, width, height) {
this._depth,
this._interlace);
bitmapData = this._parser.reverseFiltered(bitmapData, this._depth, width, height);
// todo not bitmap data any more
bitmapData = formatNormaliser(bitmapData, {
depth: this._depth, // TODO always store in this format
width: width,
height: height,
colorType: this._parser._colorType,
palette: this._parser._palette,
transColor: this._parser._transColor });
}
catch (ex) {
this._handleError(ex);

View file

@ -6,6 +6,7 @@ var SyncReader = require('./sync-reader');
var FilterSync = require('./filter-sync');
var Parser = require('./parser');
var bitmapper = require('./bitmapper');
var formatNormaliser = require('./format-normaliser');
var ParserSync = module.exports = function(buffer, options) {
@ -33,6 +34,10 @@ var ParserSync = module.exports = function(buffer, options) {
var data = zlib.inflateSync(inflateData);
if (!data || !data.length) {
throw new Error('bad png - invalid inflate data response');
}
data = FilterSync.process(
data,
this._width, this._height,
@ -41,13 +46,19 @@ var ParserSync = module.exports = function(buffer, options) {
this._interlace,
this._options
);
// todo do not store _data
this._data = bitmapper.dataToBitMap(data, this._width, this._height,
this._bpp,
this._depth,
this._interlace);
// todo yuck
this.data = this._parser.reverseFiltered(this._data, this._depth, this._width, this._height);
this.data = formatNormaliser(this._data, {
depth: this._depth, // TODO always store in this format
width: this._width,
height: this._height,
colorType: this._parser._colorType,
palette: this._parser._palette,
transColor: this._parser._transColor });
};
ParserSync.prototype._handleError = function(err) {
@ -73,5 +84,5 @@ ParserSync.prototype._createData = function(width, height, bpp, depth, interlace
this._height = height;
this._depth = depth;
this._interlace = interlace;
return this._data;
return this._data; // todo do not return
};

View file

@ -276,7 +276,6 @@ Parser.prototype._parseIDAT = function(length, data) {
}
};
Parser.prototype._handleIEND = function(length) {
this.read(length, this._parseIEND.bind(this));
};
@ -289,79 +288,3 @@ Parser.prototype._parseIEND = function(data) {
this.finished();
};
Parser.prototype.reverseFiltered = function(indata, depth, width, height) {
var outdata = indata; // only different for 16 bits
var pxLineLength = width << 2;
var x, y, i, pxPos, pxRowPos;
if (this._colorType === 3) { // paletted
//TODO abstract loop?
// use values from palette
for (y = 0; y < height; y++) {
pxRowPos = y * pxLineLength;
for (x = 0; x < width; x++) {
pxPos = pxRowPos + (x << 2);
var color = this._palette[indata[pxPos]];
if (!color) {
throw new Error('index ' + indata[pxPos] + ' not in palette');
}
for (i = 0; i < 4; i++) {
indata[pxPos + i] = color[i];
}
}
}
}
else {
if (this._transColor) {
for (y = 0; y < height; y++) {
pxRowPos = y * pxLineLength;
for (x = 0; x < width; x++) {
pxPos = pxRowPos + (x << 2);
var makeTrans = false;
//console.log(pxPos);
if (this._transColor.length === 1) {
if (this._transColor[0] === indata[pxPos]) {
makeTrans = true;
}
}
else if (this._transColor[0] === indata[pxPos] && this._transColor[1] === indata[pxPos + 1] && this._transColor[2] === indata[pxPos + 2]) {
makeTrans = true;
}
if (makeTrans) {
for (i = 0; i < 4; i++) {
indata[pxPos + i] = 0;
}
}
}
}
}
if (depth !== 8) {
if (depth === 16) {
outdata = new Buffer(width * height * 4);
}
//console.log("adjusting");
var maxOutSample = 255;
var maxInSample = Math.pow(2, depth) - 1;
for (y = 0; y < height; y++) {
pxRowPos = y * pxLineLength;
for (x = 0; x < width; x++) {
pxPos = pxRowPos + (x << 2);
for (i = 0; i < 4; i++) {
outdata[pxPos + i] = Math.floor((indata[pxPos + i] * maxOutSample) / maxInSample + 0.5);
}
}
}
}
}
return outdata;
};

View file

@ -49,6 +49,11 @@ PNG.sync = PNGSync;
PNG.prototype.pack = function() {
if (!this.data || !this.data.length) {
this.emit('error', 'No data provided');
return this;
}
process.nextTick(function() {
this._packer.pack(this.data, this.width, this.height);
}.bind(this));

View file

@ -15,9 +15,15 @@ module.exports = function(done) {
var completed = 0;
var expected = files.length * 2;
function complete() {
var anyFailures = false;
function complete(isSuccessful) {
completed++;
anyFailures = anyFailures || !isSuccessful;
if (expected === completed) {
if (anyFailures) {
process.exit(1);
return;
}
done();
}
}
@ -41,13 +47,13 @@ module.exports = function(done) {
console.log(e.stack);
}
syncError = true;
complete();
complete(expectedError);
}
if (!syncError) {
if (expectedError) {
console.log("Sync: Error expected, parsed fine ..", file);
complete();
complete(false);
} else {
var outpng = new PNG();
@ -58,7 +64,7 @@ module.exports = function(done) {
outpng.pack()
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file)
.on("finish", function () {
complete();
complete(true);
}));
}
}
@ -69,7 +75,7 @@ module.exports = function(done) {
if (!expectedError) {
console.log("Async: Unexpected error parsing.." + file, err);
}
complete();
complete(expectedError);
})
.on('parsed', function () {
@ -82,11 +88,9 @@ module.exports = function(done) {
.pipe(
fs.createWriteStream(__dirname + '/out/' + file)
.on("finish", function() {
complete();
complete(true);
}));
});
});
});
}