mirror of
https://github.com/danbulant/pngjs
synced 2026-06-17 05:21:11 +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');
|
||||
|
||||
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||
|
||||
pxData.copy(rawData, rawPos, pxPos, pxPos + byteWidth);
|
||||
}
|
||||
|
||||
|
|
@ -18,23 +17,23 @@ function filterSumNone(pxData, pxPos, byteWidth) {
|
|||
return sum;
|
||||
}
|
||||
|
||||
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||
|
||||
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;
|
||||
|
||||
rawData[rawPos + x] = val;
|
||||
}
|
||||
}
|
||||
|
||||
function filterSumSub(pxData, pxPos, byteWidth) {
|
||||
function filterSumSub(pxData, pxPos, byteWidth, BPP) {
|
||||
|
||||
var sum = 0;
|
||||
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;
|
||||
|
||||
sum += Math.abs(val);
|
||||
|
|
@ -43,7 +42,7 @@ function filterSumSub(pxData, pxPos, byteWidth) {
|
|||
return sum;
|
||||
}
|
||||
|
||||
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||
|
||||
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 length = pxPos + byteWidth;
|
||||
|
|
@ -69,11 +68,11 @@ function filterSumUp(pxData, pxPos, byteWidth) {
|
|||
return sum;
|
||||
}
|
||||
|
||||
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||
|
||||
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 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;
|
||||
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 val = pxData[pxPos + x] - ((left + up) >> 1);
|
||||
|
||||
|
|
@ -96,27 +95,26 @@ function filterSumAvg(pxData, pxPos, byteWidth) {
|
|||
return sum;
|
||||
}
|
||||
|
||||
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos) {
|
||||
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, BPP) {
|
||||
|
||||
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 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);
|
||||
|
||||
rawData[rawPos + x] = val;
|
||||
}
|
||||
}
|
||||
|
||||
function filterSumPaeth(pxData, pxPos, byteWidth) {
|
||||
|
||||
function filterSumPaeth(pxData, pxPos, byteWidth, BPP) {
|
||||
var sum = 0;
|
||||
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 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);
|
||||
|
||||
sum += Math.abs(val);
|
||||
|
|
@ -141,7 +139,7 @@ var filterSums = {
|
|||
4: filterSumPaeth
|
||||
};
|
||||
|
||||
module.exports = function(pxData, width, height, options) {
|
||||
module.exports = function(pxData, width, height, options, bpp) {
|
||||
|
||||
var filterTypes;
|
||||
if (!('filterType' in options) || options.filterType === -1) {
|
||||
|
|
@ -154,7 +152,7 @@ module.exports = function(pxData, width, height, options) {
|
|||
throw new Error('unrecognised filter types');
|
||||
}
|
||||
|
||||
var byteWidth = width << 2;
|
||||
var byteWidth = width * bpp;
|
||||
var rawPos = 0;
|
||||
var pxPos = 0;
|
||||
var rawData = new Buffer((byteWidth + 1) * height);
|
||||
|
|
@ -167,8 +165,7 @@ module.exports = function(pxData, width, height, options) {
|
|||
var min = Infinity;
|
||||
|
||||
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) {
|
||||
sel = filterTypes[i];
|
||||
min = sum;
|
||||
|
|
@ -178,9 +175,9 @@ module.exports = function(pxData, width, height, options) {
|
|||
|
||||
rawData[rawPos] = sel;
|
||||
rawPos++;
|
||||
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos);
|
||||
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
|
||||
rawPos += byteWidth;
|
||||
pxPos += byteWidth;
|
||||
}
|
||||
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 constants = require('./constants');
|
||||
|
||||
var COLOR_TYPE_TRUECOLOR = 2;
|
||||
var COLOR_TYPE_TRUECOLOR_WITH_ALPHA = 6;
|
||||
|
||||
var Packer = module.exports = function(options) {
|
||||
Stream.call(this);
|
||||
|
|
@ -18,6 +20,8 @@ var Packer = module.exports = function(options) {
|
|||
options.deflateLevel = options.deflateLevel != null ? options.deflateLevel : 9;
|
||||
options.deflateStrategy = options.deflateStrategy != null ? options.deflateStrategy : 3;
|
||||
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;
|
||||
};
|
||||
|
|
@ -25,17 +29,20 @@ util.inherits(Packer, Stream);
|
|||
|
||||
|
||||
Packer.prototype.pack = function(data, width, height, gamma) {
|
||||
|
||||
// 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) {
|
||||
this.emit('data', this._packGAMA(gamma));
|
||||
}
|
||||
|
||||
// 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
|
||||
var deflate = this._options.deflateFactory({
|
||||
|
|
@ -79,13 +86,13 @@ Packer.prototype._packGAMA = function(gamma) {
|
|||
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);
|
||||
buf.writeUInt32BE(width, 0);
|
||||
buf.writeUInt32BE(height, 4);
|
||||
buf[8] = 8;
|
||||
buf[9] = 6; // colorType
|
||||
buf[8] = bitDepth; // Bit depth
|
||||
buf[9] = colorType; // colorType
|
||||
buf[10] = 0; // compression
|
||||
buf[11] = 0; // filter
|
||||
buf[12] = 0; // interlace
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = function paethPredictor(left, above, upLeft) {
|
||||
|
||||
var paeth = left + above - upLeft;
|
||||
var pLeft = Math.abs(paeth - left);
|
||||
var pAbove = Math.abs(paeth - above);
|
||||
var pUpLeft = Math.abs(paeth - upLeft);
|
||||
|
||||
if (pLeft <= pAbove && pLeft <= pUpLeft) {
|
||||
return left;
|
||||
}
|
||||
if (pAbove <= pUpLeft) {
|
||||
return above;
|
||||
}
|
||||
return upLeft;
|
||||
'use strict';
|
||||
|
||||
module.exports = function paethPredictor(left, above, upLeft) {
|
||||
|
||||
var paeth = left + above - upLeft;
|
||||
var pLeft = Math.abs(paeth - left);
|
||||
var pAbove = Math.abs(paeth - above);
|
||||
var pUpLeft = Math.abs(paeth - upLeft);
|
||||
|
||||
if (pLeft <= pAbove && pLeft <= pUpLeft) {
|
||||
return left;
|
||||
}
|
||||
if (pAbove <= pUpLeft) {
|
||||
return above;
|
||||
}
|
||||
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.adjustGamma(this);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue