UNPKG

mdimg

Version:

Covert Markdown or HTML to image

2 lines (1 loc) 5.98 kB
"use strict";var e=require("fs"),t=require("path"),n=require("puppeteer"),i=require("cheerio"),r=require("marked");const s=async e=>{const t=new r.marked.Renderer;t.code=({text:e,lang:t})=>{const n=e.replace(/</g,"&lt;").replace(/>/g,"&gt;");return"mermaid"==t?`<pre class="mermaid">${n}</pre>`:`<pre><code class="language-${t}">${n}</code></pre>`};return r.marked.parse(e,{renderer:t})},a=(e,t)=>String(e).padStart(t,"0"),o=async({inputText:r,inputFilename:o,mdText:l,mdFile:c,outputFilename:d,type:m="png",width:p=800,height:h=100,encoding:g="binary",quality:u=100,htmlText:y,cssText:w,htmlTemplate:$="default",cssTemplate:f="default",theme:x="light",extensions:S=!0,log:b=!1,debug:v=!1,puppeteerProps:_={}})=>{const T=["jpeg","png","webp"],j=["base64","binary","blob"],M={html:"",data:"base64"===g?"":Uint8Array.from([]),path:void 0};let F="";const k=o||c,J=r||l;if(k){const n=t.resolve(k);if(!e.existsSync(n))throw new Error(`input file ${n} is not exists.\n`);if(!e.statSync(n).isFile())throw new Error("input is not a file.\n");F=e.readFileSync(n).toString(),b&&process.stderr.write(`Info: start to convert file ${n} to an image...\n`)}else{if(!J)throw new Error("text or file is required to be converted.\n");F=J,b&&process.stderr.write("Info: start to convert text to an image...\n")}const O=g,q="binary"===O;if(!j.includes(O))throw new Error(`encoding type ${O} is not supported. Valid types: ${j.join(", ")}.\n`);let E,H,U=m;if(!T.includes(U))throw new Error(`output file type ${U} is not supported. Valid types: ${T.join(", ")}.\n`);if(q)if(d){const e=t.basename(d),n=t.dirname(d),i=e.split("."),r=i.length;if(r<=1)E=t.resolve(n,`${e}.${U}`);else{const s=i[r-1];T.includes(s)?(U=s,E=t.resolve(d)):(b&&process.stderr.write(`Warning: output file type must be one of 'jpeg', 'png' or 'webp'. Use '${U}' type.\n`),E=t.resolve(n,`${e}.${U}`))}}else E=t.resolve("mdimg_output",(e=>{const t=new Date;return`mdimg_${t.getFullYear()}_${a(t.getMonth()+1,2)}_${a(t.getDate(),2)}_${a(t.getHours(),2)}_${a(t.getMinutes(),2)}_${a(t.getSeconds(),2)}_${a(t.getMilliseconds(),3)}.${e}`})(U));"png"!==U&&(H=u>0&&u<=100?u:100);const L=(({renderedHtml:n,htmlText:r,cssText:s,htmlTemplate:a="default",cssTemplate:o="default",theme:l="light",extensions:c=!0,log:d=!1})=>{let m=r,p=s;if(!m){let n=t.resolve(a.endsWith(".html")?a:`${__dirname}/../template/html/${a}.html`);try{e.accessSync(n,e.constants.R_OK)}catch(e){d&&process.stderr.write(`Warning: HTML template ${n} is not found or unreadable. Use default HTML template.\n${e}\n`),n=t.resolve(`${__dirname}/../template/html/default.html`)}m=e.readFileSync(n).toString()}if(!p){let n=t.resolve(o.endsWith(".css")?o:`${__dirname}/../template/css/${o}.css`);try{e.accessSync(n,e.constants.R_OK)}catch(e){d&&process.stderr.write(`Warning: CSS template ${n} is not found or unreadable. Use default CSS template.\n${e}\n`),n=t.resolve(`${__dirname}/../template/css/default.css`)}p=e.readFileSync(n).toString()}const h=i.load(m);if(h("head").append(`\n<meta charset="UTF-8">\n<meta name="viewport" content="width=device-width, initial-scale=1.0">\n<title>mdimg rendering preview</title>\n<style>\n${p}\n</style>\n`),h(".markdown-body").html(n),!1!==c){const n=Object.assign({highlightJs:!0,mathJax:!0,mermaid:!0},c),{highlightJs:i,mathJax:r,mermaid:s}=n;if(!1!==i){const n=Object.assign({theme:`atom-one-${l}`},i),r=e.readFileSync(t.resolve(`${__dirname}/../static/highlightjs/cdn-release@11/build/styles/${n.theme}.min.css`)),s=e.readFileSync(t.resolve(`${__dirname}/../static/highlightjs/cdn-release@11/build/highlight.min.js`));h("head").append(`\n\x3c!-- highlight.js styles --\x3e\n<style>${r}</style>\n`),h("body").append(`\n\x3c!-- highlight.js --\x3e\n<script>${s}<\/script>\n<script>\n hljs.configure(${JSON.stringify(n)});\n hljs.highlightAll();\n<\/script>\n`)}if(!1!==r){const n=Object.assign({},r),i=e.readFileSync(t.resolve(`${__dirname}/../static/mathjax@3/es5/tex-mml-chtml.js`));h("head").append(`\n\x3c!-- MathJax options --\x3e\n<script>\n MathJax = ${JSON.stringify(n)}\n<\/script>\n`),h("body").append(`\n\x3c!-- MathJax --\x3e\n<script>${i}<\/script>\n`)}if(!1!==s){const e=Object.assign({startOnLoad:!0,theme:"dark"===l?"dark":void 0},s);h("body").append(`\n\x3c!-- Mermaid --\x3e\n<script type="module">\n import mermaid from 'https://unpkg.com/mermaid@11/dist/mermaid.esm.min.mjs';\n mermaid.initialize(${JSON.stringify(e)});\n<\/script>\n`)}}return h.html()})({renderedHtml:await s(F),htmlText:y,cssText:w,htmlTemplate:$,cssTemplate:f,extensions:S,theme:x,log:b});M.html=L;const W=Math.max(h,100),A=await n.launch({defaultViewport:{width:p,height:W},args:[`--window-size=${p},${W}`],..._}),C=k?t.dirname(t.resolve(k)):process.cwd(),D=t.resolve(C,`.mdimg_temp_${(new Date).getTime()}_${a(Math.floor(1e4*Math.random()),4)}.html`);try{e.writeFileSync(D,L)}catch(e){b&&process.stderr.write(`Warning: write temporary local HTML file failed, local files may not display correctly. ${e}\n`)}const N=e.existsSync(D);try{const n=await A.newPage();N?await n.goto(`file://${D}`,{waitUntil:"networkidle0"}):await n.setContent(L,{waitUntil:"networkidle0"});const i=await n.$("#mdimg-body");if(!i)throw new Error(`missing HTML element with id: mdimg-body.\nHTML template ${$} is not valid.\n`);if("binary"===O||"blob"===O){q&&(n=>{const i=t.dirname(n);try{e.mkdirSync(i,{recursive:!0}),e.writeFileSync(n,"")}catch(e){throw new Error(`create new file ${n} failed.\n${String(e)}\n`)}})(String(E));const n=await i.screenshot({path:q?E:void 0,type:U,quality:H,encoding:"binary"});b&&process.stderr.write(`Success: convert to image${q?` and saved as ${E}`:""} successfully!\n`),M.data=n,M.path=q?E:void 0}else if("base64"===O){const e=await i.screenshot({type:U,quality:H,encoding:"base64"});b&&process.stderr.write("Success: convert to BASE64 encoded string successfully!\n"),M.data=e}}catch(e){throw new Error(String(e))}finally{await(async()=>{N&&!v&&e.rmSync(D),await A.close()})()}return M};exports.convert2img=o,exports.mdimg=o;