"use strict"; let constants = require("./constants"); module.exports = function (dataIn, width, height, options) { let outHasAlpha = [constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf( options.colorType ) !== -1; if (options.colorType === options.inputColorType) { let bigEndian = (function () { let buffer = new ArrayBuffer(2); new DataView(buffer).setInt16(0, 256, true /* littleEndian */); // Int16Array uses the platform's endianness. return new Int16Array(buffer)[0] !== 256; })(); // If no need to convert to grayscale and alpha is present/absent in both, take a fast route if (options.bitDepth === 8 || (options.bitDepth === 16 && bigEndian)) { return dataIn; } } // map to a UInt16 array if data is 16bit, fix endianness below let data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer); let maxValue = 255; let inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType]; if (inBpp === 4 && !options.inputHasAlpha) { inBpp = 3; } let outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType]; if (options.bitDepth === 16) { maxValue = 65535; outBpp *= 2; } let outData = Buffer.alloc(width * height * outBpp); let inIndex = 0; let outIndex = 0; let bgColor = options.bgColor || {}; if (bgColor.red === undefined) { bgColor.red = maxValue; } if (bgColor.green === undefined) { bgColor.green = maxValue; } if (bgColor.blue === undefined) { bgColor.blue = maxValue; } function getRGBA() { let red; let green; let blue; let alpha = maxValue; switch (options.inputColorType) { case constants.COLORTYPE_COLOR_ALPHA: alpha = data[inIndex + 3]; red = data[inIndex]; green = data[inIndex + 1]; blue = data[inIndex + 2]; break; case constants.COLORTYPE_COLOR: red = data[inIndex]; green = data[inIndex + 1]; blue = data[inIndex + 2]; break; case constants.COLORTYPE_ALPHA: alpha = data[inIndex + 1]; red = data[inIndex]; green = red; blue = red; break; case constants.COLORTYPE_GRAYSCALE: red = data[inIndex]; green = red; blue = red; break; default: throw new Error( "input color type:" + options.inputColorType + " is not supported at present" ); } if (options.inputHasAlpha) { if (!outHasAlpha) { alpha /= maxValue; red = Math.min( Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0), maxValue ); green = Math.min( Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0), maxValue ); blue = Math.min( Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0), maxValue ); } } return { red: red, green: green, blue: blue, alpha: alpha }; } for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { let rgba = getRGBA(data, inIndex); switch (options.colorType) { case constants.COLORTYPE_COLOR_ALPHA: case constants.COLORTYPE_COLOR: if (options.bitDepth === 8) { outData[outIndex] = rgba.red; outData[outIndex + 1] = rgba.green; outData[outIndex + 2] = rgba.blue; if (outHasAlpha) { outData[outIndex + 3] = rgba.alpha; } } else { outData.writeUInt16BE(rgba.red, outIndex); outData.writeUInt16BE(rgba.green, outIndex + 2); outData.writeUInt16BE(rgba.blue, outIndex + 4); if (outHasAlpha) { outData.writeUInt16BE(rgba.alpha, outIndex + 6); } } break; case constants.COLORTYPE_ALPHA: case constants.COLORTYPE_GRAYSCALE: { // Convert to grayscale and alpha let grayscale = (rgba.red + rgba.green + rgba.blue) / 3; if (options.bitDepth === 8) { outData[outIndex] = grayscale; if (outHasAlpha) { outData[outIndex + 1] = rgba.alpha; } } else { outData.writeUInt16BE(grayscale, outIndex); if (outHasAlpha) { outData.writeUInt16BE(rgba.alpha, outIndex + 2); } } break; } default: throw new Error("unrecognised color Type " + options.colorType); } inIndex += inBpp; outIndex += outBpp; } } return outData; };