130 lines
3.6 KiB
JavaScript
130 lines
3.6 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
let constants = require("./constants");
|
||
|
let CrcStream = require("./crc");
|
||
|
let bitPacker = require("./bitpacker");
|
||
|
let filter = require("./filter-pack");
|
||
|
let zlib = require("zlib");
|
||
|
|
||
|
let Packer = (module.exports = function (options) {
|
||
|
this._options = options;
|
||
|
|
||
|
options.deflateChunkSize = options.deflateChunkSize || 32 * 1024;
|
||
|
options.deflateLevel =
|
||
|
options.deflateLevel != null ? options.deflateLevel : 9;
|
||
|
options.deflateStrategy =
|
||
|
options.deflateStrategy != null ? options.deflateStrategy : 3;
|
||
|
options.inputHasAlpha =
|
||
|
options.inputHasAlpha != null ? options.inputHasAlpha : true;
|
||
|
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
|
||
|
options.bitDepth = options.bitDepth || 8;
|
||
|
// This is outputColorType
|
||
|
options.colorType =
|
||
|
typeof options.colorType === "number"
|
||
|
? options.colorType
|
||
|
: constants.COLORTYPE_COLOR_ALPHA;
|
||
|
options.inputColorType =
|
||
|
typeof options.inputColorType === "number"
|
||
|
? options.inputColorType
|
||
|
: constants.COLORTYPE_COLOR_ALPHA;
|
||
|
|
||
|
if (
|
||
|
[
|
||
|
constants.COLORTYPE_GRAYSCALE,
|
||
|
constants.COLORTYPE_COLOR,
|
||
|
constants.COLORTYPE_COLOR_ALPHA,
|
||
|
constants.COLORTYPE_ALPHA,
|
||
|
].indexOf(options.colorType) === -1
|
||
|
) {
|
||
|
throw new Error(
|
||
|
"option color type:" + options.colorType + " is not supported at present"
|
||
|
);
|
||
|
}
|
||
|
if (
|
||
|
[
|
||
|
constants.COLORTYPE_GRAYSCALE,
|
||
|
constants.COLORTYPE_COLOR,
|
||
|
constants.COLORTYPE_COLOR_ALPHA,
|
||
|
constants.COLORTYPE_ALPHA,
|
||
|
].indexOf(options.inputColorType) === -1
|
||
|
) {
|
||
|
throw new Error(
|
||
|
"option input color type:" +
|
||
|
options.inputColorType +
|
||
|
" is not supported at present"
|
||
|
);
|
||
|
}
|
||
|
if (options.bitDepth !== 8 && options.bitDepth !== 16) {
|
||
|
throw new Error(
|
||
|
"option bit depth:" + options.bitDepth + " is not supported at present"
|
||
|
);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
Packer.prototype.getDeflateOptions = function () {
|
||
|
return {
|
||
|
chunkSize: this._options.deflateChunkSize,
|
||
|
level: this._options.deflateLevel,
|
||
|
strategy: this._options.deflateStrategy,
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Packer.prototype.createDeflate = function () {
|
||
|
return this._options.deflateFactory(this.getDeflateOptions());
|
||
|
};
|
||
|
|
||
|
Packer.prototype.filterData = function (data, width, height) {
|
||
|
// convert to correct format for filtering (e.g. right bpp and bit depth)
|
||
|
let packedData = bitPacker(data, width, height, this._options);
|
||
|
|
||
|
// filter pixel data
|
||
|
let bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType];
|
||
|
let filteredData = filter(packedData, width, height, this._options, bpp);
|
||
|
return filteredData;
|
||
|
};
|
||
|
|
||
|
Packer.prototype._packChunk = function (type, data) {
|
||
|
let len = data ? data.length : 0;
|
||
|
let buf = Buffer.alloc(len + 12);
|
||
|
|
||
|
buf.writeUInt32BE(len, 0);
|
||
|
buf.writeUInt32BE(type, 4);
|
||
|
|
||
|
if (data) {
|
||
|
data.copy(buf, 8);
|
||
|
}
|
||
|
|
||
|
buf.writeInt32BE(
|
||
|
CrcStream.crc32(buf.slice(4, buf.length - 4)),
|
||
|
buf.length - 4
|
||
|
);
|
||
|
return buf;
|
||
|
};
|
||
|
|
||
|
Packer.prototype.packGAMA = function (gamma) {
|
||
|
let buf = Buffer.alloc(4);
|
||
|
buf.writeUInt32BE(Math.floor(gamma * constants.GAMMA_DIVISION), 0);
|
||
|
return this._packChunk(constants.TYPE_gAMA, buf);
|
||
|
};
|
||
|
|
||
|
Packer.prototype.packIHDR = function (width, height) {
|
||
|
let buf = Buffer.alloc(13);
|
||
|
buf.writeUInt32BE(width, 0);
|
||
|
buf.writeUInt32BE(height, 4);
|
||
|
buf[8] = this._options.bitDepth; // Bit depth
|
||
|
buf[9] = this._options.colorType; // colorType
|
||
|
buf[10] = 0; // compression
|
||
|
buf[11] = 0; // filter
|
||
|
buf[12] = 0; // interlace
|
||
|
|
||
|
return this._packChunk(constants.TYPE_IHDR, buf);
|
||
|
};
|
||
|
|
||
|
Packer.prototype.packIDAT = function (data) {
|
||
|
return this._packChunk(constants.TYPE_IDAT, data);
|
||
|
};
|
||
|
|
||
|
Packer.prototype.packIEND = function () {
|
||
|
return this._packChunk(constants.TYPE_IEND, null);
|
||
|
};
|