mirror of
https://github.com/danbulant/pngjs
synced 2026-07-05 19:20:38 +00:00
poc to support colortype 2
This commit is contained in:
parent
75d2927e75
commit
83d60edeaf
7 changed files with 51 additions and 47 deletions
0
lib/chunkstream.js
Executable file → Normal file
0
lib/chunkstream.js
Executable file → Normal file
0
lib/constants.js
Executable file → Normal file
0
lib/constants.js
Executable file → Normal file
0
lib/crc.js
Executable file → Normal file
0
lib/crc.js
Executable file → Normal file
|
|
@ -3,7 +3,6 @@
|
||||||
var paethPredictor = require('./paeth-predictor');
|
var paethPredictor = require('./paeth-predictor');
|
||||||
|
|
||||||
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
|
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||||
|
|
||||||
pxData.copy(rawData, rawPos, pxPos, pxPos + byteWidth);
|
pxData.copy(rawData, rawPos, pxPos, pxPos + byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,23 +17,23 @@ function filterSumNone(pxData, pxPos, byteWidth) {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos) {
|
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||||
|
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var val = pxData[pxPos + x] - left;
|
var val = pxData[pxPos + x] - left;
|
||||||
|
|
||||||
rawData[rawPos + x] = val;
|
rawData[rawPos + x] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSumSub(pxData, pxPos, byteWidth) {
|
function filterSumSub(pxData, pxPos, byteWidth, BPP) {
|
||||||
|
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var val = pxData[pxPos + x] - left;
|
var val = pxData[pxPos + x] - left;
|
||||||
|
|
||||||
sum += Math.abs(val);
|
sum += Math.abs(val);
|
||||||
|
|
@ -43,7 +42,7 @@ function filterSumSub(pxData, pxPos, byteWidth) {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
|
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||||
|
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
|
|
@ -54,7 +53,7 @@ function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSumUp(pxData, pxPos, byteWidth) {
|
function filterSumUp(pxData, pxPos, byteWidth, BPP) {
|
||||||
|
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
var length = pxPos + byteWidth;
|
var length = pxPos + byteWidth;
|
||||||
|
|
@ -69,11 +68,11 @@ function filterSumUp(pxData, pxPos, byteWidth) {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos) {
|
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||||
|
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
||||||
var val = pxData[pxPos + x] - ((left + up) >> 1);
|
var val = pxData[pxPos + x] - ((left + up) >> 1);
|
||||||
|
|
||||||
|
|
@ -81,12 +80,12 @@ function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSumAvg(pxData, pxPos, byteWidth) {
|
function filterSumAvg(pxData, pxPos, byteWidth, BPP) {
|
||||||
|
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
||||||
var val = pxData[pxPos + x] - ((left + up) >> 1);
|
var val = pxData[pxPos + x] - ((left + up) >> 1);
|
||||||
|
|
||||||
|
|
@ -96,27 +95,26 @@ function filterSumAvg(pxData, pxPos, byteWidth) {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos) {
|
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||||
|
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
||||||
var upleft = pxPos > 0 && x >= 4 ? pxData[pxPos + x - (byteWidth + 4)] : 0;
|
var upleft = pxPos > 0 && x >= BPP ? pxData[pxPos + x - (byteWidth + BPP)] : 0;
|
||||||
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
||||||
|
|
||||||
rawData[rawPos + x] = val;
|
rawData[rawPos + x] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSumPaeth(pxData, pxPos, byteWidth) {
|
function filterSumPaeth(pxData, pxPos, byteWidth, BPP) {
|
||||||
|
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var x = 0; x < byteWidth; x++) {
|
for (var x = 0; x < byteWidth; x++) {
|
||||||
|
|
||||||
var left = x >= 4 ? pxData[pxPos + x - 4] : 0;
|
var left = x >= BPP ? pxData[pxPos + x - BPP] : 0;
|
||||||
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
|
||||||
var upleft = pxPos > 0 && x >= 4 ? pxData[pxPos + x - (byteWidth + 4)] : 0;
|
var upleft = pxPos > 0 && x >= BPP ? pxData[pxPos + x - (byteWidth + BPP)] : 0;
|
||||||
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
var val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
|
||||||
|
|
||||||
sum += Math.abs(val);
|
sum += Math.abs(val);
|
||||||
|
|
@ -141,7 +139,7 @@ var filterSums = {
|
||||||
4: filterSumPaeth
|
4: filterSumPaeth
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = function(pxData, width, height, options) {
|
module.exports = function(pxData, width, height, options, bpp) {
|
||||||
|
|
||||||
var filterTypes;
|
var filterTypes;
|
||||||
if (!('filterType' in options) || options.filterType === -1) {
|
if (!('filterType' in options) || options.filterType === -1) {
|
||||||
|
|
@ -154,7 +152,7 @@ module.exports = function(pxData, width, height, options) {
|
||||||
throw new Error('unrecognised filter types');
|
throw new Error('unrecognised filter types');
|
||||||
}
|
}
|
||||||
|
|
||||||
var byteWidth = width << 2;
|
var byteWidth = width * bpp;
|
||||||
var rawPos = 0;
|
var rawPos = 0;
|
||||||
var pxPos = 0;
|
var pxPos = 0;
|
||||||
var rawData = new Buffer((byteWidth + 1) * height);
|
var rawData = new Buffer((byteWidth + 1) * height);
|
||||||
|
|
@ -167,8 +165,7 @@ module.exports = function(pxData, width, height, options) {
|
||||||
var min = Infinity;
|
var min = Infinity;
|
||||||
|
|
||||||
for (var i = 0; i < filterTypes.length; i++) {
|
for (var i = 0; i < filterTypes.length; i++) {
|
||||||
var sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth);
|
var sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
|
||||||
|
|
||||||
if (sum < min) {
|
if (sum < min) {
|
||||||
sel = filterTypes[i];
|
sel = filterTypes[i];
|
||||||
min = sum;
|
min = sum;
|
||||||
|
|
@ -178,9 +175,9 @@ module.exports = function(pxData, width, height, options) {
|
||||||
|
|
||||||
rawData[rawPos] = sel;
|
rawData[rawPos] = sel;
|
||||||
rawPos++;
|
rawPos++;
|
||||||
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos);
|
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
|
||||||
rawPos += byteWidth;
|
rawPos += byteWidth;
|
||||||
pxPos += byteWidth;
|
pxPos += byteWidth;
|
||||||
}
|
}
|
||||||
return rawData;
|
return rawData;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
19
lib/packer.js
Executable file → Normal file
19
lib/packer.js
Executable file → Normal file
|
|
@ -8,6 +8,8 @@ var filter = require('./filter-pack');
|
||||||
var CrcStream = require('./crc');
|
var CrcStream = require('./crc');
|
||||||
var constants = require('./constants');
|
var constants = require('./constants');
|
||||||
|
|
||||||
|
var COLOR_TYPE_TRUECOLOR = 2;
|
||||||
|
var COLOR_TYPE_TRUECOLOR_WITH_ALPHA = 6;
|
||||||
|
|
||||||
var Packer = module.exports = function(options) {
|
var Packer = module.exports = function(options) {
|
||||||
Stream.call(this);
|
Stream.call(this);
|
||||||
|
|
@ -18,6 +20,8 @@ var Packer = module.exports = function(options) {
|
||||||
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
|
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
|
||||||
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
|
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
|
||||||
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
|
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
|
||||||
|
options.bitDepth = options.bitDepth || 8;
|
||||||
|
options.colorType = (typeof options.colorType=="number") ? options.colorType : COLOR_TYPE_TRUECOLOR_WITH_ALPHA;
|
||||||
|
|
||||||
this.readable = true;
|
this.readable = true;
|
||||||
};
|
};
|
||||||
|
|
@ -25,17 +29,20 @@ util.inherits(Packer, Stream);
|
||||||
|
|
||||||
|
|
||||||
Packer.prototype.pack = function(data, width, height, gamma) {
|
Packer.prototype.pack = function(data, width, height, gamma) {
|
||||||
|
|
||||||
// Signature
|
// Signature
|
||||||
this.emit('data', new Buffer(constants.PNG_SIGNATURE));
|
this.emit('data', new Buffer(constants.PNG_SIGNATURE));
|
||||||
this.emit('data', this._packIHDR(width, height));
|
this.emit('data', this._packIHDR(width, height, this._options.bitDepth, this._options.colorType));
|
||||||
|
|
||||||
if (gamma) {
|
if (gamma) {
|
||||||
this.emit('data', this._packGAMA(gamma));
|
this.emit('data', this._packGAMA(gamma));
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter pixel data
|
// filter pixel data
|
||||||
var filteredData = filter(data, width, height, this._options);
|
var bpp = 4;
|
||||||
|
if (this._options.colorType === COLOR_TYPE_TRUECOLOR) {
|
||||||
|
bpp = 3;
|
||||||
|
}
|
||||||
|
var filteredData = filter(data, width, height, this._options, bpp);
|
||||||
|
|
||||||
// compress it
|
// compress it
|
||||||
var deflate = this._options.deflateFactory({
|
var deflate = this._options.deflateFactory({
|
||||||
|
|
@ -79,13 +86,13 @@ Packer.prototype._packGAMA = function(gamma) {
|
||||||
return this._packChunk(constants.TYPE_gAMA, buf);
|
return this._packChunk(constants.TYPE_gAMA, buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
Packer.prototype._packIHDR = function(width, height) {
|
Packer.prototype._packIHDR = function(width, height, bitDepth, colorType) {
|
||||||
|
|
||||||
var buf = new Buffer(13);
|
var buf = new Buffer(13);
|
||||||
buf.writeUInt32BE(width, 0);
|
buf.writeUInt32BE(width, 0);
|
||||||
buf.writeUInt32BE(height, 4);
|
buf.writeUInt32BE(height, 4);
|
||||||
buf[8] = 8;
|
buf[8] = bitDepth; // Bit depth
|
||||||
buf[9] = 6; // colorType
|
buf[9] = colorType; // colorType
|
||||||
buf[10] = 0; // compression
|
buf[10] = 0; // compression
|
||||||
buf[11] = 0; // filter
|
buf[11] = 0; // filter
|
||||||
buf[12] = 0; // interlace
|
buf[12] = 0; // interlace
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = function paethPredictor(left, above, upLeft) {
|
module.exports = function paethPredictor(left, above, upLeft) {
|
||||||
|
|
||||||
var paeth = left + above - upLeft;
|
var paeth = left + above - upLeft;
|
||||||
var pLeft = Math.abs(paeth - left);
|
var pLeft = Math.abs(paeth - left);
|
||||||
var pAbove = Math.abs(paeth - above);
|
var pAbove = Math.abs(paeth - above);
|
||||||
var pUpLeft = Math.abs(paeth - upLeft);
|
var pUpLeft = Math.abs(paeth - upLeft);
|
||||||
|
|
||||||
if (pLeft <= pAbove && pLeft <= pUpLeft) {
|
if (pLeft <= pAbove && pLeft <= pUpLeft) {
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
if (pAbove <= pUpLeft) {
|
if (pAbove <= pUpLeft) {
|
||||||
return above;
|
return above;
|
||||||
}
|
}
|
||||||
return upLeft;
|
return upLeft;
|
||||||
};
|
};
|
||||||
2
lib/png.js
Executable file → Normal file
2
lib/png.js
Executable file → Normal file
|
|
@ -160,4 +160,4 @@ PNG.adjustGamma = function(src) {
|
||||||
|
|
||||||
PNG.prototype.adjustGamma = function() {
|
PNG.prototype.adjustGamma = function() {
|
||||||
PNG.adjustGamma(this);
|
PNG.adjustGamma(this);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue