编辑
2024-08-12
工具
0
请注意,本文编写于 249 天前,最后修改于 249 天前,其中某些信息可能已经过时。

目录

前言
安装与简单使用
Windows平台
Linux平台
命令行参数使用
个性化配置
顶栏实现代码
后记

前言

由于个人的笔记资料大多是用latex编写的,经过编译得到pdf。但是pdf并不方便在线浏览访问,也不能被搜索引擎识别

为了更方便浏览,考虑将文档转换为html共享。首先找到的latex2html这个项目,经过一番折腾,无果,于是考虑退而求其次,能否将pdf转换为html,一番搜索后找到了pdf2htmlEX这个项目,它可以近乎无损地将pdf文件转换为html

项目地址: pdf2htmlEX

安装与简单使用

实际上项目有提供Linux版本的Release,奈何在服务器上跑并没有本地舒服。今天找到了Windows下的Release,就先从Windows讲起吧

Windows平台

虽然很早就知道了这个项目,但是它没有Windows的Release。由于懒得编译,而且还不会交叉编译,于是只能放弃。今天经过搜索发现已经有人编译好了Windows的版本

pdf2htmlEX Windows Version-RubyPdf Software Download Center

比较可惜的是它最新的Release只到0.14.6,而此时项目已经更新到了0.18。不过好在实际用起来没有什么太大差别,估计是因为我的文档比较简单吧

下载解压后得到一个文件夹,里面的的内容重要的是一个可执行文件pdf2htmlEX.exe和一个文件夹data。简单的方法就是在命令行执行

cmd
./pdf2htmlEX.exe xxx.pdf

其中xxx.pdf是需要转换的pdf,随后就可以在相同文件夹下得到xxx.htmldata文件夹是主题,可以自定义,留待下文再说

Linux平台

项目提供了0.18.8的Release v0.18.8.rc1

由于我用的是Ubuntu,选择下载 pdf2htmlEX-0.18.8.rc1-master-20200630-Ubuntu-bionic-x86_64.deb

shell
wget https://github.com/pdf2htmlEX/pdf2htmlEX/releases/download/v0.18.8.rc1/pdf2htmlEX-0.18.8.rc1-master-20200630-Ubuntu-bionic-x86_64.deb

然后使用apt安装

shell
sudo apt install ./pdf2htmlEX-0.18.8.rc1-master-20200630-Ubuntu-bionic-x86_64.deb

在使用时直接输入命令就可以了

shell
pdf2htmlEX xxx.pdf

就可以在当前目录下生成xxx.html

另外需要说明的是,用该方式安装的主题目录位于

shell
/usr/local/share/pdf2htmlEX

命令行参数使用

我用到的命令行参数有两个

shell
pdf2htmlEX --dest-dir dddd xxx.pdf

用于将转换后的xxx.html放到dddd目录下

shell
pdf2htmlEX --dpi 300 xxx.pdf

可以设置图片的dpi为300,默认的是144,比较模糊

个性化配置

总体有一个配置文件manifest,它是一个类似于html结构的文件

html
""" <!DOCTYPE html> <!-- Created by pdf2htmlEX (https://github.com/coolwanglu/pdf2htmlex) --> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8"/> <meta name="generator" content="pdf2htmlEX"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> """ @base.min.css # fancy CSS styles - Optional @fancy.min.css # PDF specific CSS styles - Do not modify $css @topbar.css """ <script> try{ pdf2htmlEX.defaultViewer = new pdf2htmlEX.Viewer({}); }catch(e){} </script> """ #TEST_IGNORE_END """ <title></title> </head> <body> """ """ <div id="sidebar" class="opened"> """ # container of outlines """ <div id="outline"> """ $outline """ </div> </div> """ """ <div id="page-container"> """ """ <div id="topbar"> <button id="sidebar-toggle" class="top-btn">Outline</button> <div id="scale"> <button id="zoom-in" class="top-btn">+</button> <button id="zoom-out" class="top-btn">-</button> <button id="auto-zoom" class="top-btn">auto</button> </div> </div> """ $pages """ </div> """ """ <div class="loading-indicator"> """ @pdf2htmlEX-64x64.png """ </div> """ @topbar.js </body> </html> """

猜测大概工作过程是进行字符串替换,其中由三个双引号包裹起来的内容将会被直接插入生成的html中

""" ... """

@开头的是文件,文件的内容将会按照类型加入。若是js脚本,会加上<script>标签放入,若是css,则会以css的形式加入,若是图片,则会以Base64编码后放入。最后生成一个相当大的html文件,不依赖于别的文件,可以直接在浏览器打开

这些东西是允许自由发挥的,像我就给他加了一个顶栏,加入了<div id="topbar">标签,topbar.css样式,和topbar.js脚本,与正平常的网站开发没有什么太大区别

而由$开头的是pdf2html由pdf文件转换得到的结果。$pages是转换出的页面,$css是转换出的css样式,这个是无法进行修改的

但是它转换出来依然是html,这就意味着我们可以用js脚本通过dom去操作它。生成的html大概是这样的一个结构

html
<head> ... </head> <body> <div id="sidebar"> ... </div> <div id="page-container"> <div id="..." class="pf w0 h0" ...> ... </div> ... </div> </body>

sidebar是它的目录展示,如果加上classopened,则会显示,若没有则会关闭,并且打开关闭的动画非常丝滑...(咳)

不过非常离奇的是不管在page-container外面写什么东西,甚至给它套层壳,都会导致sidebar无法展示,非常见鬼。我也只能就把顶栏写在page-container里面

操作sidebarpage-container可以通过id实现

js
const sidebar = document.getElementById('sidebar'); var container = document.getElementById('page-container');

文档的页面(就是pdf的一页一页)有一个共同的类名pf w0 h0w0控制的是它的宽度,h0控制的是它的高度。理论上应该用w0h0控制宽高然而实际测试并不能修改成功非常蛋疼,因而选择获取pf操作,不管那俩

js
var pf=document.getElementsByClassName('pf'); for(var i=0;i<pf.length;i++){ pf[i] ... ; }

值得欣慰的是w0h0的宽高是直接写死在css里的,推测应该是根据pdf的大小确定的

另外我还自己写了一个缩放功能,写的时候需要注意以下几点

  • 由于页面内部元素复杂,应该在pf类上添加transform: scale()属性
  • 不可以将pf包起来整体添加缩放属性,这会使所有pf都不显示内容
  • 需要注意同步修改pfmargin属性,因为没有办法直接修改它的宽高,缩放会引起页面重叠
  • 需要在缩放时将page-containertop属性设为一定的负值,以抵消pfmargin属性引起的上部空白
  • 缩放时需要注意控制滚动条的位置,使其在页面中的比例不变,否则会出现页面一缩放就找不到看的是哪的情况

顶栏实现代码

html部分已经在前文的manifest展示过,下面是topbar.css

js
#topbar{ display: flex; justify-content: space-between; align-items: center; background-color: #ffffff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); height: 60px; /* 悬浮置顶 */ position: fixed; top: 0; left: 0; right: 0; z-index: 1000 } #sidebar{ margin-top: 60px; } #page-container{ margin-top: 60px; } .top-btn{ display: inline-block; padding: 0 20px; height: 60px; line-height: 60px; color: #333; font-size: 16px; cursor: pointer; transition: all .3s; border: 0; background-color: #ffffff; transition: all .3s; } .top-btn:hover{ background-color: #f5f5f5; }

接下来是topbar.js

js
// Get the button element const sidebar_button = document.getElementById('sidebar-toggle'); // Get the sidebar element const sidebar = document.getElementById('sidebar'); var container = document.getElementById('page-container'); //检查是否有打开的侧边栏 //获取w0的宽度 //获取h0的高度 var w0=document.getElementsByClassName('w0'); var h0=document.getElementsByClassName('h0'); var w0_width=parseFloat(getComputedStyle(w0[0]).width); var h0_height=parseFloat(getComputedStyle(h0[0]).height); var pf=document.getElementsByClassName('pf'); var margin=parseFloat(getComputedStyle(pf[0]).margin); var stat=false; if (sidebar.classList.contains('opened')) { // Remove the "opened" class from the sidebar stat=true; } var scale=1; // Add event listener to the button sidebar_button.addEventListener('click', function() { // Add the "opened" class to the sidebar if(stat){ sidebar.classList.remove('opened'); stat=false; } else { sidebar.classList.add('opened'); stat=true; } }); zoom_in_button=document.getElementById('zoom-in'); // 按下时给所有'pf'类添加‘transform’属性 zoom_in_button.addEventListener('click',function(){ ratio=container.scrollTop/container.scrollHeight; scale+=0.1; var pf=document.getElementsByClassName('pf'); for(var i=0;i<pf.length;i++){ pf[i].style.transform='scale('+scale+')'; pf[i].style.margin=margin+h0_height*(scale-1)+'px auto'; } container.style.top=min(0,-h0_height*(scale-1)/2)+'px'; container.scrollTo(0,ratio*container.scrollHeight); }); zoom_out_button=document.getElementById('zoom-out'); // 按下时给所有'pf'类添加‘transform’属性 zoom_out_button.addEventListener('click',function(){ ratio=container.scrollTop/container.scrollHeight; scale-=0.1; var pf=document.getElementsByClassName('pf'); for(var i=0;i<pf.length;i++){ pf[i].style.transform='scale('+scale+')'; pf[i].style.margin=margin+h0_height*(scale-1)+'px auto'; } container.style.top=min(0,-h0_height*(scale-1)/2)+'px'; container.scrollTo(0,ratio*container.scrollHeight); }); var auto_zoom_button=document.getElementById('auto-zoom'); auto_zoom_button.addEventListener('click',function(){ ratio=container.scrollTop/container.scrollHeight; //获取page-container的宽度 var page_container=document.getElementById('page-container'); var page_container_width=parseFloat(getComputedStyle(page_container).width); scale=page_container_width/w0_width-0.1; var pf=document.getElementsByClassName('pf'); for(var i=0;i<pf.length;i++){ pf[i].style.transform='scale('+scale+')'; pf[i].style.margin=margin+h0_height*(scale-1)+'px auto'; } container.style.top=min(0,-h0_height*(scale-1)/2)+'px'; container.scrollTo(0,ratio*container.scrollHeight); }); function min(a,b){ if(a>b) return b; else return a; }

这一个缩放可真是写死人了(╯‵□′)╯︵┻━┻

后记

已经用它将我的所有pdf文档都转换成了html,现在存放在 https://神里绫华的狗.top(不要在意这个名字,咳)

只能感叹pdf2htmlEX是真的强的,肉眼完全看不出来转换前后的差别。更多的信息请参考项目的wiki

https://github.com/pdf2htmlEX/pdf2htmlEX/wiki

完结撒花 ★,°:.☆( ̄▽ ̄)/$:.°★

本文作者:GBwater

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!