@inottn/miniposter
Advanced tools
Comparing version 0.0.1 to 0.0.2
@@ -1,1 +0,1 @@ | ||
"use strict";var m=require("@inottn/fp-utils");const v=function(h,e){let t=0,i=h.length;for(;t<i;){const o=t+(i-t>>1);e(o)?i=o:t=o+1}return i-1};var b=Object.defineProperty,u=Object.getOwnPropertySymbols,F=Object.prototype.hasOwnProperty,P=Object.prototype.propertyIsEnumerable,g=(h,e,t)=>e in h?b(h,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):h[e]=t,y=(h,e)=>{for(var t in e||(e={}))F.call(e,t)&&g(h,t,e[t]);if(u)for(var t of u(e))P.call(e,t)&&g(h,t,e[t]);return h},c=(h,e,t)=>(g(h,typeof e!="symbol"?e+"":e,t),t);class I{constructor(e,t){c(this,"canvas"),c(this,"context"),c(this,"options"),c(this,"images",new Map),c(this,"fonts",new Map),this.canvas=e,this.context=e.getContext("2d"),this.options=t}async render(e){const{canvas:t,options:i}=this,{width:o,height:n,pixelRatio:r=1}=y(y({},i),e),{children:s}=e;if(!o||!n)throw Error("\u7F3A\u5C11 width \u6216 height \u53C2\u6570");if(t.width=o*r,t.height=n*r,m.isNonEmptyArray(s)){this.loadAssets(s);for(const a of s)a.type==="image"&&await this.renderImage(a),a.type==="text"&&await this.renderText(a)}}async renderImage(e){const{context:t}=this,{width:i,height:o,left:n=0,top:r,src:s,backgroundColor:a}=e,[l,f]=this.images.get(s);await f,a&&(t.fillStyle=a,t.fillRect(n,r,i,o)),t.drawImage(l,n,r,i,o)}async renderText(e){const{context:t}=this,{left:i,top:o,color:n="#333",fontFamily:r,fontSize:s=16,lineHeight:a=s*1.43,fontSrc:l,textDecoration:f}=e;l&&await this.fonts.get(l),t.textBaseline="top",t.fillStyle=n,t.font=`${s}px ${r}`,this.getAllLines(e).forEach((p,w)=>{const d=o+(a-s)/2+a*w;if(t.fillText(p,i,d),f==="line-through"){const{width:x}=t.measureText(p);t.fillRect(i,d+s*.46,x,s/14)}})}getAllLines(e){const{context:t}=this,{content:i,width:o,lineClamp:n=1/0}=e,r=[];let s=0;for(;s<i.length&&r.length<n;){const a=s;s=v(i,l=>t.measureText(i.slice(s,l+1)).width>o)+1,s===a&&(s=a+1),n===r.length+1?r.push(i.slice(a,s-1)+"..."):r.push(i.slice(a,s))}return r}loadAssets(e){e.forEach(t=>{const{type:i}=t;i==="image"&&this.loadImage(t),i==="text"&&t.fontFamily&&this.loadFont(t)})}loadImage(e){const{src:t}=e;if(!this.images.has(t)){const i=this.canvas.createImage();i.src=t,this.images.set(t,[i,new Promise((o,n)=>{i.onload=o,i.onerror=n})])}}loadFont(e){const{fontFamily:t,fontSrc:i}=e;this.fonts.has(i)||this.fonts.set(i,new Promise((o,n)=>{my.loadFontFace({family:t,source:`url('${i}')`,success:o,fail:n})}))}export(e){const{canvas:t}=this,{width:i,height:o}=this.options,{promise:n,resolve:r,reject:s}=m.withResolvers();return t.toTempFilePath({x:0,y:0,width:i,height:o,destWidth:e.width,destHeight:e.height,success:r,fail:s}),n}}exports.MiniPoster=I; | ||
"use strict";var m=require("@inottn/fp-utils");const b=function(a,i){let t=0,s=a.length;for(;t<s;){const n=t+(s-t>>1);i(n)?s=n:t=n+1}return s-1};var P=Object.defineProperty,w=Object.getOwnPropertySymbols,T=Object.prototype.hasOwnProperty,R=Object.prototype.propertyIsEnumerable,u=(a,i,t)=>i in a?P(a,i,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[i]=t,x=(a,i)=>{for(var t in i||(i={}))T.call(i,t)&&u(a,t,i[t]);if(w)for(var t of w(i))R.call(i,t)&&u(a,t,i[t]);return a},g=(a,i,t)=>(u(a,typeof i!="symbol"?i+"":i,t),t);class C{constructor(i,t){g(this,"canvas"),g(this,"context"),g(this,"options"),g(this,"images",new Map),g(this,"fonts",new Map),this.canvas=i,this.context=i.getContext("2d"),this.options=t}toPx(i){const{pixelRatio:t=1}=this.options;return typeof i=="number"?i*t:i.map(this.toPx.bind(this))}async render(i){const{canvas:t,context:s,options:n}=this,{width:e,height:r,pixelRatio:o=1,backgroundColor:h,borderRadius:l,overflow:c}=x(x({},n),i),{children:d}=i;if(!e||!r)throw Error("\u7F3A\u5C11 width \u6216 height \u53C2\u6570");if(t.width=e*o,t.height=r*o,s.save(),l&&(this.drawRoundRect(0,0,t.width,t.height,l),s.clip()),h&&(s.fillStyle=h,s.fillRect(0,0,t.width,t.height)),c!=="hidden"&&s.restore(),m.isNonEmptyArray(d)){this.loadAssets(d);for(const f of d)f.type==="image"&&await this.renderImage(f),f.type==="text"&&await this.renderText(f)}c==="hidden"&&s.restore()}async renderImage(i){const{context:t}=this,[s,n,e,r]=this.toPx([i.left,i.top,i.width,i.height]),{src:o,backgroundColor:h,borderRadius:l}=i,[c,d]=this.images.get(o);await d,t.save(),l&&(this.drawRoundRect(s,n,e,r,this.toPx(l)),t.clip()),h&&(t.fillStyle=h,t.fillRect(s,n,e,r)),t.drawImage(c,s,n,e,r),t.restore()}async renderText(i){const{context:t}=this,[s,n,e]=this.toPx([i.left,i.top,i.fontSize||16]),r=i.lineHeight?this.toPx(i.lineHeight):e*1.43,{color:o="#333",fontFamily:h,fontWeight:l=400,fontSrc:c,textDecoration:d}=i;c&&await this.fonts.get(c),t.textBaseline="top",t.fillStyle=o,t.font=`${l} ${e}px ${h}`,(i.width?this.getAllLines(i):[i.content]).forEach((f,y)=>{const p=n+(r-e)/2+r*y;if(t.fillText(f,s,p),d==="line-through"){const{width:v}=t.measureText(f);t.fillRect(s,p+e*.46,v,e/14)}})}getAllLines(i){const{context:t}=this,s=this.toPx(i.width),{content:n,lineClamp:e=1/0}=i,r=[];let o=0;for(;o<n.length&&r.length<e;){const h=o;o=b(n,l=>t.measureText(n.slice(o,l+1)).width>s)+1,o===h&&(o=h+1),e===r.length+1?r.push(n.slice(h,o-1)+"..."):r.push(n.slice(h,o))}return r}drawRoundRect(i,t,s,n,e){const{context:r}=this;typeof e=="number"?e=[e,e,e,e]:e.length===1?e=[e[0],e[0],e[0],e[0]]:e.length===2?e=[e[0],e[1],e[0],e[1]]:e.length===3&&(e=[e[0],e[1],e[2],e[1]]),r.beginPath(),r.moveTo(i+e[0],t),r.lineTo(i+s-e[1],t),r.quadraticCurveTo(i+s,t,i+s,t+e[1]),r.lineTo(i+s,t+n-e[2]),r.quadraticCurveTo(i+s,t+n,i+s-e[2],t+n),r.lineTo(i+e[3],t+n),r.quadraticCurveTo(i,t+n,i,t+n-e[3]),r.lineTo(i,t+e[0]),r.quadraticCurveTo(i,t,i+e[0],t),r.closePath()}loadAssets(i){i.forEach(t=>{const{type:s}=t;s==="image"&&this.loadImage(t),s==="text"&&t.fontFamily&&this.loadFont(t)})}loadImage(i){const{src:t}=i;if(!this.images.has(t)){const s=this.canvas.createImage();s.src=t,this.images.set(t,[s,new Promise((n,e)=>{s.onload=n,s.onerror=e})])}}loadFont(i){const{fontFamily:t,fontSrc:s}=i;this.fonts.has(s)||this.fonts.set(s,new Promise((n,e)=>{my.loadFontFace({family:t,source:`url('${s}')`,success:n,fail:e})}))}export(i){const{canvas:t}=this,{width:s,height:n}=this.options,{promise:e,resolve:r,reject:o}=m.withResolvers();return t.toTempFilePath({x:0,y:0,width:s,height:n,destWidth:i.width,destHeight:i.height,success:r,fail:o}),e}}exports.MiniPoster=C; |
@@ -1,1 +0,1 @@ | ||
import{isNonEmptyArray as x,withResolvers as v}from"@inottn/fp-utils";const b=function(h,e){let t=0,i=h.length;for(;t<i;){const o=t+(i-t>>1);e(o)?i=o:t=o+1}return i-1};var F=Object.defineProperty,m=Object.getOwnPropertySymbols,I=Object.prototype.hasOwnProperty,P=Object.prototype.propertyIsEnumerable,p=(h,e,t)=>e in h?F(h,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):h[e]=t,u=(h,e)=>{for(var t in e||(e={}))I.call(e,t)&&p(h,t,e[t]);if(m)for(var t of m(e))P.call(e,t)&&p(h,t,e[t]);return h},c=(h,e,t)=>(p(h,typeof e!="symbol"?e+"":e,t),t);class S{constructor(e,t){c(this,"canvas"),c(this,"context"),c(this,"options"),c(this,"images",new Map),c(this,"fonts",new Map),this.canvas=e,this.context=e.getContext("2d"),this.options=t}async render(e){const{canvas:t,options:i}=this,{width:o,height:n,pixelRatio:r=1}=u(u({},i),e),{children:s}=e;if(!o||!n)throw Error("\u7F3A\u5C11 width \u6216 height \u53C2\u6570");if(t.width=o*r,t.height=n*r,x(s)){this.loadAssets(s);for(const a of s)a.type==="image"&&await this.renderImage(a),a.type==="text"&&await this.renderText(a)}}async renderImage(e){const{context:t}=this,{width:i,height:o,left:n=0,top:r,src:s,backgroundColor:a}=e,[l,f]=this.images.get(s);await f,a&&(t.fillStyle=a,t.fillRect(n,r,i,o)),t.drawImage(l,n,r,i,o)}async renderText(e){const{context:t}=this,{left:i,top:o,color:n="#333",fontFamily:r,fontSize:s=16,lineHeight:a=s*1.43,fontSrc:l,textDecoration:f}=e;l&&await this.fonts.get(l),t.textBaseline="top",t.fillStyle=n,t.font=`${s}px ${r}`,this.getAllLines(e).forEach((g,y)=>{const d=o+(a-s)/2+a*y;if(t.fillText(g,i,d),f==="line-through"){const{width:w}=t.measureText(g);t.fillRect(i,d+s*.46,w,s/14)}})}getAllLines(e){const{context:t}=this,{content:i,width:o,lineClamp:n=1/0}=e,r=[];let s=0;for(;s<i.length&&r.length<n;){const a=s;s=b(i,l=>t.measureText(i.slice(s,l+1)).width>o)+1,s===a&&(s=a+1),n===r.length+1?r.push(i.slice(a,s-1)+"..."):r.push(i.slice(a,s))}return r}loadAssets(e){e.forEach(t=>{const{type:i}=t;i==="image"&&this.loadImage(t),i==="text"&&t.fontFamily&&this.loadFont(t)})}loadImage(e){const{src:t}=e;if(!this.images.has(t)){const i=this.canvas.createImage();i.src=t,this.images.set(t,[i,new Promise((o,n)=>{i.onload=o,i.onerror=n})])}}loadFont(e){const{fontFamily:t,fontSrc:i}=e;this.fonts.has(i)||this.fonts.set(i,new Promise((o,n)=>{my.loadFontFace({family:t,source:`url('${i}')`,success:o,fail:n})}))}export(e){const{canvas:t}=this,{width:i,height:o}=this.options,{promise:n,resolve:r,reject:s}=v();return t.toTempFilePath({x:0,y:0,width:i,height:o,destWidth:e.width,destHeight:e.height,success:r,fail:s}),n}}export{S as MiniPoster}; | ||
import{isNonEmptyArray as v,withResolvers as b}from"@inottn/fp-utils";const P=function(a,i){let t=0,s=a.length;for(;t<s;){const n=t+(s-t>>1);i(n)?s=n:t=n+1}return s-1};var T=Object.defineProperty,m=Object.getOwnPropertySymbols,R=Object.prototype.hasOwnProperty,C=Object.prototype.propertyIsEnumerable,u=(a,i,t)=>i in a?T(a,i,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[i]=t,x=(a,i)=>{for(var t in i||(i={}))R.call(i,t)&&u(a,t,i[t]);if(m)for(var t of m(i))C.call(i,t)&&u(a,t,i[t]);return a},g=(a,i,t)=>(u(a,typeof i!="symbol"?i+"":i,t),t);class F{constructor(i,t){g(this,"canvas"),g(this,"context"),g(this,"options"),g(this,"images",new Map),g(this,"fonts",new Map),this.canvas=i,this.context=i.getContext("2d"),this.options=t}toPx(i){const{pixelRatio:t=1}=this.options;return typeof i=="number"?i*t:i.map(this.toPx.bind(this))}async render(i){const{canvas:t,context:s,options:n}=this,{width:e,height:o,pixelRatio:r=1,backgroundColor:h,borderRadius:l,overflow:c}=x(x({},n),i),{children:d}=i;if(!e||!o)throw Error("\u7F3A\u5C11 width \u6216 height \u53C2\u6570");if(t.width=e*r,t.height=o*r,s.save(),l&&(this.drawRoundRect(0,0,t.width,t.height,l),s.clip()),h&&(s.fillStyle=h,s.fillRect(0,0,t.width,t.height)),c!=="hidden"&&s.restore(),v(d)){this.loadAssets(d);for(const f of d)f.type==="image"&&await this.renderImage(f),f.type==="text"&&await this.renderText(f)}c==="hidden"&&s.restore()}async renderImage(i){const{context:t}=this,[s,n,e,o]=this.toPx([i.left,i.top,i.width,i.height]),{src:r,backgroundColor:h,borderRadius:l}=i,[c,d]=this.images.get(r);await d,t.save(),l&&(this.drawRoundRect(s,n,e,o,this.toPx(l)),t.clip()),h&&(t.fillStyle=h,t.fillRect(s,n,e,o)),t.drawImage(c,s,n,e,o),t.restore()}async renderText(i){const{context:t}=this,[s,n,e]=this.toPx([i.left,i.top,i.fontSize||16]),o=i.lineHeight?this.toPx(i.lineHeight):e*1.43,{color:r="#333",fontFamily:h,fontWeight:l=400,fontSrc:c,textDecoration:d}=i;c&&await this.fonts.get(c),t.textBaseline="top",t.fillStyle=r,t.font=`${l} ${e}px ${h}`,(i.width?this.getAllLines(i):[i.content]).forEach((f,w)=>{const p=n+(o-e)/2+o*w;if(t.fillText(f,s,p),d==="line-through"){const{width:y}=t.measureText(f);t.fillRect(s,p+e*.46,y,e/14)}})}getAllLines(i){const{context:t}=this,s=this.toPx(i.width),{content:n,lineClamp:e=1/0}=i,o=[];let r=0;for(;r<n.length&&o.length<e;){const h=r;r=P(n,l=>t.measureText(n.slice(r,l+1)).width>s)+1,r===h&&(r=h+1),e===o.length+1?o.push(n.slice(h,r-1)+"..."):o.push(n.slice(h,r))}return o}drawRoundRect(i,t,s,n,e){const{context:o}=this;typeof e=="number"?e=[e,e,e,e]:e.length===1?e=[e[0],e[0],e[0],e[0]]:e.length===2?e=[e[0],e[1],e[0],e[1]]:e.length===3&&(e=[e[0],e[1],e[2],e[1]]),o.beginPath(),o.moveTo(i+e[0],t),o.lineTo(i+s-e[1],t),o.quadraticCurveTo(i+s,t,i+s,t+e[1]),o.lineTo(i+s,t+n-e[2]),o.quadraticCurveTo(i+s,t+n,i+s-e[2],t+n),o.lineTo(i+e[3],t+n),o.quadraticCurveTo(i,t+n,i,t+n-e[3]),o.lineTo(i,t+e[0]),o.quadraticCurveTo(i,t,i+e[0],t),o.closePath()}loadAssets(i){i.forEach(t=>{const{type:s}=t;s==="image"&&this.loadImage(t),s==="text"&&t.fontFamily&&this.loadFont(t)})}loadImage(i){const{src:t}=i;if(!this.images.has(t)){const s=this.canvas.createImage();s.src=t,this.images.set(t,[s,new Promise((n,e)=>{s.onload=n,s.onerror=e})])}}loadFont(i){const{fontFamily:t,fontSrc:s}=i;this.fonts.has(s)||this.fonts.set(s,new Promise((n,e)=>{my.loadFontFace({family:t,source:`url('${s}')`,success:n,fail:e})}))}export(i){const{canvas:t}=this,{width:s,height:n}=this.options,{promise:e,resolve:o,reject:r}=b();return t.toTempFilePath({x:0,y:0,width:s,height:n,destWidth:i.width,destHeight:i.height,success:o,fail:r}),e}}export{F as MiniPoster}; |
@@ -19,5 +19,7 @@ interface Canvas { | ||
}; | ||
type Radius = number | [number] | [number, number] | [number, number, number] | [number, number, number, number]; | ||
type Config = { | ||
backgroundColor?: string; | ||
borderRadius?: number | number[]; | ||
borderRadius?: Radius; | ||
overflow?: 'visible' | 'hidden'; | ||
children?: (TextConfig | ImageConfig)[]; | ||
@@ -40,2 +42,3 @@ }; | ||
fontFamily?: string; | ||
fontWeight?: number | string; | ||
textDecoration?: 'none' | 'line-through'; | ||
@@ -48,2 +51,3 @@ whiteSpace?: 'normal' | 'nowrap'; | ||
backgroundColor?: string; | ||
borderRadius?: Radius; | ||
}; | ||
@@ -58,2 +62,3 @@ | ||
constructor(canvas: Canvas, options: Options); | ||
private toPx; | ||
render(config: Config): Promise<void>; | ||
@@ -63,2 +68,3 @@ renderImage(data: ImageConfig): Promise<void>; | ||
getAllLines(data: TextConfig): string[]; | ||
drawRoundRect(x: number, y: number, width: number, height: number, radius: Radius): void; | ||
loadAssets(data: NonNullable<Config['children']>): void; | ||
@@ -65,0 +71,0 @@ loadImage(data: ImageConfig): void; |
{ | ||
"name": "@inottn/miniposter", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"packageManager": "pnpm@8.7.0", | ||
@@ -5,0 +5,0 @@ "description": "使用 canvas 轻松绘制小程序海报", |
@@ -1,3 +0,10 @@ | ||
使用 canvas 轻松绘制小程序海报 | ||
<p align="center">使用 canvas 轻松绘制小程序海报</p> | ||
<p align="center"> | ||
<img src="https://img.shields.io/npm/v/%40inottn%2Fminiposter" /> | ||
<img src="https://img.shields.io/bundlejs/size/%40inottn%2Fminiposter" /> | ||
<img src="https://img.shields.io/badge/tree_shaking-supported-4c1" /> | ||
<img src="https://img.shields.io/npm/l/%40inottn%2Fminiposter" /> | ||
</p> | ||
## 安装 | ||
@@ -4,0 +11,0 @@ |
12753
98
27