Speed up mapImage8Bit and mapImageCustomBit (#123)

Inner loop with `if()` comparison is eliminated and replaced with
function call.

Synthetic benchmark shows 1.5x increase in speed of mapImage8Bit for big
PNG images (e.g. 4064 x 2338, 8-bit/color RGBA, non-interlaced
screenshots).
This commit is contained in:
Victor Homyakov 2019-03-08 08:25:36 +03:00 committed by Luke Page
parent ae7b0a1534
commit 2d78949365

View file

@ -2,32 +2,107 @@
var interlaceUtils = require('./interlace');
var pixelBppMap = {
1: { // L
0: 0,
1: 0,
2: 0,
3: 0xff
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
// 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
// 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
// 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) {
@ -102,19 +177,7 @@ function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) { // eslint-di
for (var y = 0; y < imageHeight; y++) {
for (var x = 0; x < imageWidth; x++) {
var pxPos = getPxPos(x, y, imagePass);
for (var i = 0; i < 4; i++) {
var idx = pixelBppMap[bpp][i];
if (idx === 0xff) {
pxData[pxPos + i] = 0xff;
} else {
var dataPos = idx + rawPos;
if (dataPos === data.length) {
throw new Error('Ran out of data');
}
pxData[pxPos + i] = data[dataPos];
}
}
pixelBppMapper[bpp](pxData, data, pxPos, rawPos);
rawPos += bpp; //eslint-disable-line no-param-reassign
}
}
@ -129,11 +192,7 @@ function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) { // esli
for (var x = 0; x < imageWidth; x++) {
var pixelData = bits.get(bpp);
var pxPos = getPxPos(x, y, imagePass);
for (var i = 0; i < 4; i++) {
var idx = pixelBppMap[bpp][i];
pxData[pxPos + i] = idx !== 0xff ? pixelData[idx] : maxBit;
}
pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit);
}
bits.resetAfterLine();
}