page2pdf_server 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +59 -23
  2. package/package.json +24 -18
  3. package/src/CSS/345/205/274/345/256/271/346/200/247.txt +69 -0
  4. package/src/__tests__/UrltoPdf/generatePdf.test.d.ts +1 -0
  5. package/{__tests__ → src/__tests__}/UrltoPdf/generatePdf.test.ts +1 -1
  6. package/src/__tests__/UrltoPdf/pdfSplit.test.d.ts +1 -0
  7. package/{__tests__ → src/__tests__}/UrltoPdf/pdfSplit.test.ts +1 -1
  8. package/src/__tests__/helpers/index.d.ts +2 -0
  9. package/src/__tests__/home.test.d.ts +1 -0
  10. package/{__tests__ → src/__tests__}/home.test.ts +1 -1
  11. package/src/app.ts +8 -2
  12. package/src/components/home/controller.ts +8 -3
  13. package/src/components/home/pdfController.ts +6 -5
  14. package/src/components/home/services.ts +3 -3
  15. package/src/components/home/splitController.ts +6 -5
  16. package/src/components/home/validators.ts +1 -1
  17. package/src/db/home.ts +3 -3
  18. package/src/helpers/apiResponse.ts +1 -1
  19. package/src/helpers/dataSanitizers.ts +1 -0
  20. package/src/helpers/error/TimeOutError.ts +1 -1
  21. package/src/helpers/loggers.ts +5 -3
  22. package/src/index.ts +6 -1
  23. package/src/middlewares/errorHandler.ts +1 -1
  24. package/src/routes/index.ts +2 -2
  25. package/src/types/request/config.ts +7 -97
  26. package/src/types/request/home.ts +1 -1
  27. package/src/types.d.ts +97 -0
  28. package/src/utils/pdfgen.ts +64 -17
  29. package/src//346/265/213/350/257/225.txt +26 -2
  30. package/test//346/211/223/345/215/260/346/234/215/345/212/241.http +17 -0
  31. package/tsconfig.json +9 -6
  32. package/.husky/pre-commit +0 -6
  33. package/.husky/pre-push +0 -4
  34. package/.idea/codeStyles/Project.xml +0 -58
  35. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  36. package/.idea/encodings.xml +0 -7
  37. package/.idea/inspectionProfiles/Project_Default.xml +0 -7
  38. package/.idea/modules.xml +0 -8
  39. package/.idea/page2pdf-server.iml +0 -12
  40. package/.idea/tenstack-starter-main.iml +0 -12
  41. package/.idea/vcs.xml +0 -6
  42. /package/{__tests__ → src/__tests__}/helpers/index.ts +0 -0
@@ -1,95 +1,3 @@
1
- /**一次作业的模型配置;
2
- * 若本对象为空{}的话:默认是按照修改时间的顺序简易模式地合并当前工作目录的所有pdf文件。
3
- * 若某个URL不正常的,很可能无法触发页面加载完成,导致作业一致无法继续下去,大大超出预期执行时间。URL对应网页若不是一次性加载完成还会陆陆续续修改内容的就是这种情况造成死等长时间没结果。
4
- * */
5
- export interface ConfigRoot<T> {
6
- //是否生成合并的pdf:正常情况下, 默认=true进行files输出pdf全部做合并的。 除非files[]也是空的情形。
7
- //但若需对任一个URL叠加新页眉页脚的,merge就不能=false的。
8
- merge?: boolean;
9
- //重定义 合并的pdf文件名, 否则默认名。不需要加 .pdf结尾的
10
- name: string;
11
- //双面打印的合并输出pdf, 默认=true, 表示合并输出的pdf考虑到双面打印的页眉页脚的布局差异化情况了。
12
- doubleSide?: boolean;
13
- //统一一整份应该用的页眉页脚
14
- //假如files[]里面有些url自己也定义了lay{localSumNo=false}的页眉页脚输出配置,只能忽略掉它们,页码总数不算他们的,页码连续编号也不算它们的占坑:最好都挪到最后面。
15
- lay?: HeadFooter;
16
- //每一个独立的pdf生成:
17
- files: [T];
18
-
19
- //共用一个浏览器窗口 默认=true
20
- singleTab?: boolean;
21
- //自动关闭浏览器窗口 默认=false
22
- closeTab?: boolean;
23
-
24
- //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
25
- headerTemplate?: string;
26
- footerTemplate?: string;
27
- headerTemplateL?: string;
28
- footerTemplateL?: string;
29
- //第二阶段页眉页脚生成的浏览器执行窗口的targetId,不可配置。
30
- CDPtab?: string;
31
- }
32
-
33
- /**等待输出的每个独立文件:URL,这些文件可能要合并。
34
- * @前提条件 是:每个url独立文件生成的PDF,它的纸张大小必须保证同一个大小尺寸, size: 必须唯一,但是纸张方向在某些约束条件中可以横屏竖屏混合的。
35
- * 物理打印机:纸张适配,横竖方向还好能自动调节,size 真实打印纸张尺寸就不好自动处理, 不一样的尺寸?最好拆解pdf。
36
- * 标准纸张大小的:静态html内CSS定义横竖纸张方向混合的:用reverseRanges参数设置部分纸张反转纸张方向,pageRanges=''的前提下:配置比如'1-5, 8, 11-13'和landscape参数设置相反方向。
37
- * */
38
- export interface FileTransform {
39
- //[必须配置的] 特殊的前缀是 http:// https:// 没有这俩个的都是本地工作目录的文件全名(含文件类型后缀 *.pdf *.*)。
40
- //任意的本地文件类型,只要可以被Chrome装载并能够支持打印预览的都可以。http打头的网页必须确保已经登录了,也就是遗留cockies token,不能要求交互登录。本地文件不能要求输入口令。
41
- //不支持*.xls *.doc文件;不支持的格式实际在浏览器拖拽窗口后会蜕变成了下载形式的。被加密的文件必须提前解密,网站登录需提前解决。
42
- //【特殊问题】若URL网页动态化太离谱,周期性地不间断地更新页面,没法触发加载结束事件的,只能手动在浏览器查看打印另存pdf,然后把手动生成pdf合并进来。Tab切换会主动刷新的也不触发。
43
- url: string;
44
- //输出本地工作目录的文件名, 不需要加 .pdf结尾的 【注意】如果out为空表示url是pdf的没必要转换的要直接进入合并步骤。
45
- //【特别】必须配置唯一性 的本地 工作目录的文件名,同名的被直接覆盖了。
46
- out: string;
47
-
48
- //是否汇总合并阶段省略本url,不合并进去,那就是单独独立的pdf输出了。默认=true是合并进去。 和是否打印页眉页脚或页眉统计页数没有绝对关系的。
49
- merge?: boolean;
50
-
51
- //默认取值都是=true; 第一阶段不会生成页眉页脚的,汇总第二阶段这个参数才会生效!
52
- //这里配置displayHeaderFooter优先级最高。
53
- //页眉页脚如何分开控制是否打印的: 可以把lay{head,foot}其中一个配置串给设置为null,null就代表不输出。例如head=null就不输出页眉,但是页脚照旧打印的。本url的配置优先于汇总pdf配置。
54
- //若ConfigRoot<T>.merge=false那么必然导致FileTransform.merge强制=false,每个独立pdf页码独立的独立都从1开始编号吗还需要打印吗,页眉页脚需要打印吗?这个情况页眉页脚打印的默认值改成false;
55
- displayHeaderFooter: boolean;
56
-
57
- //【特别注意】frNo 可能和 headFrom 配置矛盾。
58
- //本url打印:从第几页才开始页眉页脚的打印,#页码同样也是在这之后才可能计数和编号!。默认值headFrom=1:就是第一页就开始打印页眉页脚的。
59
- //书本封面页情况的。这个参数有最高优先级。 【注意】和frNo设置相互影响, 没有页眉页脚就失去页码意义了。若真的违反了可能页码不能连续输出的,被隐藏了页码缘故。
60
- headFrom?: number;
61
- //本url打印后,从本URL输出的第几页开始才进行的页码序号的顺序输出的,前面几页不打印页码(但是页眉页脚要打印)。默认值=1全部都打页码。若frNo=0全部不打页码的。
62
- //假如displayHeaderFooter=false也即页码无法显示出来的情况:请申明frNo=0; 不然默认是连续页码的,不打印的也有占用页码的隐藏的连续数字啊。
63
- //注意若有配置 headFrom 的要协调好。
64
- frNo?: number;
65
-
66
- //是否对页码支持连续编号: Continuous numbering 是跟随汇总合并的页码 基数合计。【注意】本配置单个url范围,单个url不能混合本地页码和全局页面两种!
67
- //统计页数是否本URL独立自己范围之内进行的汇总计数。比如书本目录有多页的可以独立统计页码序号以及总页数的。默认=false;
68
- localSumNo?: boolean;
69
- //本url对应的部分应该用的页眉页脚,覆盖掉合并pdf的相对应设置。页面上只能支持输出一次页眉页脚,不重叠做输出。
70
- //若lay{localSumNo=false}只能固定支持本url自己内部的页码统计顺序编号,不考虑合并pdf总页数带来的影响的。 还是?预设其它部分的页数统计总数之后?再做偏移页码编写?
71
- lay: PartHeadFooter;
72
- //前端声明本url在第一阶段打印输出后,生成的pdf应该有几页。 count没有设置的救不会做异常检查的。不是第二阶段的计数:双面情况可能增加空白页
73
- count?: number;
74
- //双面打印的 默认=true, 表示独立分开输出的pdf文件的:考虑到双面打印的页眉页脚的布局差异化情况了。
75
- //合并输出merge=true的情况:该参数无效,要看汇总配置的哪一个 # ConfigRoot<T>{ doubleSide: }字段。
76
- doubleSide: boolean;
77
- //双面打印的情形:必须确保本URL的第一个页是正好右手边(书本翻页的奇数号页码)开始的位置页。正常第一个URL首页面就是双面打印的右手边位置页;默认值=false不必确保.
78
- rightHand: boolean;
79
-
80
- //页码是罗马数字;论文目录需要的;默认=false阿拉伯数字。"I","II","III","IV","V","VI","VII","VIII","IX" "X"XI"XII"表盘符号
81
- //roman只能针对本URL启用;数字转换范围最大支持1到12,超过了便改阿拉伯数字,且只针对pageNumber有效, totalPages不会采用。
82
- roman?: boolean;
83
-
84
- //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
85
- headerTemplate?: string;
86
- footerTemplate?: string;
87
- headerTemplateL?: string;
88
- footerTemplateL?: string;
89
- //第一阶段Url转pdf的浏览器执行窗口的targetId,不可配置。
90
- CDPtab?: string;
91
- }
92
-
93
1
  /*看 Page.printToPDF()文档说明的: 可以使用的注入参数:
94
2
  date: formatted print date
95
3
  title: document title
@@ -99,7 +7,8 @@ export interface FileTransform {
99
7
  For example, <span class=title></span> would generate span containing the title.
100
8
  */
101
9
 
102
- /**页眉页脚声明;前提条件是页眉页脚htm描述里面:不应该把-NOT_DISPLAY- ${pageNumber} ${totalPages}这三个保留字字符串当作普通文字输出的。
10
+ /**页眉页脚声明;前提条件是页眉页脚htm描述里面: 上一个版本保留字 ${pageNumber} ${totalPages}
11
+ * 不应该把 -NOT_DISPLAY- ~pageNumber~ ~totalPages~ 这三个 保留字字符串当作普通文字输出的。
103
12
  * 前端发送数据包时刻,页眉页脚的脚本需要在 HTML转JSON 工具网站 进行转换处理后的;网站地址 https://uutool.cn/html2json/ 转换htm模板后是数组[string]
104
13
  * 实际上也就进行拆分多行字符串拼接数组,还有把html语法中的 ""引号 进行转义 style="position: 变成 style=\\\"position: 处置的。
105
14
  * */
@@ -112,10 +21,11 @@ export interface HeadFooter {
112
21
  //双面打印:右手边位置的,或单面打印使用
113
22
  foot?: string | string[] | null; //实际前端发过来却是[string]的也可以啊。
114
23
  /**可注入3个参数"特殊标记字符串"如下: 服务端依据参数来对注入的html进行修改的。
115
- * ${pageNumber}
116
- * ${totalPages}
117
- * -NOT_DISPLAY-
118
- * 这三个分别代表 页码 总页数 以及页码<div style=""></div>中的可替代占位位置。-NOT_DISPLAY-在后端要直接替代成display:none;的CSS标记字符串!其它2个替换成数字号码。
24
+ * ~pageNumber~
25
+ * ~totalPages~
26
+ * -NOT_DISPLAY- 有页码才能显示,无页码就隐藏的标记。
27
+ * 这三个分别代表 页码 总页数 以及页码<div style=""></div>中的可替代占位位置。
28
+ * 其它2个替换成数字号码。
119
29
  * */
120
30
  //双面打印:左手边位置的
121
31
  headL?: string | string[] | null;
@@ -1,3 +1,3 @@
1
- import CONFIG from "@/configEnv";
1
+ import CONFIG from "../../configEnv";
2
2
 
3
3
  export type getAppInfoQuery = `${Lowercase<keyof typeof CONFIG.APP>}`;
package/src/types.d.ts ADDED
@@ -0,0 +1,97 @@
1
+ import { HeadFooter, PartHeadFooter } from "@/types/request/config";
2
+
3
+ /**一次作业的模型配置;
4
+ * 若本对象为空{}的话:默认是按照修改时间的顺序简易模式地合并当前工作目录的所有pdf文件。
5
+ * 若某个URL不正常的,很可能无法触发页面加载完成,导致作业一致无法继续下去,大大超出预期执行时间。URL对应网页若不是一次性加载完成还会陆陆续续修改内容的就是这种情况造成死等长时间没结果。
6
+ * */
7
+ export interface ConfigRoot<T> {
8
+ //是否生成合并的pdf:正常情况下, 默认=true进行files输出pdf全部做合并的。 除非files[]也是空的情形。
9
+ //但若需对任一个URL叠加新页眉页脚的,merge就不能=false的。
10
+ merge?: boolean;
11
+ //重定义 合并的pdf文件名, 否则默认名。不需要加 .pdf结尾的
12
+ name: string;
13
+ //双面打印的合并输出pdf, 默认=true, 表示合并输出的pdf考虑到双面打印的页眉页脚的布局差异化情况了。
14
+ doubleSide?: boolean;
15
+ //统一一整份应该用的页眉页脚
16
+ //假如files[]里面有些url自己也定义了lay{localSumNo=false}的页眉页脚输出配置,只能忽略掉它们,页码总数不算他们的,页码连续编号也不算它们的占坑:最好都挪到最后面。
17
+ lay?: HeadFooter;
18
+ //每一个独立的pdf生成:
19
+ files: [T];
20
+
21
+ //共用一个浏览器窗口 默认=true
22
+ singleTab?: boolean;
23
+ //自动关闭浏览器窗口 默认=false
24
+ closeTab?: boolean;
25
+
26
+ //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
27
+ headerTemplate?: string;
28
+ footerTemplate?: string;
29
+ headerTemplateL?: string;
30
+ footerTemplateL?: string;
31
+ //第二阶段页眉页脚生成的浏览器执行窗口的targetId,不可配置。
32
+ CDPtab?: string;
33
+ }
34
+
35
+ // types.d.ts
36
+ /**等待输出的每个独立文件:URL,这些文件可能要合并。
37
+ * @前提条件 是:每个url独立文件生成的PDF,它的纸张大小必须保证同一个大小尺寸, size: 必须唯一,但是纸张方向在某些约束条件中可以横屏竖屏混合的。
38
+ * 物理打印机:纸张适配,横竖方向还好能自动调节,size 真实打印纸张尺寸就不好自动处理, 不一样的尺寸?最好拆解pdf。
39
+ * 标准纸张大小的:静态html内CSS定义横竖纸张方向混合的:用reverseRanges参数设置部分纸张反转纸张方向,pageRanges=''的前提下:配置比如'1-5, 8, 11-13'和landscape参数设置相反方向。
40
+ * */
41
+ export interface FileTransform {
42
+ //[必须配置的] 特殊的前缀是 http:// https:// 没有这俩个的都是本地工作目录的文件全名(含文件类型后缀 *.pdf *.*)。
43
+ //任意的本地文件类型,只要可以被Chrome装载并能够支持打印预览的都可以。http打头的网页必须确保已经登录了,也就是遗留cockies token,不能要求交互登录。本地文件不能要求输入口令。
44
+ //不支持*.xls *.doc文件;不支持的格式实际在浏览器拖拽窗口后会蜕变成了下载形式的。被加密的文件必须提前解密,网站登录需提前解决。
45
+ //【特殊问题】若URL网页动态化太离谱,周期性地不间断地更新页面,没法触发加载结束事件的,只能手动在浏览器查看打印另存pdf,然后把手动生成pdf合并进来。Tab切换会主动刷新的也不触发。
46
+ url: string;
47
+ //输出本地工作目录的文件名, 不需要加 .pdf结尾的 【注意】如果out为空表示url是pdf的没必要转换的要直接进入合并步骤。
48
+ //【特别】必须配置唯一性 的本地 工作目录的文件名,同名的被直接覆盖了。
49
+ out: string;
50
+
51
+ //是否汇总合并阶段省略本url,不合并进去,那就是单独独立的pdf输出了。默认=true是合并进去。 和是否打印页眉页脚或页眉统计页数没有绝对关系的。
52
+ merge?: boolean;
53
+
54
+ //默认取值都是=true; 第一阶段不会生成页眉页脚的,汇总第二阶段这个参数才会生效!
55
+ //这里配置displayHeaderFooter优先级最高。
56
+ //页眉页脚如何分开控制是否打印的: 可以把lay{head,foot}其中一个配置串给设置为null,null就代表不输出。例如head=null就不输出页眉,但是页脚照旧打印的。本url的配置优先于汇总pdf配置。
57
+ //若ConfigRoot<T>.merge=false那么必然导致FileTransform.merge强制=false,每个独立pdf页码独立的独立都从1开始编号吗还需要打印吗,页眉页脚需要打印吗?这个情况页眉页脚打印的默认值改成false;
58
+ displayHeaderFooter: boolean;
59
+
60
+ //【特别注意】frNo 可能和 headFrom 配置矛盾。
61
+ //本url打印:从第几页才开始页眉页脚的打印,#页码同样也是在这之后才可能计数和编号!。默认值headFrom=1:就是第一页就开始打印页眉页脚的。
62
+ //书本封面页情况的。这个参数有最高优先级。 【注意】和frNo设置相互影响, 没有页眉页脚就失去页码意义了。若真的违反了可能页码不能连续输出的,被隐藏了页码缘故。
63
+ headFrom?: number;
64
+ //本url打印后,从本URL输出的第几页开始才进行的页码序号的顺序输出的,前面几页不打印页码(但是页眉页脚要打印)。默认值=1全部都打页码。若frNo=0全部不打页码的。
65
+ //假如displayHeaderFooter=false也即页码无法显示出来的情况:请申明frNo=0; 不然默认是连续页码的,不打印的也有占用页码的隐藏的连续数字啊。
66
+ //注意若有配置 headFrom 的要协调好。
67
+ frNo?: number;
68
+
69
+ //是否对页码支持连续编号: Continuous numbering 是跟随汇总合并的页码 基数合计。【注意】本配置单个url范围,单个url不能混合本地页码和全局页面两种!
70
+ //统计页数是否本URL独立自己范围之内进行的汇总计数。比如书本目录有多页的可以独立统计页码序号以及总页数的。默认=false;
71
+ localSumNo?: boolean;
72
+ //本url对应的部分应该用的页眉页脚,覆盖掉合并pdf的相对应设置。页面上只能支持输出一次页眉页脚,不重叠做输出。
73
+ //若lay{localSumNo=false}只能固定支持本url自己内部的页码统计顺序编号,不考虑合并pdf总页数带来的影响的。 还是?预设其它部分的页数统计总数之后?再做偏移页码编写?
74
+ lay: PartHeadFooter;
75
+ //前端声明本url在第一阶段打印输出后,生成的pdf应该有几页。 count没有设置的救不会做异常检查的。不是第二阶段的计数:双面情况可能增加空白页
76
+ count?: number;
77
+ //双面打印的 默认=true, 表示独立分开输出的pdf文件的:考虑到双面打印的页眉页脚的布局差异化情况了。
78
+ //合并输出merge=true的情况:该参数无效,要看汇总配置的哪一个 # ConfigRoot<T>{ doubleSide: }字段。
79
+ doubleSide: boolean;
80
+ //双面打印的情形:必须确保本URL的第一个页是正好右手边(书本翻页的奇数号页码)开始的位置页。正常第一个URL首页面就是双面打印的右手边位置页;默认值=false不必确保.
81
+ rightHand: boolean;
82
+
83
+ //页码是罗马数字;论文目录需要的;默认=false阿拉伯数字。"I","II","III","IV","V","VI","VII","VIII","IX" "X"XI"XII"表盘符号
84
+ //roman只能针对本URL启用;数字转换范围最大支持1到12,超过了便改阿拉伯数字,且只针对pageNumber有效, totalPages不会采用。
85
+ roman?: boolean;
86
+
87
+ //下面这5个参数不是前端配置发送过来的,而是lay{}对象预先进行转换后保存的汇总页眉页脚,只能内部使用,并非外部接口参数!Page.printToPDF需要的。
88
+ headerTemplate?: string;
89
+ footerTemplate?: string;
90
+ headerTemplateL?: string;
91
+ footerTemplateL?: string;
92
+ //这针对:可能由于动态布局导致的浏览器打印预览和实际URL纯粹js网页动态布局的真实内容页数不一致的毛病。
93
+ //开启的浏览器窗口宽度。默认最大化的。
94
+ brwidth?: number;
95
+ //第一阶段Url转pdf的浏览器执行窗口的targetId,不可配置。
96
+ CDPtab?: string;
97
+ }
@@ -5,9 +5,10 @@ import CDP from "chrome-remote-interface";
5
5
  import _ from "lodash";
6
6
  // @ts-ignore
7
7
  import config from "config";
8
- import CONFIG from "@/configEnv";
9
- import { ConfigRoot, FileTransform, MyPaperSize } from "@/types/request/config";
10
- import { filePathToUrl } from "@/utils/url";
8
+ import CONFIG from "../configEnv";
9
+ import { MyPaperSize } from "../types/request/config";
10
+ import { filePathToUrl } from "../utils/url";
11
+ import { ConfigRoot, FileTransform } from "@/types";
11
12
 
12
13
  //自定义纸张系列的:
13
14
  const paperSZs = config.get("size") as MyPaperSize[];
@@ -78,6 +79,7 @@ interface IRenderPdfOptions {
78
79
  landscape?: boolean;
79
80
  includeBackground?: boolean;
80
81
  windowSize?: boolean;
82
+ //纸张 英寸为单位的。 限制打印输出的用
81
83
  paperWidth?: number;
82
84
  paperHeight?: number;
83
85
  pageRanges?: string;
@@ -92,6 +94,7 @@ interface IRenderPdfOptions {
92
94
  marginBottom?: number;
93
95
  marginLeft?: number;
94
96
  marginRight?: number;
97
+ //有些 要打印 背景图片的需要?
95
98
  printBackground?: boolean;
96
99
  }
97
100
 
@@ -124,6 +127,7 @@ export class RenderPDF {
124
127
  * 奇数页还是偶数页的,双面打印对页码位置可能会调整位置的,而单独一个URL生成pdf时刻有可能没法就一定能够正确打印页码文字的是定位位置啊。抛弃支持:纯静态html横竖方向混合的场景,独立转换抽取部分纸张到过渡的pdf或拆解组合来做。
125
128
  * 还是考虑:保留第一阶段页眉页脚的打印能力,但是仅仅针对:特殊url:file[url:{ 只能是独立的页码编码和页码合计数独自计数,不涉及到其它的URL的 }],双面打印:页码只能放在中间位置为好,页码必须从第一页开始编码的,而且这种情况目标是不采用叠加页眉页脚两次pdf方案(一次性,不提取出CSS纸张方向)。
126
129
  * 最终采用引入reverseRanges参数设置部分纸张反转纸张方向,需要配置某某页并和CSS打印第一阶段生成的pdf能够吻合纸张方向的话,就能确保页眉页脚叠加正常位置。这里步骤就免于处理页眉页脚的生成了。
130
+ * CDP【Target】才是开启URL的。浏览器初始化; Page是打印输出的。
127
131
  * */
128
132
  async renderPdf(task: ConfigRoot<FileTransform>, tsobj: FileTransform) {
129
133
  let options = {} as IRenderPdfOptions;
@@ -139,6 +143,7 @@ export class RenderPDF {
139
143
  const { CDPclient, targetId } = await this.newTabOrPage(
140
144
  this.getCDPhostPort(),
141
145
  url,
146
+ tsobj.brwidth,
142
147
  );
143
148
  // await RenderPDF.newTabOrPage(this.getCDPhostPort(), url);
144
149
  // const client = await CDP({ host: this.host, port: this.port });
@@ -156,7 +161,7 @@ export class RenderPDF {
156
161
  url: url,
157
162
  //frameId: targetId, 不能加上: 本地pdf情形实际会有webview/iframe,实际会看到pdf之外的浏览控件框框的。
158
163
  });
159
- if (errorText) throw new Error(errorText); //若是访问失败应该抛异常的!
164
+ if (errorText) throw new Error(errorText + " URL=" + url); //若是访问失败应该抛异常的!
160
165
  frameId;
161
166
  await Emulation.setVirtualTimePolicy({
162
167
  policy: "pauseIfNetworkFetchesPending",
@@ -343,7 +348,9 @@ export class RenderPDF {
343
348
  // renderer.killChrome();
344
349
  }
345
350
 
346
- /**关键的: 某一个url的转换步骤 */
351
+ /**关键的: 某一个url的转换步骤
352
+ * @param tsobj 每一个独立URL生成 FileTransform 配置的
353
+ * */
347
354
  async generateSinglePdf(
348
355
  tsobj: FileTransform,
349
356
  task: ConfigRoot<FileTransform>,
@@ -512,7 +519,9 @@ export class RenderPDF {
512
519
  return ret;
513
520
  }
514
521
 
515
- /**汇总步骤入口: 前提 :前面已经生成独立的多个pdf */
522
+ /**汇总步骤入口: 前提 :前面已经生成独立的多个pdf
523
+ * 另外 还有await renderer.newTabOrPage(/ renderer.yemeiyejiaoPageGen( 是用于生成页眉页脚的每一页都有独立临时pdf。
524
+ * */
516
525
  static async MergeAllPdfs(
517
526
  task: ConfigRoot<FileTransform>,
518
527
  options: IRenderPdfOptions,
@@ -737,12 +746,12 @@ export class RenderPDF {
737
746
  headerTemplate0 = headerTemplate0?.replace("-NOT_DISPLAY-", "");
738
747
  headerTemplate0 = headerTemplate0
739
748
  ?.replace(
740
- "${pageNumber}",
749
+ "~pageNumber~",
741
750
  tsobj.roman && pageNumber > 0 && pageNumber < 13
742
751
  ? ROMA_NUMS[pageNumber]
743
752
  : "" + pageNumber,
744
753
  )
745
- .replace("${totalPages}", "" + totalPages);
754
+ .replace("~totalPages~", "" + totalPages);
746
755
  }
747
756
  options.headerTemplate = headerTemplate0;
748
757
  let footerTemplate0;
@@ -769,12 +778,12 @@ export class RenderPDF {
769
778
  footerTemplate0 = footerTemplate0?.replace("-NOT_DISPLAY-", "");
770
779
  footerTemplate0 = footerTemplate0
771
780
  ?.replace(
772
- "${pageNumber}",
781
+ "~pageNumber~",
773
782
  tsobj.roman && pageNumber > 0 && pageNumber < 13
774
783
  ? ROMA_NUMS[pageNumber]
775
784
  : "" + pageNumber,
776
785
  )
777
- .replace("${totalPages}", "" + totalPages);
786
+ .replace("~totalPages~", "" + totalPages);
778
787
  }
779
788
  options.footerTemplate = footerTemplate0;
780
789
 
@@ -792,16 +801,17 @@ export class RenderPDF {
792
801
  return null;
793
802
  }
794
803
 
795
- /**直接嵌入用户打开的浏览器的模式下,独立的开启新的浏览器窗口需要:
796
- * 问题:刚用createTarget立刻获取targetId(frameId)没法正常工作,
797
- * 这里await CDP(options)必须做两次!!:没法避免,否则干扰用户窗口,要么新Tab没有实际准备好的。
798
- * */
799
- async newTabOrPage(options: CDPbeginParam, url: string) {
804
+ async newTabPageInner(options: CDPbeginParam, url: string, brwidth?: number) {
800
805
  const client1 = await CDP(options); // await CDP({ host: options.host, port: options.port });
801
- const { Target } = client1;
806
+ const { Target, Browser } = client1;
807
+ //页眉页脚也会开动新的Tab; 没尝试出来:用这个入口就可控制浏览器窗口的宽度的办法。
802
808
  await Target.createTarget({
803
809
  url: url,
804
810
  background: true,
811
+ width: 719, //无效:(headless chrome only)不算无头模式的,有展示交互式窗口啊。
812
+ newWindow: true,
813
+ // enableBeginFrameControl: true,
814
+ forTab: true,
805
815
  });
806
816
  //前端编码之escape、encodeURI对的, 和 encodeURIComponent
807
817
  const { targetInfos } = await Target.getTargets();
@@ -809,12 +819,49 @@ export class RenderPDF {
809
819
  //"type": "webview", iframe, background_page, ...
810
820
  return tab.type === "page" && tab.url === url;
811
821
  });
812
- client1.close(); //原先每次关闭的:
822
+ //targetId就是目标窗口的实例。
813
823
  if (!target.targetId) throw new Error("没开启窗口:" + url);
824
+ if (brwidth) {
825
+ //需要约束浏览器 来避免打印页数不正常的,web页面的动态布局导致的,打印结果太少太多页数。
826
+ const { windowId, bounds } = await Browser.getWindowForTarget({
827
+ targetId: target.targetId,
828
+ });
829
+ const objectWidth = brwidth;
830
+ const newbounds = {
831
+ ...bounds,
832
+ width: objectWidth,
833
+ windowState: "normal",
834
+ };
835
+ await Browser.setWindowBounds({ windowId, bounds: newbounds });
836
+ const { bounds: realBound } = await Browser.getWindowBounds({ windowId });
837
+ const newRealWidth = realBound?.width;
838
+ if (objectWidth !== newRealWidth)
839
+ throw new Error("开窗口宽度不适当:" + newRealWidth);
840
+ }
841
+ client1.close(); //原先每次关闭的:
814
842
  const client = await CDP(options);
843
+
815
844
  //这些用例简易网页:frameId实际等同targetId;因没有嵌套<iframe />标签的。
816
845
  return { CDPclient: client, targetId: target.targetId };
817
846
  }
847
+ /**直接嵌入用户打开的浏览器的模式下,独立的开启新的浏览器窗口需要:
848
+ * 问题:刚用createTarget立刻获取targetId(frameId)没法正常工作,
849
+ * 这里await CDP(options)必须做两次!!:没法避免,否则干扰用户窗口,要么新Tab没有实际准备好的。
850
+ * 另外入口是:页眉页脚是使用纯粹 静态的 yemeiyejiaoHtml 来生成的每一页的独立页眉页脚pdf再合并的,不需要考虑浏览器宽度大小会影响到(不是动态布局的内容)。
851
+ * */
852
+ async newTabOrPage(options: CDPbeginParam, url: string, brwidth?: number) {
853
+ //多尝试一次, 浏览器宽度设置可能不能一次性成功的。
854
+ for (let i = 0; i < 2; i++) {
855
+ try {
856
+ const result = await this.newTabPageInner(options, url, brwidth);
857
+ return result;
858
+ } catch (e) {
859
+ // @ts-ignore
860
+ if (!e.message.startsWith("开窗口宽度不适当:")) console.error(e);
861
+ }
862
+ }
863
+ throw new Error("开启窗口尝试2次失败:" + url);
864
+ }
818
865
  /**假如不是当前刚刚操作的Tab的话?:
819
866
  * */
820
867
  async closeTabOrPage(client: any, target: string) {
@@ -1,4 +1,4 @@
1
- 工程目录:page2pdf-server/执行 npm publish 发布到npm
1
+ 工具包需要发布,工程目录:page2pdf-server/执行 npm publish 发布到npm
2
2
  后端没有单步调试模式太不好了,原本直接start就能单步调试,后来不行了,jest来解决:
3
3
  __test__/./generatePdf.test.ts问题:jest用Run模式正常,可是若Debug模式单步调试的,.post(`/api/pdf`).send就会提前中止!原因xxxController容不下多个接口函数?
4
4
  /?有断点运行卡着的并且xxxController类里有两个函数的?提前中止啊;非得拆分两个文件。
@@ -171,6 +171,8 @@ headerTemplate = `<div style="position: relative; width:100%; text-align:center;
171
171
  <div style="position: absolute; width:100%; text-align: center; bottom: 5px;"><span class=title></div>
172
172
  <div style="position: absolute; text-align: right; bottom: 5px;right: 20px;">version: 1.0</div>
173
173
  </div>`;
174
+
175
+ 默认标题 '<div style=\\"position: absolute; width:100%; text-align: center; bottom: 5px;\\"><span id=\\"titlespan\\" class=title></div>',
174
176
  使用chrome, 不能以root账号直接使用 https://www.cnblogs.com/kk1893/p/14985512.html
175
177
  let browserOptions = { args: ['--no-sandbox', '--disable-setuid-sandbox'] };
176
178
  物理打印机系统对话框设置:可能能配置装订线宽度和页码输出的{套中套}可分拆却就不能文件合并。
@@ -241,4 +243,26 @@ package.json:: start 又能使用单步调试模式运行了,奇怪,为何
241
243
  }
242
244
  BD1CE5AD1D724197A177AC4E50DDB4A6
243
245
 
244
- 去掉bcrypt包 @mapbox/node-pre-gyp node-gyp 依賴python啊
246
+ 去掉bcrypt包 @mapbox/node-pre-gyp node-gyp 依賴python啊
247
+ useMeasure(dynctRef0)?.height 所获得尺寸实际针对屏幕的,在打印机场景该取值还是来自屏幕的,并非纸张打印语义的尺寸;没法测量打印时刻的div高度?。
248
+
249
+ 新电脑,不是管理员账户跑的开发环境,POST http://localhost:9389/api/pdf 出现error: Error: connect ECONNREFUSED 127.0.0.1:9872
250
+ 只好另外管理员用户启动浏览器窗口。当前打印服务器的为何却要调用管理员账户启动的浏览器?不能直接用当前用户启动浏览器,非要windows管理员窗口的。
251
+ 奇怪浏览器手动去打印必须勾选页眉页脚才正常,没选的表格最右边会不见了,但是打印服务器不受此困扰,两者看似能确保页数一致性的。
252
+ 去掉了: 没法在生产版本中用,没包报错
253
+ "devDependencies": {
254
+ "@types/module-alias": "^2.0.1",
255
+ "module-alias": "^2.2.3",
256
+ }
257
+ 不是module-alias的问题,而是node_modules在生产目录底下也不能缺少啊!直接拷贝也行! https://blog.csdn.net/qq_35624642/article/details/128960311
258
+ windows用户若非管理员账户的:桌面上的Chrome快捷方式右键点属性在“兼容性”设置中:必须勾选“管理员身份运行”!否则端口remote-debugging-port没开启。
259
+ 【浏览器有BUG】
260
+ 预览打印的,若没有勾选页眉页脚的话可能导致表格输出的右边边框被裁剪看不见表格右边线了,就只能勾选页眉页脚,但是我这个打印转换服务器没有这个毛病。
261
+ 但问题是:勾不勾选页眉页脚会不会影响到了实际打印输出的页数啊?目前还未发现这个影响存在的。
262
+ 如何限制打印时刻浏览器宽的:
263
+ 入口代码:src/utils/pdfgen.ts 的 async renderPdf(task: ConfigRoot<FileTransform>, tsobj: FileTransform) 浏览器打印主入口:
264
+ 【CDP文档】 https://chromedevtools.github.io/devtools-protocol/tot/Target/
265
+ 首先必须手动开启chrome浏览器;而且这个浏览器窗体宽度直接影响打印输出!可能会漏打,动态div测量调整布局问题。影响到浏览器其它用途体验。
266
+ yarn又失败: 无法访问上 https://registry.npmjs.org/
267
+ 问题:有些URL网页,一直在等待加载好,死等打印命令没结果,估计CDP依据页面的网络消息决定加载结束与否的。
268
+ 端口已经被占用,启动不能访问预定端口的:查进程 netstat -ano | findstr :9872 #找出 LISTENING 10972 =进程ID;杀掉
@@ -0,0 +1,17 @@
1
+ POST http://localhost:9389/api/pdf
2
+ Accept: application/json
3
+ Content-Type: application/json; charset=utf-8
4
+
5
+ {
6
+ "merge": true,
7
+ "name": "asjsak啊实打实2",
8
+ "lay": {
9
+ },
10
+ "files": [
11
+ {
12
+ "url": "http://192.168.1.102:3765/originalView/CR-JJ/ver/1/-3kfCWcBRx66P8YA7EOkXFJlcG9ydA/printAll",
13
+ "out": "横页脚的VS2"
14
+ }
15
+ ]
16
+ }
17
+ ###
package/tsconfig.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "compilerOptions": {
3
- /* Basic Options */
4
- "incremental": true,
5
- "target": "ESNext",
6
- "module": "commonjs",
7
- "outDir": "dist",
3
+ "declaration": false, // 关闭自动生成声明文件
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
8
6
  "pretty": true,
9
7
  "removeComments": true,
10
8
 
9
+ // "declarationDir": "./dist/types", // 声明文件输出目录
10
+ // "emitDeclarationOnly": true, // 仅生成声明文件
11
+ "module": "ESNext",
12
+ "target": "ES2021",
13
+
11
14
  /* Strict Type-Checking Options */
12
15
  "strict": true,
13
16
  "noImplicitAny": true,
@@ -37,5 +40,5 @@
37
40
  },
38
41
  },
39
42
  "include": ["src/**/*", "**/__tests__/**/*"],
40
- "exclude": ["node_modules"]
43
+ "exclude": ["node_modules", "dist"] // 排除的目录
41
44
  }
package/.husky/pre-commit DELETED
@@ -1,6 +0,0 @@
1
- #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
- yarn prettify
5
- yarn lint:fix
6
- git add
package/.husky/pre-push DELETED
@@ -1,4 +0,0 @@
1
- #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
- yarn build
@@ -1,58 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <code_scheme name="Project" version="173">
3
- <HTMLCodeStyleSettings>
4
- <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
5
- <option name="HTML_ENFORCE_QUOTES" value="true" />
6
- </HTMLCodeStyleSettings>
7
- <JSCodeStyleSettings version="0">
8
- <option name="FORCE_SEMICOLON_STYLE" value="true" />
9
- <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
10
- <option name="FORCE_QUOTE_STYlE" value="true" />
11
- <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
12
- <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
13
- <option name="SPACES_WITHIN_IMPORTS" value="true" />
14
- </JSCodeStyleSettings>
15
- <TypeScriptCodeStyleSettings version="0">
16
- <option name="FORCE_SEMICOLON_STYLE" value="true" />
17
- <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
18
- <option name="FORCE_QUOTE_STYlE" value="true" />
19
- <option name="ENFORCE_TRAILING_COMMA" value="Remove" />
20
- <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
21
- <option name="SPACES_WITHIN_IMPORTS" value="true" />
22
- </TypeScriptCodeStyleSettings>
23
- <VueCodeStyleSettings>
24
- <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
25
- <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
26
- </VueCodeStyleSettings>
27
- <codeStyleSettings language="HTML">
28
- <option name="SOFT_MARGINS" value="80" />
29
- <indentOptions>
30
- <option name="INDENT_SIZE" value="2" />
31
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
32
- <option name="TAB_SIZE" value="2" />
33
- </indentOptions>
34
- </codeStyleSettings>
35
- <codeStyleSettings language="JavaScript">
36
- <option name="SOFT_MARGINS" value="80" />
37
- <indentOptions>
38
- <option name="INDENT_SIZE" value="2" />
39
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
40
- <option name="TAB_SIZE" value="2" />
41
- </indentOptions>
42
- </codeStyleSettings>
43
- <codeStyleSettings language="TypeScript">
44
- <option name="SOFT_MARGINS" value="80" />
45
- <indentOptions>
46
- <option name="INDENT_SIZE" value="2" />
47
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
48
- <option name="TAB_SIZE" value="2" />
49
- </indentOptions>
50
- </codeStyleSettings>
51
- <codeStyleSettings language="Vue">
52
- <option name="SOFT_MARGINS" value="80" />
53
- <indentOptions>
54
- <option name="CONTINUATION_INDENT_SIZE" value="2" />
55
- </indentOptions>
56
- </codeStyleSettings>
57
- </code_scheme>
58
- </component>
@@ -1,5 +0,0 @@
1
- <component name="ProjectCodeStyleConfiguration">
2
- <state>
3
- <option name="USE_PER_PROJECT_SETTINGS" value="true" />
4
- </state>
5
- </component>
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="Encoding">
4
- <file url="file://$PROJECT_DIR$/eslintrc.json" charset="GBK" />
5
- <file url="file://$PROJECT_DIR$/src/testCSS.html" charset="GBK" />
6
- </component>
7
- </project>
@@ -1,7 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
- <inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
6
- </profile>
7
- </component>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/tenstack-starter-main.iml" filepath="$PROJECT_DIR$/.idea/tenstack-starter-main.iml" />
6
- </modules>
7
- </component>
8
- </project>
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
- <excludeFolder url="file://$MODULE_DIR$/temp" />
7
- <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
- </content>
9
- <orderEntry type="inheritedJdk" />
10
- <orderEntry type="sourceFolder" forTests="false" />
11
- </component>
12
- </module>
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/.tmp" />
6
- <excludeFolder url="file://$MODULE_DIR$/temp" />
7
- <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
- </content>
9
- <orderEntry type="inheritedJdk" />
10
- <orderEntry type="sourceFolder" forTests="false" />
11
- </component>
12
- </module>