mirror of
https://github.com/danbulant/pngjs
synced 2026-06-17 21:41:10 +00:00
Support for 1,2,4 bits PNG
This commit is contained in:
parent
807ffcd66f
commit
d601f60c79
10 changed files with 278 additions and 154 deletions
120
lib/bitmapper.js
Normal file
120
lib/bitmapper.js
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
function bitRetriever(data, depth) {
|
||||
|
||||
var leftOver = [];
|
||||
var i = 0;
|
||||
function split() {
|
||||
var byte = data[i];
|
||||
i++;
|
||||
switch(depth) {
|
||||
default:
|
||||
throw new Error("unrecognised depth");
|
||||
break;
|
||||
/* case 8:
|
||||
leftOver.push(byte);
|
||||
break;*/
|
||||
case 4:
|
||||
var byte2 = byte & 0x0f;
|
||||
var byte1 = byte >> 4;
|
||||
leftOver.push(byte1, byte2);
|
||||
break;
|
||||
case 2:
|
||||
var byte4 = byte & 3;
|
||||
var byte3 = byte >> 2 & 3;
|
||||
var byte2 = byte >> 4 & 3;
|
||||
var byte1 = byte >> 6 & 3;
|
||||
leftOver.push(byte1, byte2, byte3, byte4);
|
||||
break;
|
||||
case 1:
|
||||
var byte8 = byte & 1;
|
||||
var byte7 = byte >> 1 & 1;
|
||||
var byte6 = byte >> 2 & 1;
|
||||
var byte5 = byte >> 3 & 1;
|
||||
var byte4 = byte >> 4 & 1;
|
||||
var byte3 = byte >> 5 & 1;
|
||||
var byte2 = byte >> 6 & 1;
|
||||
var byte1 = byte >> 7 & 1;
|
||||
leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
get: function(count) {
|
||||
var returner;
|
||||
if (depth === 8) {
|
||||
returner = data.slice(i, i + count);
|
||||
i += count;
|
||||
return returner;
|
||||
}
|
||||
while(leftOver.length < count) {
|
||||
split();
|
||||
}
|
||||
returner = leftOver.slice(0, count);
|
||||
leftOver = leftOver.slice(count);
|
||||
return returner;
|
||||
},
|
||||
resetAfterLine: function() {
|
||||
leftOver.length = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.dataToBitMap = function(data, width, height, bpp, depth) {
|
||||
if (depth !== 8) {
|
||||
var bits = bitRetriever(data, depth);
|
||||
}
|
||||
var pxData = new Buffer(width * height * 4);
|
||||
var pxPos = 0;
|
||||
var maxBit = Math.pow(2, depth) - 1;
|
||||
var rawPos = 0;
|
||||
var pixelData;
|
||||
|
||||
for(var y = 0; y < height; y++) {
|
||||
for(var x = 0; x < width; x++) {
|
||||
if (depth !== 8) {
|
||||
pixelData = bits.get(bpp);
|
||||
}
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[bpp][i];
|
||||
if (depth === 8) {
|
||||
pxData[pxPos] = idx !== 0xff ? data[idx + rawPos] : maxBit;
|
||||
} else {
|
||||
pxData[pxPos] = idx !== 0xff ? pixelData[idx] : maxBit;
|
||||
}
|
||||
pxPos++;
|
||||
}
|
||||
rawPos += bpp;
|
||||
}
|
||||
if (depth !== 8) {
|
||||
bits.resetAfterLine();
|
||||
}
|
||||
}
|
||||
|
||||
return pxData;
|
||||
};
|
||||
|
||||
var pixelBppMap = {
|
||||
1: { // L
|
||||
0: 0,
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 0xff
|
||||
},
|
||||
2: { // LA
|
||||
0: 0,
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 1
|
||||
},
|
||||
3: { // RGB
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 0xff
|
||||
},
|
||||
4: { // RGBA
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3
|
||||
}
|
||||
};
|
||||
|
|
@ -25,12 +25,19 @@ var util = require('util'),
|
|||
Filter = require('./filter');
|
||||
|
||||
|
||||
var FilterAsync = module.exports = function(width, height, Bpp, data, options) {
|
||||
var FilterAsync = module.exports = function(width, height, Bpp, depth, options) {
|
||||
ChunkStream.call(this);
|
||||
|
||||
this._filter = new Filter(width, height, Bpp, data, options, {
|
||||
var buffers = [];
|
||||
var that = this;
|
||||
this._filter = new Filter(width, height, Bpp, depth, options, {
|
||||
read: this.read.bind(this),
|
||||
complete: this.emit.bind(this, 'complete')
|
||||
complete: function(width, height) {
|
||||
that.emit('complete', Buffer.concat(buffers), width, height)
|
||||
},
|
||||
write: function(buffer) {
|
||||
buffers.push(buffer);
|
||||
}
|
||||
});
|
||||
|
||||
this._filter.start();
|
||||
|
|
|
|||
|
|
@ -24,14 +24,20 @@ var SyncReader = require('./sync-reader'),
|
|||
Filter = require('./filter');
|
||||
|
||||
|
||||
exports.process = function(buffer, width, height, Bpp, outData, options) {
|
||||
exports.process = function(buffer, width, height, Bpp, depth, options) {
|
||||
|
||||
var buffers = [];
|
||||
var reader = new SyncReader(buffer);
|
||||
var filter = new Filter(width, height, Bpp, outData, options, {
|
||||
var filter = new Filter(width, height, Bpp, depth, options, {
|
||||
read: reader.read.bind(reader),
|
||||
write: function(buffer) {
|
||||
buffers.push(buffer);
|
||||
},
|
||||
complete: function(){}
|
||||
});
|
||||
|
||||
filter.start();
|
||||
reader.process();
|
||||
|
||||
return Buffer.concat(buffers);
|
||||
};
|
||||
170
lib/filter.js
170
lib/filter.js
|
|
@ -20,16 +20,15 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var util = require('util'),
|
||||
ChunkStream = require('./chunkstream');
|
||||
var util = require('util');
|
||||
|
||||
|
||||
var Filter = module.exports = function(width, height, Bpp, data, options, dependencies) {
|
||||
var Filter = module.exports = function(width, height, Bpp, depth, options, dependencies) {
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._Bpp = Bpp;
|
||||
this._data = data;
|
||||
this._depth = depth;
|
||||
this._options = options;
|
||||
|
||||
this._line = 0;
|
||||
|
|
@ -49,135 +48,80 @@ var Filter = module.exports = function(width, height, Bpp, data, options, depend
|
|||
};
|
||||
|
||||
this.read = dependencies.read;
|
||||
this.write = dependencies.write;
|
||||
this.complete = dependencies.complete;
|
||||
|
||||
var byteWidth = this._width * this._Bpp;
|
||||
if (this._depth !== 8) {
|
||||
byteWidth = Math.ceil(byteWidth / (8 / this._depth));
|
||||
}
|
||||
this._byteWidth = byteWidth;
|
||||
};
|
||||
|
||||
Filter.prototype.start = function() {
|
||||
this.read(this._width * this._Bpp + 1, this._reverseFilterLine.bind(this));
|
||||
};
|
||||
|
||||
var pixelBppMap = {
|
||||
1: { // L
|
||||
0: 0,
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 0xff
|
||||
},
|
||||
2: { // LA
|
||||
0: 0,
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 1
|
||||
},
|
||||
3: { // RGB
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 0xff
|
||||
},
|
||||
4: { // RGBA
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3
|
||||
}
|
||||
this.read(this._byteWidth + 1, this._reverseFilterLine.bind(this));
|
||||
};
|
||||
|
||||
Filter.prototype._reverseFilterLine = function(rawData) {
|
||||
|
||||
var pxData = this._data,
|
||||
pxLineLength = this._width << 2,
|
||||
pxRowPos = this._line * pxLineLength,
|
||||
filter = rawData[0];
|
||||
var line = new Buffer(this._byteWidth);
|
||||
|
||||
if (filter == 0) {
|
||||
for (var x = 0; x < this._width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2),
|
||||
rawPos = 1 + x * this._Bpp;
|
||||
var filter = rawData[0];
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[this._Bpp][i];
|
||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] : 0xff;
|
||||
}
|
||||
var xComparison = this._depth === 8 ? this._Bpp : 1;
|
||||
var xBiggerThan = xComparison - 1;
|
||||
|
||||
for (var x = 0; x < this._byteWidth; x++) {
|
||||
var rawByte = rawData[1 + x];
|
||||
switch(filter) {
|
||||
case 0:
|
||||
line[x] = rawByte;
|
||||
break;
|
||||
case 1:
|
||||
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||
line[x] = rawByte + left;
|
||||
break;
|
||||
case 2:
|
||||
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||
line[x] = rawByte + up;
|
||||
break;
|
||||
case 3:
|
||||
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||
var add = Math.floor((left + up) / 2);
|
||||
line[x] = rawByte + add;
|
||||
break;
|
||||
case 4:
|
||||
var up = this._lastLine ? this._lastLine[x] : 0;
|
||||
var left = x > xBiggerThan ? line[x - xComparison] : 0;
|
||||
var upLeft = x > xBiggerThan && this._lastLine
|
||||
? this._lastLine[x - xComparison] : 0;
|
||||
var add = PaethPredictor(left, up, upLeft);
|
||||
line[x] = rawByte + add;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (filter == 1) {
|
||||
for (var x = 0; x < this._width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2),
|
||||
rawPos = 1 + x * this._Bpp;
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[this._Bpp][i],
|
||||
left = x > 0 ? pxData[pxPos + i - 4] : 0;
|
||||
|
||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + left : 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (filter == 2) {
|
||||
for (var x = 0; x < this._width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2),
|
||||
rawPos = 1 + x * this._Bpp;
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[this._Bpp][i],
|
||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0;
|
||||
|
||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + up : 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (filter == 3) {
|
||||
for (var x = 0; x < this._width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2),
|
||||
rawPos = 1 + x * this._Bpp;
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[this._Bpp][i],
|
||||
left = x > 0 ? pxData[pxPos + i - 4] : 0,
|
||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0,
|
||||
add = Math.floor((left + up) / 2);
|
||||
|
||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + add : 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (filter == 4) {
|
||||
for (var x = 0; x < this._width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2),
|
||||
rawPos = 1 + x * this._Bpp;
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var idx = pixelBppMap[this._Bpp][i],
|
||||
left = x > 0 ? pxData[pxPos + i - 4] : 0,
|
||||
up = this._line > 0 ? pxData[pxPos - pxLineLength + i] : 0,
|
||||
upLeft = x > 0 && this._line > 0
|
||||
? pxData[pxPos - pxLineLength + i - 4] : 0,
|
||||
add = PaethPredictor(left, up, upLeft);
|
||||
|
||||
pxData[pxPos + i] = idx != 0xff ? rawData[rawPos + idx] + add : 0xff;
|
||||
}
|
||||
}
|
||||
//if (x === 5) {
|
||||
// console.log("R", line[3], "G", line[4], "B", line[5]);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
this._line++;
|
||||
this._lastLine = line;
|
||||
this.write(line);
|
||||
|
||||
if (this._line < this._height)
|
||||
this.read(this._width * this._Bpp + 1, this._reverseFilterLine.bind(this));
|
||||
else
|
||||
this.complete(this._data, this._width, this._height);
|
||||
if (this._line < this._height) {
|
||||
this.read(this._byteWidth + 1, this._reverseFilterLine.bind(this));
|
||||
} else {
|
||||
this._lastLine = null;
|
||||
this.complete(this._width, this._height);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Filter.prototype.filter = function(pxData) {
|
||||
|
||||
|
||||
Filter.prototype.filter = function() {
|
||||
|
||||
var pxData = this._data,
|
||||
rawData = new Buffer(((this._width << 2) + 1) * this._height);
|
||||
var rawData = new Buffer(((this._width << 2) + 1) * this._height);
|
||||
|
||||
for (var y = 0; y < this._height; y++) {
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,9 @@ Packer.prototype.pack = function(data, width, height) {
|
|||
this.emit('data', this._packIHDR(width, height));
|
||||
|
||||
// filter pixel data
|
||||
var filter = new Filter(width, height, 4, data, this._options, {});
|
||||
var data = filter.filter();
|
||||
//TODO {}
|
||||
var filter = new Filter(width, height, 4, 8, this._options, {});
|
||||
var data = filter.filter(data);
|
||||
|
||||
// compress it
|
||||
var deflate = zlib.createDeflate({
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ var util = require('util'),
|
|||
zlib = require('zlib'),
|
||||
ChunkStream = require('./chunkstream'),
|
||||
FilterAsync = require('./filter-async'),
|
||||
Parser = require('./parser');
|
||||
Parser = require('./parser'),
|
||||
bitmapper = require('./bitmapper');
|
||||
|
||||
|
||||
var ParserAsync = module.exports = function(options) {
|
||||
|
|
@ -72,26 +73,36 @@ ParserAsync.prototype._inflateData = function(data) {
|
|||
this._inflate.write(data);
|
||||
};
|
||||
|
||||
ParserAsync.prototype._createData = function(width, height, bpp) {
|
||||
this._data = new Buffer(width * height * 4);
|
||||
ParserAsync.prototype._createData = function(width, height, bpp, depth) {
|
||||
|
||||
this._bpp = bpp;
|
||||
this._depth = depth;
|
||||
|
||||
this._filter = new FilterAsync(
|
||||
width, height,
|
||||
bpp,
|
||||
this._data,
|
||||
depth,
|
||||
this._options
|
||||
);
|
||||
return this._data;
|
||||
};
|
||||
|
||||
ParserAsync.prototype._finished = function(data) {
|
||||
// no more data to inflate
|
||||
this._inflate.end();
|
||||
if (!this._inflate) {
|
||||
this.emit('error', 'No Inflate block');
|
||||
} else {
|
||||
// no more data to inflate
|
||||
this._inflate.end();
|
||||
}
|
||||
this.destroySoon();
|
||||
};
|
||||
|
||||
ParserAsync.prototype._complete = function(data, width, height) {
|
||||
|
||||
data = this._parser.reverseFiltered(data, width, height);
|
||||
data = bitmapper.dataToBitMap(data, width, height,
|
||||
this._bpp,
|
||||
this._depth);
|
||||
|
||||
data = this._parser.reverseFiltered(data, this._depth, width, height);
|
||||
|
||||
this.emit('parsed', data);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
var zlib = require('zlib'),
|
||||
SyncReader = require('./sync-reader'),
|
||||
FilterSync = require('./filter-sync'),
|
||||
Parser = require('./parser');
|
||||
Parser = require('./parser'),
|
||||
bitmapper = require('./bitmapper');
|
||||
|
||||
|
||||
var ParserSync = module.exports = function(buffer, options) {
|
||||
|
|
@ -51,15 +52,19 @@ var ParserSync = module.exports = function(buffer, options) {
|
|||
|
||||
var data = zlib.inflateSync(inflateData);
|
||||
|
||||
FilterSync.process(
|
||||
data = FilterSync.process(
|
||||
data,
|
||||
this._width, this._height,
|
||||
this._bpp,
|
||||
this._data,
|
||||
this._depth,
|
||||
this._options
|
||||
);
|
||||
|
||||
this.data = this._parser.reverseFiltered(this._data, this._width, this._height);
|
||||
this._data = bitmapper.dataToBitMap(data, this._width, this._height,
|
||||
this._bpp,
|
||||
this._depth);
|
||||
// todo yuck
|
||||
this.data = this._parser.reverseFiltered(this._data, this._depth, this._width, this._height);
|
||||
};
|
||||
|
||||
ParserSync.prototype._handleError = function(err) {
|
||||
|
|
@ -78,10 +83,11 @@ ParserSync.prototype._inflateData = function(data) {
|
|||
this._inflateDataList.push(data);
|
||||
};
|
||||
|
||||
ParserSync.prototype._createData = function(width, height, bpp) {
|
||||
ParserSync.prototype._createData = function(width, height, bpp, depth) {
|
||||
this._data = new Buffer(width * height * 4);
|
||||
this._bpp = bpp;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._depth = depth;
|
||||
return this._data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ Parser.prototype._parseIHDR = function(data) {
|
|||
// 'compr', compr, 'filter', filter, 'interlace', interlace
|
||||
// );
|
||||
|
||||
if (depth != 8) {
|
||||
if (depth !== 8 && depth !== 4 && depth !== 2 && depth !== 1) {
|
||||
this.error(new Error('Unsupported bit depth ' + depth));
|
||||
return;
|
||||
}
|
||||
|
|
@ -187,17 +187,17 @@ Parser.prototype._parseIHDR = function(data) {
|
|||
|
||||
this._colorType = colorType;
|
||||
|
||||
this._data = this.createData(width, height, colorTypeToBppMap[this._colorType]);
|
||||
this.createData(width, height, colorTypeToBppMap[this._colorType], depth);
|
||||
|
||||
this._hasIHDR = true;
|
||||
|
||||
this.metadata({
|
||||
width: width,
|
||||
height: height,
|
||||
depth: depth,
|
||||
palette: !!(colorType & constants.COLOR_PALETTE),
|
||||
color: !!(colorType & constants.COLOR_COLOR),
|
||||
alpha: !!(colorType & constants.COLOR_ALPHA),
|
||||
data: this._data
|
||||
alpha: !!(colorType & constants.COLOR_ALPHA)
|
||||
});
|
||||
|
||||
this._handleChunkEnd();
|
||||
|
|
@ -298,10 +298,10 @@ Parser.prototype._parseIEND = function(data) {
|
|||
this.finished();
|
||||
};
|
||||
|
||||
Parser.prototype.reverseFiltered = function(data, width, height) {
|
||||
Parser.prototype.reverseFiltered = function(data, depth, width, height) {
|
||||
|
||||
if (this._colorType == 3) { // paletted
|
||||
|
||||
//console.log("paletted");
|
||||
// use values from palette
|
||||
var pxLineLength = width << 2;
|
||||
|
||||
|
|
@ -312,10 +312,31 @@ Parser.prototype.reverseFiltered = function(data, width, height) {
|
|||
var pxPos = pxRowPos + (x << 2),
|
||||
color = this._palette[data[pxPos]];
|
||||
|
||||
if (!color) {
|
||||
console.error("data - " + data[pxPos] + " got no colour");
|
||||
console.log("depth is ", depth);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
data[pxPos + i] = color[i];
|
||||
}
|
||||
}
|
||||
} else if (depth !== 8) {
|
||||
//console.log("adjusting");
|
||||
var pxLineLength = width << 2;
|
||||
var maxOutSample = 255;
|
||||
var maxInSample = Math.pow(2, depth) - 1;
|
||||
|
||||
for (var y = 0; y < height; y++) {
|
||||
var pxRowPos = y * pxLineLength;
|
||||
|
||||
for (var x = 0; x < width; x++) {
|
||||
var pxPos = pxRowPos + (x << 2);
|
||||
for (var i = 0; i < 4; i++)
|
||||
data[pxPos + i] = Math.floor((data[pxPos + i] * maxOutSample) / maxInSample + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -112,9 +112,7 @@ PNG.prototype.end = function(data) {
|
|||
PNG.prototype._metadata = function(metadata) {
|
||||
this.width = metadata.width;
|
||||
this.height = metadata.height;
|
||||
this.data = metadata.data;
|
||||
|
||||
delete metadata.data;
|
||||
this.emit('metadata', metadata);
|
||||
};
|
||||
|
||||
|
|
|
|||
36
test/test.js
36
test/test.js
|
|
@ -12,26 +12,36 @@ fs.readdir(__dirname + '/in/', function(err, files) {
|
|||
|
||||
var expectedError = false;
|
||||
if (file.match(/^x/) ||
|
||||
file.match(/^...i/) || // interlace
|
||||
file.match(/^......(01|02|04|16)/) || // 1/2/4/16 bit
|
||||
file.match(/^basn3p(01|02|04)/) // 2/4/16 colour palette
|
||||
file.match(/^...i/) ||// interlace
|
||||
file.match(/^......(16)/) // 1/2/4/16 bit
|
||||
) {
|
||||
expectedError = true;
|
||||
}
|
||||
|
||||
if (!expectedError) {
|
||||
var data = fs.readFileSync(__dirname + '/in/' + file);
|
||||
var data = fs.readFileSync(__dirname + '/in/' + file);
|
||||
try {
|
||||
console.log("Sync: parsing..", file);
|
||||
var png = PNG.sync.read(data);
|
||||
|
||||
var outpng = new PNG();
|
||||
PNG.adjustGamma(png);
|
||||
outpng.data = png.data;
|
||||
outpng.width = png.width;
|
||||
outpng.height = png.height;
|
||||
outpng.pack()
|
||||
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file));
|
||||
} catch (e) {
|
||||
if (!expectedError) {
|
||||
console.log(e);
|
||||
console.log(e.stack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (expectedError) {
|
||||
console.log("Error expected, parsed fine", file);
|
||||
}
|
||||
|
||||
var outpng = new PNG();
|
||||
PNG.adjustGamma(png);
|
||||
outpng.data = png.data;
|
||||
outpng.width = png.width;
|
||||
outpng.height = png.height;
|
||||
outpng.pack()
|
||||
.pipe(fs.createWriteStream(__dirname + '/outsync/' + file));
|
||||
|
||||
fs.createReadStream(__dirname + '/in/' + file)
|
||||
.pipe(new PNG())
|
||||
.on('error', function(err) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue