'use strict'; var interlaceUtils = require('./interlace'); var pixelBppMapper = [ // 0 - dummy entry function() {}, // 1 - L // 0: 0, 1: 0, 2: 0, 3: 0xff function(pxData, data, pxPos, rawPos) { if (rawPos === data.length) { throw new Error('Ran out of data'); } var pixel = data[rawPos]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; pxData[pxPos + 3] = 0xff; }, // 2 - LA // 0: 0, 1: 0, 2: 0, 3: 1 function(pxData, data, pxPos, rawPos) { if (rawPos + 1 >= data.length) { throw new Error('Ran out of data'); } var pixel = data[rawPos]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; pxData[pxPos + 3] = data[rawPos + 1]; }, // 3 - RGB // 0: 0, 1: 1, 2: 2, 3: 0xff function(pxData, data, pxPos, rawPos) { if (rawPos + 2 >= data.length) { throw new Error('Ran out of data'); } pxData[pxPos] = data[rawPos]; pxData[pxPos + 1] = data[rawPos + 1]; pxData[pxPos + 2] = data[rawPos + 2]; pxData[pxPos + 3] = 0xff; }, // 4 - RGBA // 0: 0, 1: 1, 2: 2, 3: 3 function(pxData, data, pxPos, rawPos) { if (rawPos + 3 >= data.length) { throw new Error('Ran out of data'); } pxData[pxPos] = data[rawPos]; pxData[pxPos + 1] = data[rawPos + 1]; pxData[pxPos + 2] = data[rawPos + 2]; pxData[pxPos + 3] = data[rawPos + 3]; } ]; var pixelBppCustomMapper = [ // 0 - dummy entry function() {}, // 1 - L // 0: 0, 1: 0, 2: 0, 3: 0xff function(pxData, pixelData, pxPos, maxBit) { var pixel = pixelData[0]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; pxData[pxPos + 3] = maxBit; }, // 2 - LA // 0: 0, 1: 0, 2: 0, 3: 1 function(pxData, pixelData, pxPos) { var pixel = pixelData[0]; pxData[pxPos] = pixel; pxData[pxPos + 1] = pixel; pxData[pxPos + 2] = pixel; pxData[pxPos + 3] = pixelData[1]; }, // 3 - RGB // 0: 0, 1: 1, 2: 2, 3: 0xff function(pxData, pixelData, pxPos, maxBit) { pxData[pxPos] = pixelData[0]; pxData[pxPos + 1] = pixelData[1]; pxData[pxPos + 2] = pixelData[2]; pxData[pxPos + 3] = maxBit; }, // 4 - RGBA // 0: 0, 1: 1, 2: 2, 3: 3 function(pxData, pixelData, pxPos) { pxData[pxPos] = pixelData[0]; pxData[pxPos + 1] = pixelData[1]; pxData[pxPos + 2] = pixelData[2]; pxData[pxPos + 3] = pixelData[3]; } ]; function bitRetriever(data, depth) { var leftOver = []; var i = 0; function split() { if (i === data.length) { throw new Error('Ran out of data'); } var byte = data[i]; i++; var byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1; switch (depth) { default: throw new Error('unrecognised depth'); case 16: byte2 = data[i]; i++; leftOver.push(((byte << 8) + byte2)); break; case 4: byte2 = byte & 0x0f; byte1 = byte >> 4; leftOver.push(byte1, byte2); break; case 2: byte4 = byte & 3; byte3 = byte >> 2 & 3; byte2 = byte >> 4 & 3; byte1 = byte >> 6 & 3; leftOver.push(byte1, byte2, byte3, byte4); break; case 1: byte8 = byte & 1; byte7 = byte >> 1 & 1; byte6 = byte >> 2 & 1; byte5 = byte >> 3 & 1; byte4 = byte >> 4 & 1; byte3 = byte >> 5 & 1; byte2 = byte >> 6 & 1; byte1 = byte >> 7 & 1; leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8); break; } } return { get: function(count) { while (leftOver.length < count) { split(); } var returner = leftOver.slice(0, count); leftOver = leftOver.slice(count); return returner; }, resetAfterLine: function() { leftOver.length = 0; }, end: function() { if (i !== data.length) { throw new Error('extra data found'); } } }; } function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-disable-line max-params var imageWidth = image.width; var imageHeight = image.height; var imagePass = image.index; for (var y = 0; y < imageHeight; y++) { for (var x = 0; x < imageWidth; x++) { var pxPos = getPxPos(x, y, imagePass); pixelBppMapper[bpp](pxData, data, pxPos, rawPos); rawPos += bpp; //eslint-disable-line no-param-reassign } } return rawPos; } function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { // eslint-disable-line max-params var imageWidth = image.width; var imageHeight = image.height; var imagePass = image.index; for (var y = 0; y < imageHeight; y++) { for (var x = 0; x < imageWidth; x++) { var pixelData = bits.get(bpp); var pxPos = getPxPos(x, y, imagePass); pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit); } bits.resetAfterLine(); } } exports.dataToBitMap = function(data, bitmapInfo) { var width = bitmapInfo.width; var height = bitmapInfo.height; var depth = bitmapInfo.depth; var bpp = bitmapInfo.bpp; var interlace = bitmapInfo.interlace; if (depth !== 8) { var bits = bitRetriever(data, depth); } var pxData; if (depth <= 8) { pxData = new Buffer(width * height * 4); } else { pxData = new Uint16Array(width * height * 4); } var maxBit = Math.pow(2, depth) - 1; var rawPos = 0; var images; var getPxPos; if (interlace) { images = interlaceUtils.getImagePasses(width, height); getPxPos = interlaceUtils.getInterlaceIterator(width, height); } else { var nonInterlacedPxPos = 0; getPxPos = function() { var returner = nonInterlacedPxPos; nonInterlacedPxPos += 4; return returner; }; images = [{ width: width, height: height }]; } for (var imageIndex = 0; imageIndex < images.length; imageIndex++) { if (depth === 8) { rawPos = mapImage8Bit(images[imageIndex], pxData, getPxPos, bpp, data, rawPos); } else { mapImageCustomBit(images[imageIndex], pxData, getPxPos, bpp, bits, maxBit); } } if (depth === 8) { if (rawPos !== data.length) { throw new Error('extra data found'); } } else { bits.end(); } return pxData; };