UPNG.js

Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless)

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/452821/1103227/UPNGjs.js

  1. var UPNG = {};
  2.  
  3.  
  4. UPNG.toRGBA8 = function(out)
  5. {
  6. var w = out.width, h = out.height;
  7. if(out.tabs.acTL==null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer];
  8. var frms = [];
  9. if(out.frames[0].data==null) out.frames[0].data = out.data;
  10. var len = w*h*4, img = new Uint8Array(len), empty = new Uint8Array(len), prev=new Uint8Array(len);
  11. for(var i=0; i<out.frames.length; i++)
  12. {
  13. var frm = out.frames[i];
  14. var fx=frm.rect.x, fy=frm.rect.y, fw = frm.rect.width, fh = frm.rect.height;
  15. var fdata = UPNG.toRGBA8.decodeImage(frm.data, fw,fh, out);
  16. if(i!=0) for(var j=0; j<len; j++) prev[j]=img[j];
  17. if (frm.blend==0) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 0);
  18. else if(frm.blend==1) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 1);
  19. frms.push(img.buffer.slice(0));
  20. if (frm.dispose==0) {}
  21. else if(frm.dispose==1) UPNG._copyTile(empty, fw, fh, img, w, h, fx, fy, 0);
  22. else if(frm.dispose==2) for(var j=0; j<len; j++) img[j]=prev[j];
  23. }
  24. return frms;
  25. }
  26. UPNG.toRGBA8.decodeImage = function(data, w, h, out)
  27. {
  28. var area = w*h, bpp = UPNG.decode._getBPP(out);
  29. var bpl = Math.ceil(w*bpp/8); // bytes per line
  30.  
  31. var bf = new Uint8Array(area*4), bf32 = new Uint32Array(bf.buffer);
  32. var ctype = out.ctype, depth = out.depth;
  33. var rs = UPNG._bin.readUshort;
  34. //console.log(ctype, depth);
  35. var time = Date.now();
  36.  
  37. if (ctype==6) { // RGB + alpha
  38. var qarea = area<<2;
  39. if(depth== 8) for(var i=0; i<qarea;i+=4) { bf[i] = data[i]; bf[i+1] = data[i+1]; bf[i+2] = data[i+2]; bf[i+3] = data[i+3]; }
  40. if(depth==16) for(var i=0; i<qarea;i++ ) { bf[i] = data[i<<1]; }
  41. }
  42. else if(ctype==2) { // RGB
  43. var ts=out.tabs["tRNS"];
  44. if(ts==null) {
  45. if(depth== 8) for(var i=0; i<area; i++) { var ti=i*3; bf32[i] = (255<<24)|(data[ti+2]<<16)|(data[ti+1]<<8)|data[ti]; }
  46. if(depth==16) for(var i=0; i<area; i++) { var ti=i*6; bf32[i] = (255<<24)|(data[ti+4]<<16)|(data[ti+2]<<8)|data[ti]; }
  47. }
  48. else { var tr=ts[0], tg=ts[1], tb=ts[2];
  49. if(depth== 8) for(var i=0; i<area; i++) { var qi=i<<2, ti=i*3; bf32[i] = (255<<24)|(data[ti+2]<<16)|(data[ti+1]<<8)|data[ti];
  50. if(data[ti] ==tr && data[ti+1] ==tg && data[ti+2] ==tb) bf[qi+3] = 0; }
  51. if(depth==16) for(var i=0; i<area; i++) { var qi=i<<2, ti=i*6; bf32[i] = (255<<24)|(data[ti+4]<<16)|(data[ti+2]<<8)|data[ti];
  52. if(rs(data,ti)==tr && rs(data,ti+2)==tg && rs(data,ti+4)==tb) bf[qi+3] = 0; }
  53. }
  54. }
  55. else if(ctype==3) { // palette
  56. var p=out.tabs["PLTE"], ap=out.tabs["tRNS"], tl=ap?ap.length:0;
  57. //console.log(p, ap);
  58. if(depth==1) for(var y=0; y<h; y++) { var s0 = y*bpl, t0 = y*w;
  59. 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; }
  60. }
  61. if(depth==2) for(var y=0; y<h; y++) { var s0 = y*bpl, t0 = y*w;
  62. 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; }
  63. }
  64. if(depth==4) for(var y=0; y<h; y++) { var s0 = y*bpl, t0 = y*w;
  65. 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; }
  66. }
  67. 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; }
  68. }
  69. else if(ctype==4) { // gray + alpha
  70. 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]; }
  71. 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]; }
  72. }
  73. else if(ctype==0) { // gray
  74. var tr = out.tabs["tRNS"] ? out.tabs["tRNS"] : -1;
  75. for(var y=0; y<h; y++) {
  76. var off = y*bpl, to = y*w;
  77. if (depth== 1) for(var x=0; x<w; x++) { var gr=255*((data[off+(x>>>3)]>>>(7 -((x&7) )))& 1), al=(gr==tr*255)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; }
  78. else if(depth== 2) for(var x=0; x<w; x++) { var gr= 85*((data[off+(x>>>2)]>>>(6 -((x&3)<<1)))& 3), al=(gr==tr* 85)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; }
  79. else if(depth== 4) for(var x=0; x<w; x++) { var gr= 17*((data[off+(x>>>1)]>>>(4 -((x&1)<<2)))&15), al=(gr==tr* 17)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; }
  80. else if(depth== 8) for(var x=0; x<w; x++) { var gr=data[off+ x], al=(gr ==tr)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; }
  81. else if(depth==16) for(var x=0; x<w; x++) { var gr=data[off+(x<<1)], al=(rs(data,off+(x<<1))==tr)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; }
  82. }
  83. }
  84. //console.log(Date.now()-time);
  85. return bf;
  86. }
  87.  
  88.  
  89.  
  90. UPNG.decode = function(buff)
  91. {
  92. var data = new Uint8Array(buff), offset = 8, bin = UPNG._bin, rUs = bin.readUshort, rUi = bin.readUint;
  93. var out = {tabs:{}, frames:[]};
  94. var dd = new Uint8Array(data.length), doff = 0; // put all IDAT data into it
  95. var fd, foff = 0; // frames
  96. var mgck = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
  97. for(var i=0; i<8; i++) if(data[i]!=mgck[i]) throw "The input is not a PNG file!";
  98.  
  99. while(offset<data.length)
  100. {
  101. var len = bin.readUint(data, offset); offset += 4;
  102. var type = bin.readASCII(data, offset, 4); offset += 4;
  103. //console.log(type,len);
  104. if (type=="IHDR") { UPNG.decode._IHDR(data, offset, out); }
  105. else if(type=="CgBI") { out.tabs[type] = data.slice(offset,offset+4); }
  106. else if(type=="IDAT") {
  107. for(var i=0; i<len; i++) dd[doff+i] = data[offset+i];
  108. doff += len;
  109. }
  110. else if(type=="acTL") {
  111. out.tabs[type] = { num_frames:rUi(data, offset), num_plays:rUi(data, offset+4) };
  112. fd = new Uint8Array(data.length);
  113. }
  114. else if(type=="fcTL") {
  115. if(foff!=0) { var fr = out.frames[out.frames.length-1];
  116. fr.data = UPNG.decode._decompress(out, fd.slice(0,foff), fr.rect.width, fr.rect.height); foff=0;
  117. }
  118. var rct = {x:rUi(data, offset+12),y:rUi(data, offset+16),width:rUi(data, offset+4),height:rUi(data, offset+8)};
  119. var del = rUs(data, offset+22); del = rUs(data, offset+20) / (del==0?100:del);
  120. var frm = {rect:rct, delay:Math.round(del*1000), dispose:data[offset+24], blend:data[offset+25]};
  121. //console.log(frm);
  122. out.frames.push(frm);
  123. }
  124. else if(type=="fdAT") {
  125. for(var i=0; i<len-4; i++) fd[foff+i] = data[offset+i+4];
  126. foff += len-4;
  127. }
  128. else if(type=="pHYs") {
  129. out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset+4), data[offset+8]];
  130. }
  131. else if(type=="cHRM") {
  132. out.tabs[type] = [];
  133. for(var i=0; i<8; i++) out.tabs[type].push(bin.readUint(data, offset+i*4));
  134. }
  135. else if(type=="tEXt" || type=="zTXt") {
  136. if(out.tabs[type]==null) out.tabs[type] = {};
  137. var nz = bin.nextZero(data, offset);
  138. var keyw = bin.readASCII(data, offset, nz-offset);
  139. var text, tl=offset+len-nz-1;
  140. if(type=="tEXt") text = bin.readASCII(data, nz+1, tl);
  141. else {
  142. var bfr = UPNG.decode._inflate(data.slice(nz+2,nz+2+tl));
  143. text = bin.readUTF8(bfr,0,bfr.length);
  144. }
  145. out.tabs[type][keyw] = text;
  146. }
  147. else if(type=="iTXt") {
  148. if(out.tabs[type]==null) out.tabs[type] = {};
  149. var nz = 0, off = offset;
  150. nz = bin.nextZero(data, off);
  151. var keyw = bin.readASCII(data, off, nz-off); off = nz + 1;
  152. var cflag = data[off], cmeth = data[off+1]; off+=2;
  153. nz = bin.nextZero(data, off);
  154. var ltag = bin.readASCII(data, off, nz-off); off = nz + 1;
  155. nz = bin.nextZero(data, off);
  156. var tkeyw = bin.readUTF8(data, off, nz-off); off = nz + 1;
  157. var text, tl=len-(off-offset);
  158. if(cflag==0) text = bin.readUTF8(data, off, tl);
  159. else {
  160. var bfr = UPNG.decode._inflate(data.slice(off,off+tl));
  161. text = bin.readUTF8(bfr,0,bfr.length);
  162. }
  163. out.tabs[type][keyw] = text;
  164. }
  165. else if(type=="PLTE") {
  166. out.tabs[type] = bin.readBytes(data, offset, len);
  167. }
  168. else if(type=="hIST") {
  169. var pl = out.tabs["PLTE"].length/3;
  170. out.tabs[type] = []; for(var i=0; i<pl; i++) out.tabs[type].push(rUs(data, offset+i*2));
  171. }
  172. else if(type=="tRNS") {
  173. if (out.ctype==3) out.tabs[type] = bin.readBytes(data, offset, len);
  174. else if(out.ctype==0) out.tabs[type] = rUs(data, offset);
  175. else if(out.ctype==2) out.tabs[type] = [ rUs(data,offset),rUs(data,offset+2),rUs(data,offset+4) ];
  176. //else console.log("tRNS for unsupported color type",out.ctype, len);
  177. }
  178. else if(type=="gAMA") out.tabs[type] = bin.readUint(data, offset)/100000;
  179. else if(type=="sRGB") out.tabs[type] = data[offset];
  180. else if(type=="bKGD")
  181. {
  182. if (out.ctype==0 || out.ctype==4) out.tabs[type] = [rUs(data, offset)];
  183. else if(out.ctype==2 || out.ctype==6) out.tabs[type] = [rUs(data, offset), rUs(data, offset+2), rUs(data, offset+4)];
  184. else if(out.ctype==3) out.tabs[type] = data[offset];
  185. }
  186. else if(type=="IEND") {
  187. break;
  188. }
  189. //else { console.log("unknown chunk type", type, len); out.tabs[type]=data.slice(offset,offset+len); }
  190. offset += len;
  191. var crc = bin.readUint(data, offset); offset += 4;
  192. }
  193. if(foff!=0) { var fr = out.frames[out.frames.length-1];
  194. fr.data = UPNG.decode._decompress(out, fd.slice(0,foff), fr.rect.width, fr.rect.height);
  195. }
  196. out.data = UPNG.decode._decompress(out, dd, out.width, out.height);
  197. delete out.compress; delete out.interlace; delete out.filter;
  198. return out;
  199. }
  200.  
  201. UPNG.decode._decompress = function(out, dd, w, h) {
  202. var time = Date.now();
  203. var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w*bpp/8), buff = new Uint8Array((bpl+1+out.interlace)*h);
  204. if(out.tabs["CgBI"]) dd = UPNG.inflateRaw(dd,buff);
  205. else dd = UPNG.decode._inflate(dd,buff);
  206. //console.log(dd.length, buff.length);
  207. //console.log(Date.now()-time);
  208.  
  209. var time=Date.now();
  210. if (out.interlace==0) dd = UPNG.decode._filterZero(dd, out, 0, w, h);
  211. else if(out.interlace==1) dd = UPNG.decode._readInterlace(dd, out);
  212. //console.log(Date.now()-time);
  213. return dd;
  214. }
  215.  
  216. UPNG.decode._inflate = function(data, buff) { var out=UPNG["inflateRaw"](new Uint8Array(data.buffer, 2,data.length-6),buff); return out; }
  217. UPNG.inflateRaw=function(){var H={};H.H={};H.H.N=function(N,W){var R=Uint8Array,i=0,m=0,J=0,h=0,Q=0,X=0,u=0,w=0,d=0,v,C;
  218. if(N[0]==3&&N[1]==0)return W?W:new R(0);var V=H.H,n=V.b,A=V.e,l=V.R,M=V.n,I=V.A,e=V.Z,b=V.m,Z=W==null;
  219. if(Z)W=new R(N.length>>>2<<5);while(i==0){i=n(N,d,1);m=n(N,d+1,2);d+=3;if(m==0){if((d&7)!=0)d+=8-(d&7);
  220. var D=(d>>>3)+4,q=N[D-4]|N[D-3]<<8;if(Z)W=H.H.W(W,w+q);W.set(new R(N.buffer,N.byteOffset+D,q),w);d=D+q<<3;
  221. w+=q;continue}if(Z)W=H.H.W(W,w+(1<<17));if(m==1){v=b.J;C=b.h;X=(1<<9)-1;u=(1<<5)-1}if(m==2){J=A(N,d,5)+257;
  222. h=A(N,d+5,5)+1;Q=A(N,d+10,4)+4;d+=14;var E=d,j=1;for(var c=0;c<38;c+=2){b.Q[c]=0;b.Q[c+1]=0}for(var c=0;
  223. c<Q;c++){var K=A(N,d+c*3,3);b.Q[(b.X[c]<<1)+1]=K;if(K>j)j=K}d+=3*Q;M(b.Q,j);I(b.Q,j,b.u);v=b.w;C=b.d;
  224. d=l(b.u,(1<<j)-1,J+h,N,d,b.v);var r=V.V(b.v,0,J,b.C);X=(1<<r)-1;var S=V.V(b.v,J,h,b.D);u=(1<<S)-1;M(b.C,r);
  225. I(b.C,r,v);M(b.D,S);I(b.D,S,C)}while(!0){var T=v[e(N,d)&X];d+=T&15;var p=T>>>4;if(p>>>8==0){W[w++]=p}else if(p==256){break}else{var z=w+p-254;
  226. if(p>264){var _=b.q[p-257];z=w+(_>>>3)+A(N,d,_&7);d+=_&7}var $=C[e(N,d)&u];d+=$&15;var s=$>>>4,Y=b.c[s],a=(Y>>>4)+n(N,d,Y&15);
  227. d+=Y&15;while(w<z){W[w]=W[w++-a];W[w]=W[w++-a];W[w]=W[w++-a];W[w]=W[w++-a]}w=z}}}return W.length==w?W:W.slice(0,w)};
  228. H.H.W=function(N,W){var R=N.length;if(W<=R)return N;var V=new Uint8Array(R<<1);V.set(N,0);return V};
  229. H.H.R=function(N,W,R,V,n,A){var l=H.H.e,M=H.H.Z,I=0;while(I<R){var e=N[M(V,n)&W];n+=e&15;var b=e>>>4;
  230. if(b<=15){A[I]=b;I++}else{var Z=0,m=0;if(b==16){m=3+l(V,n,2);n+=2;Z=A[I-1]}else if(b==17){m=3+l(V,n,3);
  231. n+=3}else if(b==18){m=11+l(V,n,7);n+=7}var J=I+m;while(I<J){A[I]=Z;I++}}}return n};H.H.V=function(N,W,R,V){var n=0,A=0,l=V.length>>>1;
  232. while(A<R){var M=N[A+W];V[A<<1]=0;V[(A<<1)+1]=M;if(M>n)n=M;A++}while(A<l){V[A<<1]=0;V[(A<<1)+1]=0;A++}return n};
  233. H.H.n=function(N,W){var R=H.H.m,V=N.length,n,A,l,M,I,e=R.j;for(var M=0;M<=W;M++)e[M]=0;for(M=1;M<V;M+=2)e[N[M]]++;
  234. var b=R.K;n=0;e[0]=0;for(A=1;A<=W;A++){n=n+e[A-1]<<1;b[A]=n}for(l=0;l<V;l+=2){I=N[l+1];if(I!=0){N[l]=b[I];
  235. b[I]++}}};H.H.A=function(N,W,R){var V=N.length,n=H.H.m,A=n.r;for(var l=0;l<V;l+=2)if(N[l+1]!=0){var M=l>>1,I=N[l+1],e=M<<4|I,b=W-I,Z=N[l]<<b,m=Z+(1<<b);
  236. while(Z!=m){var J=A[Z]>>>15-W;R[J]=e;Z++}}};H.H.l=function(N,W){var R=H.H.m.r,V=15-W;for(var n=0;n<N.length;
  237. n+=2){var A=N[n]<<W-N[n+1];N[n]=R[A]>>>V}};H.H.M=function(N,W,R){R=R<<(W&7);var V=W>>>3;N[V]|=R;N[V+1]|=R>>>8};
  238. H.H.I=function(N,W,R){R=R<<(W&7);var V=W>>>3;N[V]|=R;N[V+1]|=R>>>8;N[V+2]|=R>>>16};H.H.e=function(N,W,R){return(N[W>>>3]|N[(W>>>3)+1]<<8)>>>(W&7)&(1<<R)-1};
  239. H.H.b=function(N,W,R){return(N[W>>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16)>>>(W&7)&(1<<R)-1};H.H.Z=function(N,W){return(N[W>>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16)>>>(W&7)};
  240. H.H.i=function(N,W){return(N[W>>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16|N[(W>>>3)+3]<<24)>>>(W&7)};H.H.m=function(){var N=Uint16Array,W=Uint32Array;
  241. return{K:new N(16),j:new N(16),X:[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],S:[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,999,999,999],T:[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0],q:new N(32),p:[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,65535,65535],z:[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0],c:new W(32),J:new N(512),_:[],h:new N(32),$:[],w:new N(32768),C:[],v:[],d:new N(32768),D:[],u:new N(512),Q:[],r:new N(1<<15),s:new W(286),Y:new W(30),a:new W(19),t:new W(15e3),k:new N(1<<16),g:new N(1<<15)}}();
  242. (function(){var N=H.H.m,W=1<<15;for(var R=0;R<W;R++){var V=R;V=(V&2863311530)>>>1|(V&1431655765)<<1;
  243. V=(V&3435973836)>>>2|(V&858993459)<<2;V=(V&4042322160)>>>4|(V&252645135)<<4;V=(V&4278255360)>>>8|(V&16711935)<<8;
  244. N.r[R]=(V>>>16|V<<16)>>>17}function n(A,l,M){while(l--!=0)A.push(0,M)}for(var R=0;R<32;R++){N.q[R]=N.S[R]<<3|N.T[R];
  245. N.c[R]=N.p[R]<<4|N.z[R]}n(N._,144,8);n(N._,255-143,9);n(N._,279-255,7);n(N._,287-279,8);H.H.n(N._,9);
  246. H.H.A(N._,9,N.J);H.H.l(N._,9);n(N.$,32,5);H.H.n(N.$,5);H.H.A(N.$,5,N.h);H.H.l(N.$,5);n(N.Q,19,0);n(N.C,286,0);
  247. n(N.D,30,0);n(N.v,320,0)}());return H.H.N}()
  248.  
  249.  
  250. UPNG.decode._readInterlace = function(data, out)
  251. {
  252. var w = out.width, h = out.height;
  253. var bpp = UPNG.decode._getBPP(out), cbpp = bpp>>3, bpl = Math.ceil(w*bpp/8);
  254. var img = new Uint8Array( h * bpl );
  255. var di = 0;
  256.  
  257. var starting_row = [ 0, 0, 4, 0, 2, 0, 1 ];
  258. var starting_col = [ 0, 4, 0, 2, 0, 1, 0 ];
  259. var row_increment = [ 8, 8, 8, 4, 4, 2, 2 ];
  260. var col_increment = [ 8, 8, 4, 4, 2, 2, 1 ];
  261.  
  262. var pass=0;
  263. while(pass<7)
  264. {
  265. var ri = row_increment[pass], ci = col_increment[pass];
  266. var sw = 0, sh = 0;
  267. var cr = starting_row[pass]; while(cr<h) { cr+=ri; sh++; }
  268. var cc = starting_col[pass]; while(cc<w) { cc+=ci; sw++; }
  269. var bpll = Math.ceil(sw*bpp/8);
  270. UPNG.decode._filterZero(data, out, di, sw, sh);
  271.  
  272. var y=0, row = starting_row[pass];
  273. while(row<h)
  274. {
  275. var col = starting_col[pass];
  276. var cdi = (di+y*bpll)<<3;
  277.  
  278. while(col<w)
  279. {
  280. if(bpp==1) {
  281. var val = data[cdi>>3]; val = (val>>(7-(cdi&7)))&1;
  282. img[row*bpl + (col>>3)] |= (val << (7-((col&7)<<0)));
  283. }
  284. if(bpp==2) {
  285. var val = data[cdi>>3]; val = (val>>(6-(cdi&7)))&3;
  286. img[row*bpl + (col>>2)] |= (val << (6-((col&3)<<1)));
  287. }
  288. if(bpp==4) {
  289. var val = data[cdi>>3]; val = (val>>(4-(cdi&7)))&15;
  290. img[row*bpl + (col>>1)] |= (val << (4-((col&1)<<2)));
  291. }
  292. if(bpp>=8) {
  293. var ii = row*bpl+col*cbpp;
  294. for(var j=0; j<cbpp; j++) img[ii+j] = data[(cdi>>3)+j];
  295. }
  296. cdi+=bpp; col+=ci;
  297. }
  298. y++; row += ri;
  299. }
  300. if(sw*sh!=0) di += sh * (1 + bpll);
  301. pass = pass + 1;
  302. }
  303. return img;
  304. }
  305.  
  306. UPNG.decode._getBPP = function(out) {
  307. var noc = [1,null,3,1,2,null,4][out.ctype];
  308. return noc * out.depth;
  309. }
  310.  
  311. UPNG.decode._filterZero = function(data, out, off, w, h)
  312. {
  313. var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w*bpp/8), paeth = UPNG.decode._paeth;
  314. bpp = Math.ceil(bpp/8);
  315. var i,di, type=data[off], x=0;
  316. if(type>1) data[off]=[0,0,1][type-2];
  317. if(type==3) for(x=bpp; x<bpl; x++) data[x+1] = (data[x+1] + (data[x+1-bpp]>>>1) )&255;
  318.  
  319. for(var y=0; y<h; y++) {
  320. i = off+y*bpl; di = i+y+1;
  321. type = data[di-1]; x=0;
  322.  
  323. if (type==0) for(; x<bpl; x++) data[i+x] = data[di+x];
  324. else if(type==1) { for(; x<bpp; x++) data[i+x] = data[di+x];
  325. for(; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpp]); }
  326. else if(type==2) { for(; x<bpl; x++) data[i+x] = (data[di+x] + data[i+x-bpl]); }
  327. else if(type==3) { for(; x<bpp; x++) data[i+x] = (data[di+x] + ( data[i+x-bpl]>>>1));
  328. for(; x<bpl; x++) data[i+x] = (data[di+x] + ((data[i+x-bpl]+data[i+x-bpp])>>>1) ); }
  329. else { for(; x<bpp; x++) data[i+x] = (data[di+x] + paeth(0, data[i+x-bpl], 0));
  330. for(; x<bpl; x++) data[i+x] = (data[di+x] + paeth(data[i+x-bpp], data[i+x-bpl], data[i+x-bpp-bpl]) ); }
  331. }
  332. return data;
  333. }
  334.  
  335. UPNG.decode._paeth = function(a,b,c)
  336. {
  337. var p = a+b-c, pa = (p-a), pb = (p-b), pc = (p-c);
  338. if (pa*pa <= pb*pb && pa*pa <= pc*pc) return a;
  339. else if (pb*pb <= pc*pc) return b;
  340. return c;
  341. }
  342.  
  343. UPNG.decode._IHDR = function(data, offset, out)
  344. {
  345. var bin = UPNG._bin;
  346. out.width = bin.readUint(data, offset); offset += 4;
  347. out.height = bin.readUint(data, offset); offset += 4;
  348. out.depth = data[offset]; offset++;
  349. out.ctype = data[offset]; offset++;
  350. out.compress = data[offset]; offset++;
  351. out.filter = data[offset]; offset++;
  352. out.interlace = data[offset]; offset++;
  353. }
  354.  
  355. UPNG._bin = {
  356. nextZero : function(data,p) { while(data[p]!=0) p++; return p; },
  357. readUshort : function(buff,p) { return (buff[p]<< 8) | buff[p+1]; },
  358. writeUshort: function(buff,p,n){ buff[p] = (n>>8)&255; buff[p+1] = n&255; },
  359. readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); },
  360. 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; },
  361. readASCII : function(buff,p,l){ var s = ""; for(var i=0; i<l; i++) s += String.fromCharCode(buff[p+i]); return s; },
  362. writeASCII : function(data,p,s){ for(var i=0; i<s.length; i++) data[p+i] = s.charCodeAt(i); },
  363. readBytes : function(buff,p,l){ var arr = []; for(var i=0; i<l; i++) arr.push(buff[p+i]); return arr; },
  364. pad : function(n) { return n.length < 2 ? "0" + n : n; },
  365. readUTF8 : function(buff, p, l) {
  366. var s = "", ns;
  367. for(var i=0; i<l; i++) s += "%" + UPNG._bin.pad(buff[p+i].toString(16));
  368. try { ns = decodeURIComponent(s); }
  369. catch(e) { return UPNG._bin.readASCII(buff, p, l); }
  370. return ns;
  371. }
  372. }
  373. UPNG._copyTile = function(sb, sw, sh, tb, tw, th, xoff, yoff, mode)
  374. {
  375. var w = Math.min(sw,tw), h = Math.min(sh,th);
  376. var si=0, ti=0;
  377. for(var y=0; y<h; y++)
  378. for(var x=0; x<w; x++)
  379. {
  380. if(xoff>=0 && yoff>=0) { si = (y*sw+x)<<2; ti = (( yoff+y)*tw+xoff+x)<<2; }
  381. else { si = ((-yoff+y)*sw-xoff+x)<<2; ti = (y*tw+x)<<2; }
  382. 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]; }
  383. else if(mode==1) {
  384. var fa = sb[si+3]*(1/255), fr=sb[si]*fa, fg=sb[si+1]*fa, fb=sb[si+2]*fa;
  385. var ba = tb[ti+3]*(1/255), br=tb[ti]*ba, bg=tb[ti+1]*ba, bb=tb[ti+2]*ba;
  386. var ifa=1-fa, oa = fa+ba*ifa, ioa = (oa==0?0:1/oa);
  387. tb[ti+3] = 255*oa;
  388. tb[ti+0] = (fr+br*ifa)*ioa;
  389. tb[ti+1] = (fg+bg*ifa)*ioa;
  390. tb[ti+2] = (fb+bb*ifa)*ioa;
  391. }
  392. else if(mode==2){ // copy only differences, otherwise zero
  393. var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2];
  394. var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2];
  395. if(fa==ba && fr==br && fg==bg && fb==bb) { tb[ti]=0; tb[ti+1]=0; tb[ti+2]=0; tb[ti+3]=0; }
  396. else { tb[ti]=fr; tb[ti+1]=fg; tb[ti+2]=fb; tb[ti+3]=fa; }
  397. }
  398. else if(mode==3){ // check if can be blended
  399. var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2];
  400. var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2];
  401. if(fa==ba && fr==br && fg==bg && fb==bb) continue;
  402. //if(fa!=255 && ba!=0) return false;
  403. if(fa<220 && ba>20) return false;
  404. }
  405. }
  406. return true;
  407. }
  408.  
  409.  
  410.  
  411.  
  412.  
  413. UPNG.encode = function(bufs, w, h, ps, dels, tabs, forbidPlte)
  414. {
  415. if(ps==null) ps=0;
  416. if(forbidPlte==null) forbidPlte = false;
  417.  
  418. var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte,false]);
  419. UPNG.encode.compressPNG(nimg, -1);
  420. return UPNG.encode._main(nimg, w, h, dels, tabs);
  421. }
  422.  
  423. UPNG.encodeLL = function(bufs, w, h, cc, ac, depth, dels, tabs) {
  424. var nimg = { ctype: 0 + (cc==1 ? 0 : 2) + (ac==0 ? 0 : 4), depth: depth, frames: [] };
  425. var time = Date.now();
  426. var bipp = (cc+ac)*depth, bipl = bipp * w;
  427. for(var i=0; i<bufs.length; i++)
  428. nimg.frames.push({ rect:{x:0,y:0,width:w,height:h}, img:new Uint8Array(bufs[i]), blend:0, dispose:1, bpp:Math.ceil(bipp/8), bpl:Math.ceil(bipl/8) });
  429. UPNG.encode.compressPNG(nimg, 0, true);
  430. var out = UPNG.encode._main(nimg, w, h, dels, tabs);
  431. return out;
  432. }
  433.  
  434. UPNG.encode._main = function(nimg, w, h, dels, tabs) {
  435. if(tabs==null) tabs={};
  436. var crc = UPNG.crc.crc, wUi = UPNG._bin.writeUint, wUs = UPNG._bin.writeUshort, wAs = UPNG._bin.writeASCII;
  437. var offset = 8, anim = nimg.frames.length>1, pltAlpha = false;
  438. var leng = 8 + (16+5+4) /*+ (9+4)*/ + (anim ? 20 : 0);
  439. if(tabs["sRGB"]!=null) leng += 8+1+4;
  440. if(tabs["pHYs"]!=null) leng += 8+9+4;
  441. if(nimg.ctype==3) {
  442. var dl = nimg.plte.length;
  443. for(var i=0; i<dl; i++) if((nimg.plte[i]>>>24)!=255) pltAlpha = true;
  444. leng += (8 + dl*3 + 4) + (pltAlpha ? (8 + dl*1 + 4) : 0);
  445. }
  446. for(var j=0; j<nimg.frames.length; j++)
  447. {
  448. var fr = nimg.frames[j];
  449. if(anim) leng += 38;
  450. leng += fr.cimg.length + 12;
  451. if(j!=0) leng+=4;
  452. }
  453. leng += 12;
  454. var data = new Uint8Array(leng);
  455. var wr=[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
  456. for(var i=0; i<8; i++) data[i]=wr[i];
  457. wUi(data,offset, 13); offset+=4;
  458. wAs(data,offset,"IHDR"); offset+=4;
  459. wUi(data,offset,w); offset+=4;
  460. wUi(data,offset,h); offset+=4;
  461. data[offset] = nimg.depth; offset++; // depth
  462. data[offset] = nimg.ctype; offset++; // ctype
  463. data[offset] = 0; offset++; // compress
  464. data[offset] = 0; offset++; // filter
  465. data[offset] = 0; offset++; // interlace
  466. wUi(data,offset,crc(data,offset-17,17)); offset+=4; // crc
  467.  
  468. // 13 bytes to say, that it is sRGB
  469. if(tabs["sRGB"]!=null) {
  470. wUi(data,offset, 1); offset+=4;
  471. wAs(data,offset,"sRGB"); offset+=4;
  472. data[offset] = tabs["sRGB"]; offset++;
  473. wUi(data,offset,crc(data,offset-5,5)); offset+=4; // crc
  474. }
  475. if(tabs["pHYs"]!=null) {
  476. wUi(data,offset, 9); offset+=4;
  477. wAs(data,offset,"pHYs"); offset+=4;
  478. wUi(data,offset, tabs["pHYs"][0]); offset+=4;
  479. wUi(data,offset, tabs["pHYs"][1]); offset+=4;
  480. data[offset]=tabs["pHYs"][2]; offset++;
  481. wUi(data,offset,crc(data,offset-13,13)); offset+=4; // crc
  482. }
  483.  
  484. if(anim) {
  485. wUi(data,offset, 8); offset+=4;
  486. wAs(data,offset,"acTL"); offset+=4;
  487. wUi(data,offset, nimg.frames.length); offset+=4;
  488. wUi(data,offset, tabs["loop"]!=null?tabs["loop"]:0); offset+=4;
  489. wUi(data,offset,crc(data,offset-12,12)); offset+=4; // crc
  490. }
  491.  
  492. if(nimg.ctype==3) {
  493. var dl = nimg.plte.length;
  494. wUi(data,offset, dl*3); offset+=4;
  495. wAs(data,offset,"PLTE"); offset+=4;
  496. for(var i=0; i<dl; i++){
  497. var ti=i*3, c=nimg.plte[i], r=(c)&255, g=(c>>>8)&255, b=(c>>>16)&255;
  498. data[offset+ti+0]=r; data[offset+ti+1]=g; data[offset+ti+2]=b;
  499. }
  500. offset+=dl*3;
  501. wUi(data,offset,crc(data,offset-dl*3-4,dl*3+4)); offset+=4; // crc
  502.  
  503. if(pltAlpha) {
  504. wUi(data,offset, dl); offset+=4;
  505. wAs(data,offset,"tRNS"); offset+=4;
  506. for(var i=0; i<dl; i++) data[offset+i]=(nimg.plte[i]>>>24)&255;
  507. offset+=dl;
  508. wUi(data,offset,crc(data,offset-dl-4,dl+4)); offset+=4; // crc
  509. }
  510. }
  511. var fi = 0;
  512. for(var j=0; j<nimg.frames.length; j++)
  513. {
  514. var fr = nimg.frames[j];
  515. if(anim) {
  516. wUi(data, offset, 26); offset+=4;
  517. wAs(data, offset,"fcTL"); offset+=4;
  518. wUi(data, offset, fi++); offset+=4;
  519. wUi(data, offset, fr.rect.width ); offset+=4;
  520. wUi(data, offset, fr.rect.height); offset+=4;
  521. wUi(data, offset, fr.rect.x); offset+=4;
  522. wUi(data, offset, fr.rect.y); offset+=4;
  523. wUs(data, offset, dels[j]); offset+=2;
  524. wUs(data, offset, 1000); offset+=2;
  525. data[offset] = fr.dispose; offset++; // dispose
  526. data[offset] = fr.blend ; offset++; // blend
  527. wUi(data,offset,crc(data,offset-30,30)); offset+=4; // crc
  528. }
  529. var imgd = fr.cimg, dl = imgd.length;
  530. wUi(data,offset, dl+(j==0?0:4)); offset+=4;
  531. var ioff = offset;
  532. wAs(data,offset,(j==0)?"IDAT":"fdAT"); offset+=4;
  533. if(j!=0) { wUi(data, offset, fi++); offset+=4; }
  534. data.set(imgd,offset);
  535. offset += dl;
  536. wUi(data,offset,crc(data,ioff,offset-ioff)); offset+=4; // crc
  537. }
  538.  
  539. wUi(data,offset, 0); offset+=4;
  540. wAs(data,offset,"IEND"); offset+=4;
  541. wUi(data,offset,crc(data,offset-4,4)); offset+=4; // crc
  542.  
  543. return data.buffer;
  544. }
  545.  
  546. UPNG.encode.compressPNG = function(out, filter, levelZero) {
  547. for(var i=0; i<out.frames.length; i++) {
  548. var frm = out.frames[i], nw=frm.rect.width, nh=frm.rect.height;
  549. var fdata = new Uint8Array(nh*frm.bpl+nh);
  550. frm.cimg = UPNG.encode._filterZero(frm.img,nh,frm.bpp,frm.bpl,fdata, filter, levelZero);
  551. }
  552. }
  553.  
  554.  
  555.  
  556. UPNG.encode.compress = function(bufs, w, h, ps, prms) // prms: onlyBlend, minBits, forbidPlte
  557. {
  558. //var time = Date.now();
  559. var onlyBlend = prms[0], evenCrd = prms[1], forbidPrev = prms[2], minBits = prms[3], forbidPlte = prms[4], dither=prms[5];
  560. var ctype = 6, depth = 8, alphaAnd=255
  561. for(var j=0; j<bufs.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame
  562. var img = new Uint8Array(bufs[j]), ilen = img.length;
  563. for(var i=0; i<ilen; i+=4) alphaAnd &= img[i+3];
  564. }
  565. var gotAlpha = (alphaAnd!=255);
  566. //console.log("alpha check", Date.now()-time); time = Date.now();
  567. //var brute = gotAlpha && forGIF; // brute : frames can only be copied, not "blended"
  568. var frms = UPNG.encode.framize(bufs, w, h, onlyBlend, evenCrd, forbidPrev);
  569. //console.log("framize", Date.now()-time); time = Date.now();
  570. var cmap={}, plte=[], inds=[];
  571. if(ps!=0) {
  572. var nbufs = []; for(var i=0; i<frms.length; i++) nbufs.push(frms[i].img.buffer);
  573. var abuf = UPNG.encode.concatRGBA(nbufs), qres = UPNG.quantize(abuf, ps);
  574. for(var i=0; i<qres.plte.length; i++) plte.push(qres.plte[i].est.rgba);
  575. var cof = 0;
  576. for(var i=0; i<frms.length; i++) {
  577. var frm=frms[i], bln=frm.img.length, ind = new Uint8Array(qres.inds.buffer, cof>>2, bln>>2); inds.push(ind);
  578. var bb = new Uint8Array(qres.abuf,cof,bln);
  579. //console.log(frm.img, frm.width, frm.height);
  580. //var time = Date.now();
  581. if(dither) UPNG.encode.dither(frm.img, frm.rect.width, frm.rect.height, plte, bb, ind);
  582. //console.log(Date.now()-time);
  583. frm.img.set(bb); cof+=bln;
  584. }
  585. //console.log("quantize", Date.now()-time); time = Date.now();
  586. }
  587. else {
  588. // what if ps==0, but there are <=256 colors? we still need to detect, if the palette could be used
  589. for(var j=0; j<frms.length; j++) { // when not quantized, other frames can contain colors, that are not in an initial frame
  590. var frm = frms[j], img32 = new Uint32Array(frm.img.buffer), nw=frm.rect.width, ilen = img32.length;
  591. var ind = new Uint8Array(ilen); inds.push(ind);
  592. for(var i=0; i<ilen; i++) {
  593. var c = img32[i];
  594. if (i!=0 && c==img32[i- 1]) ind[i]=ind[i-1];
  595. else if(i>nw && c==img32[i-nw]) ind[i]=ind[i-nw];
  596. else {
  597. var cmc = cmap[c];
  598. if(cmc==null) { cmap[c]=cmc=plte.length; plte.push(c); if(plte.length>=300) break; }
  599. ind[i]=cmc;
  600. }
  601. }
  602. }
  603. //console.log("make palette", Date.now()-time); time = Date.now();
  604. }
  605. var cc=plte.length; //console.log("colors:",cc);
  606. if(cc<=256 && forbidPlte==false) {
  607. if(cc<= 2) depth=1; else if(cc<= 4) depth=2; else if(cc<=16) depth=4; else depth=8;
  608. depth = Math.max(depth, minBits);
  609. }
  610. for(var j=0; j<frms.length; j++)
  611. {
  612. var frm = frms[j], nx=frm.rect.x, ny=frm.rect.y, nw=frm.rect.width, nh=frm.rect.height;
  613. var cimg = frm.img, cimg32 = new Uint32Array(cimg.buffer);
  614. var bpl = 4*nw, bpp=4;
  615. if(cc<=256 && forbidPlte==false) {
  616. bpl = Math.ceil(depth*nw/8);
  617. var nimg = new Uint8Array(bpl*nh);
  618. var inj = inds[j];
  619. for(var y=0; y<nh; y++) { var i=y*bpl, ii=y*nw;
  620. if (depth==8) for(var x=0; x<nw; x++) nimg[i+(x) ] = (inj[ii+x] );
  621. else if(depth==4) for(var x=0; x<nw; x++) nimg[i+(x>>1)] |= (inj[ii+x]<<(4-(x&1)*4));
  622. else if(depth==2) for(var x=0; x<nw; x++) nimg[i+(x>>2)] |= (inj[ii+x]<<(6-(x&3)*2));
  623. else if(depth==1) for(var x=0; x<nw; x++) nimg[i+(x>>3)] |= (inj[ii+x]<<(7-(x&7)*1));
  624. }
  625. cimg=nimg; ctype=3; bpp=1;
  626. }
  627. else if(gotAlpha==false && frms.length==1) { // some next "reduced" frames may contain alpha for blending
  628. var nimg = new Uint8Array(nw*nh*3), area=nw*nh;
  629. for(var i=0; i<area; i++) { var ti=i*3, qi=i*4; nimg[ti]=cimg[qi]; nimg[ti+1]=cimg[qi+1]; nimg[ti+2]=cimg[qi+2]; }
  630. cimg=nimg; ctype=2; bpp=3; bpl=3*nw;
  631. }
  632. frm.img=cimg; frm.bpl=bpl; frm.bpp=bpp;
  633. }
  634. //console.log("colors => palette indices", Date.now()-time); time = Date.now();
  635. return {ctype:ctype, depth:depth, plte:plte, frames:frms };
  636. }
  637. UPNG.encode.framize = function(bufs,w,h,alwaysBlend,evenCrd,forbidPrev) {
  638. /* DISPOSE
  639. - 0 : no change
  640. - 1 : clear to transparent
  641. - 2 : retstore to content before rendering (previous frame disposed)
  642. BLEND
  643. - 0 : replace
  644. - 1 : blend
  645. */
  646. var frms = [];
  647. for(var j=0; j<bufs.length; j++) {
  648. var cimg = new Uint8Array(bufs[j]), cimg32 = new Uint32Array(cimg.buffer);
  649. var nimg;
  650. var nx=0, ny=0, nw=w, nh=h, blend=alwaysBlend?1:0;
  651. if(j!=0) {
  652. var tlim = (forbidPrev || alwaysBlend || j==1 || frms[j-2].dispose!=0)?1:2, tstp = 0, tarea = 1e9;
  653. for(var it=0; it<tlim; it++)
  654. {
  655. var pimg = new Uint8Array(bufs[j-1-it]), p32 = new Uint32Array(bufs[j-1-it]);
  656. var mix=w,miy=h,max=-1,may=-1;
  657. for(var y=0; y<h; y++) for(var x=0; x<w; x++) {
  658. var i = y*w+x;
  659. if(cimg32[i]!=p32[i]) {
  660. if(x<mix) mix=x; if(x>max) max=x;
  661. if(y<miy) miy=y; if(y>may) may=y;
  662. }
  663. }
  664. if(max==-1) mix=miy=max=may=0;
  665. if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; }
  666. var sarea = (max-mix+1)*(may-miy+1);
  667. if(sarea<tarea) {
  668. tarea = sarea; tstp = it;
  669. nx = mix; ny = miy; nw = max-mix+1; nh = may-miy+1;
  670. }
  671. }
  672. // alwaysBlend: pokud zjistím, že blendit nelze, nastavím předchozímu snímku dispose=1. Zajistím, aby obsahoval můj obdélník.
  673. var pimg = new Uint8Array(bufs[j-1-tstp]);
  674. if(tstp==1) frms[j-1].dispose = 2;
  675. nimg = new Uint8Array(nw*nh*4);
  676. UPNG._copyTile(pimg,w,h, nimg,nw,nh, -nx,-ny, 0);
  677. blend = UPNG._copyTile(cimg,w,h, nimg,nw,nh, -nx,-ny, 3) ? 1 : 0;
  678. if(blend==1) UPNG.encode._prepareDiff(cimg,w,h,nimg,{x:nx,y:ny,width:nw,height:nh});
  679. else UPNG._copyTile(cimg,w,h, nimg,nw,nh, -nx,-ny, 0);
  680. //UPNG._copyTile(cimg,w,h, nimg,nw,nh, -nx,-ny, blend==1?2:0);
  681. }
  682. else nimg = cimg.slice(0); // img may be rewritten further ... don't rewrite input
  683. frms.push({rect:{x:nx,y:ny,width:nw,height:nh}, img:nimg, blend:blend, dispose:0});
  684. }
  685. if(alwaysBlend) for(var j=0; j<frms.length; j++) {
  686. var frm = frms[j]; if(frm.blend==1) continue;
  687. var r0 = frm.rect, r1 = frms[j-1].rect
  688. var miX = Math.min(r0.x, r1.x), miY = Math.min(r0.y, r1.y);
  689. var maX = Math.max(r0.x+r0.width, r1.x+r1.width), maY = Math.max(r0.y+r0.height, r1.y+r1.height);
  690. var r = {x:miX, y:miY, width:maX-miX, height:maY-miY};
  691. frms[j-1].dispose = 1;
  692. if(j-1!=0)
  693. UPNG.encode._updateFrame(bufs, w,h,frms, j-1,r, evenCrd);
  694. UPNG.encode._updateFrame(bufs, w,h,frms, j ,r, evenCrd);
  695. }
  696. var area = 0;
  697. if(bufs.length!=1) for(var i=0; i<frms.length; i++) {
  698. var frm = frms[i];
  699. area += frm.rect.width*frm.rect.height;
  700. //if(i==0 || frm.blend!=1) continue;
  701. //var ob = new Uint8Array(
  702. //console.log(frm.blend, frm.dispose, frm.rect);
  703. }
  704. //if(area!=0) console.log(area);
  705. return frms;
  706. }
  707. UPNG.encode._updateFrame = function(bufs, w,h, frms, i, r, evenCrd) {
  708. var U8 = Uint8Array, U32 = Uint32Array;
  709. var pimg = new U8(bufs[i-1]), pimg32 = new U32(bufs[i-1]), nimg = i+1<bufs.length ? new U8(bufs[i+1]):null;
  710. var cimg = new U8(bufs[i]), cimg32 = new U32(cimg.buffer);
  711. var mix=w,miy=h,max=-1,may=-1;
  712. for(var y=0; y<r.height; y++) for(var x=0; x<r.width; x++) {
  713. var cx = r.x+x, cy = r.y+y;
  714. var j = cy*w+cx, cc = cimg32[j];
  715. // no need to draw transparency, or to dispose it. Or, if writing the same color and the next one does not need transparency.
  716. if(cc==0 || (frms[i-1].dispose==0 && pimg32[j]==cc && (nimg==null || nimg[j*4+3]!=0))/**/) {}
  717. else {
  718. if(cx<mix) mix=cx; if(cx>max) max=cx;
  719. if(cy<miy) miy=cy; if(cy>may) may=cy;
  720. }
  721. }
  722. if(max==-1) mix=miy=max=may=0;
  723. if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; }
  724. r = {x:mix, y:miy, width:max-mix+1, height:may-miy+1};
  725. var fr = frms[i]; fr.rect = r; fr.blend = 1; fr.img = new Uint8Array(r.width*r.height*4);
  726. if(frms[i-1].dispose==0) {
  727. UPNG._copyTile(pimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0);
  728. UPNG.encode._prepareDiff(cimg,w,h,fr.img,r);
  729. //UPNG._copyTile(cimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 2);
  730. }
  731. else
  732. UPNG._copyTile(cimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0);
  733. }
  734. UPNG.encode._prepareDiff = function(cimg, w,h, nimg, rec) {
  735. UPNG._copyTile(cimg,w,h, nimg,rec.width,rec.height, -rec.x,-rec.y, 2);
  736. /*
  737. var n32 = new Uint32Array(nimg.buffer);
  738. var og = new Uint8Array(rec.width*rec.height*4), o32 = new Uint32Array(og.buffer);
  739. UPNG._copyTile(cimg,w,h, og,rec.width,rec.height, -rec.x,-rec.y, 0);
  740. for(var i=4; i<nimg.length; i+=4) {
  741. if(nimg[i-1]!=0 && nimg[i+3]==0 && o32[i>>>2]==o32[(i>>>2)-1]) {
  742. n32[i>>>2]=o32[i>>>2];
  743. //var j = i, c=p32[(i>>>2)-1];
  744. //while(p32[j>>>2]==c) { n32[j>>>2]=c; j+=4; }
  745. }
  746. }
  747. for(var i=nimg.length-8; i>0; i-=4) {
  748. if(nimg[i+7]!=0 && nimg[i+3]==0 && o32[i>>>2]==o32[(i>>>2)+1]) {
  749. n32[i>>>2]=o32[i>>>2];
  750. //var j = i, c=p32[(i>>>2)-1];
  751. //while(p32[j>>>2]==c) { n32[j>>>2]=c; j+=4; }
  752. }
  753. }*/
  754. }
  755.  
  756. UPNG.encode._filterZero = function(img,h,bpp,bpl,data, filter, levelZero)
  757. {
  758. var fls = [], ftry=[0,1,2,3,4];
  759. if (filter!=-1) ftry=[filter];
  760. else if(h*bpl>500000 || bpp==1) ftry=[0];
  761. var opts; if(levelZero) opts={level:0};
  762. var CMPR = (data.length>10e6 && UZIP!=null) ? UZIP : pako;
  763. var time = Date.now();
  764. for(var i=0; i<ftry.length; i++) {
  765. for(var y=0; y<h; y++) UPNG.encode._filterLine(data, img, y, bpl, bpp, ftry[i]);
  766. //var nimg = new Uint8Array(data.length);
  767. //var sz = UZIP.F.deflate(data, nimg); fls.push(nimg.slice(0,sz));
  768. //var dfl = pako["deflate"](data), dl=dfl.length-4;
  769. //var crc = (dfl[dl+3]<<24)|(dfl[dl+2]<<16)|(dfl[dl+1]<<8)|(dfl[dl+0]<<0);
  770. //console.log(crc, UZIP.adler(data,2,data.length-6));
  771. fls.push(CMPR["deflate"](data,opts));
  772. }
  773. var ti, tsize=1e9;
  774. for(var i=0; i<fls.length; i++) if(fls[i].length<tsize) { ti=i; tsize=fls[i].length; }
  775. return fls[ti];
  776. }
  777. UPNG.encode._filterLine = function(data, img, y, bpl, bpp, type)
  778. {
  779. var i = y*bpl, di = i+y, paeth = UPNG.decode._paeth
  780. data[di]=type; di++;
  781.  
  782. if(type==0) {
  783. if(bpl<500) for(var x=0; x<bpl; x++) data[di+x] = img[i+x];
  784. else data.set(new Uint8Array(img.buffer,i,bpl),di);
  785. }
  786. else if(type==1) {
  787. for(var x= 0; x<bpp; x++) data[di+x] = img[i+x];
  788. for(var x=bpp; x<bpl; x++) data[di+x] = (img[i+x]-img[i+x-bpp]+256)&255;
  789. }
  790. else if(y==0) {
  791. for(var x= 0; x<bpp; x++) data[di+x] = img[i+x];
  792.  
  793. if(type==2) for(var x=bpp; x<bpl; x++) data[di+x] = img[i+x];
  794. if(type==3) for(var x=bpp; x<bpl; x++) data[di+x] = (img[i+x] - (img[i+x-bpp]>>1) +256)&255;
  795. 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;
  796. }
  797. else {
  798. if(type==2) { for(var x= 0; x<bpl; x++) data[di+x] = (img[i+x]+256 - img[i+x-bpl])&255; }
  799. if(type==3) { for(var x= 0; x<bpp; x++) data[di+x] = (img[i+x]+256 - (img[i+x-bpl]>>1))&255;
  800. for(var x=bpp; x<bpl; x++) data[di+x] = (img[i+x]+256 - ((img[i+x-bpl]+img[i+x-bpp])>>1))&255; }
  801. 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;
  802. 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; }
  803. }
  804. }
  805.  
  806. UPNG.crc = {
  807. table : ( function() {
  808. var tab = new Uint32Array(256);
  809. for (var n=0; n<256; n++) {
  810. var c = n;
  811. for (var k=0; k<8; k++) {
  812. if (c & 1) c = 0xedb88320 ^ (c >>> 1);
  813. else c = c >>> 1;
  814. }
  815. tab[n] = c; }
  816. return tab; })(),
  817. update : function(c, buf, off, len) {
  818. for (var i=0; i<len; i++) c = UPNG.crc.table[(c ^ buf[off+i]) & 0xff] ^ (c >>> 8);
  819. return c;
  820. },
  821. crc : function(b,o,l) { return UPNG.crc.update(0xffffffff,b,o,l) ^ 0xffffffff; }
  822. }
  823.  
  824.  
  825. UPNG.quantize = function(abuf, ps)
  826. {
  827. var sb = new Uint8Array(abuf), tb = sb.slice(0), tb32 = new Uint32Array(tb.buffer);
  828. var KD = UPNG.quantize.getKDtree(tb, ps);
  829. var root = KD[0], leafs = KD[1];
  830. var planeDst = UPNG.quantize.planeDst;
  831. var len=sb.length;
  832. var inds = new Uint8Array(len>>2), nd;
  833. if(sb.length<20e6) // precise, but slow :(
  834. for(var i=0; i<len; i+=4) {
  835. var r=sb[i]*(1/255), g=sb[i+1]*(1/255), b=sb[i+2]*(1/255), a=sb[i+3]*(1/255);
  836. nd = UPNG.quantize.getNearest(root, r, g, b, a);
  837. inds[i>>2] = nd.ind; tb32[i>>2] = nd.est.rgba;
  838. }
  839. else
  840. for(var i=0; i<len; i+=4) {
  841. var r=sb[i]*(1/255), g=sb[i+1]*(1/255), b=sb[i+2]*(1/255), a=sb[i+3]*(1/255);
  842. nd = root; while(nd.left) nd = (planeDst(nd.est,r,g,b,a)<=0) ? nd.left : nd.right;
  843. inds[i>>2] = nd.ind; tb32[i>>2] = nd.est.rgba;
  844. }
  845. return { abuf:tb.buffer, inds:inds, plte:leafs };
  846. }
  847.  
  848. UPNG.quantize.getKDtree = function(nimg, ps, err) {
  849. if(err==null) err = 0.0001;
  850. var nimg32 = new Uint32Array(nimg.buffer);
  851. var root = {i0:0, i1:nimg.length, bst:null, est:null, tdst:0, left:null, right:null }; // basic statistic, extra statistic
  852. root.bst = UPNG.quantize.stats( nimg,root.i0, root.i1 ); root.est = UPNG.quantize.estats( root.bst );
  853. var leafs = [root];
  854. while(leafs.length<ps)
  855. {
  856. var maxL = 0, mi=0;
  857. for(var i=0; i<leafs.length; i++) if(leafs[i].est.L > maxL) { maxL=leafs[i].est.L; mi=i; }
  858. if(maxL<err) break;
  859. var node = leafs[mi];
  860. var s0 = UPNG.quantize.splitPixels(nimg,nimg32, node.i0, node.i1, node.est.e, node.est.eMq255);
  861. var s0wrong = (node.i0>=s0 || node.i1<=s0);
  862. //console.log(maxL, leafs.length, mi);
  863. if(s0wrong) { node.est.L=0; continue; }
  864. var ln = {i0:node.i0, i1:s0, bst:null, est:null, tdst:0, left:null, right:null }; ln.bst = UPNG.quantize.stats( nimg, ln.i0, ln.i1 );
  865. ln.est = UPNG.quantize.estats( ln.bst );
  866. 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};
  867. for(var i=0; i<16; i++) rn.bst.R[i] = node.bst.R[i]-ln.bst.R[i];
  868. for(var i=0; i< 4; i++) rn.bst.m[i] = node.bst.m[i]-ln.bst.m[i];
  869. rn.est = UPNG.quantize.estats( rn.bst );
  870. node.left = ln; node.right = rn;
  871. leafs[mi]=ln; leafs.push(rn);
  872. }
  873. leafs.sort(function(a,b) { return b.bst.N-a.bst.N; });
  874. for(var i=0; i<leafs.length; i++) leafs[i].ind=i;
  875. return [root, leafs];
  876. }
  877.  
  878. UPNG.quantize.getNearest = function(nd, r,g,b,a)
  879. {
  880. if(nd.left==null) { nd.tdst = UPNG.quantize.dist(nd.est.q,r,g,b,a); return nd; }
  881. var planeDst = UPNG.quantize.planeDst(nd.est,r,g,b,a);
  882. var node0 = nd.left, node1 = nd.right;
  883. if(planeDst>0) { node0=nd.right; node1=nd.left; }
  884. var ln = UPNG.quantize.getNearest(node0, r,g,b,a);
  885. if(ln.tdst<=planeDst*planeDst) return ln;
  886. var rn = UPNG.quantize.getNearest(node1, r,g,b,a);
  887. return rn.tdst<ln.tdst ? rn : ln;
  888. }
  889. UPNG.quantize.planeDst = function(est, r,g,b,a) { var e = est.e; return e[0]*r + e[1]*g + e[2]*b + e[3]*a - est.eMq; }
  890. UPNG.quantize.dist = function(q, r,g,b,a) { var d0=r-q[0], d1=g-q[1], d2=b-q[2], d3=a-q[3]; return d0*d0+d1*d1+d2*d2+d3*d3; }
  891.  
  892. UPNG.quantize.splitPixels = function(nimg, nimg32, i0, i1, e, eMq)
  893. {
  894. var vecDot = UPNG.quantize.vecDot;
  895. i1-=4;
  896. var shfs = 0;
  897. while(i0<i1)
  898. {
  899. while(vecDot(nimg, i0, e)<=eMq) i0+=4;
  900. while(vecDot(nimg, i1, e)> eMq) i1-=4;
  901. if(i0>=i1) break;
  902. var t = nimg32[i0>>2]; nimg32[i0>>2] = nimg32[i1>>2]; nimg32[i1>>2]=t;
  903. i0+=4; i1-=4;
  904. }
  905. while(vecDot(nimg, i0, e)>eMq) i0-=4;
  906. return i0+4;
  907. }
  908. UPNG.quantize.vecDot = function(nimg, i, e)
  909. {
  910. return nimg[i]*e[0] + nimg[i+1]*e[1] + nimg[i+2]*e[2] + nimg[i+3]*e[3];
  911. }
  912. UPNG.quantize.stats = function(nimg, i0, i1){
  913. var R = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
  914. var m = [0,0,0,0];
  915. var N = (i1-i0)>>2;
  916. for(var i=i0; i<i1; i+=4)
  917. {
  918. var r = nimg[i]*(1/255), g = nimg[i+1]*(1/255), b = nimg[i+2]*(1/255), a = nimg[i+3]*(1/255);
  919. //var r = nimg[i], g = nimg[i+1], b = nimg[i+2], a = nimg[i+3];
  920. m[0]+=r; m[1]+=g; m[2]+=b; m[3]+=a;
  921. R[ 0] += r*r; R[ 1] += r*g; R[ 2] += r*b; R[ 3] += r*a;
  922. R[ 5] += g*g; R[ 6] += g*b; R[ 7] += g*a;
  923. R[10] += b*b; R[11] += b*a;
  924. R[15] += a*a;
  925. }
  926. R[4]=R[1]; R[8]=R[2]; R[9]=R[6]; R[12]=R[3]; R[13]=R[7]; R[14]=R[11];
  927. return {R:R, m:m, N:N};
  928. }
  929. UPNG.quantize.estats = function(stats){
  930. var R = stats.R, m = stats.m, N = stats.N;
  931. // when all samples are equal, but N is large (millions), the Rj can be non-zero ( 0.0003.... - precission error)
  932. var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], iN = (N==0 ? 0 : 1/N);
  933. var Rj = [
  934. R[ 0] - m0*m0*iN, R[ 1] - m0*m1*iN, R[ 2] - m0*m2*iN, R[ 3] - m0*m3*iN,
  935. R[ 4] - m1*m0*iN, R[ 5] - m1*m1*iN, R[ 6] - m1*m2*iN, R[ 7] - m1*m3*iN,
  936. R[ 8] - m2*m0*iN, R[ 9] - m2*m1*iN, R[10] - m2*m2*iN, R[11] - m2*m3*iN,
  937. R[12] - m3*m0*iN, R[13] - m3*m1*iN, R[14] - m3*m2*iN, R[15] - m3*m3*iN
  938. ];
  939. var A = Rj, M = UPNG.M4;
  940. var b = [Math.random(),Math.random(),Math.random(),Math.random()], mi = 0, tmi = 0;
  941. if(N!=0)
  942. for(var i=0; i<16; i++) {
  943. b = M.multVec(A, b); tmi = Math.sqrt(M.dot(b,b)); b = M.sml(1/tmi, b);
  944. if(i!=0 && Math.abs(tmi-mi)<1e-9) break; mi = tmi;
  945. }
  946. //b = [0,0,1,0]; mi=N;
  947. var q = [m0*iN, m1*iN, m2*iN, m3*iN];
  948. var eMq255 = M.dot(M.sml(255,q),b);
  949. return { Cov:Rj, q:q, e:b, L:mi, eMq255:eMq255, eMq : M.dot(b,q),
  950. rgba: (((Math.round(255*q[3])<<24) | (Math.round(255*q[2])<<16) | (Math.round(255*q[1])<<8) | (Math.round(255*q[0])<<0))>>>0) };
  951. }
  952. UPNG.M4 = {
  953. multVec : function(m,v) {
  954. return [
  955. m[ 0]*v[0] + m[ 1]*v[1] + m[ 2]*v[2] + m[ 3]*v[3],
  956. m[ 4]*v[0] + m[ 5]*v[1] + m[ 6]*v[2] + m[ 7]*v[3],
  957. m[ 8]*v[0] + m[ 9]*v[1] + m[10]*v[2] + m[11]*v[3],
  958. m[12]*v[0] + m[13]*v[1] + m[14]*v[2] + m[15]*v[3]
  959. ];
  960. },
  961. dot : function(x,y) { return x[0]*y[0]+x[1]*y[1]+x[2]*y[2]+x[3]*y[3]; },
  962. sml : function(a,y) { return [a*y[0],a*y[1],a*y[2],a*y[3]]; }
  963. }
  964.  
  965. UPNG.encode.concatRGBA = function(bufs) {
  966. var tlen = 0;
  967. for(var i=0; i<bufs.length; i++) tlen += bufs[i].byteLength;
  968. var nimg = new Uint8Array(tlen), noff=0;
  969. for(var i=0; i<bufs.length; i++) {
  970. var img = new Uint8Array(bufs[i]), il = img.length;
  971. for(var j=0; j<il; j+=4) {
  972. var r=img[j], g=img[j+1], b=img[j+2], a = img[j+3];
  973. if(a==0) r=g=b=0;
  974. nimg[noff+j]=r; nimg[noff+j+1]=g; nimg[noff+j+2]=b; nimg[noff+j+3]=a; }
  975. noff += il;
  976. }
  977. return nimg.buffer;
  978. }
  979.  
  980. UPNG.encode.dither = function(sb, w, h, plte, tb, oind) {
  981. function addErr(er, tg, ti, f) {
  982. 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;
  983. }
  984. function N(x) { return Math.max(0, Math.min(255, x)); }
  985. 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); }
  986. var pc=plte.length, nplt = [], rads=[];
  987. for(var i=0; i<pc; i++) {
  988. var c = plte[i];
  989. nplt.push([((c>>>0)&255), ((c>>>8)&255), ((c>>>16)&255), ((c>>>24)&255)]);
  990. }
  991. for(var i=0; i<pc; i++) {
  992. var ne=0xffffffff, ni=0;
  993. for(var j=0; j<pc; j++) { var ce=D(nplt[i],nplt[j]); if(j!=i && ce<ne) { ne=ce; ni=j; } }
  994. var hd = Math.sqrt(ne)/2;
  995. rads[i] = ~~(hd*hd);
  996. }
  997. var tb32 = new Uint32Array(tb.buffer);
  998. var err = new Int16Array(w*h*4);
  999. for(var y=0; y<h; y++) {
  1000. for(var x=0; x<w; x++) {
  1001. var i = (y*w+x)*4;
  1002. var cc = [N(sb[i]+err[i]), N(sb[i+1]+err[i+1]), N(sb[i+2]+err[i+2]), N(sb[i+3]+err[i+3])];
  1003. var ni=0, nd = 0xffffff;
  1004. for(var j=0; j<pc; j++) {
  1005. var cd = D(cc,nplt[j]);
  1006. if(cd<nd) { nd=cd; ni=j; }
  1007. }
  1008. //ni = oind[i>>2];
  1009. var nc = nplt[ni];
  1010. var er = [cc[0]-nc[0], cc[1]-nc[1], cc[2]-nc[2], cc[3]-nc[3]];
  1011. //addErr(er, err, i+4, 16);
  1012. //*
  1013. if(x!=w-1) addErr(er, err, i+4 , 7);
  1014. if(y!=h-1) {
  1015. if(x!= 0) addErr(er, err, i+4*w-4, 3);
  1016. addErr(er, err, i+4*w , 5);
  1017. if(x!=w-1) addErr(er, err, i+4*w+4, 1); //*/
  1018. }
  1019. oind[i>>2] = ni; tb32[i>>2] = plte[ni];
  1020. }
  1021. }
  1022. }