favium
Version:
Favium generates favicon assets from canvas in the browser and from image files in the terminal.
1 lines • 7.09 kB
JavaScript
;var e=Object.defineProperty,t=(t,n,a)=>((t,n,a)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[n]=a)(t,n+"",a),n=class{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}resize(e,t){if(!Number.isInteger(e)||!Number.isInteger(t))throw new RangeError("Width and height must be integers");if(e<=0||t<=0)throw new RangeError("Width and height must be positive");for(;this.canvas.width/2>=e&&this.canvas.height/2>=t;)this._resize(Math.max(e,Math.floor(this.canvas.width/2)),Math.max(t,Math.floor(this.canvas.height/2)));return this.canvas.width===e&&this.canvas.height===t||this._resize(e,t),this.canvas}_resize(e,t){const n=document.createElement("canvas"),a=n.getContext("2d");if(!a)throw new Error("Failed to get 2D context");n.width=e,n.height=t,a.drawImage(this.canvas,0,0,e,t),this.canvas=n}},a=class{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}generate(e=[16,32,48]){if(0===e.length)throw new RangeError("At least one size must be provided");if(!e.every(e=>Number.isInteger(e)&&e>0&&e<=256))throw new RangeError("Sizes must be positive integers between 1 and 256");const t=this.createIconDirHeader(e.length);let a="",r="";for(let t=0;t<e.length;t++){const i=e[t],s=new n(this.canvas).resize(i,i),o=i>=256?this.createPngImageData(s):this.createBitmapInfoHeader(i)+this.createBitmapImageData(s),h=o.length,c=6+16*e.length+r.length;a+=this.createIconDirEntry(i,h,c),r+=o}return`data:image/x-icon;base64,${btoa(t+a+r)}`}createIconDirHeader(e){const t=new ArrayBuffer(6),n=new DataView(t);return n.setUint16(0,0,!0),n.setUint16(2,1,!0),n.setUint16(4,e,!0),this.bytesToBinary(new Uint8Array(t))}createIconDirEntry(e,t,n){const a=new ArrayBuffer(16),r=new DataView(a);return r.setUint8(0,256===e?0:e),r.setUint8(1,256===e?0:e),r.setUint8(2,0),r.setUint8(3,0),r.setUint16(4,1,!0),r.setUint16(6,32,!0),r.setUint32(8,t,!0),r.setUint32(12,n,!0),this.bytesToBinary(new Uint8Array(a))}createBitmapInfoHeader(e){const t=new ArrayBuffer(40),n=new DataView(t);return n.setUint32(0,40,!0),n.setInt32(4,e,!0),n.setInt32(8,2*e,!0),n.setUint16(12,1,!0),n.setUint16(14,32,!0),n.setUint32(16,0,!0),n.setUint32(20,0,!0),this.bytesToBinary(new Uint8Array(t))}createBitmapImageData(e){const t=e.getContext("2d");if(!t)throw new Error("Failed to get 2D context");const{width:n,height:a}=e,r=t.getImageData(0,0,n,a).data,i=new Uint8ClampedArray(r.length);for(let e=0;e<a;e++)for(let t=0;t<n;t++){const s=4*(e*n+t),o=4*((a-1-e)*n+t);i[o]=r[s+2],i[o+1]=r[s+1],i[o+2]=r[s],i[o+3]=r[s+3]}const s=4*Math.ceil(n/32),o=new Uint8Array(s*a).fill(0);return this.bytesToBinary(i)+this.bytesToBinary(o)}createPngImageData(e){const t=e.toDataURL("image/png").split(",")[1];if(!t)throw new Error("Failed to serialize PNG data");return atob(t)}bytesToBinary(e){let t="";for(let n=0;n<e.length;n+=32768){const a=Array.prototype.slice.call(e,n,n+32768);t+=String.fromCharCode(...a)}return t}},r=class{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}generate(e){if(!Number.isInteger(e)||e<=0)throw new RangeError("Size must be a positive integer");return new n(this.canvas).resize(e,e).toDataURL()}},i=[16,32,48],s=[16,32,150,180,192,512],o={16:"png16",32:"png32",150:"png150",180:"png180",192:"png192",512:"png512"},h=class{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}generate(e={}){var t,n;const h=new a(this.canvas),c=new r(this.canvas),l=null!=(t=e.icoSizes)?t:i,g=null!=(n=e.pngSizes)?n:s,w={ico:h.generate(l),pngs:{}};for(const e of g){const t=c.generate(e);w.pngs[e]=t;const n=o[e];n&&(w[n]=t)}return w}},c=class e{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}generate(e={}){const t=this.canvas.getContext("2d");if(!t)throw new Error("Failed to get 2D context");const n={width:128,height:128,text:"F",fontColor:"white",fontFamily:"Helvetica",fontSize:64,fontWeight:"400",fontStyle:"normal",cornerRadius:0,backgroundColor:"black",pixelRatio:this.getDefaultPixelRatio()},{width:a,height:r,text:i,fontColor:s,fontFamily:o,fontSize:h,fontWeight:c,fontStyle:l,cornerRadius:g,backgroundColor:w,pixelRatio:f}={...n,...e};if("number"!=typeof a||a<=0)throw new Error("Width must be a positive number");if("number"!=typeof r||r<=0)throw new Error("Height must be a positive number");if("number"!=typeof h||h<=0)throw new Error("Font size must be a positive number");if("number"!=typeof g||g<0)throw new Error("Corner radius must be a non-negative number");if("number"!=typeof f||!Number.isFinite(f)||f<=0)throw new Error("Pixel ratio must be a positive number");if(this.canvas.width=Math.round(a*f),this.canvas.height=Math.round(r*f),this.canvas.style.width=`${a}px`,this.canvas.style.height=`${r}px`,t.setTransform(f,0,0,f,0,0),this.drawBackground(t,a,r,g,w),i){const e=`${l} ${c} ${h}px ${o}`;t.fillStyle=s,t.font=e,t.textBaseline="alphabetic",t.textAlign="center";const n=this.measureOffsets(t,i,h);t.fillText(i,a/2+n.horizontal,r/2+n.vertical)}return this.canvas}drawBackground(e,t,n,a,r){e.fillStyle=r;const i=Math.min(t,n)/2,s=Math.min(a,i);0===s?e.fillRect(0,0,t,n):(e.beginPath(),e.moveTo(s,0),e.arcTo(t,0,t,n,s),e.arcTo(t,n,0,n,s),e.arcTo(0,n,0,0,s),e.arcTo(0,0,t,0,s),e.closePath(),e.fill())}measureOffsets(e,t,n){const a=document.createElement("canvas"),r=a.getContext("2d");if(!r)throw new Error("Failed to get 2D context");a.width=2*e.measureText(t).width||1,a.height=2*n,r.font=e.font,r.textBaseline="alphabetic",r.textAlign="center",r.fillStyle="white",r.fillText(t,a.width/2,a.height/2);const i=r.getImageData(0,0,a.width,a.height).data;let s,o,h,c;for(let e=0;e<a.height;e++)for(let t=0;t<a.width;t++)if(255===i[4*(e*a.width+t)]){s=void 0===s?e:s,o=e;break}for(let e=0;e<a.width;e++)for(let t=0;t<a.height;t++)if(255===i[4*(t*a.width+e)]){h=void 0===h?e:h,c=e;break}const l=a.height/2,g=a.width/2;return{vertical:l-(void 0!==s&&void 0!==o?s+(o-s)/2:l),horizontal:g-(void 0!==h&&void 0!==c?h+(c-h)/2:g)}}static generate(t={}){const n=document.createElement("canvas");return new e(n).generate(t)}getDefaultPixelRatio(){return"number"==typeof globalThis.devicePixelRatio&&Number.isFinite(globalThis.devicePixelRatio)&&globalThis.devicePixelRatio>0?globalThis.devicePixelRatio:1}},l=class{constructor(e){if(t(this,"canvas"),!(e instanceof HTMLCanvasElement))throw new TypeError("Parameter must be an HTMLCanvasElement");this.canvas=e}bundle(e){return new h(this.canvas).generate(null!=e?e:{})}ico(e=[16,32,48]){return new a(this.canvas).generate(e)}png(e){return new r(this.canvas).generate(e)}resize(e){return new n(this.canvas).resize(e,e)}};exports.CanvasResize=n,exports.FaviconComposer=l,exports.IcoGenerator=a,exports.ImageBundleGenerator=h,exports.PngGenerator=r,exports.TextIconGenerator=c;