使用Apache POI和Jsoup将Word文档转换为HTML
简介
在现代办公环境中,Word文档和HTML页面都是常见的信息表达方式。有时,我们需要将Word文档转换为HTML格式,以便在网页上展示或进行进一步的处理。本文将介绍如何使用Apache POI库和Jsoup库来实现Word文档到HTML的转换,并处理文档中的图片资源。
环境准备
Java开发环境
Apache POI库
Jsoup库
Hutool工具库(用于简化文件和字符串操作)
1. 步骤1:创建项目和依赖
- 首先,我们需要创建一个Java项目,并添加Apache POI和Jsoup库的依赖。可以通过Maven或Gradle来管理这些依赖。
<poi.version>4.1.2</poi.version>
<!--注意版本保持一致 poi poi-ooxml poi-scratchpad-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<!-- 操作doc ppt xls -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- 操作docx pptx xlsx -->
<!--word S-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.xhtml</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.converter.docx.xwpf</artifactId>
<version>2.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
步骤2:读取Word文档
使用Apache POI库读取Word文档。对于.docx文件,使用XWPFDocument类;对于.doc文件,使用HWPFDocument类。
docx:
/**
* 解析docx成html
*
* @param file
* @return
* @throws IOException
*/
public static String Word2007ToHtml(MultipartFile file) throws IOException {
if (file.isEmpty() || file.getSize() <= 0) {
log.error("Sorry File does not Exists!");
return null;
} else {
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
// 1) 加载word文档生成 XWPFDocument对象
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
setParagraphs(document);
//解析XHTML配置
XHTMLOptions xhtmlOptions = XHTMLOptions.create();
// 将样式都写为内联样式,而不是写到style标签中 默认false
xhtmlOptions.setFragment(true);
xhtmlOptions.setIgnoreStylesIfUnused(false);
// 也可以使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XHTMLConverter.getInstance().convert(document, baos, xhtmlOptions);
String content = baos.toString();
org.jsoup.nodes.Document doc = setDocXStyle(content);
baos.close();
return doc.html();
} else {
log.error("Enter only MS Office 2007+ files");
return null;
}
}
}
doc读取代码
/**
* 解析doc成html 并保存图片文件到本地
*
* @param file
* @return
* @throws IOException
* @throws ParserConfigurationException
* @throws TransformerException
*/
public static String Word2003ToHtmlAndSaveImage(MultipartFile file) throws IOException {
//使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream outStream = new BufferedOutputStream(baos);
try {
//将上传的文件传入Document转换
HWPFDocument wordDocument = new HWPFDocument(file.getInputStream());
//处理标题
Range range = wordDocument.getRange();
HashSet<String> hashSet = new HashSet<>();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph paragraph = range.getParagraph(i);
int lvl = paragraph.getLvl();
if (StrUtil.isNotEmpty(paragraph.text().trim())) {
//标题
if (lvl == 1 || lvl == 0 || lvl == 2 || lvl == 4) {
String newContent = HEADLINE_DJ_ + RandomUtil.randomNumbers(8) + "_";
paragraph.insertBefore(newContent);
// paragraph.replaceText(paragraph.text(), newContent+paragraph.text() );
hashSet.add(newContent);
}
}
}
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(document);
//将读取到的图片上传并添加链接地址
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
return getImgUrl(suggestedName, content);
}
});
// word文档转Html文档
wordToHtmlConverter.processDocument(wordDocument);
Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer serializer = factory.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
String content = baos.toString();
// 使用Jsoup解析HTML内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
// 查找并修改目标段落
hashSet.forEach(text -> {
text = getReplaceAllNR(text);
Elements elements = doc.select("p");
String finalText = text;
elements.forEach(el -> {
if (el.text().contains(finalText)) {
Element h2Element = new Element("h2");
h2Element.text(el.text().replaceAll(finalText, ""));
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
el.replaceWith(h2Element);
}
});
// 添加CSS样式
org.jsoup.select.Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; "));
});
// log.info("docToHtmlText--->{}", content);
return doc.html();
} catch (Exception e) {
log.error("docToHtmlText 异常", e);
throw new MyException("docToHtmlText 异常!", e.getMessage());
} finally {
baos.close();
outStream.close();
}
}
步骤3:转换文档内容为HTML
对于.docx文件,使用XWPF库提供的XHTMLConverter类将文档内容转换为HTML。对于.doc文件,使用WordToHtmlConverter类进行转换。
步骤4:处理文档中的图片
在转换过程中,需要特别处理文档中的图片。对于.docx文件,可以通过遍历段落和运行(XWPFRun)来获取图片数据,并使用MinioUtil(或其他存储服务)保存图片并获取图片的URL。对于.doc文件,可以通过PicturesManager接口来处理图片的保存和链接更新。
步骤5:样式调整和优化
使用Jsoup库对生成的HTML内容进行样式调整和优化。例如,可以通过CSS选择器来定位并修改特定的元素样式。
处理html,添加h2标签到富文本,显示目录用。
// 遍历文档中的段落,标记标题
private static void setParagraphs(XWPFDocument document) {
// 遍历文档中的段落,标记标题
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
boolean isTitle = false;
String style = paragraph.getStyle();
if (StrUtil.isEmpty(style)) {
continue;
}
//paragraph.getStyle() 是获取段落标题等级
if (style.equals("1") || style.equals("2") || style.equals("3") || style.equals("4")) {
Long res = new Date().getTime();
String headline = HEADLINE_DJ_ + RandomUtil.randomNumbers(5) + "_" + res;
paragraph.setStyle(headline);
isTitle = true;
}
for (XWPFRun run : paragraph.getRuns()) {
run.setFontSize(40);
if (isTitle) {
run.setFontSize(60);
run.setBold(true);
}
}
}
}
步骤6:完整代码示例
点击查看代码
package com.csot.kms.common.poi;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.csot.kms.common.utill.MinioUtil;
import com.csot.kms.common.valid.MyException;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.*;
@Slf4j
public class WordToHtmlPoiUtil {
public static final String HEADLINE_DJ_ = "HEADLINE_DJ_";
public static String docImport(MultipartFile file) throws Exception {
//返回的html字符串
String html = "";
//word类型是否doc
boolean wordType = false;
//临时图片存放文件夹 图片会保存在此路径(临时保存)(doc类型使用)
String docsTempImages = System.getProperty("java.io.tmpdir") + IdUtil.simpleUUID() + "/";
//判断类型
String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
html = WordToHtmlPoiUtil.Word2007ToHtml(file);
} else if (file.getOriginalFilename().endsWith(".doc") || file.getOriginalFilename().endsWith(".DOC")) {
wordType = true;
html = WordToHtmlPoiUtil.Word2003ToHtmlAndSaveImage(file);
}
//获取图片名称和本地url,这一步上传图片到本地,并把名字和url处理成map
// String uploadPath = "";//word中的图片上传到哪
Map<String, String> imageMaps = WordToHtmlPoiUtil.getImageMaps(docsTempImages, file);
//如果有图片替换成本地地址
if (!imageMaps.isEmpty()) {
html = replaceImgToLocal(html, imageMaps, wordType);
}
html = getReplaceAllNR(html);
return html;
}
/**
* 解析docx成html
*
* @param file
* @return
* @throws IOException
*/
public static String Word2007ToHtml(MultipartFile file) throws IOException {
if (file.isEmpty() || file.getSize() <= 0) {
log.error("Sorry File does not Exists!");
return null;
} else {
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
// 1) 加载word文档生成 XWPFDocument对象
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
setParagraphs(document);
//解析XHTML配置
XHTMLOptions xhtmlOptions = XHTMLOptions.create();
// 将样式都写为内联样式,而不是写到style标签中 默认false
xhtmlOptions.setFragment(true);
xhtmlOptions.setIgnoreStylesIfUnused(false);
// 也可以使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XHTMLConverter.getInstance().convert(document, baos, xhtmlOptions);
String content = baos.toString();
org.jsoup.nodes.Document doc = setDocXStyle(content);
baos.close();
return doc.html();
} else {
log.error("Enter only MS Office 2007+ files");
return null;
}
}
}
private static org.jsoup.nodes.Document setDocXStyle(String content) {
//根据标记替换标题内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
Elements elements = doc.select("p[class^=HEADLINE_DJ_]");
for (Element element : elements) {
Element h2Element = new Element("h2");
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
h2Element.text(element.text());
element.replaceWith(h2Element);
}
// 添加CSS样式
Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; "));
return doc;
}
// 遍历文档中的段落,标记标题
private static void setParagraphs(XWPFDocument document) {
// 遍历文档中的段落,标记标题
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
boolean isTitle = false;
String style = paragraph.getStyle();
if (StrUtil.isEmpty(style)) {
continue;
}
if (style.equals("1") || style.equals("2") || style.equals("3") || style.equals("4")) {
Long res = new Date().getTime();
String headline = HEADLINE_DJ_ + RandomUtil.randomNumbers(5) + "_" + res;
paragraph.setStyle(headline);
isTitle = true;
}
for (XWPFRun run : paragraph.getRuns()) {
run.setFontSize(40);
if (isTitle) {
run.setFontSize(60);
run.setBold(true);
}
}
}
}
/**
* 解析doc成html 并保存图片文件到本地
*
* @param file
* @return
* @throws IOException
* @throws ParserConfigurationException
* @throws TransformerException
*/
public static String Word2003ToHtmlAndSaveImage(MultipartFile file) throws IOException {
//使用字符数组流获取解析的内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream outStream = new BufferedOutputStream(baos);
try {
//将上传的文件传入Document转换
HWPFDocument wordDocument = new HWPFDocument(file.getInputStream());
//处理标题
Range range = wordDocument.getRange();
HashSet<String> hashSet = new HashSet<>();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph paragraph = range.getParagraph(i);
int lvl = paragraph.getLvl();
if (StrUtil.isNotEmpty(paragraph.text().trim())) {
//标题
if (lvl == 1 || lvl == 0 || lvl == 2 || lvl == 4) {
String newContent = HEADLINE_DJ_ + RandomUtil.randomNumbers(8) + "_";
paragraph.insertBefore(newContent);
// paragraph.replaceText(paragraph.text(), newContent+paragraph.text() );
hashSet.add(newContent);
}
}
}
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(document);
//将读取到的图片上传并添加链接地址
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
@Override
public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
return getImgUrl(suggestedName, content);
}
});
// word文档转Html文档
wordToHtmlConverter.processDocument(wordDocument);
Document htmlDocument = wordToHtmlConverter.getDocument();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(outStream);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer serializer = factory.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
String content = baos.toString();
// 使用Jsoup解析HTML内容
org.jsoup.nodes.Document doc = Jsoup.parse(content);
// 查找并修改目标段落
hashSet.forEach(text -> {
text = getReplaceAllNR(text);
Elements elements = doc.select("p");
String finalText = text;
elements.forEach(el -> {
if (el.text().contains(finalText)) {
Element h2Element = new Element("h2");
h2Element.text(el.text().replaceAll(finalText, ""));
h2Element.attr("style", "font-weight: bold;font-size: 22px;");
el.replaceWith(h2Element);
}
});
// 添加CSS样式
org.jsoup.select.Elements elementsfontSize = doc.select("span");
elementsfontSize.forEach(fs -> fs.attr("style", "font-size: 19px; "));
});
// log.info("docToHtmlText--->{}", content);
return doc.html();
} catch (Exception e) {
log.error("docToHtmlText 异常", e);
throw new MyException("docToHtmlText 异常!", e.getMessage());
} finally {
baos.close();
outStream.close();
}
}
private static String getReplaceAllNR(String text) {
text = text.replaceAll("\r\n", "")
.replaceAll("\r", "")
.replaceAll("\n", "");
return text;
}
/**
* 获取word中的图片名称和本地url(doc或docx)
* 返回map<图片名称, 存储的图片url地址>
*
* @param
* @param docsTempImages 本地临时图片存放地址(这个工具类Word2003ToHtmlAndSaveImage的方法存到了系统临时文件夹里)
* @param file
* @return
* @throws IOException
*/
public static Map<String, String> getImageMaps(String docsTempImages, MultipartFile file) throws Exception {
//返回map
HashMap<String, String> map = new HashMap<>();
if (file.getOriginalFilename().endsWith(".docx") || file.getOriginalFilename().endsWith(".DOCX")) {
//获取存在word里的图片文件
InputStream in = file.getInputStream();
XWPFDocument document = new XWPFDocument(in);
List<XWPFParagraph> paragraphs = document.getParagraphs();
if (CollUtil.isNotEmpty(paragraphs)) {
paragraphs.forEach(p -> {
List<XWPFRun> runs = p.getRuns();
if (CollUtil.isNotEmpty(runs)) {
runs.forEach(r -> {
List<XWPFPicture> pictures = r.getEmbeddedPictures();
if (CollUtil.isNotEmpty(pictures)) {
pictures.forEach(c -> {
//这里找到word中的图片的名字和数据
XWPFPictureData pictureData = c.getPictureData();
String fileName = pictureData.getFileName();
byte[] data = pictureData.getData();
String localUrl = getImgUrl(fileName, data);
map.put(pictureData.getFileName(), localUrl);
});
}
});
}
});
}
} else if (file.getOriginalFilename().endsWith(".doc") || file.getOriginalFilename().endsWith(".DOC")) {
try {
File dir = new File(docsTempImages);
//如果目录不为空遍历存储到项目中
if (!FileUtil.isEmpty(dir)) {
Arrays.asList(FileUtil.ls(docsTempImages)).forEach(f -> {
String name = f.getName();
BufferedInputStream inputStream = FileUtil.getInputStream(f);
String localUrl = getOssImgUrl(name, inputStream);
map.put(name, localUrl);
});
}
} finally {
//删除临时文件夹
FileUtil.del(docsTempImages);
}
}
return map;
}
private static String getOssImgUrl(String name, BufferedInputStream inputStream) {
Long res = new Date().getTime();
//设置文件存储路径,可以存放在你想要指定的路径里面
// 新文件名
String newFileName = res + name.substring(name.lastIndexOf("."));
String localUrl = null;
try {
localUrl = MinioUtil.upload(inputStream, newFileName);
} catch (Exception e) {
e.printStackTrace();
}
return localUrl;
}
private static String getImgUrl(String fileName, byte[] data) {
if (data.length == 0) {
return "";
}
//保存到本地获取url
Long res = new Date().getTime();
//设置文件存储路径,可以存放在你想要指定的路径里面
// 新文件名
String newFileName = res + fileName.substring(fileName.lastIndexOf("."));
InputStream inputStream = new ByteArrayInputStream(data);
String localUrl = null;
try {
localUrl = MinioUtil.upload(inputStream, newFileName);
} catch (Exception e) {
e.printStackTrace();
}
return localUrl;
}
/**
* 替换html图片的路径
*
* @param html
* @param imageMaps
* @throws
*/
public static String replaceImgToLocal(String html, Map<String, String> imageMaps, boolean wordType) {
String returnHtml = "";
//获取当前服务器ip和端口用于图片路径
org.jsoup.nodes.Document doc = Jsoup.parse(html);
// 获取 带有src属性的img元素
Elements imgTags = doc.select("img[src]");
//替换图片
for (org.jsoup.nodes.Element element : imgTags) {
String imageName = StrUtil.subAfter(element.attr("src"), "/", true);
//根据名字获取map中的url,并覆盖之前存的word中的路径
element.attr("src", imageMaps.get(imageName));
}
returnHtml = doc.toString();
//doc格式样式在外部,所以要把style从外部移到内部
if (wordType) {
returnHtml = JsoupUtils.changeHtmlCssLineStyle(doc.toString());
}
return returnHtml;
}
}
使用Apache POI和Jsoup将Word文档转换为HTML的更多相关文章
- Java中用Apache POI生成excel和word文档
概述: 近期在做项目的过程中遇到了excel的数据导出和word的图文表报告的导出功能.最后决定用Apache POI来完毕该项功能.本文就项目实现过程中的一些思路与代码与大家共享.同一时候.也作为自 ...
- 使用poi根据模版生成word文档,支持插入数据和图片
一.制作word模版,${xxxx}是一会要替换的内容,最下面的表格是要插入数据,根据是否以$开头来判断是需要替换还是插入数据, 注意如果是需要插入数据,制作的表格模版需要一行空行,也只能有一行空行, ...
- poi根据模板导出word文档
POI结构与常用类 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI ...
- 利用POI操作不同版本号word文档中的图片以及创建word文档
我们都知道要想利用java对office操作最经常使用的技术就应该是POI了,在这里本人就不多说到底POI是什么和怎么用了. 先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写 ...
- 使用Java POI来选择提取Word文档中的表格信息
通过使用Java POI来提取Word(1992)文档中的表格信息,其中POI支持不同的ms文档类型,在具体操作中需要注意.本文主要是通过POI来提取微软2003文档中的表格信息,具体code如下(事 ...
- 使用Aspose.Words将Word文档转换为Tiff格式图片文件
用Aspose组件的优点是操作Word文档不需要安装Office就可以实现. 首先需要引用Aspose.Words.dll,链接地址:链接:https://pan.baidu.com/s/1rJvjp ...
- Java 使用 jacob 将 word 文档转换为 pdf 文件
网上查询了许许多多的博客,说利用 poi.iText.Jsoup.jdoctopdf.使用 jodconverter 来调用 openOffice 的服务来转换等等,我尝试了很多种,但要么显示不完全, ...
- 使用VBA将批量的WORD文档转换为PDF
Sub BatchConvertToPDF() Dim destFolderPath As String destFolderPath = GetFolderPath If destFolderPat ...
- DEV word文档转换为pdf文件
引用aspose.net控件2.0. docement doc=new document(文件路径和名称); doc.save(输出路径\file.pdf);
- Java将数据写入word文档(.doc)
Java可用org.apache.poi包来操作word文档.org.apache.poi包可于官网上下载,解压后各jar作用如下图所示: 可根据需求导入对应的jar. 一.HWPFDocument类 ...
随机推荐
- 【LeetCode二叉树#01】二叉树的遍历(递归/迭代)
二叉树递归遍历 写递归算法时候需要遵循的三个点: 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函 ...
- expect tcl 摘录
目录 部分参考来源说明 例子 expect命令 核心命令有三个 spawn.expect.send 其他expect命令 expect命令的选项 变量 tcl摘录 数据类型 符号 命令 其他说明 部分 ...
- OpenCV开发笔记(七十六):相机标定(一):识别棋盘并绘制角点
前言 知道图像畸变矫映射的原理之后,那么如何得到相机的内参是矫正的第一步,内参决定了内参矩阵(中心点.焦距等),用内参矩阵才能计算出投影矩阵,从而将原本畸变的图像矫正为平面投影图像. 本篇描述了 ...
- Dyno File Utils - VSCode Extension 新建目录 新建文件 很好用
Dyno File Utils - VSCode Extension 新建目录 新建文件 很好用 快捷键 绑定了 ctrl + n
- dangle = dance + toggle - dan 向上跳 gle 摆动
dangle = dance + toggle - dan 向上跳 gle 摆动 dangle 英 [ˈdæŋɡl] 美 [ˈdæŋɡl] v.悬垂;悬挂;悬荡;悬摆;提着(某物,任其自然下垂或摆动) ...
- 宝塔Linux面板 https://www.bt.cn/ 服务器环境搭建软件
宝塔Linux面板 https://www.bt.cn/
- 【机器学习】统计学习方法读书笔记-EM算法(期望最大化算法)
Expectation Maximization,EM算法是带有隐变量的概率模型参数的极大似然估计(MLE为给定参数,观测数据出现/生成的可能性). 如下为<统计机器学习>中对应EM算法的 ...
- day03-1-查看账单&结账功能
满汉楼03 4.功能实现05 4.8查看账单功能 按照之间搭建起来的框架,在BillService编写方法 4.8.1代码实现 1.修改Bill类 重写Bill类中的toString方法 @Overr ...
- 大年学习linux(第四节---文件权限)
四.文件权限 文件类型 Linux文件类型和linux文件的文件名所代表的意义是两个不同的概念.我们通过一般应用程序而创建的比如 file.txt.file.tar.gz ,这些文件虽然要用不同的程序 ...
- 浅谈React与SolidJS对于JSX的应用
React将JSX这一概念深入人心.但,并非只有React利用了JSX,VUE.SolidJS等JS库或者框架都使用了JSX这一概念.网上已经有大量关于JSX的概念与形式的讲述文章,不在本文的讨论范围 ...