var UPNG = (function() { var _bin = { nextZero : function(data,p) { while(data[p]!=0) p++; return p; }, readUshort : function(buff,p) { return (buff[p]<< 8) | buff[p+1]; }, writeUshort: function(buff,p,n){ buff[p] = (n>>8)&255; buff[p+1] = n&255; }, readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); }, writeUint : function(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(buff,p,l){ var s = ""; for(var i=0; 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>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>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>>3)]>>>(7 -((x&7) )))& 1), al=(gr==tr*255)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 2) for(var x=0; x>>2)]>>>(6 -((x&3)<<1)))& 3), al=(gr==tr* 85)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 4) for(var x=0; x>>1)]>>>(4 -((x&1)<<2)))&15), al=(gr==tr* 17)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 8) for(var x=0; x>1,G=o[i+1],f=y<<4|G,a=j-G,k=o[i]<>>15-j;I[x]=f;k++}}}function g(o,j){var I=D.i,A=15-j;for(var r=0;r>>A}}(function(){var o=1<<15;for(var j=0;j>>1|(I&1431655765)<<1; I=(I&3435973836)>>>2|(I&858993459)<<2;I=(I&4042322160)>>>4|(I&252645135)<<4;I=(I&4278255360)>>>8|(I&16711935)<<8; D.i[j]=(I>>>16|I<<16)>>>17}function A(r,i,y){while(i--!=0)r.push(0,y)}for(var j=0;j<32;j++){D.B[j]=D.o[j]<<3|D.z[j]; D.h[j]=D.p[j]<<4|D.w[j]}A(D.s,144,8);A(D.s,255-143,9);A(D.s,279-255,7);A(D.s,287-279,8);C(D.s,9);t(D.s,9,D.g); g(D.s,9);A(D.t,32,5);C(D.t,5);t(D.t,5,D.A);g(D.t,5);A(D.b,19,0);A(D.c,286,0);A(D.e,30,0);A(D.a,320,0)}()); function F(o,j,I){return(o[j>>>3]|o[(j>>>3)+1]<<8)>>>(j&7)&(1<>>3]|o[(j>>>3)+1]<<8|o[(j>>>3)+2]<<16)>>>(j&7)&(1<>>3]|o[(j>>>3)+1]<<8|o[(j>>>3)+2]<<16)>>>(j&7)}function b(o,j){return(o[j>>>3]|o[(j>>>3)+1]<<8|o[(j>>>3)+2]<<16|o[(j>>>3)+3]<<24)>>>(j&7)} function v(o,j){var I=Uint8Array,r=0,i=0,y=0,G=0,f=0,a=0,k=0,N=0,x=0,P,J; if(o[0]==3&&o[1]==0)return j?j:new I(0);var A=j==null;if(A)j=new I(o.length>>>2<<3);while(r==0){r=s(o,x,1); i=s(o,x+1,2);x+=3;if(i==0){if((x&7)!=0)x+=8-(x&7);var K=(x>>>3)+4,m=o[K-4]|o[K-3]<<8;if(A)j=H(j,N+m); j.set(new I(o.buffer,o.byteOffset+K,m),N);x=K+m<<3;N+=m;continue}if(A)j=H(j,N+(1<<17));if(i==1){P=D.g; J=D.A;a=(1<<9)-1;k=(1<<5)-1}if(i==2){y=F(o,x,5)+257;G=F(o,x+5,5)+1;f=F(o,x+10,4)+4;x+=14;var O=x,Q=1; for(var p=0;p<38;p+=2){D.b[p]=0;D.b[p+1]=0}for(var p=0;pQ)Q=l}x+=3*f;C(D.b,Q);t(D.b,Q,D.C);P=D.k;J=D.n;x=B(D.C,(1<>>4;if(L>>>8==0){j[N++]=L}else if(L==256){break}else{var M=N+L-254;if(L>264){var z=D.B[L-257]; M=N+(z>>>3)+F(o,x,z&7);x+=z&7}var e=J[w(o,x)&k];x+=e&15;var E=e>>>4,c=D.h[E],q=(c>>>4)+s(o,x,c&15);x+=c&15; if(A)j=H(j,N+(1<<17));while(N>>4;if(f<=15){i[y]=f;y++}else{var a=0,k=0;if(f==16){k=3+F(A,r,2); r+=2;a=i[y-1]}else if(f==17){k=3+F(A,r,3);r+=3}else if(f==18){k=11+F(A,r,7);r+=7}var N=y+k;while(y>>1;while(ir)r=G;i++}while(i>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>3]; val = (val>>(7-(cdi&7)))&1; img[row*bpl + (col>>3)] |= (val << (7-((col&7)<<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>3)+j]; } cdi+=bpp; col+=ci; } y++; row += ri; } if(sw*sh!=0) di += sh * (1 + bpll); pass = pass + 1; } return img; } function _getBPP(out) { var noc = [1,null,3,1,2,null,4][out.ctype]; return noc * out.depth; } function _filterZero(data, out, off, w, h) { var bpp = _getBPP(out), bpl = Math.ceil(w*bpp/8); bpp = Math.ceil(bpp/8); var i,di, type=data[off], x=0; if(type>1) data[off]=[0,0,1][type-2]; if(type==3) for(x=bpp; x>>1) )&255; for(var y=0; y>>1)); for(; x>>1) ); } else { for(; x=0 && yoff>=0) { si = (y*sw+x)<<2; ti = (( yoff+y)*tw+xoff+x)<<2; } else { si = ((-yoff+y)*sw-xoff+x)<<2; ti = (y*tw+x)<<2; } if (mode==0) { tb[ti] = sb[si]; tb[ti+1] = sb[si+1]; tb[ti+2] = sb[si+2]; tb[ti+3] = sb[si+3]; } else if(mode==1) { var fa = sb[si+3]*(1/255), fr=sb[si]*fa, fg=sb[si+1]*fa, fb=sb[si+2]*fa; var ba = tb[ti+3]*(1/255), br=tb[ti]*ba, bg=tb[ti+1]*ba, bb=tb[ti+2]*ba; var ifa=1-fa, oa = fa+ba*ifa, ioa = (oa==0?0:1/oa); tb[ti+3] = 255*oa; tb[ti+0] = (fr+br*ifa)*ioa; tb[ti+1] = (fg+bg*ifa)*ioa; tb[ti+2] = (fb+bb*ifa)*ioa; } else if(mode==2){ // copy only differences, otherwise zero var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2]; var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2]; if(fa==ba && fr==br && fg==bg && fb==bb) { tb[ti]=0; tb[ti+1]=0; tb[ti+2]=0; tb[ti+3]=0; } else { tb[ti]=fr; tb[ti+1]=fg; tb[ti+2]=fb; tb[ti+3]=fa; } } else if(mode==3){ // check if can be blended var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2]; var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2]; if(fa==ba && fr==br && fg==bg && fb==bb) continue; //if(fa!=255 && ba!=0) return false; if(fa<220 && ba>20) return false; } } return true; } return { decode:decode, toRGBA8:toRGBA8, _paeth:_paeth, _copyTile:_copyTile, _bin:_bin }; })(); (function() { var _copyTile = UPNG._copyTile, _bin=UPNG._bin, paeth = UPNG._paeth; var crcLib = { 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(c, buf, off, len) { for (var i=0; i>> 8); return c; }, crc : function(b,o,l) { return crcLib.update(0xffffffff,b,o,l) ^ 0xffffffff; } } function addErr(er, tg, ti, f) { tg[ti]+=(er[0]*f)>>4; tg[ti+1]+=(er[1]*f)>>4; tg[ti+2]+=(er[2]*f)>>4; tg[ti+3]+=(er[3]*f)>>4; } function N(x) { return Math.max(0, Math.min(255, x)); } function D(a,b) { var dr=a[0]-b[0], dg=a[1]-b[1], db=a[2]-b[2], da=a[3]-b[3]; return (dr*dr + dg*dg + db*db + da*da); } // MTD: 0: None, 1: floyd-steinberg, 2: Bayer function dither(sb, w, h, plte, tb, oind, MTD) { if(MTD==null) MTD=1; var pc=plte.length, nplt = [], rads=[]; for(var i=0; i>>0)&255), ((c>>>8)&255), ((c>>>16)&255), ((c>>>24)&255)]); } for(var i=0; i>2] = ni; tb32[i>>2] = plte[ni]; } } } function encode(bufs, w, h, ps, dels, tabs, forbidPlte) { if(ps==null) ps=0; if(forbidPlte==null) forbidPlte = false; var nimg = compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte,false]); compressPNG(nimg, -1); return _main(nimg, w, h, dels, tabs); } function encodeLL(bufs, w, h, cc, ac, depth, dels, tabs) { var nimg = { ctype: 0 + (cc==1 ? 0 : 2) + (ac==0 ? 0 : 4), depth: depth, frames: [] }; var time = Date.now(); var bipp = (cc+ac)*depth, bipl = bipp * w; for(var i=0; i1, pltAlpha = false; var cicc; var leng = 8 + (16+5+4) /*+ (9+4)*/ + (anim ? 20 : 0); if(tabs["sRGB"]!=null) leng += 8+1+4; if(tabs["pHYs"]!=null) leng += 8+9+4; if(tabs["iCCP"]!=null) { cicc = pako.deflate(tabs["iCCP"]); leng += 8 + 11 + 2 + cicc.length + 4; } if(nimg.ctype==3) { var dl = nimg.plte.length; for(var i=0; i>>24)!=255) pltAlpha = true; leng += (8 + dl*3 + 4) + (pltAlpha ? (8 + dl*1 + 4) : 0); } for(var j=0; j>>8)&255, b=(c>>>16)&255; data[offset+ti+0]=r; data[offset+ti+1]=g; data[offset+ti+2]=b; } offset+=dl*3; wUi(data,offset,crc(data,offset-dl*3-4,dl*3+4)); offset+=4; // crc if(pltAlpha) { wUi(data,offset, dl); offset+=4; wAs(data,offset,"tRNS"); offset+=4; for(var i=0; i>>24)&255; offset+=dl; wUi(data,offset,crc(data,offset-dl-4,dl+4)); offset+=4; // crc } } var fi = 0; for(var j=0; j>2, bln>>2); inds.push(ind); var bb = new Uint8Array(qres.abuf,cof,bln); //console.log(frm.img, frm.width, frm.height); //var time = Date.now(); if(dith) dither(frm.img, frm.rect.width, frm.rect.height, plte, bb, ind); //console.log(Date.now()-time); frm.img.set(bb); cof+=bln; } //console.log("quantize", Date.now()-time); time = Date.now(); } else { // what if ps==0, but there are <=256 colors? we still need to detect, if the palette could be used for(var j=0; jnw && c==img32[i-nw]) ind[i]=ind[i-nw]; else { var cmc = cmap[c]; if(cmc==null) { cmap[c]=cmc=plte.length; plte.push(c); if(plte.length>=300) break; } ind[i]=cmc; } } } //console.log("make palette", Date.now()-time); time = Date.now(); } var cc=plte.length; //console.log("colors:",cc); if(cc<=256 && forbidPlte==false) { if(cc<= 2) depth=1; else if(cc<= 4) depth=2; else if(cc<=16) depth=4; else depth=8; depth = Math.max(depth, minBits); } for(var j=0; j>1)] |= (inj[ii+x]<<(4-(x&1)*4)); else if(depth==2) for(var x=0; x>2)] |= (inj[ii+x]<<(6-(x&3)*2)); else if(depth==1) for(var x=0; x>3)] |= (inj[ii+x]<<(7-(x&7)*1)); } cimg=nimg; ctype=3; bpp=1; } else if(gotAlpha==false && frms.length==1) { // some next "reduced" frames may contain alpha for blending var nimg = new Uint8Array(nw*nh*3), area=nw*nh; for(var i=0; i palette indices", Date.now()-time); time = Date.now(); return {ctype:ctype, depth:depth, plte:plte, frames:frms }; } function framize(bufs,w,h,alwaysBlend,evenCrd,forbidPrev) { /* DISPOSE - 0 : no change - 1 : clear to transparent - 2 : retstore to content before rendering (previous frame disposed) BLEND - 0 : replace - 1 : blend */ var frms = []; for(var j=0; jmax) max=x; if(ymay) may=y; } } if(max==-1) mix=miy=max=may=0; if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; } var sarea = (max-mix+1)*(may-miy+1); if(sareamax) max=cx; if(cymay) may=cy; } } if(max==-1) mix=miy=max=may=0; if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; } r = {x:mix, y:miy, width:max-mix+1, height:may-miy+1}; var fr = frms[i]; fr.rect = r; fr.blend = 1; fr.img = new Uint8Array(r.width*r.height*4); if(frms[i-1].dispose==0) { _copyTile(pimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0); _prepareDiff(cimg,w,h,fr.img,r); } else _copyTile(cimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0); } function _prepareDiff(cimg, w,h, nimg, rec) { _copyTile(cimg,w,h, nimg,rec.width,rec.height, -rec.x,-rec.y, 2); } function _filterZero(img,h,bpp,bpl,data, filter, levelZero) { var fls = [], ftry=[0,1,2,3,4]; if (filter!=-1) ftry=[filter]; else if(h*bpl>500000 || bpp==1) ftry=[0]; var opts; if(levelZero) opts={level:0}; var CMPR = (data.length>10e6 && window.UZIP!=null) ? window.UZIP : pako; var time = Date.now(); for(var i=0; i>1) +256)&255; if(type==4) for(var x=bpp; x>1))&255; for(var x=bpp; x>1))&255; } if(type==4) { for(var x= 0; x>2), nd; if(K<=60) { findNearest(sb,inds,clr8); remap(inds,tb32,cl32); } else if(sb.length<32e6) // precise, but slow :( //for(var j=0; j<4; j++) for(var i=0; i>2] = nd.ind; tb32[i>>2] = nd.est.rgba; } else for(var i=0; i>2] = nd.ind; tb32[i>>2] = nd.est.rgba; } //console.log(Date.now()-time, "nearest found"); time = Date.now(); if(doKmeans || sb.length*K<10*4e6) { var le = 1e9; for(var i=0; i<10; i++) { var ce = kmeans(sb, inds, clr8); //console.log(i,ce); if(ce/le>0.997) break; le=ce; } for(var i=0; i>>2; var sums = new Uint32Array(K*4), cnts = new Uint32Array(K); for(var i=0; i>>2], qi=ind*4; cnts[ind]++; sums[qi ]+=sb[i ]; sums[qi+1]+=sb[i+1]; sums[qi+2]+=sb[i+2]; sums[qi+3]+=sb[i+3]; } for(var i=0; i>>2]); } function findNearest(sb,inds,plte) { var terr = 0, K=plte.length>>>2; var nd = []; // squared half-distance to the nearest color for(var i=0; i>>2], qi=ti*4, dr=r-plte[qi], dg=g-plte[qi+1], db=b-plte[qi+2], da=a-plte[qi+3], te = dr*dr+dg*dg+db*db+da*da; if(te>nd[ti]) for(var j=0; j>>2]=ti; terr+=te; } return terr/(sb.length>>>2); } function getKDtree(nimg, ps, err) { if(err==null) err = 0.0001; var nimg32 = new Uint32Array(nimg.buffer); var root = {i0:0, i1:nimg.length, bst:null, est:null, tdst:0, left:null, right:null }; // basic statistic, extra statistic root.bst = stats( nimg,root.i0, root.i1 ); root.est = estats( root.bst ); var leafs = [root]; while(leafs.length maxL) { maxL=leafs[i].est.L; mi=i; } if(maxL=s0 || node.i1<=s0); //console.log(maxL, leafs.length, mi); if(s0wrong) { node.est.L=0; continue; } var ln = {i0:node.i0, i1:s0, bst:null, est:null, tdst:0, left:null, right:null }; ln.bst = stats( nimg, ln.i0, ln.i1 ); ln.est = estats( ln.bst ); var rn = {i0:s0, i1:node.i1, bst:null, est:null, tdst:0, left:null, right:null }; rn.bst = {R:[], m:[], N:node.bst.N-ln.bst.N}; for(var i=0; i<16; i++) rn.bst.R[i] = node.bst.R[i]-ln.bst.R[i]; for(var i=0; i< 4; i++) rn.bst.m[i] = node.bst.m[i]-ln.bst.m[i]; rn.est = estats( rn.bst ); node.left = ln; node.right = rn; leafs[mi]=ln; leafs.push(rn); } leafs.sort(function(a,b) { return b.bst.N-a.bst.N; }); for(var i=0; i0) { node0=nd.right; node1=nd.left; } var ln = getNearest(node0, r,g,b,a); if(ln.tdst<=pd*pd) return ln; var rn = getNearest(node1, r,g,b,a); return rn.tdst eMq) i1-=4; if(i0>=i1) break; var t = nimg32[i0>>2]; nimg32[i0>>2] = nimg32[i1>>2]; nimg32[i1>>2]=t; i0+=4; i1-=4; } while(vecDot(nimg, i0, e)>eMq) i0-=4; return i0+4; } function vecDot(nimg, i, e) { return nimg[i]*e[0] + nimg[i+1]*e[1] + nimg[i+2]*e[2] + nimg[i+3]*e[3]; } function stats(nimg, i0, i1){ var R = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; var m = [0,0,0,0]; var N = (i1-i0)>>2; for(var i=i0; i>>0) }; } var M4 = { multVec : function(m,v) { return [ m[ 0]*v[0] + m[ 1]*v[1] + m[ 2]*v[2] + m[ 3]*v[3], m[ 4]*v[0] + m[ 5]*v[1] + m[ 6]*v[2] + m[ 7]*v[3], m[ 8]*v[0] + m[ 9]*v[1] + m[10]*v[2] + m[11]*v[3], m[12]*v[0] + m[13]*v[1] + m[14]*v[2] + m[15]*v[3] ]; }, dot : function(x,y) { return x[0]*y[0]+x[1]*y[1]+x[2]*y[2]+x[3]*y[3]; }, sml : function(a,y) { return [a*y[0],a*y[1],a*y[2],a*y[3]]; } } function concatRGBA(bufs) { var tlen = 0; for(var i=0; i