mirror of
https://github.com/danbulant/pngjs
synced 2026-07-07 20:20:45 +00:00
Pull out format normaliser. Fix #18
This commit is contained in:
parent
8cf14b9ca2
commit
71a371d6cd
7 changed files with 131 additions and 93 deletions
|
|
@ -129,7 +129,7 @@
|
||||||
"generator-star-spacing": 0,
|
"generator-star-spacing": 0,
|
||||||
"guard-for-in": 1,
|
"guard-for-in": 1,
|
||||||
"handle-callback-err": 2,
|
"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}],
|
"indent": [1, 2, {"SwitchCase": 1}],
|
||||||
"init-declarations": 0,
|
"init-declarations": 0,
|
||||||
"key-spacing": [1, { "beforeColon": false, "afterColon": true }],
|
"key-spacing": [1, { "beforeColon": false, "afterColon": true }],
|
||||||
|
|
|
||||||
89
lib/format-normaliser.js
Normal file
89
lib/format-normaliser.js
Normal 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;
|
||||||
|
};
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var zlib = require('zlib');
|
var zlib = require('zlib');
|
||||||
var ChunkStream = require('./chunkstream');
|
var ChunkStream = require('./chunkstream');
|
||||||
var FilterAsync = require('./filter-async');
|
var FilterAsync = require('./filter-async');
|
||||||
var Parser = require('./parser');
|
var Parser = require('./parser');
|
||||||
var bitmapper = require('./bitmapper');
|
var bitmapper = require('./bitmapper');
|
||||||
|
var formatNormaliser = require('./format-normaliser');
|
||||||
|
|
||||||
var ParserAsync = module.exports = function(options) {
|
var ParserAsync = module.exports = function(options) {
|
||||||
ChunkStream.call(this);
|
ChunkStream.call(this);
|
||||||
|
|
@ -98,7 +97,14 @@ ParserAsync.prototype._complete = function(filteredData, width, height) {
|
||||||
this._depth,
|
this._depth,
|
||||||
this._interlace);
|
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) {
|
catch (ex) {
|
||||||
this._handleError(ex);
|
this._handleError(ex);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ var SyncReader = require('./sync-reader');
|
||||||
var FilterSync = require('./filter-sync');
|
var FilterSync = require('./filter-sync');
|
||||||
var Parser = require('./parser');
|
var Parser = require('./parser');
|
||||||
var bitmapper = require('./bitmapper');
|
var bitmapper = require('./bitmapper');
|
||||||
|
var formatNormaliser = require('./format-normaliser');
|
||||||
|
|
||||||
|
|
||||||
var ParserSync = module.exports = function(buffer, options) {
|
var ParserSync = module.exports = function(buffer, options) {
|
||||||
|
|
@ -33,6 +34,10 @@ var ParserSync = module.exports = function(buffer, options) {
|
||||||
|
|
||||||
var data = zlib.inflateSync(inflateData);
|
var data = zlib.inflateSync(inflateData);
|
||||||
|
|
||||||
|
if (!data || !data.length) {
|
||||||
|
throw new Error('bad png - invalid inflate data response');
|
||||||
|
}
|
||||||
|
|
||||||
data = FilterSync.process(
|
data = FilterSync.process(
|
||||||
data,
|
data,
|
||||||
this._width, this._height,
|
this._width, this._height,
|
||||||
|
|
@ -41,13 +46,19 @@ var ParserSync = module.exports = function(buffer, options) {
|
||||||
this._interlace,
|
this._interlace,
|
||||||
this._options
|
this._options
|
||||||
);
|
);
|
||||||
|
// todo do not store _data
|
||||||
this._data = bitmapper.dataToBitMap(data, this._width, this._height,
|
this._data = bitmapper.dataToBitMap(data, this._width, this._height,
|
||||||
this._bpp,
|
this._bpp,
|
||||||
this._depth,
|
this._depth,
|
||||||
this._interlace);
|
this._interlace);
|
||||||
// todo yuck
|
|
||||||
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) {
|
ParserSync.prototype._handleError = function(err) {
|
||||||
|
|
@ -73,5 +84,5 @@ ParserSync.prototype._createData = function(width, height, bpp, depth, interlace
|
||||||
this._height = height;
|
this._height = height;
|
||||||
this._depth = depth;
|
this._depth = depth;
|
||||||
this._interlace = interlace;
|
this._interlace = interlace;
|
||||||
return this._data;
|
return this._data; // todo do not return
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,6 @@ Parser.prototype._parseIDAT = function(length, data) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Parser.prototype._handleIEND = function(length) {
|
Parser.prototype._handleIEND = function(length) {
|
||||||
this.read(length, this._parseIEND.bind(this));
|
this.read(length, this._parseIEND.bind(this));
|
||||||
};
|
};
|
||||||
|
|
@ -289,79 +288,3 @@ Parser.prototype._parseIEND = function(data) {
|
||||||
|
|
||||||
this.finished();
|
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,11 @@ PNG.sync = PNGSync;
|
||||||
|
|
||||||
PNG.prototype.pack = function() {
|
PNG.prototype.pack = function() {
|
||||||
|
|
||||||
|
if (!this.data || !this.data.length) {
|
||||||
|
this.emit('error', 'No data provided');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
this._packer.pack(this.data, this.width, this.height);
|
this._packer.pack(this.data, this.width, this.height);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,15 @@ module.exports = function(done) {
|
||||||
|
|
||||||
var completed = 0;
|
var completed = 0;
|
||||||
var expected = files.length * 2;
|
var expected = files.length * 2;
|
||||||
function complete() {
|
var anyFailures = false;
|
||||||
|
function complete(isSuccessful) {
|
||||||
completed++;
|
completed++;
|
||||||
|
anyFailures = anyFailures || !isSuccessful;
|
||||||
if (expected === completed) {
|
if (expected === completed) {
|
||||||
|
if (anyFailures) {
|
||||||
|
process.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,13 +47,13 @@ module.exports = function(done) {
|
||||||
console.log(e.stack);
|
console.log(e.stack);
|
||||||
}
|
}
|
||||||
syncError = true;
|
syncError = true;
|
||||||
complete();
|
complete(expectedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!syncError) {
|
if (!syncError) {
|
||||||
if (expectedError) {
|
if (expectedError) {
|
||||||
console.log("Sync: Error expected, parsed fine ..", file);
|
console.log("Sync: Error expected, parsed fine ..", file);
|
||||||
complete();
|
complete(false);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var outpng = new PNG();
|
var outpng = new PNG();
|
||||||
|
|
@ -58,7 +64,7 @@ module.exports = function(done) {
|
||||||
outpng.pack()
|
outpng.pack()
|
||||||
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file)
|
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file)
|
||||||
.on("finish", function () {
|
.on("finish", function () {
|
||||||
complete();
|
complete(true);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +75,7 @@ module.exports = function(done) {
|
||||||
if (!expectedError) {
|
if (!expectedError) {
|
||||||
console.log("Async: Unexpected error parsing.." + file, err);
|
console.log("Async: Unexpected error parsing.." + file, err);
|
||||||
}
|
}
|
||||||
complete();
|
complete(expectedError);
|
||||||
})
|
})
|
||||||
.on('parsed', function () {
|
.on('parsed', function () {
|
||||||
|
|
||||||
|
|
@ -82,11 +88,9 @@ module.exports = function(done) {
|
||||||
.pipe(
|
.pipe(
|
||||||
fs.createWriteStream(__dirname + '/out/' + file)
|
fs.createWriteStream(__dirname + '/out/' + file)
|
||||||
.on("finish", function() {
|
.on("finish", function() {
|
||||||
complete();
|
complete(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue