Skip to content

Commit ead4cbf

Browse files
committed
Merge pull request #4600 from p01/JPX_optimization_2
Optimized JPX decoder ~6% faster
2 parents e9cdf6b + a66326c commit ead4cbf

File tree

1 file changed

+75
-33
lines changed

1 file changed

+75
-33
lines changed

src/core/jpx.js

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ var JpxImage = (function JpxImageClosure() {
954954
var magnitudeCorrection = reversible ? 0 : 0.5;
955955
var k, n, nb;
956956
position = 0;
957-
// Do the interleaving of Section F.3.3 here, so we do not need
957+
// Do the interleaving of Section F.3.3 here, so we do not need
958958
// to copy later. LL level is not interleaved, just copied.
959959
var interleave = (subband.type !== 'LL');
960960
for (j = 0; j < blockHeight; j++) {
@@ -1566,12 +1566,16 @@ var JpxImage = (function JpxImageClosure() {
15661566
var oneRowDown = width;
15671567
var twoRowsDown = width * 2;
15681568
var threeRowsDown = width * 3;
1569-
for (var i0 = 0; i0 < height; i0 += 4) {
1569+
var iNext;
1570+
for (var i0 = 0; i0 < height; i0 = iNext) {
1571+
iNext = Math.min(i0 + 4, height);
1572+
var indexBase = i0 * width;
1573+
var checkAllEmpty = i0 + 3 < height;
15701574
for (var j = 0; j < width; j++) {
1571-
var index0 = i0 * width + j;
1575+
var index0 = indexBase + j;
15721576
// using the property: labels[neighborsSignificance[index]] == 0
15731577
// when neighborsSignificance[index] == 0
1574-
var allEmpty = (i0 + 3 < height &&
1578+
var allEmpty = (checkAllEmpty &&
15751579
processingFlags[index0] === 0 &&
15761580
processingFlags[index0 + oneRowDown] === 0 &&
15771581
processingFlags[index0 + twoRowsDown] === 0 &&
@@ -1581,7 +1585,7 @@ var JpxImage = (function JpxImageClosure() {
15811585
neighborsSignificance[index0 + twoRowsDown] === 0 &&
15821586
neighborsSignificance[index0 + threeRowsDown] === 0);
15831587
var i1 = 0, index = index0;
1584-
var i, sign;
1588+
var i = i0, sign;
15851589
if (allEmpty) {
15861590
var hasSignificantCoefficent =
15871591
decoder.readBit(contexts, RUNLENGTH_CONTEXT);
@@ -1594,8 +1598,10 @@ var JpxImage = (function JpxImageClosure() {
15941598
}
15951599
i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
15961600
decoder.readBit(contexts, UNIFORM_CONTEXT);
1597-
i = i0 + i1;
1598-
index += i1 * width;
1601+
if (i1 !== 0) {
1602+
i = i0 + i1;
1603+
index += i1 * width;
1604+
}
15991605

16001606
sign = this.decodeSignBit(i, j, index);
16011607
coefficentsSign[index] = sign;
@@ -1610,20 +1616,15 @@ var JpxImage = (function JpxImageClosure() {
16101616

16111617
i1++;
16121618
}
1613-
for (; i1 < 4; i1++, index += width) {
1614-
i = i0 + i1;
1615-
if (i >= height) {
1616-
break;
1617-
}
1618-
1619+
for (i = i0 + i1; i < iNext; i++, index += width) {
16191620
if (coefficentsMagnitude[index] ||
16201621
(processingFlags[index] & processedMask) !== 0) {
16211622
continue;
16221623
}
16231624

16241625
var contextLabel = labels[neighborsSignificance[index]];
16251626
var decision = decoder.readBit(contexts, contextLabel);
1626-
if (decision == 1) {
1627+
if (decision === 1) {
16271628
sign = this.decodeSignBit(i, j, index);
16281629
coefficentsSign[index] = sign;
16291630
coefficentsMagnitude[index] = 1;
@@ -1678,7 +1679,6 @@ var JpxImage = (function JpxImageClosure() {
16781679
};
16791680
Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
16801681
u0, v0) {
1681-
16821682
var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
16831683
var width = hl_lh_hh.width;
16841684
var height = hl_lh_hh.height;
@@ -1711,7 +1711,7 @@ var JpxImage = (function JpxImageClosure() {
17111711
rowBuffer.set(items.subarray(k, k + width), bufferPadding);
17121712

17131713
this.extend(rowBuffer, bufferPadding, width);
1714-
this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
1714+
this.filter(rowBuffer, bufferPadding, width);
17151715

17161716
items.set(
17171717
rowBuffer.subarray(bufferPadding, bufferPadding + width),
@@ -1757,7 +1757,7 @@ var JpxImage = (function JpxImageClosure() {
17571757
currentBuffer--;
17581758
var buffer = colBuffers[currentBuffer];
17591759
this.extend(buffer, bufferPadding, height);
1760-
this.filter(buffer, bufferPadding, height, v0, buffer);
1760+
this.filter(buffer, bufferPadding, height);
17611761

17621762
// If this is last buffer in this group of buffers, flush all buffers.
17631763
if (currentBuffer === 0) {
@@ -1788,44 +1788,86 @@ var JpxImage = (function JpxImageClosure() {
17881788

17891789
IrreversibleTransform.prototype = Object.create(Transform.prototype);
17901790
IrreversibleTransform.prototype.filter =
1791-
function irreversibleTransformFilter(y, offset, length, i0, x) {
1791+
function irreversibleTransformFilter(x, offset, length) {
17921792
var len = length >> 1;
17931793
offset = offset | 0;
1794+
var j, n, current, next;
17941795

17951796
var alpha = -1.586134342059924;
17961797
var beta = -0.052980118572961;
17971798
var gamma = 0.882911075530934;
17981799
var delta = 0.443506852043971;
17991800
var K = 1.230174104914001;
18001801
var K_ = 1 / K;
1801-
var j, n;
18021802

18031803
// step 1 is combined with step 3
18041804

18051805
// step 2
1806-
for (j = offset - 3, n = len + 4; n--; j += 2) {
1807-
x[j] = K_ * y[j];
1806+
j = offset - 3;
1807+
for (n = len + 4; n--; j += 2) {
1808+
x[j] *= K_;
18081809
}
18091810

18101811
// step 1 & 3
1811-
for (j = offset - 2, n = len + 3; n--; j += 2) {
1812-
x[j] = K * y[j] -
1813-
delta * (x[j - 1] + x[j + 1]);
1812+
j = offset - 2;
1813+
current = delta * x[j -1];
1814+
for (n = len + 3; n--; j += 2) {
1815+
next = delta * x[j + 1];
1816+
x[j] = K * x[j] - current - next;
1817+
if (n--) {
1818+
j += 2;
1819+
current = delta * x[j + 1];
1820+
x[j] = K * x[j] - current - next;
1821+
} else {
1822+
break;
1823+
}
18141824
}
18151825

18161826
// step 4
1817-
for (j = offset - 1, n = len + 2; n--; j += 2) {
1818-
x[j] -= gamma * (x[j - 1] + x[j + 1]);
1827+
j = offset - 1;
1828+
current = gamma * x[j - 1];
1829+
for (n = len + 2; n--; j += 2) {
1830+
next = gamma * x[j + 1];
1831+
x[j] -= current + next;
1832+
if (n--) {
1833+
j += 2;
1834+
current = gamma * x[j + 1];
1835+
x[j] -= current + next;
1836+
} else {
1837+
break;
1838+
}
18191839
}
18201840

18211841
// step 5
1822-
for (j = offset, n = len + 1; n--; j += 2) {
1823-
x[j] -= beta * (x[j - 1] + x[j + 1]);
1842+
j = offset;
1843+
current = beta * x[j - 1];
1844+
for (n = len + 1; n--; j += 2) {
1845+
next = beta * x[j + 1];
1846+
x[j] -= current + next;
1847+
if (n--) {
1848+
j += 2;
1849+
current = beta * x[j + 1];
1850+
x[j] -= current + next;
1851+
} else {
1852+
break;
1853+
}
18241854
}
18251855

18261856
// step 6
1827-
for (j = offset + 1, n = len; n--; j += 2) {
1828-
x[j] -= alpha * (x[j - 1] + x[j + 1]);
1857+
if (len !== 0) {
1858+
j = offset + 1;
1859+
current = alpha * x[j - 1];
1860+
for (n = len; n--; j += 2) {
1861+
next = alpha * x[j + 1];
1862+
x[j] -= current + next;
1863+
if (n--) {
1864+
j += 2;
1865+
current = alpha * x[j + 1];
1866+
x[j] -= current + next;
1867+
} else {
1868+
break;
1869+
}
1870+
}
18291871
}
18301872
};
18311873

@@ -1840,17 +1882,17 @@ var JpxImage = (function JpxImageClosure() {
18401882

18411883
ReversibleTransform.prototype = Object.create(Transform.prototype);
18421884
ReversibleTransform.prototype.filter =
1843-
function reversibleTransformFilter(y, offset, length, i0, x) {
1885+
function reversibleTransformFilter(x, offset, length) {
18441886
var len = length >> 1;
18451887
offset = offset | 0;
18461888
var j, n;
18471889

18481890
for (j = offset, n = len + 1; n--; j += 2) {
1849-
x[j] = y[j] - ((y[j - 1] + y[j + 1] + 2) >> 2);
1891+
x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
18501892
}
18511893

18521894
for (j = offset + 1, n = len; n--; j += 2) {
1853-
x[j] = y[j] + ((x[j - 1] + x[j + 1]) >> 1);
1895+
x[j] += (x[j - 1] + x[j + 1]) >> 1;
18541896
}
18551897
};
18561898

0 commit comments

Comments
 (0)