pngjs/lib/bitmapper.js
2015-08-02 11:06:21 +01:00

167 lines
No EOL
4 KiB
JavaScript

var interlaceUtils = require('./interlace');
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++;
switch(depth) {
default:
throw new Error("unrecognised depth");
break;
case 16:
var byte2 = data[i];
i++;
byte = Math.floor((((byte << 8) + byte2) * 255) / (Math.pow(2, 16) - 1) + 0.5);
leftOver.push(byte);
break;
case 4:
var byte2 = byte & 0x0f;
var byte1 = byte >> 4;
leftOver.push(byte1, byte2);
break;
case 2:
var byte4 = byte & 3;
var byte3 = byte >> 2 & 3;
var byte2 = byte >> 4 & 3;
var byte1 = byte >> 6 & 3;
leftOver.push(byte1, byte2, byte3, byte4);
break;
case 1:
var byte8 = byte & 1;
var byte7 = byte >> 1 & 1;
var byte6 = byte >> 2 & 1;
var byte5 = byte >> 3 & 1;
var byte4 = byte >> 4 & 1;
var byte3 = byte >> 5 & 1;
var byte2 = byte >> 6 & 1;
var 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");
}
}
};
}
exports.dataToBitMap = function(data, width, height, bpp, depth, interlace) {
if (depth !== 8) {
var bits = bitRetriever(data, depth);
}
var pxData = new Buffer(width * height * 4);
var maxBit = depth >= 8 ? 255 : (Math.pow(2, depth) - 1);
var rawPos = 0;
var pixelData;
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 y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
pxData[(y * 4 * width) + (x * 4) + 0] = 255;
pxData[(y * 4 * width) + (x * 4) + 1] = 0;
pxData[(y * 4 * width) + (x * 4) + 2] = 0;
pxData[(y * 4 * width) + (x * 4) + 3] = 255;
}
}
for(var imageIndex = 0; imageIndex < images.length; imageIndex++) {
var imageWidth = images[imageIndex].width;
var imageHeight = images[imageIndex].height;
for (var y = 0; y < imageHeight; y++) {
for (var x = 0; x < imageWidth; x++) {
if (depth !== 8) {
pixelData = bits.get(bpp);
}
var pxPos = getPxPos(x, y, imageIndex);
//console.log(x,y,imageIndex, pxPos);
for (var i = 0; i < 4; i++) {
var idx = pixelBppMap[bpp][i];
if (depth === 8) {
if (i === data.length) {
throw new Error("Ran out of data");
}
pxData[pxPos + i] = idx !== 0xff ? data[idx + rawPos] : maxBit;
} else {
pxData[pxPos + i] = idx !== 0xff ? pixelData[idx] : maxBit;
}
}
//console.log("R", pxData[pxPos], "G", pxData[pxPos + 1], "B", pxData[pxPos + 2], "A", pxData[pxPos + 3]);
rawPos += bpp;
}
if (depth !== 8) {
bits.resetAfterLine();
}
}
}
if (depth === 8) {
if (rawPos !== data.length) {
throw new Error("extra data found");
}
} else {
bits.end();
}
return pxData;
};
var pixelBppMap = {
1: { // L
0: 0,
1: 0,
2: 0,
3: 0xff
},
2: { // LA
0: 0,
1: 0,
2: 0,
3: 1
},
3: { // RGB
0: 0,
1: 1,
2: 2,
3: 0xff
},
4: { // RGBA
0: 0,
1: 1,
2: 2,
3: 3
}
};