lib/png/processor/normalizer.js
// Copyright 2015 Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.
var BufferedStream = require('../utils/bufferedStream');
/**
* @class Normalizer
* @module PNG
* @submodule PNGCore
* @param {Chunk} headerChunk Header chunk of data stream
* @param {object} [options] Options for the compressor
* @constructor
*/
var Normalizer = function (headerChunk, options) {
this._headerChunk = headerChunk;
this._options = options || {};
};
/**
* Gets the options
*
* @method getOptions
* @return {object}
*/
Normalizer.prototype.getOptions = function () {
return this._options;
};
/**
* Gets the header chunk
*
* @method getHeaderChunk
* @return {Chunk}
*/
Normalizer.prototype.getHeaderChunk = function () {
return this._headerChunk;
};
/**
* Encodes color values of an image
*
* @method encode
* @param {Buffer} image
*/
Normalizer.prototype.encode = function (image) {
return image;
//TODO: Writing is currently only 8-bit
};
/**
* Determines the max number for a bit-depth
*
* @method _determineMaxValue
* @return {int}
* @private
*/
Normalizer.prototype._determineMaxValue = function () {
var headerChunk = this.getHeaderChunk(),
result;
if (headerChunk.isColorTypeIndexedColor()) {
result = 255;
} else {
switch (headerChunk.getBitDepth()) {
case 1:
result = 1;
break;
case 2:
result = 3;
break;
case 4:
result = 15;
break;
case 8:
result = 255;
break;
case 16:
result = 65535;
break;
}
}
return result;
};
/**
* Determines the writer according to header data
*
* @method _determineWriter
* @return {object}
* @private
*/
Normalizer.prototype._determineWriter = function () {
var headerChunk = this.getHeaderChunk(),
isColor, hasAlpha, isIndexed,
result = null;
isColor = headerChunk.isColor();
hasAlpha = headerChunk.hasAlphaChannel();
isIndexed = headerChunk.isColorTypeIndexedColor();
if (isIndexed) {
result = {
valuesNeeded: 1,
writer: '_writeInIndexedBytes'
};
} else {
if (isColor) {
if (hasAlpha) {
result = {
valuesNeeded: 4,
writer: '_writeInColorAlphaBytes'
};
} else {
result = {
valuesNeeded: 3,
writer: '_writeInColorNoAlphaBytes'
};
}
} else {
if (hasAlpha) {
result = {
valuesNeeded: 2,
writer: '_writeInNoColorAlphaBytes'
};
} else {
result = {
valuesNeeded: 1,
writer: '_writeInNoColorNoAlphaBytes'
};
}
}
}
return result;
};
/**
* Decodes color values
*
* @method decode
* @param {Buffer} image
* @return {Buffer}
*/
Normalizer.prototype.decode = function (image) {
var writerInfo,
maxValue,
offset = 0,
len = image.length,
internalImageSize = this.getHeaderChunk().getImageSizeInBytes() * 2, // 16-bit
imageStream, outputStream;
writerInfo = this._determineWriter();
// Skip normalization since nothing needs to be done here.
if (writerInfo.valuesNeeded === 4) {
return image;
}
maxValue = this._determineMaxValue();
imageStream = new BufferedStream(image, false);
outputStream = new BufferedStream(null, null, internalImageSize);
while (len > offset) {
this[writerInfo.writer](imageStream, outputStream, maxValue);
offset += writerInfo.valuesNeeded * 2;
}
return outputStream.toBuffer();
};
/**
* Write bytes when image is color and has already an alpha-channel
*
* @method _writeInColorAlphaBytes
* @param {BufferedStream} input Input stream
* @param {BufferedStream} output Output stream
* @private
*/
Normalizer.prototype._writeInColorAlphaBytes = function (input, output) {
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(input.readUInt16BE());
};
/**
* Write bytes when image is color and has no alpha-channel
*
* @method _writeInColorNoAlphaBytes
* @param {BufferedStream} input Input stream
* @param {BufferedStream} output Output stream
* @param {int} maxValue Max value for bit-depth
* @private
*/
Normalizer.prototype._writeInColorNoAlphaBytes = function (input, output, maxValue) {
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(input.readUInt16BE());
output.writeUInt16BE(maxValue);
};
/**
* Write bytes when image is grayNormalizer and has already an alpha-channel
*
* @method _writeInNoColorAlphaBytes
* @param {BufferedStream} input Input stream
* @param {BufferedStream} output Output stream
* @private
*/
Normalizer.prototype._writeInNoColorAlphaBytes = function (input, output) {
var value = input.readUInt16BE();
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(input.readUInt16BE());
};
/**
* Write bytes when image is grayNormalizer and has no alpha-channel
*
* @method _writeInNoColorNoAlphaBytes
* @param {BufferedStream} input Input stream
* @param {BufferedStream} output Output stream
* @param {int} maxValue Max value for bit-depth
* @private
*/
Normalizer.prototype._writeInNoColorNoAlphaBytes = function (input, output, maxValue) {
var value = input.readUInt16BE();
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(maxValue);
};
/**
* Write bytes when image is indexed on a palette
*
* @method _writeInIndexedBytes
* @param {BufferedStream} input Input stream
* @param {BufferedStream} output Output stream
* @param {int} maxValue Max value for bit-depth
* @private
*/
Normalizer.prototype._writeInIndexedBytes = function (input, output, maxValue) {
var value = input.readUInt16BE();
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(value);
output.writeUInt16BE(maxValue);
};
module.exports = Normalizer;