Reduces amount of used memory during PNG creation.
This commit is contained in:
parent
458b69b649
commit
56f0539045
@ -30,7 +30,12 @@ function createScratchSVG(width, height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
||||||
var crcTable = [];
|
var PNG_HEADER =
|
||||||
|
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
||||||
|
|
||||||
|
var CHUNK_WRAPPER_SIZE = 12;
|
||||||
|
|
||||||
|
var crcTable = new Int32Array(256);
|
||||||
for (var i = 0; i < 256; i++) {
|
for (var i = 0; i < 256; i++) {
|
||||||
var c = i;
|
var c = i;
|
||||||
for (var h = 0; h < 8; h++) {
|
for (var h = 0; h < 8; h++) {
|
||||||
@ -53,32 +58,32 @@ var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
|||||||
return crc ^ -1;
|
return crc ^ -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPngChunk(type, data) {
|
function writePngChunk(type, body, data, offset) {
|
||||||
var chunk = new Uint8Array(12 + data.length);
|
var p = offset;
|
||||||
var p = 0;
|
|
||||||
|
|
||||||
var len = data.length;
|
var len = body.length;
|
||||||
chunk[p] = len >> 24 & 0xff;
|
|
||||||
chunk[p + 1] = len >> 16 & 0xff;
|
|
||||||
chunk[p + 2] = len >> 8 & 0xff;
|
|
||||||
chunk[p + 3] = len & 0xff;
|
|
||||||
|
|
||||||
chunk[p + 4] = type.charCodeAt(0) & 0xff;
|
data[p] = len >> 24 & 0xff;
|
||||||
chunk[p + 5] = type.charCodeAt(1) & 0xff;
|
data[p + 1] = len >> 16 & 0xff;
|
||||||
chunk[p + 6] = type.charCodeAt(2) & 0xff;
|
data[p + 2] = len >> 8 & 0xff;
|
||||||
chunk[p + 7] = type.charCodeAt(3) & 0xff;
|
data[p + 3] = len & 0xff;
|
||||||
|
p += 4;
|
||||||
|
|
||||||
chunk.set(data, 8);
|
data[p] = type.charCodeAt(0) & 0xff;
|
||||||
|
data[p + 1] = type.charCodeAt(1) & 0xff;
|
||||||
|
data[p + 2] = type.charCodeAt(2) & 0xff;
|
||||||
|
data[p + 3] = type.charCodeAt(3) & 0xff;
|
||||||
|
p += 4;
|
||||||
|
|
||||||
p = 8 + len;
|
data.set(body, p);
|
||||||
|
p += body.length;
|
||||||
|
|
||||||
var crc = crc32(chunk, 4, p);
|
var crc = crc32(data, offset + 4, p);
|
||||||
chunk[p] = crc >> 24 & 0xff;
|
|
||||||
chunk[p + 1] = crc >> 16 & 0xff;
|
|
||||||
chunk[p + 2] = crc >> 8 & 0xff;
|
|
||||||
chunk[p + 3] = crc & 0xff;
|
|
||||||
|
|
||||||
return chunk;
|
data[p] = crc >> 24 & 0xff;
|
||||||
|
data[p + 1] = crc >> 16 & 0xff;
|
||||||
|
data[p + 2] = crc >> 8 & 0xff;
|
||||||
|
data[p + 3] = crc & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
function adler32(data, start, end) {
|
function adler32(data, start, end) {
|
||||||
@ -119,18 +124,26 @@ var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
|||||||
throw new Error('invalid format');
|
throw new Error('invalid format');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prefix every row with predictor 0
|
||||||
var literals = new Uint8Array((1 + lineSize) * height);
|
var literals = new Uint8Array((1 + lineSize) * height);
|
||||||
var offsetLiterals = 0, offsetBytes = 0;
|
var offsetLiterals = 0, offsetBytes = 0;
|
||||||
for (var y = 0; y < height; ++y) {
|
var y, i;
|
||||||
literals[offsetLiterals++] = 0;
|
for (y = 0; y < height; ++y) {
|
||||||
|
literals[offsetLiterals++] = 0; // no prediction
|
||||||
literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),
|
literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),
|
||||||
offsetLiterals);
|
offsetLiterals);
|
||||||
offsetBytes += lineSize;
|
offsetBytes += lineSize;
|
||||||
offsetLiterals += lineSize;
|
offsetLiterals += lineSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind === ImageKind.GRAYSCALE_1BPP) {
|
if (kind === ImageKind.GRAYSCALE_1BPP) {
|
||||||
for (var i = 0, ii = bytes.length; i < ii; i++) {
|
// inverting for B/W
|
||||||
bytes[i] ^= 0xFF;
|
offsetLiterals = 0;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
offsetLiterals++; // skipping predictor
|
||||||
|
for (i = 0; i < lineSize; i++) {
|
||||||
|
literals[offsetLiterals++] ^= 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,14 +166,15 @@ var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
|||||||
var len = literals.length;
|
var len = literals.length;
|
||||||
var maxBlockLength = 0xFFFF;
|
var maxBlockLength = 0xFFFF;
|
||||||
|
|
||||||
var idat = new Uint8Array(2 + len +
|
var deflateBlocks = Math.ceil(len / maxBlockLength);
|
||||||
Math.ceil(len / maxBlockLength) * 5 + 4);
|
var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);
|
||||||
var pi = 0;
|
var pi = 0;
|
||||||
idat[pi++] = 0x78; // compression method and flags
|
idat[pi++] = 0x78; // compression method and flags
|
||||||
idat[pi++] = 0x9c; // flags
|
idat[pi++] = 0x9c; // flags
|
||||||
|
|
||||||
var pos = 0;
|
var pos = 0;
|
||||||
while (len > maxBlockLength) {
|
while (len > maxBlockLength) {
|
||||||
|
// writing non-final DEFLATE blocks type 0 and length of 65535
|
||||||
idat[pi++] = 0x00;
|
idat[pi++] = 0x00;
|
||||||
idat[pi++] = 0xff;
|
idat[pi++] = 0xff;
|
||||||
idat[pi++] = 0xff;
|
idat[pi++] = 0xff;
|
||||||
@ -172,12 +186,12 @@ var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
|||||||
len -= maxBlockLength;
|
len -= maxBlockLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writing non-final DEFLATE blocks type 0
|
||||||
idat[pi++] = 0x01;
|
idat[pi++] = 0x01;
|
||||||
idat[pi++] = len & 0xff;
|
idat[pi++] = len & 0xff;
|
||||||
idat[pi++] = len >> 8 & 0xff;
|
idat[pi++] = len >> 8 & 0xff;
|
||||||
idat[pi++] = (~len & 0xffff) & 0xff;
|
idat[pi++] = (~len & 0xffff) & 0xff;
|
||||||
idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
|
idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
|
||||||
|
|
||||||
idat.set(literals.subarray(pos), pi);
|
idat.set(literals.subarray(pos), pi);
|
||||||
pi += literals.length - pos;
|
pi += literals.length - pos;
|
||||||
|
|
||||||
@ -187,28 +201,26 @@ var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
|||||||
idat[pi++] = adler >> 8 & 0xff;
|
idat[pi++] = adler >> 8 & 0xff;
|
||||||
idat[pi++] = adler & 0xff;
|
idat[pi++] = adler & 0xff;
|
||||||
|
|
||||||
var chunks = [
|
// PNG will consists: header, IHDR+data, IDAT+data, and IEND.
|
||||||
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
|
var pngLength = PNG_HEADER.length + CHUNK_WRAPPER_SIZE * 3 +
|
||||||
createPngChunk('IHDR', ihdr),
|
ihdr.length + idat.length;
|
||||||
createPngChunk('IDAT', idat),
|
var data = new Uint8Array(pngLength);
|
||||||
createPngChunk('IEND', new Uint8Array(0))
|
var offset = 0;
|
||||||
];
|
data.set(PNG_HEADER, offset);
|
||||||
|
offset += PNG_HEADER.length;
|
||||||
|
writePngChunk('IHDR', ihdr, data, offset);
|
||||||
|
offset += CHUNK_WRAPPER_SIZE + ihdr.length;
|
||||||
|
writePngChunk('IDATA', idat, data, offset);
|
||||||
|
offset += CHUNK_WRAPPER_SIZE + idat.length;
|
||||||
|
writePngChunk('IEND', new Uint8Array(0), data, offset);
|
||||||
|
|
||||||
var data = [];
|
|
||||||
for (var j = 0; j < 3; j++) {
|
|
||||||
data.push.apply(data, chunks[j]);
|
|
||||||
}
|
|
||||||
data = new Uint8Array(data);
|
|
||||||
return PDFJS.createObjectURL(data, 'image/png');
|
return PDFJS.createObjectURL(data, 'image/png');
|
||||||
}
|
}
|
||||||
|
|
||||||
return function convertImgDataToPng(imgData) {
|
return function convertImgDataToPng(imgData) {
|
||||||
var kind = (imgData.kind === undefined ?
|
var kind = (imgData.kind === undefined ?
|
||||||
ImageKind.GRAYSCALE_1BPP : imgData.kind);
|
ImageKind.GRAYSCALE_1BPP : imgData.kind);
|
||||||
var url = encode(imgData, kind);
|
return encode(imgData, kind);
|
||||||
if (url) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user