You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
6.2 KiB
256 lines
6.2 KiB
'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; |
|
};
|
|
|