diff --git a/demo/js/woff2ttf.js b/demo/js/woff2ttf.js new file mode 100644 index 0000000..2b65ba2 --- /dev/null +++ b/demo/js/woff2ttf.js @@ -0,0 +1,55 @@ +/** + * @file woff2ttf.js + * @author mengke01 + * @date + * @description + * woff 转ttf + */ + +define( + function(require) { + var ajaxBinaryFile = require('common/ajaxBinaryFile'); + var woff2ttf = require('ttf/woff2ttf'); + var TTFReader = require('ttf/ttfreader'); + var inflate = require('inflate').inflate; + var ttf2base64 = require('ttf/ttf2base64'); + + function write() { + + ajaxBinaryFile({ + url: '../font/iconfont.woff', + onSuccess: function(buffer) { + + var ttfBuffer = woff2ttf(buffer, { + inflate: inflate + }); + + var saveBtn = $('.saveas'); + saveBtn.attr('href', ttf2base64(ttfBuffer)); + saveBtn.attr('download', 'save.woff'); + + var ttfReader = new TTFReader(); + var ttfData = ttfReader.read(ttfBuffer); + console.log(ttfData); + }, + onError: function() { + console.error('error read file'); + } + }); + } + + var entry = { + + /** + * 初始化 + */ + init: function () { + write(); + } + }; + + entry.init(); + + return entry; + } +); diff --git a/demo/woff2ttf.html b/demo/woff2ttf.html new file mode 100644 index 0000000..2442f4f --- /dev/null +++ b/demo/woff2ttf.html @@ -0,0 +1,29 @@ + + + + + woff2ttf + + + + + +保存 + + + + + + + \ No newline at end of file diff --git a/dep/pako_inflate.min.js b/dep/pako_inflate.min.js new file mode 100644 index 0000000..58662fb --- /dev/null +++ b/dep/pako_inflate.min.js @@ -0,0 +1,2 @@ +/* pako 0.2.5 nodeca/pako */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.pako=e()}}(function(){return function e(t,i,n){function a(s,o){if(!i[s]){if(!t[s]){var f="function"==typeof require&&require;if(!o&&f)return f(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var l=i[s]={exports:{}};t[s][0].call(l.exports,function(e){var i=t[s][1][e];return a(i?i:e)},l,l.exports,e,t,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s=0&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(t.windowBits>=0&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&0===(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new d,this.strm.avail_out=0;var i=r.inflateInit2(this.strm,t.windowBits);if(i!==f.Z_OK)throw new Error(l[i]);this.header=new h,r.inflateGetHeader(this.strm,this.header)};u.prototype.push=function(e,t){var i,n,a,l,d,h=this.strm,u=this.options.chunkSize;if(this.ended)return!1;n=t===~~t?t:t===!0?f.Z_FINISH:f.Z_NO_FLUSH,h.input="string"==typeof e?o.binstring2buf(e):e,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new s.Buf8(u),h.next_out=0,h.avail_out=u),i=r.inflate(h,f.Z_NO_FLUSH),i!==f.Z_STREAM_END&&i!==f.Z_OK)return this.onEnd(i),this.ended=!0,!1;h.next_out&&(0===h.avail_out||i===f.Z_STREAM_END||0===h.avail_in&&n===f.Z_FINISH)&&("string"===this.options.to?(a=o.utf8border(h.output,h.next_out),l=h.next_out-a,d=o.buf2string(h.output,a),h.next_out=l,h.avail_out=u-l,l&&s.arraySet(h.output,h.output,a,l,0),this.onData(d)):this.onData(s.shrinkBuf(h.output,h.next_out)))}while(h.avail_in>0&&i!==f.Z_STREAM_END);return i===f.Z_STREAM_END&&(n=f.Z_FINISH),n===f.Z_FINISH?(i=r.inflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===f.Z_OK):!0},u.prototype.onData=function(e){this.chunks.push(e)},u.prototype.onEnd=function(e){e===f.Z_OK&&(this.result="string"===this.options.to?this.chunks.join(""):s.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},i.Inflate=u,i.inflate=n,i.inflateRaw=a,i.ungzip=n},{"./utils/common":2,"./utils/strings":3,"./zlib/constants":5,"./zlib/gzheader":7,"./zlib/inflate.js":9,"./zlib/messages":11,"./zlib/zstream":12}],2:[function(e,t,i){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;i.assign=function(e){for(var t=Array.prototype.slice.call(arguments,1);t.length;){var i=t.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])}}return e},i.shrinkBuf=function(e,t){return e.length===t?e:e.subarray?e.subarray(0,t):(e.length=t,e)};var a={arraySet:function(e,t,i,n,a){if(t.subarray&&e.subarray)return void e.set(t.subarray(i,i+n),a);for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){var t,i,n,a,r,s;for(n=0,t=0,i=e.length;i>t;t++)n+=e[t].length;for(s=new Uint8Array(n),a=0,t=0,i=e.length;i>t;t++)r=e[t],s.set(r,a),a+=r.length;return s}},r={arraySet:function(e,t,i,n,a){for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){return[].concat.apply([],e)}};i.setTyped=function(e){e?(i.Buf8=Uint8Array,i.Buf16=Uint16Array,i.Buf32=Int32Array,i.assign(i,a)):(i.Buf8=Array,i.Buf16=Array,i.Buf32=Array,i.assign(i,r))},i.setTyped(n)},{}],3:[function(e,t,i){"use strict";function n(e,t){if(65537>t&&(e.subarray&&s||!e.subarray&&r))return String.fromCharCode.apply(null,a.shrinkBuf(e,t));for(var i="",n=0;t>n;n++)i+=String.fromCharCode(e[n]);return i}var a=e("./common"),r=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(o){r=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(o){s=!1}for(var f=new a.Buf8(256),l=0;256>l;l++)f[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;f[254]=f[254]=1,i.string2buf=function(e){var t,i,n,r,s,o=e.length,f=0;for(r=0;o>r;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),f+=128>i?1:2048>i?2:65536>i?3:4;for(t=new a.Buf8(f),s=0,r=0;f>s;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),128>i?t[s++]=i:2048>i?(t[s++]=192|i>>>6,t[s++]=128|63&i):65536>i?(t[s++]=224|i>>>12,t[s++]=128|i>>>6&63,t[s++]=128|63&i):(t[s++]=240|i>>>18,t[s++]=128|i>>>12&63,t[s++]=128|i>>>6&63,t[s++]=128|63&i);return t},i.buf2binstring=function(e){return n(e,e.length)},i.binstring2buf=function(e){for(var t=new a.Buf8(e.length),i=0,n=t.length;n>i;i++)t[i]=e.charCodeAt(i);return t},i.buf2string=function(e,t){var i,a,r,s,o=t||e.length,l=new Array(2*o);for(a=0,i=0;o>i;)if(r=e[i++],128>r)l[a++]=r;else if(s=f[r],s>4)l[a++]=65533,i+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&o>i;)r=r<<6|63&e[i++],s--;s>1?l[a++]=65533:65536>r?l[a++]=r:(r-=65536,l[a++]=55296|r>>10&1023,l[a++]=56320|1023&r)}return n(l,a)},i.utf8border=function(e,t){var i;for(t=t||e.length,t>e.length&&(t=e.length),i=t-1;i>=0&&128===(192&e[i]);)i--;return 0>i?t:0===i?t:i+f[e[i]]>t?i:t}},{"./common":2}],4:[function(e,t){"use strict";function i(e,t,i,n){for(var a=65535&e|0,r=e>>>16&65535|0,s=0;0!==i;){s=i>2e3?2e3:i,i-=s;do a=a+t[n++]|0,r=r+a|0;while(--s);a%=65521,r%=65521}return a|r<<16|0}t.exports=i},{}],5:[function(e,t){t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],6:[function(e,t){"use strict";function i(){for(var e,t=[],i=0;256>i;i++){e=i;for(var n=0;8>n;n++)e=1&e?3988292384^e>>>1:e>>>1;t[i]=e}return t}function n(e,t,i,n){var r=a,s=n+i;e=-1^e;for(var o=n;s>o;o++)e=e>>>8^r[255&(e^t[o])];return-1^e}var a=i();t.exports=n},{}],7:[function(e,t){"use strict";function i(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}t.exports=i},{}],8:[function(e,t){"use strict";var i=30,n=12;t.exports=function(e,t){var a,r,s,o,f,l,d,h,u,c,b,w,m,k,g,_,v,p,x,y,S,B,E,Z,A;a=e.state,r=e.next_in,Z=e.input,s=r+(e.avail_in-5),o=e.next_out,A=e.output,f=o-(t-e.avail_out),l=o+(e.avail_out-257),d=a.dmax,h=a.wsize,u=a.whave,c=a.wnext,b=a.window,w=a.hold,m=a.bits,k=a.lencode,g=a.distcode,_=(1<m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,0===x)A[o++]=65535&p;else{if(!(16&x)){if(0===(64&x)){p=k[(65535&p)+(w&(1<m&&(w+=Z[r++]<>>=x,m-=x),15>m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,!(16&x)){if(0===(64&x)){p=g[(65535&p)+(w&(1<m&&(w+=Z[r++]<m&&(w+=Z[r++]<d){e.msg="invalid distance too far back",a.mode=i;break e}if(w>>>=x,m-=x,x=o-f,S>x){if(x=S-x,x>u&&a.sane){e.msg="invalid distance too far back",a.mode=i;break e}if(B=0,E=b,0===c){if(B+=h-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}else if(x>c){if(B+=h+c-x,x-=c,y>x){y-=x;do A[o++]=b[B++];while(--x);if(B=0,y>c){x=c,y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}}else if(B+=c-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}for(;y>2;)A[o++]=E[B++],A[o++]=E[B++],A[o++]=E[B++],y-=3;y&&(A[o++]=E[B++],y>1&&(A[o++]=E[B++]))}else{B=o-S;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],y-=3;while(y>2);y&&(A[o++]=A[B++],y>1&&(A[o++]=A[B++]))}break}}break}}while(s>r&&l>o);y=m>>3,r-=y,m-=y<<3,w&=(1<r?5+(s-r):5-(r-s),e.avail_out=l>o?257+(l-o):257-(o-l),a.hold=w,a.bits=m}},{}],9:[function(e,t,i){"use strict";function n(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function a(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new k.Buf16(320),this.work=new k.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=F,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new k.Buf32(bt),t.distcode=t.distdyn=new k.Buf32(wt),t.sane=1,t.back=-1,A):C}function s(e){var t;return e&&e.state?(t=e.state,t.wsize=0,t.whave=0,t.wnext=0,r(e)):C}function o(e,t){var i,n;return e&&e.state?(n=e.state,0>t?(i=0,t=-t):(i=(t>>4)+1,48>t&&(t&=15)),t&&(8>t||t>15)?C:(null!==n.window&&n.wbits!==t&&(n.window=null),n.wrap=i,n.wbits=t,s(e))):C}function f(e,t){var i,n;return e?(n=new a,e.state=n,n.window=null,i=o(e,t),i!==A&&(e.state=null),i):C}function l(e){return f(e,kt)}function d(e){if(gt){var t;for(w=new k.Buf32(512),m=new k.Buf32(32),t=0;144>t;)e.lens[t++]=8;for(;256>t;)e.lens[t++]=9;for(;280>t;)e.lens[t++]=7;for(;288>t;)e.lens[t++]=8;for(p(y,e.lens,0,288,w,0,e.work,{bits:9}),t=0;32>t;)e.lens[t++]=5;p(S,e.lens,0,32,m,0,e.work,{bits:5}),gt=!1}e.lencode=w,e.lenbits=9,e.distcode=m,e.distbits=5}function h(e,t,i,n){var a,r=e.state;return null===r.window&&(r.wsize=1<=r.wsize?(k.arraySet(r.window,t,i-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(a=r.wsize-r.wnext,a>n&&(a=n),k.arraySet(r.window,t,i-n,a,r.wnext),n-=a,n?(k.arraySet(r.window,t,i-n,n,0),r.wnext=n,r.whave=r.wsize):(r.wnext+=a,r.wnext===r.wsize&&(r.wnext=0),r.whavec;){if(0===f)break e;f--,u+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0),u=0,c=0,i.mode=D;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",i.mode=ht;break}if((15&u)!==T){e.msg="unknown compression method",i.mode=ht;break}if(u>>>=4,c-=4,xt=(15&u)+8,0===i.wbits)i.wbits=xt;else if(xt>i.wbits){e.msg="invalid window size",i.mode=ht;break}i.dmax=1<c;){if(0===f)break e;f--,u+=a[s++]<>8&1),512&i.flags&&(Zt[0]=255&u,Zt[1]=u>>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0,i.mode=U;case U:for(;32>c;){if(0===f)break e;f--,u+=a[s++]<>>8&255,Zt[2]=u>>>16&255,Zt[3]=u>>>24&255,i.check=_(i.check,Zt,4,0)),u=0,c=0,i.mode=L;case L:for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>8),512&i.flags&&(Zt[0]=255&u,Zt[1]=u>>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0,i.mode=H;case H:if(1024&i.flags){for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0}else i.head&&(i.head.extra=null);i.mode=M;case M:if(1024&i.flags&&(m=i.length,m>f&&(m=f),m&&(i.head&&(xt=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),k.arraySet(i.head.extra,a,s,m,xt)),512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,i.length-=m),i.length))break e;i.length=0,i.mode=K;case K:if(2048&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.name+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.name=null);i.length=0,i.mode=j;case j:if(4096&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.comment+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.comment=null);i.mode=P;case P:if(512&i.flags){for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>9&1,i.head.done=!0),e.adler=i.check=0,i.mode=G;break;case q:for(;32>c;){if(0===f)break e;f--,u+=a[s++]<>>=7&c,c-=7&c,i.mode=ft;break}for(;3>c;){if(0===f)break e;f--,u+=a[s++]<>>=1,c-=1,3&u){case 0:i.mode=W;break;case 1:if(d(i),i.mode=tt,t===Z){u>>>=2,c-=2;break e}break;case 2:i.mode=V;break;case 3:e.msg="invalid block type",i.mode=ht}u>>>=2,c-=2;break;case W:for(u>>>=7&c,c-=7&c;32>c;){if(0===f)break e;f--,u+=a[s++]<>>16^65535)){e.msg="invalid stored block lengths",i.mode=ht;break}if(i.length=65535&u,u=0,c=0,i.mode=J,t===Z)break e;case J:i.mode=Q;case Q:if(m=i.length){if(m>f&&(m=f),m>l&&(m=l),0===m)break e;k.arraySet(r,a,s,m,o),f-=m,s+=m,l-=m,o+=m,i.length-=m;break}i.mode=G;break;case V:for(;14>c;){if(0===f)break e;f--,u+=a[s++]<>>=5,c-=5,i.ndist=(31&u)+1,u>>>=5,c-=5,i.ncode=(15&u)+4,u>>>=4,c-=4,i.nlen>286||i.ndist>30){e.msg="too many length or distance symbols",i.mode=ht;break}i.have=0,i.mode=$;case $:for(;i.havec;){if(0===f)break e;f--,u+=a[s++]<>>=3,c-=3}for(;i.have<19;)i.lens[At[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,St={bits:i.lenbits},yt=p(x,i.lens,0,19,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid code lengths set",i.mode=ht;break}i.have=0,i.mode=et;case et:for(;i.have>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<gt)u>>>=mt,c-=mt,i.lens[i.have++]=gt;else{if(16===gt){for(Bt=mt+2;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,0===i.have){e.msg="invalid bit length repeat",i.mode=ht;break}xt=i.lens[i.have-1],m=3+(3&u),u>>>=2,c-=2}else if(17===gt){for(Bt=mt+3;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,xt=0,m=3+(7&u),u>>>=3,c-=3}else{for(Bt=mt+7;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,xt=0,m=11+(127&u),u>>>=7,c-=7}if(i.have+m>i.nlen+i.ndist){e.msg="invalid bit length repeat",i.mode=ht;break}for(;m--;)i.lens[i.have++]=xt}}if(i.mode===ht)break;if(0===i.lens[256]){e.msg="invalid code -- missing end-of-block",i.mode=ht;break}if(i.lenbits=9,St={bits:i.lenbits},yt=p(y,i.lens,0,i.nlen,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid literal/lengths set",i.mode=ht;break}if(i.distbits=6,i.distcode=i.distdyn,St={bits:i.distbits},yt=p(S,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,St),i.distbits=St.bits,yt){e.msg="invalid distances set",i.mode=ht;break}if(i.mode=tt,t===Z)break e;case tt:i.mode=it;case it:if(f>=6&&l>=258){e.next_out=o,e.avail_out=l,e.next_in=s,e.avail_in=f,i.hold=u,i.bits=c,v(e,w),o=e.next_out,r=e.output,l=e.avail_out,s=e.next_in,a=e.input,f=e.avail_in,u=i.hold,c=i.bits,i.mode===G&&(i.back=-1);break}for(i.back=0;Et=i.lencode[u&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,u+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(u>>>=mt,c-=mt,i.back+=mt,i.length=gt,0===kt){i.mode=ot;break}if(32&kt){i.back=-1,i.mode=G;break}if(64&kt){e.msg="invalid literal/length code",i.mode=ht;break}i.extra=15&kt,i.mode=nt;case nt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=at;case at:for(;Et=i.distcode[u&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,u+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(u>>>=mt,c-=mt,i.back+=mt,64&kt){e.msg="invalid distance code",i.mode=ht;break}i.offset=gt,i.extra=15&kt,i.mode=rt;case rt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){e.msg="invalid distance too far back",i.mode=ht;break}i.mode=st;case st:if(0===l)break e;if(m=w-l,i.offset>m){if(m=i.offset-m,m>i.whave&&i.sane){e.msg="invalid distance too far back",i.mode=ht;break}m>i.wnext?(m-=i.wnext,bt=i.wsize-m):bt=i.wnext-m,m>i.length&&(m=i.length),wt=i.window}else wt=r,bt=o-i.offset,m=i.length;m>l&&(m=l),l-=m,i.length-=m;do r[o++]=wt[bt++];while(--m);0===i.length&&(i.mode=it);break;case ot:if(0===l)break e;r[o++]=i.length,l--,i.mode=it;break;case ft:if(i.wrap){for(;32>c;){if(0===f)break e;f--,u|=a[s++]<c;){if(0===f)break e;f--,u+=a[s++]<=z;z++)M[z]=0;for(R=0;b>R;R++)M[t[c+R]]++;for(I=A,N=n;N>=1&&0===M[N];N--);if(I>N&&(I=N),0===N)return w[m++]=20971520,w[m++]=20971520,g.bits=1,0;for(C=1;N>C&&0===M[C];C++);for(C>I&&(I=C),F=1,z=1;n>=z;z++)if(F<<=1,F-=M[z],0>F)return-1;if(F>0&&(e===s||1!==N))return-1;for(K[1]=0,z=1;n>z;z++)K[z+1]=K[z]+M[z];for(R=0;b>R;R++)0!==t[c+R]&&(k[K[t[c+R]]++]=R);if(e===s?(L=j=k,S=19):e===o?(L=l,H-=257,j=d,P-=257,S=256):(L=h,j=u,S=-1),U=0,R=0,z=C,y=m,O=I,T=0,p=-1,D=1<a||e===f&&D>r)return 1;for(var q=0;;){q++,B=z-T,k[R]S?(E=j[P+k[R]],Z=L[H+k[R]]):(E=96,Z=0),_=1<>T)+v]=B<<24|E<<16|Z|0;while(0!==v);for(_=1<>=1;if(0!==_?(U&=_-1,U+=_):U=0,R++,0===--M[z]){if(z===N)break;z=t[c+k[R]]}if(z>I&&(U&x)!==p){for(0===T&&(T=I),y+=C,O=z-T,F=1<O+T&&(F-=M[O+T],!(0>=F));)O++,F<<=1;if(D+=1<a||e===f&&D>r)return 1;p=U&x,w[p]=I<<24|O<<16|y-m|0}}return 0!==U&&(w[y+U]=z-T<<24|64<<16|0),g.bits=I,0}},{"../utils/common":2}],11:[function(e,t){"use strict";t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],12:[function(e,t){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}t.exports=i},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/src/fonteditor/ttf/main.js b/src/fonteditor/ttf/main.js index 8a7a329..bc0d7d7 100644 --- a/src/fonteditor/ttf/main.js +++ b/src/fonteditor/ttf/main.js @@ -11,18 +11,22 @@ define( var program = require('../program'); var TTFReader = require('ttf/ttfreader'); - var contours2svg = require('ttf/util/contours2svg'); + var glyf2svg = require('ttf/util/glyf2svg'); var svg2ttfobject = require('ttf/svg2ttfobject'); var string = require('common/string'); var pathAdjust = require('graphics/pathAdjust'); var TTFWriter = require('ttf/ttfwriter'); var ttf2woff = require('ttf/ttf2woff'); + var woff2ttf = require('ttf/woff2ttf'); var ttf2base64 = require('ttf/ttf2base64'); var woff2base64 = require('ttf/woff2base64'); + var woffOptions = { + inflate: require('inflate').inflate + }; var GLYF_ITEM_TPL = '' - + '
' + + '
' + '' + '
${unicode}
${name}
' + '
'; @@ -35,7 +39,7 @@ define( $('#font-import').click(); }, export: function() { - $(this).attr('href', '#'); + //$(this).attr('href', '#'); } }; @@ -43,18 +47,23 @@ define( function showGLYF(ttf) { var unitsPerEm = ttf.head.unitsPerEm; var descent = unitsPerEm + ttf.hhea.descent; - var glyfStr = ''; - ttf.glyf.forEach(function(glyf) { + var glyfStr = '', d = ''; + ttf.glyf.forEach(function(glyf, index) { var g = { + index: index, modify: glyf.modify, unitsPerEm: unitsPerEm, descent: descent, unicode: (glyf.unicode || []).map(function(u) { return '$' + u.toString(16).toUpperCase(); }).join(','), - name: glyf.name, - d: glyf.contours && glyf.contours.length ? 'd="'+ contours2svg(glyf.contours) +'"': '' + name: glyf.name }; + + if (d = glyf2svg(glyf, ttf)) { + g.d = 'd="'+ d +'"'; + } + glyfStr += string.format(GLYF_ITEM_TPL, g); }); @@ -62,11 +71,16 @@ define( } // 加载ttf - function loadTTF(file) { + function loadSFNT(file, type) { program.loading.show(); var fileReader = new FileReader(); fileReader.onload = function(e) { var buffer = e.target.result; + + if (type == 'woff') { + buffer = woff2ttf(buffer, woffOptions); + } + var ttfReader = new TTFReader(); program.data.ttf = ttfReader.read(buffer); showGLYF(program.data.ttf); @@ -127,9 +141,9 @@ define( function onUpFile(e) { var file = e.target.files[0]; - if (program.action == 'open' && file.name.match(/\.ttf$/)) { + if (program.action == 'open' && file.name.match(/(\.ttf|\.woff)$/)) { program.data.file = file.name; - loadTTF(file); + loadSFNT(file, file.name.slice(file.name.lastIndexOf('.') + 1)); } else if (program.action == 'svg' && file.name.match(/\.svg$/)) { if (program.data.ttf) { @@ -149,8 +163,9 @@ define( var ttf = program.data.ttf; if (ttf) { var buffer = new TTFWriter().write(ttf); - e.target.download = (ttf.name.fontFamily || 'export') + '.ttf'; - e.target.href = ttf2base64(buffer); + var target = $(e.target); + target.attr('download', (ttf.name.fontFamily || 'export') + '.ttf'); + target.attr('href', ttf2base64(buffer)); } } diff --git a/src/ttf/svg2ttfobject.js b/src/ttf/svg2ttfobject.js index fd4ad18..be2fa4a 100644 --- a/src/ttf/svg2ttfobject.js +++ b/src/ttf/svg2ttfobject.js @@ -76,7 +76,7 @@ define( ttf.head.xMax = Math.round(ttf.head.xMax); ttf.head.yMin = Math.round(ttf.head.yMin); ttf.head.yMax = Math.round(ttf.head.yMax); - ttf.head.unitsPerEm = Math.round(ttf.head.unitsPerEm || 1024); + ttf.head.unitsPerEm = ttf.head.unitsPerEm ? Math.round(ttf.head.unitsPerEm) : 0; return ttf; } @@ -148,6 +148,14 @@ define( } } + // 如果没有定义unitsPerEm,可以用viewBox代替 + if (!ttf.head.unitsPerEm && svgNode.getAttribute('viewBox')) { + var bound = svgNode.getAttribute('viewBox').split(' '); + if (bound.length == 4) { + ttf.head.unitsPerEm = +bound[2]; + } + } + // 解析glyf var d, unicode; if (missingNode) { diff --git a/src/ttf/ttf2woff.js b/src/ttf/ttf2woff.js index e7ea048..2cdc775 100644 --- a/src/ttf/ttf2woff.js +++ b/src/ttf/ttf2woff.js @@ -19,7 +19,6 @@ define( function(require) { var Reader = require('./reader'); var Writer = require('./writer'); - var checkSum = require('./util/checkSum'); var string = require('common/string'); /** @@ -134,6 +133,7 @@ define( * @param {ArrayBuffer} ttfBuffer ttf缓冲数组 * @param {Object} options 选项 * @param {Object} options.metadata 字体相关的信息 + * @param {Object} options.deflate 压缩相关函数 * * @return {ArrayBuffer} woff格式byte流 */ diff --git a/src/ttf/util/glyf2svg.js b/src/ttf/util/glyf2svg.js index 38c6690..aacf7fd 100644 --- a/src/ttf/util/glyf2svg.js +++ b/src/ttf/util/glyf2svg.js @@ -14,8 +14,10 @@ define( function(require) { var contour2svg = require('./contour2svg'); + var contours2svg = require('./contours2svg'); var pathAdjust = require('graphics/pathAdjust'); var matrixTransform = require('graphics/transform'); + var lang = require('common/lang'); /** * glyf转换svg @@ -23,29 +25,25 @@ define( * @param {Object} glyf 解析后的glyf结构 * @return {string} svg文本 */ - function glyf2svg(glyf, options) { - if(!glyf) { - return null; - } - var pathArray = []; - var contours = glyf.contours; - var height = glyf.yMax; - var x = options.x || 0; - var y = height + (options.y || 0); - var scale = options.scale || 1; + function glyf2svg(glyf, ttf) { + if(!glyf) { + return ''; + } + + var pathArray = []; if (!glyf.compound) { - for ( var i = 0, l = contours.length; i < l; i++) { - pathAdjust(contours[i], 1, -1); - pathAdjust(contours[i], scale, scale, x, y); - pathArray.push(contour2svg(contours[i])); + if (glyf.contours && glyf.contours.length) { + pathArray.push(contours2svg(glyf.contours)); } + } else { var glyfs = glyf.glyfs; glyfs.forEach(function(g) { - var contours = g.glyf.contours; + var compound = ttf.glyf[g.glyphIndex]; + var contours = lang.clone(compound.contours); // 这里需要进行matrix变换,需要复制一份 var transform = g.transform; for ( var i = 0, l = contours.length; i < l; i++) { matrixTransform(contours[i], @@ -56,8 +54,6 @@ define( transform.e, transform.f ); - pathAdjust(contours[i], 1, -1); - pathAdjust(contours[i], scale, scale, x, y); pathArray.push(contour2svg(contours[i])); } }); diff --git a/src/ttf/util/svg2contours.js b/src/ttf/util/svg2contours.js index 5fdd8f7..844a5dc 100644 --- a/src/ttf/util/svg2contours.js +++ b/src/ttf/util/svg2contours.js @@ -71,9 +71,10 @@ define( // 获取segments var segments = []; - var cmd, lastIndex, args, segReg = /\-?\d+(?:\.\d+)?\b/g; + var cmd, relative = false, c, r, lastIndex, args, segReg = /\-?\d+(?:\.\d+)?\b/g; for (var i = 0, l = path.length;i < l; i++) { - var c = path.charAt(i).toUpperCase(); + c = path[i].toUpperCase(); + r = c != path[i]; switch (c) { case 'M': if (i == 0) { @@ -97,6 +98,7 @@ define( args = path.slice(lastIndex, i); segments.push({ cmd: cmd, + relative: relative, args: args.match(segReg).map(function(d) { return +d.trim(); }) @@ -104,6 +106,7 @@ define( } cmd = c; + relative = r; lastIndex = i + 1; break; } @@ -115,39 +118,86 @@ define( var contours = [], contour = [], prevX = 0, prevY = 0, prevc1; for (var i = 0, l = segments.length;i < l; i++) { segment = segments[i]; + cmd = segment.cmd; + relative = segment.relative; - if (segment.cmd === 'Z') { + if (cmd === 'Z') { contours.push(contour); contour = []; } - else if (segment.cmd === 'M') { - prevX = segment.args[0]; - prevY = segment.args[1]; + else if (cmd === 'M') { + if (relative) { + prevX += segment.args[0]; + prevY += segment.args[1]; + } + else { + prevX = segment.args[0]; + prevY = segment.args[1]; + } + contour.push({ x: prevX, y: prevY, onCurve: true }); } - else if (segment.cmd === 'H') { - prevX += segment.args[0]; + else if (cmd === 'H') { + + if (relative) { + prevX += segment.args[0]; + } + else { + prevX = segment.args[0]; + } + contour.push({ x: prevX, y: prevY, onCurve: true }); } - else if (segment.cmd === 'V') { - prevY += segment.args[0]; + else if (cmd === 'V') { + + if (relative) { + prevY += segment.args[0]; + } + else { + prevY = segment.args[0]; + } + contour.push({ x: prevX, y: prevY, onCurve: true }); } - else if (segment.cmd === 'L') { - prevX += segment.args[0]; - prevY += segment.args[1]; + else if (cmd === 'L') { + + // 这里可能会连续绘制,最后一个是终点 + var q = 0, ql = segment.args.length - 2, px = 0, py = 0; + + if (relative) { + px = prevX; + py = prevY; + } + + for (; q < ql ; q += 2) { + contour.push({ + x: px + segment.args[q], + y: py + segment.args[q + 1], + onCurve: true + }); + } + + if (relative) { + prevX += segment.args[ql]; + prevY += segment.args[ql + 1]; + } + else { + prevX = segment.args[ql]; + prevY = segment.args[ql + 1]; + } + contour.push({ x: prevX, y: prevY, @@ -155,40 +205,78 @@ define( }); } // 二次贝塞尔 - else if (segment.cmd === 'Q') { + else if (cmd === 'Q') { // 这里可能会连续绘制,最后一个是终点 - var q = 0, ql = segment.args.length - 2; - for (; q < ql ; q += 2) { + var q = 0, ql = segment.args.length, px = 0, py = 0; + + if (relative) { + px = prevX; + py = prevY; + } + + for (; q < ql ; q += 4) { contour.push({ - x: prevX + segment.args[q], - y: prevY + segment.args[q + 1] + x: px + segment.args[q], + y: py + segment.args[q + 1] + }); + contour.push({ + x: px + segment.args[q + 2], + y: py + segment.args[q + 3], + onCurve: true }); } - prevX += segment.args[ql]; - prevY += segment.args[ql + 1]; - - contour.push({ - x: prevX, - y: prevY, - onCurve: true - }); + ql = segment.args.length - 2; + if (relative) { + prevX += segment.args[ql]; + prevY += segment.args[ql + 1]; + } + else { + prevX = segment.args[ql]; + prevY = segment.args[ql + 1]; + } } // 二次贝塞尔平滑 - else if (segment.cmd === 'T') { + else if (cmd === 'T') { - var pc = contour[contour.length - 2]; - // 这里需要移除上一个曲线的终点 - contour.pop(); + var last = contour.pop(); + + var pc = contour[contour.length - 1]; contour.push({ - x: 2 * prevX - pc.x, - y: 2 * prevY - pc.y + x: 2 * last.x - pc.x, + y: 2 * last.y - pc.y }); - prevX += segment.args[0]; - prevY += segment.args[1]; + var q = 0, ql = segment.args.length - 2, px = 0, py = 0; + + if (relative) { + px = prevX; + py = prevY; + } + + for (; q < ql ; q += 2) { + pc = contour[contour.length - 1]; + last = { + x: px + segment.args[q], + y: py + segment.args[q + 1] + }; + contour.push({ + x: 2 * last.x - pc.x, + y: 2 * last.y - pc.y + }); + } + + if (relative) { + prevX += segment.args[ql]; + prevY += segment.args[ql + 1]; + } + else { + prevX = segment.args[ql]; + prevY = segment.args[ql + 1]; + } + contour.push({ x: prevX, y: prevY, @@ -197,21 +285,26 @@ define( } // 三次贝塞尔 - else if (segment.cmd === 'C') { + else if (cmd === 'C') { // 这里可能会连续绘制,最后一个是终点 - var q = 0, ql = segment.args.length - 2; + var q = 0, ql = segment.args.length - 2, px = 0, py = 0; var cubicList = []; + if (relative) { + px = prevX; + py = prevY; + } + for (; q < ql ; q += 4) { var cubic = []; var c1 = { - x: prevX + segment.args[q], - y: prevY + segment.args[q + 1] + x: px + segment.args[q], + y: py + segment.args[q + 1] }; var c2 = { - x: prevX + segment.args[q + 2], - y: prevY + segment.args[q + 3] + x: px + segment.args[q + 2], + y: py + segment.args[q + 3] }; // 计算中间点 @@ -236,29 +329,53 @@ define( cubicList.push(cubic); } - prevX += segment.args[ql]; - prevY += segment.args[ql + 1]; + if (relative) { + prevX += segment.args[ql]; + prevY += segment.args[ql + 1]; + } + else { + prevX = segment.args[ql]; + prevY = segment.args[ql + 1]; + } cubicList[cubicList.length - 1].push({x: prevX, y: prevY}); cubic2Points(cubicList, contour); prevc1 = cubicList[cubicList.length - 1][2]; } // 三次贝塞尔平滑 - else if (segment.cmd === 'S') { + else if (cmd === 'S') { + // TODO 这里没有支持连续的情况,有时间再搞 + if (segment.args.length > 4) { + throw 'not support svg "S" command continuous!' + } + // 这里需要移除上一个曲线的终点 var p1 = contour.pop(); var c1 = { x: 2 * p1.x - prevc1.x, y: 2 * p1.y - prevc1.y }; + + var px = 0, py = 0; + + if (relative) { + px = prevX; + py = prevY; + } var c2 = { - x: prevX + segment.args[0], - y: prevX + segment.args[1] + x: px + segment.args[0], + y: py + segment.args[1] }; - prevX += segment.args[2]; - prevY += segment.args[3]; + if (relative) { + prevX += segment.args[2]; + prevY += segment.args[3]; + } + else { + prevX = segment.args[2]; + prevY = segment.args[3]; + } var p2 = { x: prevX, @@ -269,7 +386,7 @@ define( prevc1 = c2; } // 圆弧 - else if (segment.cmd === 'A') { + else if (cmd === 'A') { throw 'not support arc'; } } diff --git a/src/ttf/woff2ttf.js b/src/ttf/woff2ttf.js new file mode 100644 index 0000000..ab43d72 --- /dev/null +++ b/src/ttf/woff2ttf.js @@ -0,0 +1,122 @@ +/** + * @file woff2ttf.js + * @author mengke01 + * @date + * @description + * woff转换ttf + */ + + +define( + function(require) { + + var Reader = require('./reader'); + var Writer = require('./writer'); + + /** + * 写空数据 + * + * @param {Writer} writer writer对象 + * @param {number} length 大小 + * @return {Writer} + */ + function writeEmpty(writer, length) { + while (length-- > 0) { + writer.writeUint8(0); + } + return writer; + } + + /** + * woff格式转换成ttf字体格式 + * + * @param {ArrayBuffer} woffBuffer ttf缓冲数组 + * @param {Object} options 选项 + * @param {Object} options.inflate 解压相关函数 + * + * @return {ArrayBuffer} woff格式byte流 + */ + function woff2ttf(woffBuffer, options) { + options = options || {}; + + var reader = new Reader(woffBuffer); + var signature = reader.readUint32(0); + var flavor = reader.readUint32(4); + + if (signature !== 0x774F4646 || flavor !== 0x10000) { + reader.dispose(); + throw 'not a ttf sfnt format!'; + } + + var numTables = reader.readUint16(12); + var ttfSize = reader.readUint32(16); + var tableEntries = []; + + // 读取woff表索引信息 + for (var i = 0; i < numTables; ++i) { + reader.seek(44 + i * 20); + var tableEntry = { + tag: reader.readString(reader.offset, 4), + offset: reader.readUint32(), + compLength: reader.readUint32(), + length: reader.readUint32(), + checkSum: reader.readUint32() + }; + + // ttf 表数据 + var deflateData = reader.readBytes(tableEntry.offset, tableEntry.compLength); + // 需要解压 + if (deflateData.length < tableEntry.length) { + if (!options.inflate) { + reader.dispose(); + throw 'no inflate function!'; + } + tableEntry.data = options.inflate(deflateData); + } + else { + tableEntry.data = deflateData; + } + tableEntry.length = tableEntry.data.length; + + tableEntries.push(tableEntry); + } + + + var writer = new Writer(new ArrayBuffer(ttfSize)); + // 写头部 + var entrySelector = Math.floor(Math.log(numTables)/Math.LN2); + var searchRange = Math.pow(2, entrySelector) * 16; + var rangeShift = numTables * 16 - searchRange; + writer.writeFixed(1); + writer.writeUint16(numTables); + writer.writeUint16(searchRange); + writer.writeUint16(entrySelector); + writer.writeUint16(rangeShift); + + // 写ttf表索引 + var tblOffset = 12 + 16 * tableEntries.length; + for (var i = 0, l = tableEntries.length; i < l; ++i) { + var tableEntry = tableEntries[i]; + writer.writeString(tableEntry.tag); + writer.writeUint32(tableEntry.checkSum); + writer.writeUint32(tblOffset); + writer.writeUint32(tableEntry.length); + tblOffset += tableEntry.length + (tableEntry.length % 4 ? 4 - tableEntry.length % 4 : 0) + } + + // 写ttf表数据 + for (var i = 0, l = tableEntries.length; i < l; ++i) { + var tableEntry = tableEntries[i]; + writer.writeBytes(tableEntry.data); + if (tableEntry.length % 4) { + writeEmpty(writer, 4 - tableEntry.length % 4); + } + } + + return writer.getBuffer(); + } + + + return woff2ttf; + } +); diff --git a/ttf.html b/ttf.html index 80942d3..aae9d79 100644 --- a/ttf.html +++ b/ttf.html @@ -36,7 +36,11 @@