@dualbox/dualbox-lib-upng
Version:
PNG encoder/decoder
1,818 lines (1,543 loc) • 852 kB
JavaScript
require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({"@dualbox/dualbox-lib-upng":[function(require,module,exports){
"use strict";
/* eslint-env es6 */
// I don't know why, but this is required for Uint* stuff
var UPNG = {};
var pako = require('pako');
UPNG.toRGBA8 = function (out) {
//console.log(out.ctype, out.depth);
var w = out.width,
h = out.height,
area = w * h,
bpp = UPNG.decode._getBPP(out);
var bpl = Math.ceil(w * bpp / 8); // bytes per line
var bf = new Uint8Array(area * 4),
bf32 = new Uint32Array(bf.buffer);
var data = out.data,
ctype = out.ctype,
depth = out.depth;
var rs = UPNG._bin.readUshort;
if (ctype == 6) {
// RGB + alpha
var qarea = area << 2;
if (depth == 8) for (var i = 0; i < qarea; i++) {
bf[i] = data[i];
/*if((i&3)==3) bf[i]=255;*/
}
if (depth == 16) for (var i = 0; i < qarea; i++) {
bf[i] = data[i << 1];
}
} else if (ctype == 2) {
// RGB
var ts = out.tabs["tRNS"],
tr = -1,
tg = -1,
tb = -1;
if (ts) {
tr = ts[0];
tg = ts[1];
tb = ts[2];
}
if (depth == 8) for (var i = 0; i < area; i++) {
var qi = i << 2,
ti = i * 3;
bf[qi] = data[ti];
bf[qi + 1] = data[ti + 1];
bf[qi + 2] = data[ti + 2];
bf[qi + 3] = 255;
if (tr != -1 && data[ti] == tr && data[ti + 1] == tg && data[ti + 2] == tb) bf[qi + 3] = 0;
}
if (depth == 16) for (var i = 0; i < area; i++) {
var qi = i << 2,
ti = i * 6;
bf[qi] = data[ti];
bf[qi + 1] = data[ti + 2];
bf[qi + 2] = data[ti + 4];
bf[qi + 3] = 255;
if (tr != -1 && rs(data, ti) == tr && rs(data, ti + 2) == tg && rs(data, ti + 4) == tb) bf[qi + 3] = 0;
}
} else if (ctype == 3) {
// palette
var p = out.tabs["PLTE"],
ap = out.tabs["tRNS"],
tl = ap ? ap.length : 0;
if (depth == 1) for (var y = 0; y < h; y++) {
var s0 = y * bpl,
t0 = y * w;
for (var i = 0; i < w; i++) {
var qi = t0 + i << 2,
j = data[s0 + (i >> 3)] >> 7 - ((i & 7) << 0) & 1,
cj = 3 * j;
bf[qi] = p[cj];
bf[qi + 1] = p[cj + 1];
bf[qi + 2] = p[cj + 2];
bf[qi + 3] = j < tl ? ap[j] : 255;
}
}
if (depth == 2) for (var y = 0; y < h; y++) {
var s0 = y * bpl,
t0 = y * w;
for (var i = 0; i < w; i++) {
var qi = t0 + i << 2,
j = data[s0 + (i >> 2)] >> 6 - ((i & 3) << 1) & 3,
cj = 3 * j;
bf[qi] = p[cj];
bf[qi + 1] = p[cj + 1];
bf[qi + 2] = p[cj + 2];
bf[qi + 3] = j < tl ? ap[j] : 255;
}
}
if (depth == 4) for (var y = 0; y < h; y++) {
var s0 = y * bpl,
t0 = y * w;
for (var i = 0; i < w; i++) {
var qi = t0 + i << 2,
j = data[s0 + (i >> 1)] >> 4 - ((i & 1) << 2) & 15,
cj = 3 * j;
bf[qi] = p[cj];
bf[qi + 1] = p[cj + 1];
bf[qi + 2] = p[cj + 2];
bf[qi + 3] = j < tl ? ap[j] : 255;
}
}
if (depth == 8) for (var i = 0; i < area; i++) {
var qi = i << 2,
j = data[i],
cj = 3 * j;
bf[qi] = p[cj];
bf[qi + 1] = p[cj + 1];
bf[qi + 2] = p[cj + 2];
bf[qi + 3] = j < tl ? ap[j] : 255;
}
} else if (ctype == 4) {
// gray + alpha
if (depth == 8) for (var i = 0; i < area; i++) {
var qi = i << 2,
di = i << 1,
gr = data[di];
bf[qi] = gr;
bf[qi + 1] = gr;
bf[qi + 2] = gr;
bf[qi + 3] = data[di + 1];
}
if (depth == 16) for (var i = 0; i < area; i++) {
var qi = i << 2,
di = i << 2,
gr = data[di];
bf[qi] = gr;
bf[qi + 1] = gr;
bf[qi + 2] = gr;
bf[qi + 3] = data[di + 2];
}
} else if (ctype == 0) {
// gray
var tr = out.tabs["tRNS"] ? out.tabs["tRNS"] : -1;
if (depth == 1) for (var i = 0; i < area; i++) {
var gr = 255 * (data[i >> 3] >> 7 - (i & 7) & 1),
al = gr == tr * 255 ? 0 : 255;
bf32[i] = al << 24 | gr << 16 | gr << 8 | gr;
}
if (depth == 2) for (var i = 0; i < area; i++) {
var gr = 85 * (data[i >> 2] >> 6 - ((i & 3) << 1) & 3),
al = gr == tr * 85 ? 0 : 255;
bf32[i] = al << 24 | gr << 16 | gr << 8 | gr;
}
if (depth == 4) for (var i = 0; i < area; i++) {
var gr = 17 * (data[i >> 1] >> 4 - ((i & 1) << 2) & 15),
al = gr == tr * 17 ? 0 : 255;
bf32[i] = al << 24 | gr << 16 | gr << 8 | gr;
}
if (depth == 8) for (var i = 0; i < area; i++) {
var gr = data[i],
al = gr == tr ? 0 : 255;
bf32[i] = al << 24 | gr << 16 | gr << 8 | gr;
}
if (depth == 16) for (var i = 0; i < area; i++) {
var gr = data[i << 1],
al = rs(data, i << 1) == tr ? 0 : 255;
bf32[i] = al << 24 | gr << 16 | gr << 8 | gr;
}
} else console.log("unsupported color type", ctype);
return bf;
};
UPNG.encode = function (buff, w, h, ps) {
if (ps == null) ps = 0;
var img = new Uint8Array(buff);
var data = new Uint8Array(img.length + 100);
var wr = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
for (var i = 0; i < 8; i++) {
data[i] = wr[i];
}
var offset = 8,
bin = UPNG._bin,
crc = UPNG.crc.crc;
var nimg = UPNG.encode.compress(img, w, h, ps);
bin.writeUint(data, offset, 13);
offset += 4;
bin.writeASCII(data, offset, "IHDR");
offset += 4;
bin.writeUint(data, offset, w);
offset += 4;
bin.writeUint(data, offset, h);
offset += 4;
data[offset] = nimg.depth;
offset++; // depth
data[offset] = nimg.ctype;
offset++; // ctype
data[offset] = 0;
offset++; // compress
data[offset] = 0;
offset++; // filter
data[offset] = 0;
offset++; // interlace
bin.writeUint(data, offset, crc(data, offset - 17, 17));
offset += 4; // crc
// 9 bytes to say, that it is sRGB
bin.writeUint(data, offset, 1);
offset += 4;
bin.writeASCII(data, offset, "sRGB");
offset += 4;
data[offset] = 1;
offset++;
bin.writeUint(data, offset, crc(data, offset - 5, 5));
offset += 4; // crc
if (nimg.ctype == 3) {
var dl = nimg.plte.length;
bin.writeUint(data, offset, dl * 3);
offset += 4;
bin.writeASCII(data, offset, "PLTE");
offset += 4;
for (var i = 0; i < dl; i++) {
var ti = i * 3,
c = nimg.plte[i],
r = c & 255,
g = c >> 8 & 255,
b = c >> 16 & 255;
data[offset + ti + 0] = r;
data[offset + ti + 1] = g;
data[offset + ti + 2] = b;
}
offset += dl * 3;
bin.writeUint(data, offset, crc(data, offset - dl * 3 - 4, dl * 3 + 4));
offset += 4; // crc
if (nimg.gotAlpha) {
bin.writeUint(data, offset, dl);
offset += 4;
bin.writeASCII(data, offset, "tRNS");
offset += 4;
for (var i = 0; i < dl; i++) {
data[offset + i] = nimg.plte[i] >> 24 & 255;
}
offset += dl;
bin.writeUint(data, offset, crc(data, offset - dl - 4, dl + 4));
offset += 4; // crc
}
}
var dl = nimg.data.length;
bin.writeUint(data, offset, dl);
offset += 4;
bin.writeASCII(data, offset, "IDAT");
offset += 4;
for (var i = 0; i < dl; i++) {
data[offset + i] = nimg.data[i];
}
offset += dl;
bin.writeUint(data, offset, crc(data, offset - dl - 4, dl + 4));
offset += 4; // crc
bin.writeUint(data, offset, 0);
offset += 4;
bin.writeASCII(data, offset, "IEND");
offset += 4;
bin.writeUint(data, offset, crc(data, offset - 4, 4));
offset += 4; // crc
return data.buffer.slice(0, offset);
};
UPNG.encode.compress = function (img, w, h, ps) {
if (ps != 0) img = UPNG.quantize(img, w, h, ps);
var ctype = 6,
depth = 8,
plte = [],
bpp = 4,
bpl = 4 * w;
var img32 = new Uint32Array(img.buffer);
var gotAlpha = false,
cmap = [];
for (var i = 0; i < img.length; i += 4) {
var c = img32[i >> 2];
if (plte.length < 600 && cmap[c] == null) {
cmap[c] = plte.length;
plte.push(c);
}
if (img[i + 3] != 255) gotAlpha = true;
}
var cc = plte.length;
if (cc <= 256) {
if (cc <= 2) depth = 1;else if (cc <= 4) depth = 2;else if (cc <= 16) depth = 4;else depth = 8;
bpl = Math.ceil(depth * w / 8), nimg = new Uint8Array(bpl * h);
for (var y = 0; y < h; y++) {
var i = y * bpl,
ii = y * w;
if (depth == 1) for (var x = 0; x < w; x++) {
nimg[i + (x >> 3)] |= cmap[img32[ii + x]] << 7 - (x & 7);
}
if (depth == 2) for (var x = 0; x < w; x++) {
nimg[i + (x >> 2)] |= cmap[img32[ii + x]] << 6 - (x & 3) * 2;
}
if (depth == 4) for (var x = 0; x < w; x++) {
nimg[i + (x >> 1)] |= cmap[img32[ii + x]] << 4 - (x & 1) * 4;
}
if (depth == 8) for (var x = 0; x < w; x++) {
nimg[i + x] = cmap[img32[ii + x]];
}
}
img = nimg;
ctype = 3;
bpp = 1;
} else if (gotAlpha == false) {
var nimg = new Uint8Array(w * h * 3),
area = w * h;
for (var i = 0; i < area; i++) {
var ti = i * 3,
qi = i * 4;
nimg[ti] = img[qi];
nimg[ti + 1] = img[qi + 1];
nimg[ti + 2] = img[qi + 2];
}
img = nimg;
ctype = 2;
bpp = 3;
bpl = 3 * w;
}
var data = new Uint8Array(w * h * bpp + h);
return {
ctype: ctype,
depth: depth,
plte: plte,
gotAlpha: gotAlpha,
data: UPNG.encode._filterZero(img, h, bpp, bpl, data)
};
};
UPNG.encode._filterZero = function (img, h, bpp, bpl, data) {
var fls = [];
for (var t = 0; t < 5; t++) {
if (h * bpl > 500000 && (t == 2 || t == 3 || t == 4)) continue;
for (var y = 0; y < h; y++) {
UPNG.encode._filterLine(data, img, y, bpl, bpp, t);
}
fls.push(pako["deflate"](data));
if (bpp == 1) break;
}
var ti,
tsize = 1e9;
for (var i = 0; i < fls.length; i++) {
if (fls[i].length < tsize) {
ti = i;
tsize = fls[i].length;
}
} //console.log("top filter", ti);
return fls[ti];
};
UPNG.encode._filterLine = function (data, img, y, bpl, bpp, type) {
var i = y * bpl,
di = i + y,
paeth = UPNG.decode._paeth;
data[di] = type;
di++;
if (type == 0) for (var x = 0; x < bpl; x++) {
data[di + x] = img[i + x];
} else if (type == 1) {
for (var x = 0; x < bpp; x++) {
data[di + x] = img[i + x];
}
for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x] - img[i + x - bpp] + 256 & 255;
}
} else if (y == 0) {
for (var x = 0; x < bpp; x++) {
data[di + x] = img[i + x];
}
if (type == 2) for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x];
}
if (type == 3) for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x] - (img[i + x - bpp] >> 1) + 256 & 255;
}
if (type == 4) for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x] - paeth(img[i + x - bpp], 0, 0) + 256 & 255;
}
} else {
if (type == 2) {
for (var x = 0; x < bpl; x++) {
data[di + x] = img[i + x] + 256 - img[i + x - bpl] & 255;
}
}
if (type == 3) {
for (var x = 0; x < bpp; x++) {
data[di + x] = img[i + x] + 256 - (img[i + x - bpl] >> 1) & 255;
}
for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x] + 256 - (img[i + x - bpl] + img[i + x - bpp] >> 1) & 255;
}
}
if (type == 4) {
for (var x = 0; x < bpp; x++) {
data[di + x] = img[i + x] + 256 - paeth(0, img[i + x - bpl], 0) & 255;
}
for (var x = bpp; x < bpl; x++) {
data[di + x] = img[i + x] + 256 - paeth(img[i + x - bpp], img[i + x - bpl], img[i + x - bpp - bpl]) & 255;
}
}
}
};
UPNG.crc = {
table: function () {
var tab = new Uint32Array(256);
for (var n = 0; n < 256; n++) {
var c = n;
for (var k = 0; k < 8; k++) {
if (c & 1) c = 0xedb88320 ^ c >>> 1;else c = c >>> 1;
}
tab[n] = c;
}
return tab;
}(),
update: function update(c, buf, off, len) {
for (var i = 0; i < len; i++) {
c = UPNG.crc.table[(c ^ buf[off + i]) & 0xff] ^ c >>> 8;
}
return c;
},
crc: function crc(b, o, l) {
return UPNG.crc.update(0xffffffff, b, o, l) ^ 0xffffffff;
}
};
UPNG.quantize = function (img, w, h, ps) {
var nimg = new Uint8Array(img.length),
pind = new Uint16Array(w * h),
area = w * h,
edist = UPNG.quantize.dist;
for (var i = 0; i < area; i++) {
var qi = i << 2,
a = img[qi + 3] / 255;
nimg[qi + 0] = img[qi + 0] * a;
nimg[qi + 1] = img[qi + 1] * a;
nimg[qi + 2] = img[qi + 2] * a;
nimg[qi + 3] = img[qi + 3];
}
var plte = [],
used = [],
pr = 0,
plim = Math.max(100, 10 * ps);
while (true) {
used = [];
plte = [];
var msk = 0xff - ((1 << pr) - 1),
add = 1 << pr >> 1;
for (var i = 0; i < area; i++) {
var qi = i << 2;
var r = nimg[qi],
g = nimg[qi + 1],
b = nimg[qi + 2],
a = nimg[qi + 3];
var nr = (r & msk) + add,
ng = (g & msk) + add,
nb = (b & msk) + add,
na = (a & msk) + add,
key = na << 24 | nb << 16 | ng << 8 | nr;
if (used[key]) {
var pv = plte[used[key]];
pv.occ++;
} else {
used[key] = plte.length;
plte.push({
occ: 1,
r: nr,
g: ng,
b: nb,
a: na
});
}
if (plte.length > plim) break;
}
if (plte.length > plim) {
pr++;
continue;
}
break;
}
if (pr == 0 && plte.length <= ps) return img;
plte.sort(function (a, b) {
return b.occ - a.occ;
});
ps = Math.min(ps, plte.length);
var nplte = new Uint8Array(ps * 4);
for (var i = 0; i < ps; i++) {
var qi = i << 2,
c = plte[i];
nplte[qi] = c.r;
nplte[qi + 1] = c.g;
nplte[qi + 2] = c.b;
nplte[qi + 3] = c.a;
}
plte = nplte; //*/
var icnt = Math.max(1, Math.min(10, Math.floor(1024 / ps)));
for (var it = 0; it < icnt; it++) {
var hist = new Uint32Array(ps),
nplt = new Uint32Array(ps * 4);
var ndst = new Uint32Array(ps),
nind = new Uint32Array(ps);
for (var i = 0; i < ps; i++) {
var qi = i << 2;
var r = plte[qi],
g = plte[qi + 1],
b = plte[qi + 2],
a = plte[qi + 3];
var ci = 0;
cd = 1e9;
for (var j = 0; j < ps; j++) {
if (j == i) continue;
var dst = edist(r, g, b, a, plte, j << 2);
if (dst < cd) {
ci = j;
cd = dst;
}
}
ndst[i] = cd;
nind[i] = ci;
}
for (var i = 0; i < area; i++) {
var qi = i << 2;
var r = nimg[qi],
g = nimg[qi + 1],
b = nimg[qi + 2],
a = nimg[qi + 3];
var ci = 0,
cd = 1e9;
ci = pind[i];
cd = edist(r, g, b, a, plte, ci << 2);
if (cd <= ndst[ci] >> 1) {} else for (var j = 0; j < ps; j++) {
var dst = edist(r, g, b, a, plte, j << 2);
if (dst < cd) {
ci = j;
cd = dst;
if (dst <= ndst[ci] >> 1) break;
var dst = edist(r, g, b, a, plte, nind[j] << 2);
if (dst <= ndst[ci] >> 1) {
ci = nind[j];
break;
}
}
}
pind[i] = ci;
hist[ci]++;
var qci = ci << 2;
nplt[qci] += r;
nplt[qci + 1] += g;
nplt[qci + 2] += b;
nplt[qci + 3] += a;
}
for (var i = 0; i < ps; i++) {
var qi = i << 2,
den = 1 / hist[i];
plte[qi] = nplt[qi] * den;
plte[qi + 1] = nplt[qi + 1] * den;
plte[qi + 2] = nplt[qi + 2] * den;
plte[qi + 3] = nplt[qi + 3] * den;
}
} //UPNG.quantize.dither(nimg, w,h, pind,plte, ps); // I think that (current) dithering is not worth it
for (var i = 0; i < area; i++) {
var qi = i << 2,
ci = pind[i],
qci = ci << 2,
ia = plte[qci + 3] == 0 ? 0 : 255 / plte[qci + 3];
nimg[qi + 0] = plte[qci + 0] * ia;
nimg[qi + 1] = plte[qci + 1] * ia;
nimg[qi + 2] = plte[qci + 2] * ia;
nimg[qi + 3] = plte[qci + 3];
}
return nimg;
};
UPNG.quantize.dist = function (r, g, b, a, ba, bi) {
var pr = ba[bi],
pg = ba[bi + 1],
pb = ba[bi + 2],
pa = ba[bi + 3];
return (pr - r) * (pr - r) + (pg - g) * (pg - g) + (pb - b) * (pb - b) + (pa - a) * (pa - a);
};
UPNG.quantize.dither = function (nimg, w, h, pind, plte, ps) {
var err = new Float32Array(w * h * 4),
i16 = 1 / 16;
var edist = UPNG.quantize.dist,
round = Math.round,
qw = w << 2;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
var i = y * w + x,
qi = i << 2;
for (var j = 0; j < 4; j++) {
err[qi + j] = Math.max(-8, Math.min(8, err[qi + j]));
}
var r = round(nimg[qi] + err[qi]),
g = round(nimg[qi + 1] + err[qi + 1]),
b = round(nimg[qi + 2] + err[qi + 2]),
a = round(nimg[qi + 3] + err[qi + 3]);
var ci = 0,
cd = 1e9;
for (var j = 0; j < ps; j++) {
var dst = edist(r, g, b, a, plte, j << 2);
if (dst < cd) {
ci = j;
cd = dst;
}
}
pind[i] = ci;
var ciq = ci << 2;
var dr = r - plte[ciq],
dg = g - plte[ciq + 1],
db = b - plte[ciq + 2],
da = a - plte[ciq + 3];
err[qi + 4 + 0] += 7 * dr * i16;
err[qi + 4 + 1] += 7 * dg * i16;
err[qi + 4 + 2] += 7 * db * i16;
err[qi + 4 + 3] += 7 * da * i16;
err[qi + qw - 4 + 0] += 3 * dr * i16;
err[qi + qw - 4 + 1] += 3 * dg * i16;
err[qi + qw - 4 + 2] += 3 * db * i16;
err[qi + qw - 4 + 3] += 3 * da * i16;
err[qi + qw + 0] += 5 * dr * i16;
err[qi + qw + 1] += 5 * dg * i16;
err[qi + qw + 2] += 5 * db * i16;
err[qi + qw + 3] += 5 * da * i16;
err[qi + qw + 4 + 0] += 1 * dr * i16;
err[qi + qw + 4 + 1] += 1 * dg * i16;
err[qi + qw + 4 + 2] += 1 * db * i16;
err[qi + qw + 4 + 3] += 1 * da * i16;
}
}
};
UPNG.decode = function (buff) {
var data = new Uint8Array(buff),
offset = 8,
bin = UPNG._bin,
rUs = bin.readUshort;
var out = {
tabs: {}
};
var dd = new Uint8Array(data.length),
doff = 0; // put all IDAT data into it
while (true) {
var len = bin.readUint(data, offset);
offset += 4;
var type = bin.readASCII(data, offset, 4);
offset += 4; //console.log(offset, len, type);
if (type == "IHDR") {
UPNG.decode._IHDR(data, offset, out);
} else if (type == "IDAT") {
for (var i = 0; i < len; i++) {
dd[doff + i] = data[offset + i];
}
doff += len;
} else if (type == "pHYs") {
out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset + 4), data[offset + 8]];
} else if (type == "cHRM") {
out.tabs[type] = [];
for (var i = 0; i < 8; i++) {
out.tabs[type].push(bin.readUint(data, offset + i * 4));
}
} else if (type == "tEXt") {
if (out.tabs[type] == null) out.tabs[type] = {};
var nz = bin.nextZero(data, offset);
var keyw = bin.readASCII(data, offset, nz - offset);
var text = bin.readASCII(data, nz + 1, offset + len - nz - 1);
out.tabs[type][keyw] = text;
} else if (type == "iTXt") {
if (out.tabs[type] == null) out.tabs[type] = {};
var nz = 0,
off = offset;
nz = bin.nextZero(data, off);
var keyw = bin.readASCII(data, off, nz - off);
off = nz + 1;
var cflag = data[off],
cmeth = data[off + 1];
off += 2;
nz = bin.nextZero(data, off);
var ltag = bin.readASCII(data, off, nz - off);
off = nz + 1;
nz = bin.nextZero(data, off);
var tkeyw = bin.readUTF8(data, off, nz - off);
off = nz + 1;
var text = bin.readUTF8(data, off, len - (off - offset));
out.tabs[type][keyw] = text;
} else if (type == "PLTE") {
out.tabs[type] = bin.readBytes(data, offset, len);
} else if (type == "hIST") {
var pl = out.tabs["PLTE"].length / 3;
out.tabs[type] = [];
for (var i = 0; i < pl; i++) {
out.tabs[type].push(rUs(data, offset + i * 2));
}
} else if (type == "tRNS") {
if (out.ctype == 3) out.tabs[type] = bin.readBytes(data, offset, len);else if (out.ctype == 0) out.tabs[type] = rUs(data, offset);else if (out.ctype == 2) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)];else console.log("tRNS for unsupported color type", out.ctype, len);
} else if (type == "gAMA") out.tabs[type] = bin.readUint(data, offset) / 100000;else if (type == "sRGB") out.tabs[type] = data[offset];else if (type == "bKGD") {
if (out.ctype == 0 || out.ctype == 4) out.tabs[type] = [rUs(data, offset)];else if (out.ctype == 2 || out.ctype == 6) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)];else if (out.ctype == 3) out.tabs[type] = data[offset];
} else if (type == "IEND") {
if (out.compress == 0) dd = UPNG.decode._inflate(dd);else console.log("unsupported compression method:", out.interlace);
if (out.filter != 0) console.log("unsupported filter method:", out.filter);
if (out.interlace == 0) out.data = UPNG.decode._filterZero(dd, out, 0, out.width, out.height);else if (out.interlace == 1) out.data = UPNG.decode._readInterlace(dd, out);else console.log("unsupported interlace method:", out.interlace);
break;
} else {
console.log("unknown chunk type", type, len);
}
offset += len;
var crc = bin.readUint(data, offset);
offset += 4;
}
delete out.compress;
delete out.interlace;
delete out.filter;
return out;
};
UPNG.decode._inflate = function (data) {
return pako["inflate"](data);
};
UPNG.decode._readInterlace = function (data, out) {
var w = out.width,
h = out.height;
var bpp = UPNG.decode._getBPP(out),
cbpp = bpp >> 3,
bpl = Math.ceil(w * bpp / 8);
var img = new Uint8Array(h * bpl);
var di = 0;
var starting_row = [0, 0, 4, 0, 2, 0, 1];
var starting_col = [0, 4, 0, 2, 0, 1, 0];
var row_increment = [8, 8, 8, 4, 4, 2, 2];
var col_increment = [8, 8, 4, 4, 2, 2, 1];
var pass = 0;
while (pass < 7) {
var ri = row_increment[pass],
ci = col_increment[pass];
var sw = 0,
sh = 0;
var cr = starting_row[pass];
while (cr < h) {
cr += ri;
sh++;
}
var cc = starting_col[pass];
while (cc < w) {
cc += ci;
sw++;
}
var bpll = Math.ceil(sw * bpp / 8);
UPNG.decode._filterZero(data, out, di, sw, sh);
var y = 0,
row = starting_row[pass];
while (row < h) {
var col = starting_col[pass];
var cdi = di + y * bpll << 3;
while (col < w) {
if (bpp == 1) {
var val = data[cdi >> 3];
val = val >> 7 - (cdi & 7) & 1;
img[row * bpl + (col >> 3)] |= val << 7 - ((col & 3) << 0);
}
if (bpp == 2) {
var val = data[cdi >> 3];
val = val >> 6 - (cdi & 7) & 3;
img[row * bpl + (col >> 2)] |= val << 6 - ((col & 3) << 1);
}
if (bpp == 4) {
var val = data[cdi >> 3];
val = val >> 4 - (cdi & 7) & 15;
img[row * bpl + (col >> 1)] |= val << 4 - ((col & 1) << 2);
}
if (bpp >= 8) {
var ii = row * bpl + col * cbpp;
for (var j = 0; j < cbpp; j++) {
img[ii + j] = data[(cdi >> 3) + j];
}
}
cdi += bpp;
col += ci;
}
y++;
row += ri;
}
if (sw * sh != 0) di += sh * (1 + bpll);
pass = pass + 1;
}
return img;
};
UPNG.decode._getBPP = function (out) {
var noc = [1, null, 3, 1, 2, null, 4][out.ctype];
if (noc == null) console.log("unsupported color type", out.ctype);
return noc * out.depth;
};
UPNG.decode._filterZero = function (data, out, off, w, h) {
var bpp = UPNG.decode._getBPP(out),
bpl = Math.ceil(w * bpp / 8),
paeth = UPNG.decode._paeth;
bpp = Math.ceil(bpp / 8);
for (var y = 0; y < h; y++) {
var i = off + y * bpl,
di = i + y + 1;
var type = data[di - 1];
if (type == 0) for (var x = 0; x < bpl; x++) {
data[i + x] = data[di + x];
} else if (type == 1) {
for (var x = 0; x < bpp; x++) {
data[i + x] = data[di + x];
}
for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] + data[i + x - bpp] & 255;
}
} else if (y == 0) {
for (var x = 0; x < bpp; x++) {
data[i + x] = data[di + x];
}
if (type == 2) for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] & 255;
}
if (type == 3) for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] + (data[i + x - bpp] >> 1) & 255;
}
if (type == 4) for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] + paeth(data[i + x - bpp], 0, 0) & 255;
}
} else {
if (type == 2) {
for (var x = 0; x < bpl; x++) {
data[i + x] = data[di + x] + data[i + x - bpl] & 255;
}
}
if (type == 3) {
for (var x = 0; x < bpp; x++) {
data[i + x] = data[di + x] + (data[i + x - bpl] >> 1) & 255;
}
for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] + (data[i + x - bpl] + data[i + x - bpp] >> 1) & 255;
}
}
if (type == 4) {
for (var x = 0; x < bpp; x++) {
data[i + x] = data[di + x] + paeth(0, data[i + x - bpl], 0) & 255;
}
for (var x = bpp; x < bpl; x++) {
data[i + x] = data[di + x] + paeth(data[i + x - bpp], data[i + x - bpl], data[i + x - bpp - bpl]) & 255;
}
}
}
}
return data;
};
UPNG.decode._paeth = function (a, b, c) {
var p = a + b - c,
pa = Math.abs(p - a),
pb = Math.abs(p - b),
pc = Math.abs(p - c);
if (pa <= pb && pa <= pc) return a;else if (pb <= pc) return b;
return c;
};
UPNG.decode._IHDR = function (data, offset, out) {
var bin = UPNG._bin;
out.width = bin.readUint(data, offset);
offset += 4;
out.height = bin.readUint(data, offset);
offset += 4;
out.depth = data[offset];
offset++;
out.ctype = data[offset];
offset++;
out.compress = data[offset];
offset++;
out.filter = data[offset];
offset++;
out.interlace = data[offset];
offset++;
};
UPNG._bin = {
nextZero: function nextZero(data, p) {
while (data[p] != 0) {
p++;
}
return p;
},
readUshort: function readUshort(buff, p) {
return buff[p] << 8 | buff[p + 1];
},
writeUshort: function writeUshort(buff, p, n) {
buff[p] = n >> 8 & 255;
buff[p + 1] = n & 255;
},
readUint: function readUint(buff, p) {
return buff[p] * (256 * 256 * 256) + (buff[p + 1] << 16 | buff[p + 2] << 8 | buff[p + 3]);
},
writeUint: function writeUint(buff, p, n) {
buff[p] = n >> 24 & 255;
buff[p + 1] = n >> 16 & 255;
buff[p + 2] = n >> 8 & 255;
buff[p + 3] = n & 255;
},
readASCII: function readASCII(buff, p, l) {
var s = "";
for (var i = 0; i < l; i++) {
s += String.fromCharCode(buff[p + i]);
}
return s;
},
writeASCII: function writeASCII(data, p, s) {
for (var i = 0; i < s.length; i++) {
data[p + i] = s.charCodeAt(i);
}
},
readBytes: function readBytes(buff, p, l) {
var arr = [];
for (var i = 0; i < l; i++) {
arr.push(buff[p + i]);
}
return arr;
},
pad: function pad(n) {
return n.length < 2 ? "0" + n : n;
},
readUTF8: function readUTF8(buff, p, l) {
var s = "",
ns;
for (var i = 0; i < l; i++) {
s += "%" + UPNG._bin.pad(buff[p + i].toString(16));
}
try {
ns = decodeURIComponent(s);
} catch (e) {
return UPNG._bin.readASCII(buff, p, l);
}
return ns;
}
};
module.exports = UPNG;
},{"pako":1}],1:[function(require,module,exports){
// Top level file is just a mixin of submodules & constants
'use strict';
var assign = require('./lib/utils/common').assign;
var deflate = require('./lib/deflate');
var inflate = require('./lib/inflate');
var constants = require('./lib/zlib/constants');
var pako = {};
assign(pako, deflate, inflate, constants);
module.exports = pako;
},{"./lib/deflate":2,"./lib/inflate":3,"./lib/utils/common":4,"./lib/zlib/constants":7}],2:[function(require,module,exports){
'use strict';
var zlib_deflate = require('./zlib/deflate');
var utils = require('./utils/common');
var strings = require('./utils/strings');
var msg = require('./zlib/messages');
var ZStream = require('./zlib/zstream');
var toString = Object.prototype.toString;
/* Public constants ==========================================================*/
/* ===========================================================================*/
var Z_NO_FLUSH = 0;
var Z_FINISH = 4;
var Z_OK = 0;
var Z_STREAM_END = 1;
var Z_SYNC_FLUSH = 2;
var Z_DEFAULT_COMPRESSION = -1;
var Z_DEFAULT_STRATEGY = 0;
var Z_DEFLATED = 8;
/* ===========================================================================*/
/**
* class Deflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[deflate]],
* [[deflateRaw]] and [[gzip]].
**/
/* internal
* Deflate.chunks -> Array
*
* Chunks of output data, if [[Deflate#onData]] not overridden.
**/
/**
* Deflate.result -> Uint8Array|Array
*
* Compressed result, generated by default [[Deflate#onData]]
* and [[Deflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Deflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Deflate.err -> Number
*
* Error code after deflate finished. 0 (Z_OK) on success.
* You will not need it in real life, because deflate errors
* are possible only on wrong options or bad `onData` / `onEnd`
* custom handlers.
**/
/**
* Deflate.msg -> String
*
* Error message, if [[Deflate.err]] != 0
**/
/**
* new Deflate(options)
* - options (Object): zlib deflate options.
*
* Creates new deflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `level`
* - `windowBits`
* - `memLevel`
* - `strategy`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw deflate
* - `gzip` (Boolean) - create gzip wrapper
* - `to` (String) - if equal to 'string', then result will be "binary string"
* (each char code [0..255])
* - `header` (Object) - custom header for gzip
* - `text` (Boolean) - true if compressed data believed to be text
* - `time` (Number) - modification time, unix timestamp
* - `os` (Number) - operation system code
* - `extra` (Array) - array of bytes with extra data (max 65536)
* - `name` (String) - file name (binary string)
* - `comment` (String) - comment (binary string)
* - `hcrc` (Boolean) - true if header crc should be added
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var deflate = new pako.Deflate({ level: 3});
*
* deflate.push(chunk1, false);
* deflate.push(chunk2, true); // true -> last chunk
*
* if (deflate.err) { throw new Error(deflate.err); }
*
* console.log(deflate.result);
* ```
**/
function Deflate(options) {
if (!(this instanceof Deflate)) return new Deflate(options);
this.options = utils.assign({
level: Z_DEFAULT_COMPRESSION,
method: Z_DEFLATED,
chunkSize: 16384,
windowBits: 15,
memLevel: 8,
strategy: Z_DEFAULT_STRATEGY,
to: ''
}, options || {});
var opt = this.options;
if (opt.raw && opt.windowBits > 0) {
opt.windowBits = -opt.windowBits;
} else if (opt.gzip && opt.windowBits > 0 && opt.windowBits < 16) {
opt.windowBits += 16;
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
var status = zlib_deflate.deflateInit2(this.strm, opt.level, opt.method, opt.windowBits, opt.memLevel, opt.strategy);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
if (opt.header) {
zlib_deflate.deflateSetHeader(this.strm, opt.header);
}
if (opt.dictionary) {
var dict; // Convert data if needed
if (typeof opt.dictionary === 'string') {
// If we need to compress text, change encoding to utf8.
dict = strings.string2buf(opt.dictionary);
} else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
dict = new Uint8Array(opt.dictionary);
} else {
dict = opt.dictionary;
}
status = zlib_deflate.deflateSetDictionary(this.strm, dict);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
this._dict_set = true;
}
}
/**
* Deflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
* converted to utf8 byte sequence.
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
* new compressed chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the compression context.
*
* On fail call [[Deflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* array format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
Deflate.prototype.push = function (data, mode) {
var strm = this.strm;
var chunkSize = this.options.chunkSize;
var status, _mode;
if (this.ended) {
return false;
}
_mode = mode === ~~mode ? mode : mode === true ? Z_FINISH : Z_NO_FLUSH; // Convert data if needed
if (typeof data === 'string') {
// If we need to compress text, change encoding to utf8.
strm.input = strings.string2buf(data);
} else if (toString.call(data) === '[object ArrayBuffer]') {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new utils.Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = zlib_deflate.deflate(strm, _mode);
/* no bad return value */
if (status !== Z_STREAM_END && status !== Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.avail_out === 0 || strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH)) {
if (this.options.to === 'string') {
this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
} else {
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
}
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); // Finalize on the last chunk.
if (_mode === Z_FINISH) {
status = zlib_deflate.deflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === Z_OK;
} // callback interim results if Z_SYNC_FLUSH.
if (_mode === Z_SYNC_FLUSH) {
this.onEnd(Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Deflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
Deflate.prototype.onData = function (chunk) {
this.chunks.push(chunk);
};
/**
* Deflate#onEnd(status) -> Void
* - status (Number): deflate status. 0 (Z_OK) on success,
* other if not.
*
* Called once after you tell deflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
Deflate.prototype.onEnd = function (status) {
// On success - join
if (status === Z_OK) {
if (this.options.to === 'string') {
this.result = this.chunks.join('');
} else {
this.result = utils.flattenChunks(this.chunks);
}
}
this.chunks = [];
this.err = status;
this.msg = this.strm.msg;
};
/**
* deflate(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* Compress `data` with deflate algorithm and `options`.
*
* Supported options are:
*
* - level
* - windowBits
* - memLevel
* - strategy
* - dictionary
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Sugar (options):
*
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
* negative windowBits implicitly.
* - `to` (String) - if equal to 'string', then result will be "binary string"
* (each char code [0..255])
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
*
* console.log(pako.deflate(data));
* ```
**/
function deflate(input, options) {
var deflator = new Deflate(options);
deflator.push(input, true); // That will never happens, if you don't cheat with options :)
if (deflator.err) {
throw deflator.msg || msg[deflator.err];
}
return deflator.result;
}
/**
* deflateRaw(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* The same as [[deflate]], but creates raw data, without wrapper
* (header and adler32 crc).
**/
function deflateRaw(input, options) {
options = options || {};
options.raw = true;
return deflate(input, options);
}
/**
* gzip(data[, options]) -> Uint8Array|Array|String
* - data (Uint8Array|Array|String): input data to compress.
* - options (Object): zlib deflate options.
*
* The same as [[deflate]], but create gzip wrapper instead of
* deflate one.
**/
function gzip(input, options) {
options = options || {};
options.gzip = true;
return deflate(input, options);
}
exports.Deflate = Deflate;
exports.deflate = deflate;
exports.deflateRaw = deflateRaw;
exports.gzip = gzip;
},{"./utils/common":4,"./utils/strings":5,"./zlib/deflate":9,"./zlib/messages":14,"./zlib/zstream":16}],3:[function(require,module,exports){
'use strict';
var zlib_inflate = require('./zlib/inflate');
var utils = require('./utils/common');
var strings = require('./utils/strings');
var c = require('./zlib/constants');
var msg = require('./zlib/messages');
var ZStream = require('./zlib/zstream');
var GZheader = require('./zlib/gzheader');
var toString = Object.prototype.toString;
/**
* class Inflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[inflate]]
* and [[inflateRaw]].
**/
/* internal
* inflate.chunks -> Array
*
* Chunks of output data, if [[Inflate#onData]] not overridden.
**/
/**
* Inflate.result -> Uint8Array|Array|String
*
* Uncompressed result, generated by default [[Inflate#onData]]
* and [[Inflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Inflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Inflate.err -> Number
*
* Error code after inflate finished. 0 (Z_OK) on success.
* Should be checked if broken data possible.
**/
/**
* Inflate.msg -> String
*
* Error message, if [[Inflate.err]] != 0
**/
/**
* new Inflate(options)
* - options (Object): zlib inflate options.
*
* Creates new inflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `windowBits`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw inflate
* - `to` (String) - if equal to 'string', then result will be converted
* from utf8 to utf16 (javascript) string. When string output requested,
* chunk length can differ from `chunkSize`, depending on content.
*
* By default, when no options set, autodetect deflate/gzip data format via
* wrapper header.
*
* ##### Example:
*
* ```javascript
* var pako = require('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var inflate = new pako.Inflate({ level: 3});
*
* inflate.push(chunk1, false);
* inflate.push(chunk2, true); // true -> last chunk
*
* if (inflate.err) { throw new Error(inflate.err); }
*
* console.log(inflate.result);
* ```
**/
function Inflate(options) {
if (!(this instanceof Inflate)) return new Inflate(options);
this.options = utils.assign({
chunkSize: 16384,
windowBits: 0,
to: ''
}, options || {});
var opt = this.options; // Force window size for `raw` data, if not set directly,
// because we have no header for autodetect.
if (opt.raw && opt.windowBits >= 0 && opt.windowBits < 16) {
opt.windowBits = -opt.windowBits;
if (opt.windowBits === 0) {
opt.windowBits = -15;
}
} // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
if (opt.windowBits >= 0 && opt.windowBits < 16 && !(options && options.windowBits)) {
opt.windowBits += 32;
} // Gzip header has no info about windows size, we can do autodetect only
// for deflate. So, if window size not set, force it to max when gzip possible
if (opt.windowBits > 15 && opt.windowBits < 48) {
// bit 3 (16) -> gzipped data
// bit 4 (32) -> autodetect gzip/deflate
if ((opt.windowBits & 15) === 0) {
opt.windowBits |= 15;
}
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
var status = zlib_inflate.inflateInit2(this.strm, opt.windowBits);
if (status !== c.Z_OK) {
throw new Error(msg[status]);
}
this.header = new GZheader();
zlib_inflate.inflateGetHeader(this.strm, this.header);
}
/**
* Inflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
* new output chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the decompression context.
*
* On fail call [[Inflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
Inflate.prototype.push = function (data, mode) {
var strm = this.strm;
var chunkSize = this.options.chunkSize;
var dictionary = this.options.dictionary;
var status, _mode;
var next_out_utf8, tail, utf8str;
var dict; // Flag to properly process Z_BUF_ERROR on testing inflate call
// when we check that all output data was flushed.
var allowBufError = false;
if (this.ended) {
return false;
}
_mode = mode === ~~mode ? mode : mode === true ? c.Z_FINISH : c.Z_NO_FLUSH; // Convert data if needed
if (typeof data === 'string') {
// Only binary strings can be decompressed on practice
strm.input = strings.binstring2buf(data);
} else if (toString.call(data) === '[object ArrayBuffer]') {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new utils.Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);
/* no bad return value */
if (status === c.Z_NEED_DICT && dictionary) {
// Convert data if needed
if (typeof dictionary === 'string') {
dict = strings.string2buf(dictionary);
} else if (toString.call(dictionary) === '[object ArrayBuffer]') {
dict = new Uint8Array(dictionary);
} else {
dict = dictionary;
}
status = zlib_inflate.inflateSetDictionary(this.strm, dict);
}
if (status === c.Z_BUF_ERROR && allowBufError === true) {
status = c.Z_OK;
allowBufError = false;
}
if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.next_out) {
if (strm.avail_out === 0 || status === c.Z_STREAM_END || strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH)) {
if (this.options.to === 'string') {
next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
tail = strm.next_out - next_out_utf8;
utf8str = strings.buf2string(strm.output, next_out_utf8); // move tail
strm.next_out = tail;
strm.avail_out = chunkSize - tail;
if (tail) {
utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0);
}
this.onData(utf8str);
} else {
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
}
}
} // When no more input data, we should check that internal inflate buffers
// are flushed. The only way to do it when avail_out = 0 - run one more
// inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
// Here we set flag to process this error properly.
//
// NOTE. Deflate does not return error in this case and does not needs such
// logic.
if (strm.avail_in === 0 && strm.avail_out === 0) {
allowBufError = true;
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);
if (status === c.Z_STREAM_END) {
_mode = c.Z_FINISH;
} // Finalize on the last chunk.
if (_mode === c.Z_FINISH) {
status = zlib_inflate.inflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === c.Z_OK;
} // callback interim results if Z_SYNC_FLUSH.
if (_mode === c.Z_SYNC_FLUSH) {
this.onEnd(c.Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Inflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
Inflate.prototype.onData = function (chunk) {
this.chunks.push(chunk);
};
/**
* Inflate#onEnd(status) -> Void
* - status (Number): inflate status. 0 (Z_OK) on success,
* other if not.
*
* Called either after you tell inflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
Inflate.prototype.onEnd = function (status) {
// On success - join
if (status === c.Z_OK) {
if (this.options.to === 'string') {
// Glue & convert here, until we teach pako to send
// utf8 aligned strings to onData
this.result = this.chunks.join('');
} else {
this.result = utils.flattenChunks(this.chunks);
}
}
this.chunks = [];
this.err = stat