制作在线Markdown文档转Html以及Pdf工具

原文链接

欢迎大家对于本站的访问 - AsterCasc

前言

最近整理的文档比较多,手写的话比较习惯markdown,但由于其中一大部分需要提供给对接方,所以转换成Html以及Pdf就是需要处理的部分了。这种流程在线工具比较多,但是一来很多有次数限制(有一说一,对于涉及服务端资源的有次数限制很正常,但是很多这种纯Web端的任务流有次数限制我不理解),二来以备不时之需,我们可以需要搭一个简易的转换平台。如果文档转换量不大,可以参考使用markdowntopdf。当然可以也使用一些markdonwn的客户端编辑器,很多都带有这个功能,比如Obisian

再次重申,站长非前端工程师,本站所有前端代码仅供参考,该工具已部署到本站工具箱中,需要小伙伴可以参考

实现

这里我们借助一些工具包,就不手动造轮子了,目前考虑使用人数比较多、相对比较好用的包markdown-itmarkedjspdfpdfmake以及他们的一些衍生包,本站的文章渲染就是使用的marked,可以参考相关源码,同时也可以参考本站文章Marked.js渲染下md内图片点击放大解决方案。对于markedmarkdown-itmarked的使用人数要稍多一些,社区会更活跃,但是相差地不是特别多,而markdown-it可以定制的选项相比marked更多,拓展性以及自定义性会更强,相对易用性会差一点

由于我们之前使用的是marked,这里我们就以markdonw-it进行文档举例,具体本站自己的工具实现还是采用marked

Markdown转Html

markdown-it
markdown-it包引用
"dependencies": {  
  "markdown-it": "^14.1.0",
}

markdown-it-github

markdown-it使用

一般当我们不考虑在后面转Pdf的话,一般的处理方式是引用highlight.js进行代码渲染,然后再定义基础类的渲染,比如your_parent_class pre code {}相关及以下的渲染,基本示例如下:

import hljs from "highlight.js";
import markdownit from 'markdown-it'

const md = markdownit('default', {  
  html: true,  
  linkify: true,  
  typographer: true,  
  langPrefix: 'hljs language-',  
  highlight: (code, lang) => {  
    //correct  
    lang = lang === 'mysql' ? 'sql' : lang  
    lang = lang === 'sh' ? 'powershell' : lang  
    lang = lang === 'shell' ? 'powershell' : lang  
    //convert  
    const language = hljs.getLanguage(lang) ? lang : 'plaintext';  
    return hljs.highlight(code, {language}).value;  
  }  
})

const ret = md.render("## something")

如果你使用的是marked,基本示例如下:

import {marked} from "marked";  
import {markedHighlight} from "marked-highlight";  
import hljs from "highlight.js";  
import {gfmHeadingId} from "marked-gfm-heading-id";  
  
marked.use(markedHighlight({  
    langPrefix: 'hljs language-',  
    highlight(code, lang) {  
        //correct  
        lang = lang === 'mysql' ? 'sql' : lang  
        lang = lang === 'sh' ? 'powershell' : lang  
        lang = lang === 'shell' ? 'powershell' : lang  
        //convert  
        const language = hljs.getLanguage(lang) ? lang : 'plaintext';  
        return hljs.highlight(code, {language}).value;  
    }  
}));  
marked.use(gfmHeadingId({}));  
marked.use({  
    mangle: false,  
    headerIds: false  
});

const ret = marked.parse("## something ")

但是由于独立导出Html以及Pdf的需求,我们这里需要对于标签进行直接注入式地渲染,以markdown-it为例,如果我们需要渲染标题为绿色,处理方案为:

const md = markdownit('default', {  
  html: true,  
  linkify: true,  
  typographer: true,  
})  
  
md.renderer.rules.heading_open = (tokens, idx) => {  
  return '<' + tokens[idx].tag + ' style="color: green; font-size: 24px;">';  
};  
const ret = md.render("## 前言");

这里可以根据tokensidx进行标签定位,更丰富地渲染导出的Html。更多标签选项,比如codehrtable,可以参考renderer以及rules_block

如果你使用的是marked对于不同标签的渲染,大概形式为:

const renderer = {  
  heading(text, level) {  
    if (level === 2) {  
      return `<h${level} style="color: red;">${text}</h${level}>`  
    } else {  
      return `<h${level} style="color: blue;">${text}</h${level}>`  
    }  
  },  
};  
marked.use({renderer})

更多marked不同标签的渲染函数可以参考marked-render

样式内嵌渲染

我们在引用其他渲染包的时候,比如highlight.js这种,我们会发现他们的渲染逻辑是基于类的,但是后续转PDF或者直接导出html文件是无法直接处理class文件的。所以如果小伙伴们有需求,是需要对于生成的html进行css整合的,将渲染直接内嵌到元素当中。这里我们可以选择已有的工具包进行处理,juice或者inline-css都可以,这里我们以juice举例

首先写一个样式文件,如果你使用highlight.js,可以在highlightjs-style中选择一个喜欢的样式,然后在node_modules/highlight.js/styles/将他拷贝出来,创建自己导出样式文件,然后再在上面做修改,大概类似于:

/*code style*/
pre code.hljs {  
    display: block;  
    overflow-x: auto;  
    padding: 1em  
}  
  
code.hljs {  
    padding: 3px 5px  
}  
  
.hljs-comment, .hljs-meta {  
    color: #9699a3  
}  
  
.hljs-deletion, .hljs-doctag, .hljs-regexp, .hljs-selector-attr, .hljs-selector-class, .hljs-selector-id, .hljs-selector-pseudo, .hljs-tag, .hljs-template-tag, .hljs-variable.language_ {  
    color: #8c4351  
}  
  
.hljs-link, .hljs-literal, .hljs-number, .hljs-params, .hljs-template-variable, .hljs-type, .hljs-variable {  
    color: #965027  
}  
  
.hljs-attribute, .hljs-built_in {  
    color: #8f5e15  
}  
  
.hljs-keyword, .hljs-property, .hljs-subst, .hljs-title, .hljs-title.class_, .hljs-title.class_.inherited__, .hljs-title.function_ {  
    color: #0f4b6e  
}  
  
.hljs-selector-tag {  
    color: #33635c  
}  
  
.hljs-addition, .hljs-bullet, .hljs-quote, .hljs-string, .hljs-symbol {  
    color: #485e30  
}  
  
.hljs-code, .hljs-formula, .hljs-section {  
    color: #34548a  
}  
  
.hljs-attr, .hljs-char.escape_, .hljs-keyword, .hljs-name, .hljs-operator {  
    color: #5a4a78  
}  
  
.hljs-punctuation {  
    color: #343b58  
}  
  
.hljs {  
    background: white;  
    color: #565a6e  
}  
  
.hljs-emphasis {  
    font-style: italic  
}  
  
.hljs-strong {  
    font-weight: 700  
}

/*your else style*/
p {
	color: green;
}

然后我们利用raw-loader.js将样式从文件中读入,再利用juice重新渲染html文件即可:

import juice from 'juice';  
import markdownCss from '!!raw-loader!@/styles/output-pdf.css';

let inputMarkdown = ref("")

function render() {  
  htmlRet.value = marked.parse(inputMarkdown.value)  
  
  htmlRet.value = juice(htmlRet.value, {  
    extraCss: markdownCss  
  })  

  //...
}

Html转Pdf

对于Pdf的转换,我们一般处理是,先转Html然后再转Pdf,直接转Pdf的包没有特别好用的,主要是对于表格等特殊元素的支持较差,比如propra-tech/mdpdfmake或者patricsteiner/mdpdfmake。如果小伙伴们有什么比较好用的可以直接转的浏览器可用的工具包,可以在下方留言分享。HtmlPdf的主要的转换方式有两种使用jspdf,或者使用pdfmake搭配html-to-pdfmake,我们这里选择后者,虽然两者都需要导入字体,但是jspdf更难用一些,在导入字体后还需要配置页面大小,字间距等,如果不配置几乎用不了,而且目前版本非常难用,可以参考html method can’t handle Chinese correctly, even after used the .setFont method.jsPDF.html output very large fields in document.issues。总之,虽然jspdf只有一个包,但是对于Html的转换是做地非常粗糙的

pdfmake
pdfmake包引用
"dependencies": {  
  "html-to-pdfmake": "^2.5.7",  
  "pdfmake": "^0.2.10",
}

pdfmake-githubhtml-to-pdfmake-github

pdfmake使用

由于浏览器和Pdf对于字体的支持并不兼容,比如Pdf并不能直接支持woff2。所以我们在转换器单独设定可用的字体,当然可以使用pdfmake的默认字体,但是默认字体基本对于非英文字符都不支持。我们这里可以下载一个自己喜欢的字体,然后转Base64,加载进pdfmake即可,具体操作步骤为:

  • 选择字体可以在任意字体网站上下载,注意商业条款和中文特殊字符的加入弄问题。比较方便的话也可以在GoogleFont中选择,可以下载字体包的包括BlackLightBold版本后续注入pdfmake
  • Base64,这个随便搜一下font convert base64或者file convert base64或者base64-encode啥的能出来一堆,由于这种网站很多都不稳定我这里就不直接摆链接了
  • 创建字体资源,创建一个your_font_name_data.js之类的文件,然后在其中写入类似下方代码,因为一般字体包都不止一个字体文件,将名称和Base64对应即可,当然如果你不需要Pdf更丰富的字体显示,只写一个也没有问题
     export const yourFontNameVfs = {
    	 "YourFontName-Regular.ttf": "Regular-base64",
    	 "YourFontName-Bold.ttf": "Bold-base64",
    	 "YourFontName-Italics.tff": "Italics-base64",
    	 "YourFontName-BoldItalics.tff": "BoldItalics-base64",
     } 
    
  • 最后注入以及使用示例:
    import htmlToPdfmake from 'html-to-pdfmake';
    import pdfMake from 'pdfmake/build/pdfmake';
    import {yourFontNameVfs} from '@/your_path/your_font_name_data'
    
    pdfMake.vfs = yourFontNameVfs;  
    pdfMake.fonts = {  
    	//如果你只创建一个字体资源,那么可以将所有类型都指向改资源即可
    	YourFontName: {  
    	    normal: 'YourFontName-Regular.ttf',  
    	    bold: 'YourFontName-Bold.ttf',  
    	    italics: 'YourFontName-Italics.tff',  
    	    bolditalics: 'YourFontName-BoldItalics.tff',  
    	},  
      }  
    
    let dataText = htmlToPdfmake("<div><h1 style='background-color: #2B5853'>数据类型</h1> <p>数据类型数据类型</p> </div>");  
    const docDefinition = {  
    	content: dataText,  
        defaultStyle: {  
    	    font: 'YourFontName'  
        }  
    };  
    const pdfDocGenerator = pdfMake.createPdf(docDefinition);  
    pdfDocGenerator.download('document.pdf');
    

这里我们就可以完成从HtmlPdf的转换了,当然我们可以简单定义一些自己样式比如,背景色,字体颜色,页边距,方向等,这里大家参考官方文档自行定义即可

Tips:这里字体设置其实有个更简单的方法,直接使用URL链接注入,不需要自己创建字体资源了:

pdfMake.fonts = {  
   YourFontName: {  
		normal: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Regular.ttf',  
   	bold: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Medium.ttf',  
   	italics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Italic.ttf',  
   	bolditalics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-MediumItalic.ttf',  
   }
}

但是我没有找到合适的支持ttf且支持中文的库,谷歌的库只支持对外提供woff2链接,比如M PLUS Rounded 1c,或者不支持中文字体,类似google-webfonts.ttf.css,如果有找到合适在线字体库的小伙伴可以在下方留言分享

原文链接

欢迎大家对于本站的访问 - AsterCasc

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值