3v324v23's picture
Add PNG files and track with Git LFS
befd7da
const { Transform } = require('stream');
/**
* Transforms a Buffer stream of binary data to a stream of Base64 text. Note that this will
* also work on a stream of pure strings, as the Writeable base class will automatically decode
* text string chunks into Buffers.
* You can pass optionally a line length or a prefix
* @extends Transform
*/
module.exports = class Base64Encode extends Transform {
/**
* Creates a Base64Encode
* @param {Object=} options - Options for stream creation. Passed to Transform constructor as-is.
* @param {string=} options.inputEncoding - The input chunk format. Default is 'utf8'. No effect on Buffer input chunks.
* @param {string=} options.outputEncoding - The output chunk format. Default is 'utf8'. Pass `null` for Buffer chunks.
* @param {number=} options.lineLength - The max line-length of the output stream.
* @param {string=} options.prefix - Prefix for output string.
*/
constructor(options) {
super(options);
// Any extra chars from the last chunk
this.extra = null;
this.lineLength = options && options.lineLength;
this.currLineLength = 0;
if (options && options.prefix) {
this.push(options.prefix);
}
// Default string input to be treated as 'utf8'
const encIn = options && options.inputEncoding;
this.setDefaultEncoding(encIn || 'utf8');
// Default output to be strings
const encOut = options && options.outputEncoding;
if (encOut !== null) {
this.setEncoding(encOut || 'utf8');
}
}
/**
* Adds \r\n as needed to the data chunk to ensure that the output Base64 string meets
* the maximum line length requirement.
* @param {string} chunk
* @returns {string}
* @private
*/
_fixLineLength(chunk) {
// If we care about line length, add line breaks
if (!this.lineLength) {
return chunk;
}
const size = chunk.length;
const needed = this.lineLength - this.currLineLength;
let start, end;
let _chunk = '';
for (start = 0, end = needed; end < size; start = end, end += this.lineLength) {
_chunk += chunk.slice(start, end);
_chunk += '\r\n';
}
const left = chunk.slice(start);
this.currLineLength = left.length;
_chunk += left;
return _chunk;
}
/**
* Transforms a Buffer chunk of data to a Base64 string chunk.
* @param {Buffer} chunk
* @param {string} encoding - unused since chunk is always a Buffer
* @param cb
* @private
*/
_transform(chunk, encoding, cb) {
// Add any previous extra bytes to the chunk
if (this.extra) {
chunk = Buffer.concat([this.extra, chunk]);
this.extra = null;
}
// 3 bytes are represented by 4 characters, so we can only encode in groups of 3 bytes
const remaining = chunk.length % 3;
if (remaining !== 0) {
// Store the extra bytes for later
this.extra = chunk.slice(chunk.length - remaining);
chunk = chunk.slice(0, chunk.length - remaining);
}
// Convert chunk to a base 64 string
chunk = chunk.toString('base64');
// Push the chunk
this.push(Buffer.from(this._fixLineLength(chunk)));
cb();
}
/**
* Emits 0 or 4 extra characters of Base64 data.
* @param cb
* @private
*/
_flush(cb) {
if (this.extra) {
this.push(Buffer.from(this._fixLineLength(this.extra.toString('base64'))));
}
cb();
}
};