Skip to content

Commit

Permalink
Implement interlace support based on foliojs#8
Browse files Browse the repository at this point in the history
  • Loading branch information
blikblum committed Sep 29, 2019
1 parent cd085b7 commit 57f7644
Show file tree
Hide file tree
Showing 4 changed files with 35,537 additions and 12,890 deletions.
204 changes: 121 additions & 83 deletions png-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,110 +185,148 @@ module.exports = class PNG {
throw err;
}

const { width, height } = this;
const pixelBytes = this.pixelBitlength / 8;
const scanlineLength = pixelBytes * this.width;

const pixels = new Buffer(scanlineLength * this.height);
const pixels = new Buffer(width * height * pixelBytes);
const { length } = data;
let row = 0;
let pos = 0;
let c = 0;

while (pos < length) {
var byte, col, i, left, upper;
switch (data[pos++]) {
case 0: // None
for (i = 0; i < scanlineLength; i++) {
pixels[c++] = data[pos++];
}
break;

case 1: // Sub
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
pixels[c++] = (byte + left) % 256;
}
break;

case 2: // Up
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
upper =
row &&
pixels[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
pixels[c++] = (upper + byte) % 256;
}
break;

case 3: // Average
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
upper =
row &&
pixels[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256;
}
break;

case 4: // Paeth
for (i = 0; i < scanlineLength; i++) {
var paeth, upperLeft;
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : pixels[c - pixelBytes];

if (row === 0) {
upper = upperLeft = 0;
} else {
function pass(x0, y0, dx, dy, singlePass = false) {
const w = Math.ceil((width - x0) / dx);
const h = Math.ceil((height - y0) / dy);
const scanlineLength = pixelBytes * w;
const buffer = singlePass ? pixels : new Buffer(scanlineLength * h);
let row = 0;
let c = 0;
while (row < h && pos < length) {
var byte, col, i, left, upper;
switch (data[pos++]) {
case 0: // None
for (i = 0; i < scanlineLength; i++) {
buffer[c++] = data[pos++];
}
break;

case 1: // Sub
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];
buffer[c++] = (byte + left) % 256;
}
break;

case 2: // Up
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
upper =
pixels[
row &&
buffer[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
upperLeft =
col &&
pixels[
buffer[c++] = (upper + byte) % 256;
}
break;

case 3: // Average
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];
upper =
row &&
buffer[
(row - 1) * scanlineLength +
(col - 1) * pixelBytes +
col * pixelBytes +
(i % pixelBytes)
];
buffer[c++] = (byte + Math.floor((left + upper) / 2)) % 256;
}
break;

case 4: // Paeth
for (i = 0; i < scanlineLength; i++) {
var paeth, upperLeft;
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];

if (row === 0) {
upper = upperLeft = 0;
} else {
upper =
buffer[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
upperLeft =
col &&
buffer[
(row - 1) * scanlineLength +
(col - 1) * pixelBytes +
(i % pixelBytes)
];
}

const p = left + upper - upperLeft;
const pa = Math.abs(p - left);
const pb = Math.abs(p - upper);
const pc = Math.abs(p - upperLeft);

if (pa <= pb && pa <= pc) {
paeth = left;
} else if (pb <= pc) {
paeth = upper;
} else {
paeth = upperLeft;
}

const p = left + upper - upperLeft;
const pa = Math.abs(p - left);
const pb = Math.abs(p - upper);
const pc = Math.abs(p - upperLeft);

if (pa <= pb && pa <= pc) {
paeth = left;
} else if (pb <= pc) {
paeth = upper;
} else {
paeth = upperLeft;
buffer[c++] = (byte + paeth) % 256;
}
break;

default:
throw new Error(`Invalid filter algorithm: ${data[pos - 1]}`);
}

pixels[c++] = (byte + paeth) % 256;
if (!singlePass) {
let pixelsPos = ((y0 + row * dy) * width + x0) * pixelBytes;
let bufferPos = row * scanlineLength;
for (i = 0; i < w; i++) {
for (let j = 0; j < pixelBytes; j++)
pixels[pixelsPos++] = buffer[bufferPos++];
pixelsPos += (dx - 1) * pixelBytes;
}
break;
}

default:
throw new Error(`Invalid filter algorithm: ${data[pos - 1]}`);
row++;
}
}

row++;
if (this.interlaceMethod === 1) {
/*
1 6 4 6 2 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
3 6 4 6 3 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
*/
pass(0, 0, 8, 8); // 1
pass(4, 0, 8, 8); // 2
pass(0, 4, 4, 8); // 3
pass(2, 0, 4, 4); // 4
pass(0, 2, 2, 4); // 5
pass(1, 0, 2, 2); // 6
pass(0, 1, 1, 2); // 7
} else {
pass(0, 0, 1, 1, true);
}

return fn(pixels);
Expand Down

0 comments on commit 57f7644

Please sign in to comment.