png-async
Version:
A simple and non-blocking PNG encoder / decoder.
75 lines • 2.48 kB
JavaScript
"use strict";
const zlib = require("zlib");
const stream = require("stream");
const png = require("./index");
const constants = require("./constants");
const CrcStream = require("./crc");
const Filter = require("./filter");
class Packer extends stream.Readable {
constructor(option) {
super();
this._option = option;
option.deflateChunkSize = option.deflateChunkSize || 32 * 1024;
option.deflateLevel = option.deflateLevel || 9;
if (option.deflateStrategy === undefined) {
option.deflateStrategy = png.EDeflateStrategy.RLE;
}
this.readable = true;
}
pack(data, width, height) {
// Signature
this.emit("data", Buffer.from(constants.PNG_SIGNATURE));
this.emit("data", this._packIHDR(width, height));
// filter pixel data
const filter = new Filter(width, height, 4, data, this._option);
data = filter.filter();
// compress it
const deflate = zlib.createDeflate({
chunkSize: this._option.deflateChunkSize,
level: this._option.deflateLevel,
strategy: this._option.deflateStrategy
});
deflate.on("error", this.emit.bind(this, "error"));
deflate.on("data", (data) => {
this.emit("data", this._packIDAT(data));
});
deflate.on("end", () => {
this.emit("data", this._packIEND());
this.emit("end");
});
deflate.end(data);
}
_read() {
//todo
}
_packChunk(type, data) {
const len = (data ? data.length : 0);
const 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;
}
_packIHDR(width, height) {
const buf = Buffer.alloc(13);
buf.writeUInt32BE(width, 0);
buf.writeUInt32BE(height, 4);
buf[8] = 8;
buf[9] = 6; // colorType
buf[10] = 0; // compression
buf[11] = 0; // filter
buf[12] = 0; // interlace
return this._packChunk(constants.TYPE_IHDR, buf);
}
_packIDAT(data) {
return this._packChunk(constants.TYPE_IDAT, data);
}
_packIEND() {
return this._packChunk(constants.TYPE_IEND, null);
}
}
module.exports = Packer;
//# sourceMappingURL=packer.js.map