整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

一个免费的开源的html转markdown语法的工具

个免费的开源的html转markdown语法的工具


大家好,今天为大家分享一个由 www.helloworld.net 网站开发并开源的一个非常好用的工具 html2md, 并且源码已经开源,再遇到喜欢的文章,就可以只输入一个url,就能转换成markdown文件了,使用非常的简单


现在好的技术文章确实多,每天各种技术群里,各种技术社区,有很多质量非常好的技术文章,于是我们就收藏了,可是问题来了,我们收藏到哪呢?

怎么收藏呢?

  1. 微信群里发的文章,我们可以收藏
  2. csdn中的技术文章我们也可以注册一个账号收藏
  3. helloworld.net技术社区里面的文章再注册一个账号收藏
    可是技术社区好多呢,每个社区都要注册一个账号,收藏也是可以的,只不过不方便我们统一的管理,实在是不方便,当然也有人用浏览器的收藏夹去收藏,比如我就是这样做的,可是我们程序员大部分用的还是chrome浏览器,所以问题来了,chrome浏览器登录账号,必须要会科学上网,也是很麻烦

最可气的是,我收藏的文章,可能过了10天后,作者把这个文章删除了,我真是。。。。。无语了。。。。


所以,helloworld.net的创始人之一水手花了一个周末的时间,开发了一款这样的小工具,使用很简单,代码也很简单,并且将其开源了出去,非常的好用
而且
helloworld.net也提供了官方的链接, 大家可以试用一下

github地址呢?

html2md已经开源并托管在github上
地址: https://github.com/helloworld-Co/html2md

是用什么语言开发的?

javascript 开发的,具体是用vue框架开发的,做前端开发的小伙伴们恭喜了

主要使用以下技术栈

- vue 前端三剑客之一,主张最少,具有高度灵活性的渐进式框架
- nuxt 通过利用 Vue.js 和 Node.js最佳实践来构建高性能应用程序
- express 基于 Node.js 平台,快速、开放、极简的 Web 开发框架
- element-ui 宇宙第一 Vue 第三方组件库,有不服?
- js-dom 一款可在 Node 环境下模拟浏览器的 API 的库
- turndown 使用 JavaScript 将 HTML 转换为 Markdown
- axios 易用、简洁且高效的 http库,支持浏览器和 Node 环境。
- mavon-editor 一款基于 Vue 的 markdown 编辑器,支持所见即所得
- sass 强大的 Css 预处理器之一

使用教程,如下图



也可以下载源码编译直接可以跑起来的

具体步骤如下:

第一步:下载

git clone git@github.com:helloworld-Co/html2md.git
cd ./html2md

第二步:安装

npm install
或者
yarn install

第三步:启动

npm run dev
或者
yarn dev

是不是很简单,由于时仓促,代码难免有bug,欢迎提出,我们随时修改

html2md只是www.helloworld.net官方开源的一个小工具,后续我们还会开发出其它的有用的工具或者一些软件,做一个真正为程序员着想的开发者社区


最后 ,如果你赶兴趣,可以关注一下我们

后面还会发布更多的关于IT技术,编程,创业,资讯相关的文章

家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

1.什么是 ai2html

ai2html 是 Adob​e Illustrator 的开源脚本,可将 Illustrator 文档转换为 html 和 css,基于 ai2html 的诸多示例登上了 New York Times。

ai2html由不同的组成部分:

  • ai2html-css:支持插入到 html 中的 css,可以将其包含在 Illustrator 文档中某处的文本块中,但不要包含在画板上。
  • ai2html-js:支持添加始终插入到 html 部分中的 javascript,可以将其包含在 Illustrator 文档中某处的文本块中,但不要包含在画板上。
  • ai2html-html:添加始终插入到 html 部分中的 html,请将其包含在 Illustrator 文档中某处的文本块中,但不要包含在画板上。
  • ai2html-text:可以将文本存储到变量中,并使用基本的 Mustache 或 erb/ejs 表示法将它们插入到文档中。

目前 ai2html 在 Github 上开源,是一个值得关注的 AI 类前端开源项目。

2.为什么需要 ai2html

很多人会有此疑问,为什么不直接将 Illustrator 文件导出为图像或 SVG?

图像和 SVG 中的文本会随着图像的缩放而缩放,因此当艺术品缩小时,文本很快就会变得难以辨认,或者在放大时看起来非常大。

通过将文本渲染为 html,可以上下缩放“图形”同时保持文本在相同的字体大小和行高下可读,从而适应从手机到巨型桌面显示器的视口。

可以打开链接 http://nyti.ms/1CQdkwq ,然后查看页面时更改窗口大小,此时将看到图稿比例变化,但文本保持相同大小。 更多示例可以查看 https://del.icio.us/archietse/ai2html+responsive

同时,当 Illustrator 保存 SVG 时,每一行文本都会被分解为单独的 SVG 元素,这使得编辑文本变得非常困难。 通过以 HTML 形式渲染文本,编辑人员可以更轻松地进入 CMS 并进行编辑,而无需费力地浏览一堆 SVG 代码。

当然,ai2html 也有一定的局限性,主要体现在以下几点:

  • 由于在设置文本格式和定位元素时,网页会将数字四舍五入为整像素,因此图形的 html 版本将不会与其 Illustrator 版本完全一致。 如果文本块跨越多行并且在 Illustrator 中具有小数行距,则舍入差异会特别复杂。
  • 设置为 valign:bottom 的非常大的文本目前无法正确定位
  • ai2html 只关注文本,而可能忽略艺术的成分
  • 画板应该有唯一的名称。
  • 图形对象中的标签将渲染为图像的一部分。 如果希望图表标签显示为 html,则需要取消图表分组。
  • 在区域文本块中,由于溢出框而隐藏的文本将出现在 html 输出中。

3.安装/使用 ai2html

将 ai2html 的 CDN 文件下载保存到电脑,下载地址已经在文末给出。

将 ai2html.js 文件移动到脚本所在的 Illustrator 文件夹中。 例如,在运行 Adobe Illustrator CC 2015 的 Mac 上,路径为:

/Applications/Adobe Illustrator CC 2015/Presets/en_US/Scripts/ai2html.js

接着按照以下步骤使用 ai2html:

  • 创建 Illustrator 作品。例如:将画板调整为希望以 div 在网页上显示的尺寸;确保文档颜色模式设置为 RGB;保存文档;使用 Arial 或 Georgia,除非已将自己的字体添加到脚本中的字体数组中。
  • 通过选择以下方式运行脚本:File > Scripts > ai2html
  • 转到包含 Illustrator 文件的文件夹, 里面有一个名为 ai2html-output 的输出文件夹, 在浏览器中打开 html 文件以预览输出。

参考资料

http://ai2html.org/

https://github.com/newsdev/ai2html

https://raw.githubusercontent.com/newsdev/ai2html/master/ai2html.js

、前言

1、什么是poi-tl

poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库。同类型的FreeMarker或Velocity基于文本模板和数据生成新的html页面或配置文件。而poi tl是一个基于Word模板和数据生成新文档的Word模板引擎。

Word模板具有丰富的样式。Poi-tl将在生成的文档中完美地保留模板中的样式。也可以设置标记的样式。标记的样式将应用于替换的文本,因此您可以专注于模板设计。

poi-tl是一个“无逻辑”模板引擎。没有复杂的控制结构和变量分配,只有标签,有些标签可以用文本、图片、表格等代替,有些标签会隐藏某些文档内容,而另一些标签会循环一系列文档内容。

像变量赋值或条件语句这样的“强大”构造可以很容易地在模板系统中专门修改应用程序的外观。。。然而,以分离为代价,将模板本身变成应用程序逻辑的一部分。

poi-tl支持自定义函数(插件),函数可以在Word模板的任何地方执行,在文档的任何地方做任何事情都是poi-tl的目标。

2、官方信息

2.1 源码仓库

GitHub - Sayi/poi-tl: Generate awesome word(docx) with template

2.2 中文文档

Poi-tl Documentation (deepoove.com)

2.3 开源协议

Apache License 2.0

3、poi-tl的优势

3.1 poi-tl和其他模板引擎的对比

下面表格是官方文档中提供的与其他模板引擎的对比

方案

移植性

功能性

易用性

Poi-tl

Java跨平台

Word模板引擎,基于Apache POI,提供更友好的API

低代码,准备文档模板和数据即可

Apache POI

Java跨平台

Apache项目,封装了常见的文档操作,也可以操作底层XML结构

文档不全,这里有一个教程:Apache POI Word快速入门

Freemarker

XML跨平台

仅支持文本,很大的局限性

不推荐,XML结构的代码几乎无法维护

OpenOffice

部署OpenOffice,移植性较差

-

需要了解OpenOffice的API

HTML浏览器导出

依赖浏览器的实现,移植性较差

HTML不能很好的兼容Word的格式,样式糟糕

-

Jacob、winlib

Windows平台

-

复杂,完全不推荐使用


3.2 poi-tl Word模板引擎支持的功能

Word模板引擎功能

描述

文本

将标签渲染为文本

图片

将标签渲染为图片

表格

将标签渲染为表格

列表

将标签渲染为列表

图表

条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、饼图(3D饼图)、散点图等图表渲染

If Condition判断

根据条件隐藏或者显示某些文档内容(包括文本、段落、图片、表格、列表、图表等)

Foreach Loop循环

根据集合循环某些文档内容(包括文本、段落、图片、表格、列表、图表等)

Loop表格行

循环复制渲染表格的某一行

Loop表格列

循环复制渲染表格的某一列

Loop有序列表

支持有序列表的循环,同时支持多级列表

Highlight代码高亮

word中代码块高亮展示,支持26种语言和上百种着色样式

Markdown

将Markdown渲染为word文档

Word批注

完整的批注功能,创建批注、修改批注等

Word附件

Word中插入附件

SDT内容控件

内容控件内标签支持

Textbox文本框

文本框内标签支持

图片替换

将原有图片替换成另一张图片

书签、锚点、超链接

支持设置书签,文档内锚点和超链接功能

Expression Language

完全支持SpringEL表达式,可以扩展更多的表达式:OGNL, MVEL…

样式

模板即样式,同时代码也可以设置样式

模板嵌套

模板包含子模板,子模板再包含子模板

合并

Word合并Merge,也可以在指定位置进行合并

用户自定义函数(插件)

插件化设计,在文档任何位置执行函数


二、基本的使用配置

1、引入依赖

1.1 Maven

<dependency>
  <groupId>com.deepoove</groupId>
  <artifactId>poi-tl</artifactId>
  <version>1.12.1</version>
</dependency>

1.2 Gradle

implementation 'com.deepoove:poi-tl:1.12.1'

2、配置

2.1 新建配置

ConfigureBuilder builder = Configure.builder();

2.2 标签前后缀替换

poi-tl所有的标签都是以{{开头,以}}结尾,这是为了致敬Google CTemplate。标签可以出现在任何位置,包括页眉,页脚,表格内部,文本框等,表格布局可以设计出很多优秀专业的文档,推荐使用表格布局。

当然如果你更偏爱freemarker ${} 的方式,也可以添加如下配置修改标签的前后缀配置:

builder.buildGramer("${", "}");

2.3 加载模板

XWPFTemplate template = XWPFTemplate.compile("template.docx", builder.buid());

poi-tl加载使用XWPFTemplate.compile方法来加载模板,支持模板以绝对路径(String),File、InputStream、XWPFDocument四种格式传入。

2.4 填充数据

poi-tl数据类似于哈希或者字典,可以是Map结构(key是标签名称):

Map<String, Object> data = new HashMap<>();
data.put("name", "Sayi");
data.put("start_time", "2019-08-04");
template.render(dataMap);

2.5 输出文件

poi-tl以流的方式进行输出:

template.write(OutputStream stream);

可以写到任意输出流中,比如文件流:

template.write(new FileOutputStream("output.docx"));

如网络流:

response.setContentType("application/octet-stream");
response.setHeader("Content-disposition","attachment;filename=\""+"out_template.docx"+"\"");

// HttpServletResponse response
OutputStream out = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
template.write(bos);
bos.flush();
out.flush();
PoitlIOUtils.closeQuietlyMulti(template, bos, out);

三、各类模板标签替换和填充

1 文本

1.1 文本的标签如下

{{var}}

1.2 支持数据类型

  • String :文本
  • TextRenderData :有样式的文本
  • HyperlinkTextRenderData :超链接和锚点文本
  • Object :调用 toString() 方法转化为文本

1.3 文本数据填充方式如下

代码示例

put("name", "Sayi");
put("author", new TextRenderData("000000", "Sayi"));
put("link", new HyperlinkTextRenderData("website", "http://deepoove.com"));
put("anchor", new HyperlinkTextRenderData("anchortxt", "anchor:appendix1"));

除了new操作符,还提供了更加优雅的工厂 Texts 和链式调用的方式轻松构建文本模型。

链式代码示例

put("author", Texts.of("Sayi").color("000000").create());
put("link", Texts.of("website").link("http://deepoove.com").create());
put("anchor", Texts.of("anchortxt").anchor("appendix1").create());

2 图片

2.1 图片的标签如下:

图片标签以@开始:{{@var}}

2.2 支持数据类型

  • String :图片url或者本地路径,默认使用图片自身尺寸
  • PictureRenderData
  • ByteArrayPictureRenderData
  • FilePictureRenderData
  • UrlPictureRenderData

2.3 图片数据填充方式如下

// 指定图片路径
put("image", "logo.png");
// svg图片
put("svg", "https://img.shields.io/badge/jdk-1.6%2B-orange.svg");

// 设置图片宽高
put("image1", Pictures.ofLocal("logo.png").size(120, 120).create());

// 图片流
put("streamImg", Pictures.ofStream(new FileInputStream("logo.jpeg"), PictureType.JPEG)
  .size(100, 120).create());

// 网络图片(注意网络耗时对系统可能的性能影响)
put("urlImg", Pictures.ofUrl("http://deepoove.com/images/icecream.png")
  .size(100, 100).create());

// java图片
put("buffered", Pictures.ofBufferedImage(bufferImage, PictureType.PNG)
  .size(100, 100).create());

3 表格

3.1 表格的标签如下:

表格标签以#开始:{{#var}}

3.2 支持数据类型

  • TableRenderData

3.3 表格数据填充方式如下

  1. 基础表格示例
// 一个2行2列的表格
put("table0", Tables.of(new String[][] {
                new String[] { "00", "01" },
                new String[] { "10", "11" }
            }).border(BorderStyle.DEFAULT).create());
  1. 表格样式示例
// 第0行居中且背景为蓝色的表格
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
      .bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
put("table1", Tables.create(row0, row1));
  1. 表格合并示例
// 合并第1行所有单元格的表格
RowRenderData row0 = Rows.of("列0", "列1", "列2").center().bgColor("4472C4").create();
RowRenderData row1 = Rows.create("没有数据", null, null);
MergeCellRule rule = MergeCellRule.builder().map(Grid.of(1, 0), Grid.of(1, 2)).build();
put("table3", Tables.of(row0, row1).mergeRule(rule).create());

4、列表

4.1 列表的标签如下:

列表标签以*开始:{{*var}}

4.2 支持数据类型

  • List<String>
  • NumberingRenderData

4.3 列表数据填充方式如下

put("list", Numberings.create("Plug-in grammar",
                    "Supports word text, pictures, table...",
                    "Not just templates"));

四、验证

1、准备模板

首先我们建立一个word文件,在word文件里填充一下内容。



2、准备测试代码

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.*;
import dto.Qiankuan;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*;

public class PoitlTest {

    public static void main(String[] args) throws IOException {
        ConfigureBuilder builder = Configure.builder();
        //获取模板的文件流
        FileInputStream fileInputStream = new FileInputStream("D:\\文章\\word生成\\poi-tl\\qiantiao.docx");

        HashMap<String, Object> dataMap = new HashMap<>();
        //添加文本
        LocalDate currentDate = LocalDate.now();
        LocalDate endDate = currentDate.plusYears(1L);
        dataMap.put("debtor", "陈有楚");
        dataMap.put("nowYear", String.valueOf(currentDate.getYear()));
        dataMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
        dataMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
        //验证换行的情况
        dataMap.put("arrears", "\n一顿老魏,\n贵州大黄牛,\nv我50");
        dataMap.put("endYear", String.valueOf(endDate.getYear()));
        dataMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
        dataMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
        //添加列表
        List<String> list = Arrays.asList("阿大", "阿二", "阿三");
        Numberings.NumberingBuilder numberingBuilder = Numberings.of(NumberingFormat.DECIMAL);
        for (String s : list) {
            numberingBuilder.addItem(s);
        }
        dataMap.put("witness", numberingBuilder.create());
        //添加图片,考虑到实际生产环境图片大都都从文件服务获取,所以这里用图片流做例子
        PictureRenderData pictureRenderData = Pictures.ofStream(Files.newInputStream(Paths.get("D:\\picture\\其他\\24-05-23-142418.png")), PictureType.JPEG)
                .size(300, 220).create();
        dataMap.put("image1", pictureRenderData);
        List<Qiankuan> qiankuanList = getQiankuanList();
        //添加表格
        //填充表头,表格的第一行
        RowRenderData row0 = Rows.of("拖欠物品", "拖欠次数", "偿还期限").center().bgColor("4472C4").create();
        Tables.TableBuilder tableBuilder = Tables.of(row0);
        //填充表格内容
        for (Qiankuan qiankuan : qiankuanList) {
            RowRenderData row = Rows.create(qiankuan.getName(), String.valueOf(qiankuan.getCount()), qiankuan.getQixian());
            tableBuilder.addRow(row);
        }
        //MergeCellRule rule = MergeCellRule.builder().map(MergeCellRule.Grid.of(1, 0), MergeCellRule.Grid.of(1, 2)).build();
        //tableBuilder.mergeRule(rule);
        dataMap.put("table1", tableBuilder.create());

        ChartMultiSeriesRenderData chart = Charts
                .ofMultiSeries("ChartTitle", new String[] { "中文", "English" })
                .addSeries("countries", new Double[] { 15.0, 6.0 })
                .addSeries("speakers", new Double[] { 223.0, 119.0 })
                .create();

        dataMap.put("barChart", chart);
        XWPFTemplate template = XWPFTemplate.compile(fileInputStream, builder.build())
                .render(dataMap);
        template.writeAndClose(Files.newOutputStream(Paths.get("D:\\test\\qiantiao-poitl.docx")));
        System.out.println("success");
    }

    static List<Qiankuan> getQiankuanList() {
        List<Qiankuan> list = new ArrayList<>();
        Qiankuan q1 = new Qiankuan();
        q1.setName("一顿老魏");
        q1.setCount(1);
        q1.setQixian("三月内");
        list.add(q1);

        Qiankuan q2 = new Qiankuan();
        q2.setName("一顿大黄牛");
        q2.setCount(1);
        q2.setQixian("半年内");
        list.add(q2);

        Qiankuan q3 = new Qiankuan();
        q3.setName("特一特");
        q3.setCount(3);
        q3.setQixian("一周内");
        list.add(q3);

        Qiankuan q4 = new Qiankuan();
        q4.setName("v我50");
        q4.setCount(5);
        q4.setQixian("一周内");
        list.add(q4);
        return list;
    }

}

3、生成效果