poc to support colortype 2

This commit is contained in:
michuNEEO 2015-09-13 14:31:22 +02:00
parent 75d2927e75
commit 83d60edeaf
7 changed files with 51 additions and 47 deletions

0
lib/chunkstream.js Executable file → Normal file
View file

0
lib/constants.js Executable file → Normal file
View file

0
lib/crc.js Executable file → Normal file
View file

View 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
View 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

View file

@ -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
View file

@ -160,4 +160,4 @@ PNG.adjustGamma = function(src) {
PNG.prototype.adjustGamma = function() { PNG.prototype.adjustGamma = function() {
PNG.adjustGamma(this); PNG.adjustGamma(this);
}; };