├── bin ├── pdf-a4-landscape.bat ├── pdf-a4-portrait.bat ├── pdf-a5-landscape.bat ├── pdf-a5-portrait.bat ├── html2pdf.bat ├── pdf-a4-landscape ├── pdf-a4-portrait ├── pdf-a5-landscape ├── pdf-a5-portrait ├── pdf-print ├── pdf-print.bat └── html2pdf ├── dist ├── cover.jpg ├── img │ └── 1.png ├── static │ ├── img │ │ └── nop.jpg │ └── js │ │ └── qrcode-generator │ │ └── 1.4.4 │ │ └── qrcode.min.js ├── data │ ├── chart-2.json │ └── chart-1.json ├── eazy-3.html ├── eazy-4.html ├── eazy-2.html ├── eazy-6.html └── eazy-1.html ├── qq-group-1.png ├── .gitignore ├── eazy-2-qrcode.png ├── simple-4-qrcode.png ├── converter ├── wkhtml2pdf │ ├── wkhtmltopdf-webkit-suport.pdf │ └── modernizr.html ├── puppeteer │ └── index.js └── chrome-headless │ └── index.js ├── docker-stop.bat ├── docker-stop.sh ├── .editorconfig ├── package.json ├── docker-start.bat ├── docker-start.sh ├── wslpath.bat ├── LICENSE ├── BookJsHelper.md ├── .gitattributes ├── README.md └── README-en.md /bin/pdf-a4-landscape.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | "%~pd0\pdf-print.bat" A4 Landscape %* 4 | -------------------------------------------------------------------------------- /bin/pdf-a4-portrait.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | "%~pd0\pdf-print.bat" A4 Portrait %* 4 | -------------------------------------------------------------------------------- /bin/pdf-a5-landscape.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | "%~pd0\pdf-print.bat" A5 Landscape %* 4 | -------------------------------------------------------------------------------- /bin/pdf-a5-portrait.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | "%~pd0\pdf-print.bat" A5 Portrait %* 4 | -------------------------------------------------------------------------------- /dist/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/dist/cover.jpg -------------------------------------------------------------------------------- /dist/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/dist/img/1.png -------------------------------------------------------------------------------- /qq-group-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/qq-group-1.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /yarn.lock 2 | /package-lock.json 3 | /node_modules 4 | /.idea 5 | /dist/pdf 6 | -------------------------------------------------------------------------------- /eazy-2-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/eazy-2-qrcode.png -------------------------------------------------------------------------------- /simple-4-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/simple-4-qrcode.png -------------------------------------------------------------------------------- /bin/html2pdf.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SCRIPT_PATH=%~dp0 4 | node "%SCRIPT_PATH%\html2pdf" %* 5 | -------------------------------------------------------------------------------- /dist/static/img/nop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/dist/static/img/nop.jpg -------------------------------------------------------------------------------- /bin/pdf-a4-landscape: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | script_path=$(cd `dirname "$0"`;pwd) 4 | "${script_path}/pdf-print" A4 Landscape $@ 5 | -------------------------------------------------------------------------------- /bin/pdf-a4-portrait: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | script_path=$(cd `dirname "$0"`;pwd) 4 | "${script_path}/pdf-print" A4 Portrait $@ 5 | -------------------------------------------------------------------------------- /bin/pdf-a5-landscape: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | script_path=$(cd `dirname "$0"`;pwd) 4 | "${script_path}/pdf-print" A5 Landscape $@ 5 | -------------------------------------------------------------------------------- /bin/pdf-a5-portrait: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | script_path=$(cd `dirname "$0"`;pwd) 4 | "${script_path}/pdf-print" A5 Portrait $@ 5 | -------------------------------------------------------------------------------- /converter/wkhtml2pdf/wkhtmltopdf-webkit-suport.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuxue107/bookjs-eazy/HEAD/converter/wkhtml2pdf/wkhtmltopdf-webkit-suport.pdf -------------------------------------------------------------------------------- /docker-stop.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SCRIPT_PATH=%~dp0 4 | cd %SCRIPT_PATH% 5 | 6 | 7 | echo docker stop screenshot-api-server 8 | docker stop screenshot-api-server 9 | -------------------------------------------------------------------------------- /docker-stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_PATH=$(cd `dirname "$0"`;pwd) 4 | cd "${SCRIPT_PATH}"; 5 | 6 | 7 | echo docker stop screenshot-api-server 8 | docker stop screenshot-api-server 9 | # docker rm screenshot-api-server 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = false 10 | [*.bat] 11 | end_of_line = crlf 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.{yml,yaml}] 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /converter/wkhtml2pdf/modernizr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | My Beautiful Sample Page 6 | 7 | 8 | 9 |
10 | 
11 | 
12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bookjs-eazy", 3 | "version": "1.17.0", 4 | "main": "index.js", 5 | "repository": "https://gitee.com/wuxue107/bookjs-eazy.git", 6 | "author": "nop <575065955@qq.com>", 7 | "license": "MIT", 8 | "bin": { 9 | "html2pdf": "bin/html2pdf" 10 | }, 11 | "scripts": { 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "devDependencies": { 17 | }, 18 | "dependencies": { 19 | "chrome-remote-interface": "^0.28.2", 20 | "commander": "<12", 21 | "puppeteer": "^5.5.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bin/pdf-print: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | PAGE_SIZE=$1 5 | ORIENTATION=$2 6 | URL=$3 7 | OUTPUT=$4 8 | 9 | [ "${PAGE_SIZE}" == "" ] && PAGE_SIZE=A4 10 | [ "${ORIENTATION}" != "Landscape" ] && ORIENTATION=Portrait 11 | [ "${OUTPUT}" == "" ] && OUTPUT=output.pdf 12 | 13 | wkhtmltopdf --window-status "PDFComplete" \ 14 | --disable-smart-shrinking \ 15 | --margin-left 0 --margin-right 0 --margin-top 0 --margin-bottom 0 --page-size "${PAGE_SIZE}" \ 16 | --orientation "${ORIENTATION}" \ 17 | --no-stop-slow-scripts \ 18 | --enable-internal-links \ 19 | --debug-javascript \ 20 | --print-media-type \ 21 | --outline --outline-depth 3 \ 22 | --log-level info \ 23 | "${URL}" "${OUTPUT}" 24 | -------------------------------------------------------------------------------- /docker-start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set SCRIPT_PATH=%~dp0 4 | cd %SCRIPT_PATH% 5 | 6 | set WEB_PORT=%1 7 | set IMAGE_TAG=%2 8 | 9 | IF "%IMAGE_TAG%" == "" set IMAGE_TAG=latest 10 | IF "%WEB_PORT%" == "" set WEB_PORT=3000 11 | 12 | call wslpath.bat "dist" WEB_PATH 2>NUL 13 | 14 | echo docker run --cpus="0.7" -p %WEB_PORT%:3000 -td --rm -v "%WEB_PATH%:/screenshot-api-server/public" --name=screenshot-api-server wuxue107/screenshot-api-server:%IMAGE_TAG% 15 | docker run --cpus="0.7" -p %WEB_PORT%:3000 -td --rm -v "%WEB_PATH%:/screenshot-api-server/public" --name=screenshot-api-server wuxue107/screenshot-api-server:%IMAGE_TAG% 16 | 17 | echo LISTEN : %WEB_PORT% 18 | echo WEB_ROOT : %WEB_PATH% 19 | -------------------------------------------------------------------------------- /bin/pdf-print.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set URL=%3 4 | set URL=%URL:&=^&% 5 | set FILE=%4 6 | set PAGE_SIZE=%1 7 | set ORIENTATION=%2 8 | 9 | IF "%FILE%" == "" SET FILE=output.pdf 10 | IF "%PAGE_SIZE%" == "" SET PAGE_SIZE=A4 11 | IF NOT "%ORIENTATION%" == "Landscape" SET ORIENTATION=Portrait 12 | 13 | wkhtmltopdf --window-status "PDFComplete" ^ 14 | --disable-smart-shrinking ^ 15 | --margin-left 0 --margin-right 0 --margin-top 0 --margin-bottom 0 ^ 16 | --no-stop-slow-scripts ^ 17 | --enable-internal-links ^ 18 | --debug-javascript ^ 19 | --print-media-type ^ 20 | --outline --outline-depth 3 ^ 21 | --log-level info ^ 22 | --page-size %PAGE_SIZE% ^ 23 | --orientation %ORIENTATION% ^ 24 | %URL% %FILE% 25 | -------------------------------------------------------------------------------- /docker-start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_PATH=$(cd `dirname "$0"`;pwd) 4 | cd "${SCRIPT_PATH}"; 5 | 6 | WEB_PORT=$1 7 | IMAGE_TAG=$2 8 | [ "${IMAGE_TAG}" == "" ] && IMAGE_TAG=latest 9 | [ "${WEB_PORT}" == "" ] && WEB_PORT=3000 10 | 11 | WEB_PATH=${PWD}/dist 12 | [ -d "${WEB_PATH}" ] || mkdir "${WEB_PATH}" 13 | 14 | echo docker run --cpus="0.7" -p ${WEB_PORT}:3000 -td --rm -v ${WEB_PATH}:/screenshot-api-server/public --name=screenshot-api-server wuxue107/screenshot-api-server:${IMAGE_TAG} 15 | docker run --cpus="0.7" -p ${WEB_PORT}:3000 -td --rm -v ${WEB_PATH}:/screenshot-api-server/public --name=screenshot-api-server wuxue107/screenshot-api-server:${IMAGE_TAG} 16 | 17 | echo LISTEN : ${WEB_PORT} 18 | echo WEB_ROOT : ${WEB_PATH} 19 | -------------------------------------------------------------------------------- /wslpath.bat: -------------------------------------------------------------------------------- 1 | 2 | :: 取个怪异的名字加"__",尽量不干扰全局的变量 3 | :: 使用方式: call wslpath.bat [WINDOW路径] [保存的变量名] 4 | :: call wslpath.bat . MOUNT_PATH 5 | :: call wslpath.bat "C:\Program Files\Docker" MOUNT_PATH 6 | :: 7 | :: MIT License 8 | :: @https://gitee.com/wuxue107/wslpath.bat 9 | :: 10 | :: SETLOCAL 11 | 12 | set __SET_PARAM_NAME=%2 13 | set __FULL_PATH=%~f1 14 | set __FILE_PATH=%__FULL_PATH:~2% 15 | set __FILE_PATH=%__FILE_PATH:\=/% 16 | set __DEVICE_NAME=%~d1 17 | set __DEVICE_NAME=%__DEVICE_NAME::=% 18 | 19 | for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do call set __DEVICE_NAME=%%__DEVICE_NAME:%%i=%%i%% 20 | :: ENDLOCAL 21 | if "%__SET_PARAM_NAME%" == "" ( 22 | echo /%__DEVICE_NAME%%__FILE_PATH% 23 | ) else ( 24 | set %__SET_PARAM_NAME%=/%__DEVICE_NAME%%__FILE_PATH% 25 | ) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 wuxue107 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /BookJsHelper.md: -------------------------------------------------------------------------------- 1 | # BookJsHelper 辅助函数说明 2 | 3 | 4 | ## BookJsHelper.getQueryParam(queryParamName, defaultValue, url) 获取页面Query参数 5 | ```javascript 6 | // 当前页: /eazy-1.html?aa=11&bb=22 7 | ret = BookJsHelper.getQueryParam() 8 | //ret => {aa:'11',bb:'22'} 9 | ret = BookJsHelper.getQueryParam('cc','33') 10 | //ret => '33' 11 | ret = BookJsHelper.getQueryParam('dd','444','/some?dd=44') 12 | //ret => 44 13 | ``` 14 | 15 | ## BookJsHelper.showMsg(msg) 显示一个弹出层消息,返回msgId 16 | ```javascript 17 | ret = BookJsHelper.showMsg(msg) 18 | // ret => 'id-xxxxxx' 消息ID 19 | ``` 20 | ### BookJsHelper.closeMsg(msgId) 根据msgId关闭弹出层消息 21 | 22 | 23 | ### BookJsHelper.closeAllMsg() 关闭所有弹出层消息 24 | 25 | ### BookJsHelper.isMobile() 返回当前是否为在手机端浏览 26 | ### BookJsHelper.isWkHtmlToPdf() 返回当前浏览器是否为wkhtmltopdf内核 27 | ### BookJsHelper.isHeadless() 返回当前是否无头浏览器模式下浏览 28 | 29 | ### BookJsHelper.tag(tagName,attrs,content) 构建html片段 30 | - tagName: 标签名 31 | - attrs : String/Object 属性 32 | - content : String/Array 内容 33 | ```javascript 34 | ret = BookJsHelper.tag( 35 | 'select', 36 | {class:'form-control',name:'type',data:{aa:1,bb:2}}, 37 | [ 38 | ['option',{value:"2"},"选项2"], 39 | ['option',{value:"1"},"选项1"], 40 | ] 41 | ); 42 | 43 | 44 | // ret => 45 | 46 | ``` 47 | 48 | ### BookJsHelper.dataPath(path,sourceData,defaultValue) 从多层级数据中取值,不存在的返回默认值 49 | ```javascript 50 | data = {a1:{a2:111},b1:[{b2:222}]}; 51 | 52 | // BookJsHelper.dataPath('a1.a2',data) => 111 53 | // BookJsHelper.dataPath('a1.a2.a3',data) => null 54 | // BookJsHelper.dataPath('a1.a2.a3',data,123) => 123 55 | // BookJsHelper.dataPath('b1[0].b2',data) => 222 56 | 57 | ``` 58 | -------------------------------------------------------------------------------- /bin/html2pdf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // apt install chromium-browser 3 | // docker run -d -p 9222:9222 --rm --name headless-shell chromedp/headless-shell 4 | // "C:\Program Files\Google\Chrome\Application\chrome.exe" --headless --disable-gpu --remote-debugging-port=9222 --disable-extensions --mute-audio 5 | // "chromium-browser" --headless --disable-gpu --remote-debugging-port=9222 --disable-extensions --mute-audio 6 | // "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu --remote-debugging-port=9222 7 | 8 | // node bin/html2pdf print --agent=puppeteer --checkJs "window.status === 'PDFComplete'" --output simple-4.pdf --timeout 60000 --printDelay 1000 "https://bookjs.zhouwuxue.com/simple-4.html" 9 | 10 | const program = require('commander'); 11 | program.version('1.0.0') 12 | .command('print ') 13 | .option('-o --output [outputfile]', '保存PDF文件的路径','output.pdf') 14 | .option('-t --timeout [type]', '超时时间',60000) 15 | .option('-a --agent [agent]', '指定转换引擎chrome-headless|puppeteer,默认:puppeteer','puppeteer') 16 | .option('-d --printDelay [delay]', '打印前等待延迟(毫秒)', 1000) 17 | .option('-c --checkJs [jsExpression]', '检查是否渲染完成的js表达式', "window.status === 'PDFComplete'") // 'window.document.readyState === "complete"' 18 | .action(function(url,cmd){ 19 | let html2pdf; 20 | if(cmd.agent === 'puppeteer'){ 21 | html2pdf = require('../converter/puppeteer'); 22 | }else if(cmd.agent === 'chrome-headless'){ 23 | html2pdf = require('../converter/chrome-headless'); 24 | }else{ 25 | console.error("无效参数:--agent [agent]"); 26 | process.exit(1); 27 | } 28 | 29 | // 要转为PDF的网页URL 30 | //let url = 'http://localhost:8080/simple-4.html'; 31 | // 输出保持PDF的文件路径 32 | let pdfFile = cmd.output; 33 | // 渲染超时时间 34 | let timeout = parseInt(cmd.timeout); 35 | 36 | // 检查PDF实付完成的JS表达式,定时检测直到表达式值为true,是看上渲染 37 | let checkJs = cmd.checkJs; 38 | let printDelay = parseInt(cmd.printDelay); 39 | 40 | html2pdf(url,pdfFile,timeout,printDelay,checkJs); 41 | }); 42 | 43 | program.parse(process.argv); 44 | -------------------------------------------------------------------------------- /converter/puppeteer/index.js: -------------------------------------------------------------------------------- 1 | // puppeteer 库会下载自带chrome,使用自带chrome启动并渲染 2 | const puppeteer = require('puppeteer'); 3 | // const fs = require('fs'); 4 | let sleep = async function(timeout){ 5 | return new Promise(function(resolve){ 6 | setTimeout(function(){ 7 | resolve(); 8 | },timeout) 9 | }); 10 | }; 11 | 12 | const html2pdf = function(pageUrl,pdfFile,timeout,printDelay,checkPdfRenderCompleteJs){ 13 | (async () => { 14 | const browser = await puppeteer.launch({ 15 | headless: true, 16 | dumpio : true, 17 | timeout : timeout + 5, 18 | args: ['--no-sandbox', '--disable-setuid-sandbox','--disable-gpu', '--disable-extensions', '--mute-audio','–no-first-run'] 19 | }); 20 | 21 | const page = await browser.newPage() 22 | 23 | let option = { 24 | //landscape : false, 25 | displayHeaderFooter: false, 26 | printBackground : true, 27 | scale : 1, 28 | // paperWidth : '1mm', 29 | // paperHeight : '1mm', 30 | marginTop : 0, 31 | marginBottom : 0, 32 | marginLeft : 0, 33 | marginRight : 0, 34 | // Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. 35 | pageRanges : '', 36 | // Whether to silently ignore invalid but successfully parsed page ranges, such as '3-2'. Defaults to false. 37 | ignoreInvalidPageRanges : false, 38 | // HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: 39 | // date: formatted print date 40 | // title: document title 41 | // url: document location 42 | // pageNumber: current page number 43 | // totalPages: total pages in the document 44 | // For example, would generate span containing the title. 45 | headerTemplate : '', 46 | footerTemplate : '', 47 | // Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. 48 | preferCSSPageSize: true, 49 | // Allowed Values: ReturnAsBase64, ReturnAsStream 50 | transferMode : 'ReturnAsStream', 51 | }; 52 | 53 | option.path = pdfFile; 54 | 55 | 56 | 57 | let waitPdfRenderComplete = async function(timeout){ 58 | let time = 0; 59 | return new Promise(function(resolve, reject){ 60 | let t = setInterval( function(){ 61 | time += 500; 62 | page.evaluate((checkPdfRenderCompleteJs || 'window.document.readyState === "complete"')).then(function(isOk){ 63 | if(isOk){ 64 | clearInterval(t); 65 | resolve(); 66 | } 67 | }); 68 | 69 | if(time > timeout){ 70 | setTimeout(function () { 71 | clearInterval(t); 72 | reject('timeout'); 73 | },20); 74 | } 75 | },500) 76 | }); 77 | }; 78 | 79 | 80 | console.log("open url:" + pageUrl); 81 | await page.goto(pageUrl) 82 | console.log("wait pdf render ..."); 83 | await waitPdfRenderComplete(timeout); 84 | console.log("print delay:" + printDelay); 85 | await sleep(printDelay); 86 | console.log("save pdf file:" + pdfFile); 87 | await page.pdf(option); 88 | // await page.close() 89 | await browser.close(); 90 | })() 91 | } 92 | 93 | module.exports = html2pdf; 94 | -------------------------------------------------------------------------------- /dist/data/chart-2.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["2013/1/24", 2320.26,2320.26,2287.3,2362.94], 3 | ["2013/1/25", 2300,2291.3,2288.26,2308.38], 4 | ["2013/1/28", 2295.35,2346.5,2295.35,2346.92], 5 | ["2013/1/29", 2347.22,2358.98,2337.35,2363.8], 6 | ["2013/1/30", 2360.75,2382.48,2347.89,2383.76], 7 | ["2013/1/31", 2383.43,2385.42,2371.23,2391.82], 8 | ["2013/2/1", 2377.41,2419.02,2369.57,2421.15], 9 | ["2013/2/4", 2425.92,2428.15,2417.58,2440.38], 10 | ["2013/2/5", 2411,2433.13,2403.3,2437.42], 11 | ["2013/2/6", 2432.68,2434.48,2427.7,2441.73], 12 | ["2013/2/7", 2430.69,2418.53,2394.22,2433.89], 13 | ["2013/2/8", 2416.62,2432.4,2414.4,2443.03], 14 | ["2013/2/18", 2441.91,2421.56,2415.43,2444.8], 15 | ["2013/2/19", 2420.26,2382.91,2373.53,2427.07], 16 | ["2013/2/20", 2383.49,2397.18,2370.61,2397.94], 17 | ["2013/2/21", 2378.82,2325.95,2309.17,2378.82], 18 | ["2013/2/22", 2322.94,2314.16,2308.76,2330.88], 19 | ["2013/2/25", 2320.62,2325.82,2315.01,2338.78], 20 | ["2013/2/26", 2313.74,2293.34,2289.89,2340.71], 21 | ["2013/2/27", 2297.77,2313.22,2292.03,2324.63], 22 | ["2013/2/28", 2322.32,2365.59,2308.92,2366.16], 23 | ["2013/3/1", 2364.54,2359.51,2330.86,2369.65], 24 | ["2013/3/4", 2332.08,2273.4,2259.25,2333.54], 25 | ["2013/3/5", 2274.81,2326.31,2270.1,2328.14], 26 | ["2013/3/6", 2333.61,2347.18,2321.6,2351.44], 27 | ["2013/3/7", 2340.44,2324.29,2304.27,2352.02], 28 | ["2013/3/8", 2326.42,2318.61,2314.59,2333.67], 29 | ["2013/3/11", 2314.68,2310.59,2296.58,2320.96], 30 | ["2013/3/12", 2309.16,2286.6,2264.83,2333.29], 31 | ["2013/3/13", 2282.17,2263.97,2253.25,2286.33], 32 | ["2013/3/14", 2255.77,2270.28,2253.31,2276.22], 33 | ["2013/3/15", 2269.31,2278.4,2250,2312.08], 34 | ["2013/3/18", 2267.29,2240.02,2239.21,2276.05], 35 | ["2013/3/19", 2244.26,2257.43,2232.02,2261.31], 36 | ["2013/3/20", 2257.74,2317.37,2257.42,2317.86], 37 | ["2013/3/21", 2318.21,2324.24,2311.6,2330.81], 38 | ["2013/3/22", 2321.4,2328.28,2314.97,2332], 39 | ["2013/3/25", 2334.74,2326.72,2319.91,2344.89], 40 | ["2013/3/26", 2318.58,2297.67,2281.12,2319.99], 41 | ["2013/3/27", 2299.38,2301.26,2289,2323.48], 42 | ["2013/3/28", 2273.55,2236.3,2232.91,2273.55], 43 | ["2013/3/29", 2238.49,2236.62,2228.81,2246.87], 44 | ["2013/4/1", 2229.46,2234.4,2227.31,2243.95], 45 | ["2013/4/2", 2234.9,2227.74,2220.44,2253.42], 46 | ["2013/4/3", 2232.69,2225.29,2217.25,2241.34], 47 | ["2013/4/8", 2196.24,2211.59,2180.67,2212.59], 48 | ["2013/4/9", 2215.47,2225.77,2215.47,2234.73], 49 | ["2013/4/10", 2224.93,2226.13,2212.56,2233.04], 50 | ["2013/4/11", 2236.98,2219.55,2217.26,2242.48], 51 | ["2013/4/12", 2218.09,2206.78,2204.44,2226.26], 52 | ["2013/4/15", 2199.91,2181.94,2177.39,2204.99], 53 | ["2013/4/16", 2169.63,2194.85,2165.78,2196.43], 54 | ["2013/4/17", 2195.03,2193.8,2178.47,2197.51], 55 | ["2013/4/18", 2181.82,2197.6,2175.44,2206.03], 56 | ["2013/4/19", 2201.12,2244.64,2200.58,2250.11], 57 | ["2013/4/22", 2236.4,2242.17,2232.26,2245.12], 58 | ["2013/4/23", 2242.62,2184.54,2182.81,2242.62], 59 | ["2013/4/24", 2187.35,2218.32,2184.11,2226.12], 60 | ["2013/4/25", 2213.19,2199.31,2191.85,2224.63], 61 | ["2013/4/26", 2203.89,2177.91,2173.86,2210.58], 62 | ["2013/5/2", 2170.78,2174.12,2161.14,2179.65], 63 | ["2013/5/3", 2179.05,2205.5,2179.05,2222.81], 64 | ["2013/5/6", 2212.5,2231.17,2212.5,2236.07], 65 | ["2013/5/7", 2227.86,2235.57,2219.44,2240.26], 66 | ["2013/5/8", 2242.39,2246.3,2235.42,2255.21], 67 | ["2013/5/9", 2246.96,2232.97,2221.38,2247.86], 68 | ["2013/5/10", 2228.82,2246.83,2225.81,2247.67], 69 | ["2013/5/13", 2247.68,2241.92,2231.36,2250.85], 70 | ["2013/5/14", 2238.9,2217.01,2205.87,2239.93], 71 | ["2013/5/15", 2217.09,2224.8,2213.58,2225.19], 72 | ["2013/5/16", 2221.34,2251.81,2210.77,2252.87], 73 | ["2013/5/17", 2249.81,2282.87,2248.41,2288.09], 74 | ["2013/5/20", 2286.33,2299.99,2281.9,2309.39], 75 | ["2013/5/21", 2297.11,2305.11,2290.12,2305.3], 76 | ["2013/5/22", 2303.75,2302.4,2292.43,2314.18], 77 | ["2013/5/23", 2293.81,2275.67,2274.1,2304.95], 78 | ["2013/5/24", 2281.45,2288.53,2270.25,2292.59], 79 | ["2013/5/27", 2286.66,2293.08,2283.94,2301.7], 80 | ["2013/5/28", 2293.4,2321.32,2281.47,2322.1], 81 | ["2013/5/29", 2323.54,2324.02,2321.17,2334.33], 82 | ["2013/5/30", 2316.25,2317.75,2310.49,2325.72], 83 | ["2013/5/31", 2320.74,2300.59,2299.37,2325.53], 84 | ["2013/6/3", 2300.21,2299.25,2294.11,2313.43], 85 | ["2013/6/4", 2297.1,2272.42,2264.76,2297.1], 86 | ["2013/6/5", 2270.71,2270.93,2260.87,2276.86], 87 | ["2013/6/6", 2264.43,2242.11,2240.07,2266.69], 88 | ["2013/6/7", 2242.26,2210.9,2205.07,2250.63], 89 | ["2013/6/13", 2190.1,2148.35,2126.22,2190.1] 90 | ] -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## GITATTRIBUTES FOR WEB PROJECTS 2 | # 3 | # These settings are for any web project. 4 | # 5 | # Details per file setting: 6 | # text These files should be normalized (i.e. convert CRLF to LF). 7 | # binary These files are binary and should be left untouched. 8 | # 9 | # Note that binary is a macro for -text -diff. 10 | ###################################################################### 11 | 12 | # Auto detect 13 | ## Handle line endings automatically for files detected as 14 | ## text and leave all files detected as binary untouched. 15 | ## This will handle all files NOT defined below. 16 | * text=auto 17 | 18 | # Source code 19 | *.bash text eol=lf 20 | *.bat text eol=crlf 21 | *.cmd text eol=crlf 22 | *.coffee text 23 | *.css text diff=css 24 | *.htm text diff=html 25 | *.html text diff=html 26 | *.inc text 27 | *.ini text 28 | *.js text 29 | *.json text 30 | *.jsx text 31 | *.less text 32 | *.ls text 33 | *.map text -diff 34 | *.od text 35 | *.onlydata text 36 | *.php text diff=php 37 | *.pl text 38 | *.ps1 text eol=crlf 39 | *.py text diff=python 40 | *.rb text diff=ruby 41 | *.sass text 42 | *.scm text 43 | *.scss text diff=css 44 | *.sh text eol=lf 45 | *.sql text 46 | *.styl text 47 | *.tag text 48 | *.ts text 49 | *.tsx text 50 | *.xml text 51 | *.xhtml text diff=html 52 | 53 | # Docker 54 | Dockerfile text 55 | 56 | # Documentation 57 | *.ipynb text 58 | *.markdown text diff=markdown 59 | *.md text diff=markdown 60 | *.mdwn text diff=markdown 61 | *.mdown text diff=markdown 62 | *.mkd text diff=markdown 63 | *.mkdn text diff=markdown 64 | *.mdtxt text 65 | *.mdtext text 66 | *.txt text 67 | AUTHORS text 68 | CHANGELOG text 69 | CHANGES text 70 | CONTRIBUTING text 71 | COPYING text 72 | copyright text 73 | *COPYRIGHT* text 74 | INSTALL text 75 | license text 76 | LICENSE text 77 | NEWS text 78 | readme text 79 | *README* text 80 | TODO text 81 | 82 | # Templates 83 | *.dot text 84 | *.ejs text 85 | *.haml text 86 | *.handlebars text 87 | *.hbs text 88 | *.hbt text 89 | *.jade text 90 | *.latte text 91 | *.mustache text 92 | *.njk text 93 | *.phtml text 94 | *.tmpl text 95 | *.tpl text 96 | *.twig text 97 | *.vue text 98 | 99 | # Configs 100 | *.cnf text 101 | *.conf text 102 | *.config text 103 | .editorconfig text 104 | .env text 105 | .gitattributes text 106 | .gitconfig text 107 | .htaccess text 108 | *.lock text -diff 109 | package.json text eol=lf 110 | package-lock.json text -diff 111 | pnpm-lock.yaml text eol=lf -diff 112 | yarn.lock text -diff 113 | *.toml text 114 | *.yaml text 115 | *.yml text 116 | browserslist text 117 | Makefile text 118 | makefile text 119 | 120 | # Heroku 121 | Procfile text 122 | 123 | # Graphics 124 | *.ai binary 125 | *.bmp binary 126 | *.eps binary 127 | *.gif binary 128 | *.gifv binary 129 | *.ico binary 130 | *.jng binary 131 | *.jp2 binary 132 | *.jpg binary 133 | *.jpeg binary 134 | *.jpx binary 135 | *.jxr binary 136 | *.pdf binary 137 | *.png binary 138 | *.psb binary 139 | *.psd binary 140 | # SVG treated as an asset (binary) by default. 141 | *.svg text 142 | # If you want to treat it as binary, 143 | # use the following line instead. 144 | # *.svg binary 145 | *.svgz binary 146 | *.tif binary 147 | *.tiff binary 148 | *.wbmp binary 149 | *.webp binary 150 | 151 | # Audio 152 | *.kar binary 153 | *.m4a binary 154 | *.mid binary 155 | *.midi binary 156 | *.mp3 binary 157 | *.ogg binary 158 | *.ra binary 159 | 160 | # Video 161 | *.3gpp binary 162 | *.3gp binary 163 | *.as binary 164 | *.asf binary 165 | *.asx binary 166 | *.fla binary 167 | *.flv binary 168 | *.m4v binary 169 | *.mng binary 170 | *.mov binary 171 | *.mp4 binary 172 | *.mpeg binary 173 | *.mpg binary 174 | *.ogv binary 175 | *.swc binary 176 | *.swf binary 177 | *.webm binary 178 | 179 | # Archives 180 | *.7z binary 181 | *.gz binary 182 | *.jar binary 183 | *.rar binary 184 | *.tar binary 185 | *.zip binary 186 | 187 | # Fonts 188 | *.ttf binary 189 | *.eot binary 190 | *.otf binary 191 | *.woff binary 192 | *.woff2 binary 193 | 194 | # Executables 195 | *.exe binary 196 | *.pyc binary 197 | 198 | # RC files (like .babelrc or .eslintrc) 199 | *.*rc text 200 | 201 | # Ignore files (like .npmignore or .gitignore) 202 | *.*ignore text 203 | -------------------------------------------------------------------------------- /converter/chrome-headless/index.js: -------------------------------------------------------------------------------- 1 | const Chrome = require('chrome-remote-interface'); 2 | const fs = require('fs'); 3 | 4 | 5 | let sleep = async function(timeout){ 6 | return new Promise(function(resolve){ 7 | setTimeout(function(){ 8 | resolve(); 9 | },timeout) 10 | }); 11 | }; 12 | 13 | const html2pdf = function(pageUrl,pdfFile,timeout,printDelay,checkPdfRenderCompleteJs){ 14 | checkPdfRenderCompleteJs = checkPdfRenderCompleteJs || 'window.document.readyState === "complete"'; 15 | console.log({pageUrl,pdfFile,timeout,printDelay,checkPdfRenderCompleteJs}) 16 | Chrome({},function (chrome) { 17 | with (chrome) { 18 | // 显示PDF网页的Console输出消息 19 | Console.enable(); 20 | Console.messageAdded(function(param){ 21 | console.log("Console:" + param.message.level.toUpperCase() + ':' +JSON.stringify(param)); 22 | }); 23 | 24 | Network.enable(); 25 | let networkRequest = {}; 26 | Network.requestWillBeSent(function (requestParam) { 27 | networkRequest[requestParam.requestId] = requestParam; 28 | }); 29 | 30 | Network.loadingFailed(function(param){ 31 | let requestParam = networkRequest[param.requestId]; 32 | if(requestParam){ 33 | console.warn("Network:" + requestParam.request.url + "\n" + JSON.stringify(param)); 34 | }else{ 35 | console.log("Network:" + JSON.stringify(param)); 36 | } 37 | }); 38 | 39 | 40 | let printPdf = async function(filePath,userOption){ 41 | if(userOption === undefined){ 42 | userOption = {}; 43 | } 44 | let option = { 45 | //landscape : false, 46 | displayHeaderFooter: false, 47 | printBackground : true, 48 | scale : 1, 49 | // paperWidth : '1mm', 50 | // paperHeight : '1mm', 51 | marginTop : 0, 52 | marginBottom : 0, 53 | marginLeft : 0, 54 | marginRight : 0, 55 | // Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. 56 | pageRanges : '', 57 | // Whether to silently ignore invalid but successfully parsed page ranges, such as '3-2'. Defaults to false. 58 | ignoreInvalidPageRanges : false, 59 | // HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: 60 | // date: formatted print date 61 | // title: document title 62 | // url: document location 63 | // pageNumber: current page number 64 | // totalPages: total pages in the document 65 | // For example, would generate span containing the title. 66 | headerTemplate : '', 67 | footerTemplate : '', 68 | // Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size. 69 | preferCSSPageSize: true, 70 | // Allowed Values: ReturnAsBase64, ReturnAsStream 71 | transferMode : 'ReturnAsStream', 72 | }; 73 | 74 | Object.assign(option,userOption); 75 | let result = await Page.printToPDF(option); 76 | // transferMode ReturnAsBase64 77 | // return fs.writeFileSync(filePath, result.data, 'base64'); 78 | 79 | let pdfFd= fs.openSync(filePath,'w'); 80 | let blockSize = 1024000; 81 | let block; 82 | let readParam = { 83 | handle : result.stream, 84 | size : blockSize, 85 | }; 86 | do{ 87 | block = await IO.read(readParam); 88 | let data = block.base64Encoded ? Buffer.from(block.data, 'base64') : block.data; 89 | fs.writeSync(pdfFd,data); 90 | }while (!block.eof); 91 | fs.fsyncSync(pdfFd); 92 | fs.closeSync(pdfFd); 93 | }; 94 | 95 | let waitPdfRenderComplete = async function(timeout){ 96 | let time = 0; 97 | return new Promise(function(resolve, reject){ 98 | let t = setInterval(function(){ 99 | time += 500; 100 | Runtime.evaluate({expression: checkPdfRenderCompleteJs}).then(function(ret){ 101 | let isOk = ret.result.value === true; 102 | if(isOk){ 103 | clearInterval(t); 104 | resolve(); 105 | } 106 | }); 107 | if(time > timeout){ 108 | clearInterval(t); 109 | reject('timeout'); 110 | } 111 | },500) 112 | }); 113 | }; 114 | 115 | let renderPdf = async function(){ 116 | console.log("open url:" + pageUrl); 117 | await Page.navigate({'url': pageUrl}); 118 | console.log("wait pdf render ..."); 119 | await waitPdfRenderComplete(timeout); 120 | console.log("print delay:" + printDelay); 121 | await sleep(printDelay); 122 | console.log("save pdf file:" + pdfFile); 123 | await printPdf(pdfFile); 124 | }; 125 | 126 | once('ready', function () { 127 | renderPdf().finally(function(){ 128 | // 清除缓存 129 | // Network.clearBrowserCache(); 130 | chrome.close() 131 | }) 132 | }); 133 | } 134 | }).on('error', function (err) { 135 | console.error('Cannot connect to Chrome:', err); 136 | }); 137 | }; 138 | 139 | module.exports = html2pdf; 140 | 141 | -------------------------------------------------------------------------------- /dist/eazy-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NOP BOOK TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 146 | 174 | 197 | 199 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /dist/eazy-4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NOP BOOK TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 145 |
146 | 178 | 201 | 203 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /dist/eazy-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NOP BOOK TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 145 | 147 | 171 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /dist/eazy-6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NOP BOOK TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 32 | 44 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /dist/static/js/qrcode-generator/1.4.4/qrcode.min.js: -------------------------------------------------------------------------------- 1 | var qrcode=function(){function i(t,r){function a(t,r){g=function(t){for(var r=new Array(t),e=0;e>e&1);g[Math.floor(e/3)][e%3+l-8-3]=n}for(e=0;e<18;e+=1){n=!t&&1==(r>>e&1);g[e%3+l-8-3][Math.floor(e/3)]=n}},v=function(t,r){for(var e=f<<3|r,n=B.getBCHTypeInfo(e),o=0;o<15;o+=1){var i=!t&&1==(n>>o&1);o<6?g[o][8]=i:o<8?g[o+1][8]=i:g[l-15+o][8]=i}for(o=0;o<15;o+=1){i=!t&&1==(n>>o&1);o<8?g[8][l-o-1]=i:o<9?g[8][15-o-1+1]=i:g[8][15-o-1]=i}g[l-8][8]=!t},d=function(t,r){for(var e=-1,n=l-1,o=7,i=0,a=B.getMaskFunction(r),u=l-1;0>>o&1)),a(n,u-f)&&(c=!c),g[n][u-f]=c,-1==(o-=1)&&(i+=1,o=7)}if((n+=e)<0||l<=n){n-=e,e=-e;break}}},w=function(t,r,e){for(var n=b.getRSBlocks(t,r),o=M(),i=0;i8*u)throw"code length overflow. ("+o.getLengthInBits()+">"+8*u+")";for(o.getLengthInBits()+4<=8*u&&o.put(0,4);o.getLengthInBits()%8!=0;)o.putBit(!1);for(;!(o.getLengthInBits()>=8*u||(o.put(236,8),o.getLengthInBits()>=8*u));)o.put(17,8);return function(t,r){for(var e=0,n=0,o=0,i=new Array(r.length),a=new Array(r.length),u=0;u',e+="";for(var n=0;n";for(var o=0;o';e+=""}return e+="",e+=""},s.createSvgTag=function(t,r,e,n){var o={};"object"==typeof t&&(t=(o=t).cellSize,r=o.margin,e=o.alt,n=o.title),t=t||2,r=void 0===r?4*t:r,(e="string"==typeof e?{text:e}:e||{}).text=e.text||null,e.id=e.text?e.id||"qrcode-description":null,(n="string"==typeof n?{text:n}:n||{}).text=n.text||null,n.id=n.text?n.id||"qrcode-title":null;var i,a,u,f,c=s.getModuleCount()*t+2*r,g="";for(f="l"+t+",0 0,"+t+" -"+t+",0 0,-"+t+"z ",g+=''+p(n.text)+"":"",g+=e.text?''+p(e.text)+"":"",g+='',g+='":r+=">";break;case"&":r+="&";break;case'"':r+=""";break;default:r+=n}}return r};return s.createASCII=function(t,r){if((t=t||1)<2)return function(t){t=void 0===t?2:t;var r,e,n,o,i,a=1*s.getModuleCount()+2*t,u=t,f=a-t,c={"██":"█","█ ":"▀"," █":"▄"," ":" "},g={"██":"▀","█ ":"▀"," █":" "," ":" "},l="";for(r=0;r>>8),r.push(255&o)):r.push(a)}}return r}};var r,t,a=1,u=2,o=4,f=8,y={L:1,M:0,Q:3,H:2},e=0,n=1,c=2,g=3,l=4,h=5,s=6,v=7,B=(r=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],(t={}).getBCHTypeInfo=function(t){for(var r=t<<10;0<=d(r)-d(1335);)r^=1335<>>=1;return r}var w=function(){for(var r=new Array(256),e=new Array(256),t=0;t<8;t+=1)r[t]=1<>>8)},writeBytes:function(t,r,e){r=r||0,e=e||t.length;for(var n=0;n>>7-t%8&1)},put:function(t,r){for(var e=0;e>>r-e-1&1))},getLengthInBits:function(){return n},putBit:function(t){var r=Math.floor(n/8);e.length<=r&&e.push(0),t&&(e[r]|=128>>>n%8),n+=1}};return o},x=function(t){var r=a,n=t,e={getMode:function(){return r},getLength:function(t){return n.length},write:function(t){for(var r=n,e=0;e+2>>8&255)+(255&n),t.put(n,13),e+=2}if(e=e.length){if(0==i)return-1;throw"unexpected end of file./"+i}var t=e.charAt(n);if(n+=1,"="==t)return i=0,-1;t.match(/^\s$/)||(o=o<<6|a(t.charCodeAt(0)),i+=6)}var r=o>>>i-8&255;return i-=8,r}},a=function(t){if(65<=t&&t<=90)return t-65;if(97<=t&&t<=122)return t-97+26;if(48<=t&&t<=57)return t-48+52;if(43==t)return 62;if(47==t)return 63;throw"c:"+t};return r},I=function(t,r,e){for(var n=function(t,r){var n=t,o=r,l=new Array(t*r),e={setPixel:function(t,r,e){l[r*n+t]=e},write:function(t){t.writeString("GIF87a"),t.writeShort(n),t.writeShort(o),t.writeByte(128),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(255),t.writeByte(255),t.writeByte(255),t.writeString(","),t.writeShort(0),t.writeShort(0),t.writeShort(n),t.writeShort(o),t.writeByte(0);var r=i(2);t.writeByte(2);for(var e=0;255>>r!=0)throw"length over";for(;8<=n+r;)e.writeByte(255&(t<>>=8-n,n=o=0;o|=t<>>o-6),o-=6},t.flush=function(){if(0>6,128|63&n):n<55296||57344<=n?r.push(224|n>>12,128|n>>6&63,128|63&n):(e++,n=65536+((1023&n)<<10|1023&t.charCodeAt(e)),r.push(240|n>>18,128|n>>12&63,128|n>>6&63,128|63&n))}return r}(t)},function(t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&(module.exports=t())}(function(){return qrcode}); -------------------------------------------------------------------------------- /dist/data/chart-1.json: -------------------------------------------------------------------------------- 1 | [["2015/12/31","3570.47","3539.18","-33.69","-0.94%","3538.35","3580.6","176963664","25403106","-"],["2015/12/30","3566.73","3572.88","9.14","0.26%","3538.11","3573.68","187889600","26778766","-"],["2015/12/29","3528.4","3563.74","29.96","0.85%","3515.52","3564.17","182551920","25093890","-"],["2015/12/28","3635.77","3533.78","-94.13","-2.59%","3533.78","3641.59","269983264","36904280","-"],["2015/12/25","3614.05","3627.91","15.43","0.43%","3601.74","3635.26","198451120","27466004","-"],["2015/12/24","3631.31","3612.49","-23.6","-0.65%","3572.28","3640.22","227785216","31542126","-"],["2015/12/23","3653.28","3636.09","-15.68","-0.43%","3633.03","3684.57","298201792","41990292","-"],["2015/12/22","3645.99","3651.77","9.3","0.26%","3616.87","3652.63","261178752","36084604","-"],["2015/12/21","3568.58","3642.47","63.51","1.77%","3565.75","3651.06","299849280","39831696","-"],["2015/12/18","3574.94","3578.96","-1.03","-0.03%","3568.16","3614.7","273707904","36538580","-"],["2015/12/17","3533.63","3580","63.81","1.81%","3533.63","3583.41","283856480","38143960","-"],["2015/12/16","3522.09","3516.19","5.83","0.17%","3506.29","3538.69","193482304","26528864","-"],["2015/12/15","3518.13","3510.35","-10.31","-0.29%","3496.85","3529.96","200471344","27627494","-"],["2015/12/14","3403.51","3520.67","86.09","2.51%","3399.28","3521.78","215374624","27921354","-"],["2015/12/11","3441.6","3434.58","-20.91","-0.61%","3410.92","3455.55","182908880","24507642","-"],["2015/12/10","3469.81","3455.5","-16.94","-0.49%","3446.27","3503.65","200427520","27949970","-"],["2015/12/9","3462.58","3472.44","2.37","0.07%","3454.88","3495.7","195698848","26785488","-"],["2015/12/8","3518.65","3470.07","-66.86","-1.89%","3466.79","3518.65","224367312","29782174","-"],["2015/12/7","3529.81","3536.93","11.94","0.34%","3506.62","3543.95","208302576","28056158","-"],["2015/12/4","3558.15","3524.99","-59.83","-1.67%","3510.41","3568.97","251736416","31976682","-"],["2015/12/3","3525.73","3584.82","47.92","1.35%","3517.23","3591.73","281111232","33885908","-"],["2015/12/2","3450.28","3536.91","80.6","2.33%","3427.66","3538.85","301491488","36918304","-"],["2015/12/1","3442.44","3456.31","10.9","0.32%","3417.54","3483.41","252390752","33025674","-"],["2015/11/30","3433.85","3445.4","9.1","0.26%","3327.81","3470.37","304197888","38750364","-"],["2015/11/27","3616.54","3436.3","-199.25","-5.48%","3412.43","3621.9","354287520","46431124","-"],["2015/11/26","3659.57","3635.55","-12.38","-0.34%","3629.86","3668.38","306761600","42624744","-"],["2015/11/25","3614.07","3647.93","31.82","0.88%","3607.52","3648.37","273024864","38080292","-"],["2015/11/24","3602.89","3616.11","5.79","0.16%","3563.1","3616.48","248810512","32775852","-"],["2015/11/23","3630.87","3610.31","-20.18","-0.56%","3598.87","3654.75","315997472","41414824","-"],["2015/11/20","3620.79","3630.5","13.44","0.37%","3607.92","3640.53","310801984","41391088","-"],["2015/11/19","3573.78","3617.06","48.59","1.36%","3561.04","3618.21","247915584","32844260","-"],["2015/11/18","3605.06","3568.47","-36.33","-1.01%","3558.7","3617.07","297580736","39233876","-"],["2015/11/17","3629.98","3604.8","-2.16","-0.06%","3598.07","3678.27","383575456","52152036","-"],["2015/11/16","3522.46","3606.96","26.12","0.73%","3519.42","3607.61","276187040","36942184","-"],["2015/11/13","3600.76","3580.84","-52.06","-1.43%","3564.81","3632.56","345870944","46866864","-"],["2015/11/12","3656.82","3632.9","-17.35","-0.48%","3603.23","3659.31","361717600","48283260","-"],["2015/11/11","3635","3650.25","9.76","0.27%","3605.62","3654.88","360972672","46782220","-"],["2015/11/10","3617.4","3640.49","-6.4","-0.18%","3607.89","3669.53","429746592","56005512","-"],["2015/11/9","3588.5","3646.88","56.85","1.58%","3588.5","3673.76","503016704","63618404","-"],["2015/11/6","3514.44","3590.03","67.21","1.91%","3508.83","3596.38","429167040","54328220","-"],["2015/11/5","3459.22","3522.82","63.18","1.83%","3455.53","3585.66","553254976","67867464","-"],["2015/11/4","3325.62","3459.64","142.94","4.31%","3325.62","3459.65","339078752","42610440","-"],["2015/11/3","3330.32","3316.7","-8.39","-0.25%","3302.18","3346.27","192897440","24436056","-"],["2015/11/2","3337.58","3325.08","-57.48","-1.70%","3322.31","3391.06","230951136","28601932","-"],["2015/10/30","3380.28","3382.56","-4.75","-0.14%","3346.59","3417.2","243595120","30726678","-"],["2015/10/29","3387.77","3387.32","12.12","0.36%","3362.51","3411.71","235676016","29450842","-"],["2015/10/28","3417.01","3375.2","-59.14","-1.72%","3367.23","3439.76","293523296","36165620","-"],["2015/10/27","3409.14","3434.34","4.76","0.14%","3332.62","3441.57","328172768","40888724","-"],["2015/10/26","3448.65","3429.58","17.15","0.50%","3402","3457.52","365560864","45394252","-"],["2015/10/23","3377.55","3412.43","43.7","1.30%","3360.22","3422.02","347372864","42526308","-"],["2015/10/22","3292.29","3368.74","48.06","1.45%","3282.99","3373.78","323739328","37545200","-"],["2015/10/21","3428.56","3320.68","-104.65","-3.06%","3265.44","3447.26","458455424","51850924","-"],["2015/10/20","3377.55","3425.33","38.63","1.14%","3357.86","3425.52","318973760","38358252","-"],["2015/10/19","3401.63","3386.7","-4.65","-0.14%","3355.57","3423.4","378112160","45330364","-"],["2015/10/16","3358.3","3391.35","53.28","1.60%","3334.85","3393.02","395460576","45944784","-"],["2015/10/15","3255.03","3338.07","75.63","2.32%","3254.39","3338.3","316283840","36256556","-"],["2015/10/14","3280.02","3262.44","-30.79","-0.93%","3256.25","3307.32","295077760","33027752","-"],["2015/10/13","3262.16","3293.23","5.57","0.17%","3253.25","3298.63","297153120","33480608","-"],["2015/10/12","3193.54","3287.66","104.51","3.28%","3188.41","3318.71","386294688","43554100","-"],["2015/10/9","3146.64","3183.15","39.79","1.27%","3137.79","3192.72","234851456","25637910","-"],["2015/10/8","3156.07","3143.36","90.58","2.97%","3133.13","3172.28","234276048","25883034","-"],["2015/9/30","3052.84","3052.78","14.64","0.48%","3039.74","3073.3","146642448","15656919","-"],["2015/9/29","3055.22","3038.14","-62.62","-2.02%","3021.16","3068.3","163222672","16968660","-"],["2015/9/28","3085.57","3100.76","8.41","0.27%","3042.31","3103.07","156727536","16642240","-"],["2015/9/25","3130.85","3092.35","-50.34","-1.60%","3063","3149.95","236263872","24897112","-"],["2015/9/24","3126.49","3142.69","26.8","0.86%","3109.69","3151.16","212887712","23136904","-"],["2015/9/23","3137.72","3115.89","-69.73","-2.19%","3104.74","3164.04","236322672","25756004","-"],["2015/9/22","3161.32","3185.62","29.08","0.92%","3152.48","3213.48","274786176","30507132","-"],["2015/9/21","3072.09","3156.54","58.62","1.89%","3060.86","3159.88","239897360","25979668","-"],["2015/9/18","3100.28","3097.92","11.86","0.38%","3070.34","3122.05","209175392","21844244","-"],["2015/9/17","3131.98","3086.06","-66.2","-2.10%","3085.31","3204.7","317602912","33739328","-"],["2015/9/16","2998.04","3152.26","147.09","4.89%","2983.54","3182.93","277524512","28199226","-"],["2015/9/15","3043.8","3005.17","-109.63","-3.52%","2983.92","3081.7","249194448","24390460","-"],["2015/9/14","3221.17","3114.8","-85.44","-2.67%","3049.23","3229.48","346631168","37357680","-"],["2015/9/11","3189.48","3200.23","2.34","0.07%","3163.45","3223.76","224557808","25276946","-"],["2015/9/10","3190.55","3197.89","-45.2","-1.39%","3178.9","3243.28","273261760","29958108","-"],["2015/9/9","3182.55","3243.09","72.64","2.29%","3165.7","3256.74","375328000","41299144","-"],["2015/9/8","3054.44","3170.45","90.03","2.92%","3011.12","3174.71","255415456","26391038","-"],["2015/9/7","3149.38","3080.42","-79.75","-2.52%","3066.3","3217.58","296468096","30268972","-"],["2015/9/2","3027.68","3160.17","-6.46","-0.20%","3019.09","3194.48","438170176","42326236","-"],["2015/9/1","3157.83","3166.62","-39.36","-1.23%","3053.74","3180.33","432432448","42041164","-"],["2015/8/31","3203.56","3205.99","-26.36","-0.82%","3109.16","3207.86","397431392","43106860","-"],["2015/8/28","3125.26","3232.35","148.76","4.82%","3102.95","3235.84","443136928","47463100","-"],["2015/8/27","2978.03","3083.59","156.3","5.34%","2906.49","3085.42","400308384","40428928","-"],["2015/8/26","2980.79","2927.29","-37.68","-1.27%","2850.71","3092.04","466699680","46178896","-"],["2015/8/25","3004.13","2964.97","-244.94","-7.63%","2947.94","3123.03","352325088","35873576","-"],["2015/8/24","3373.48","3209.91","-297.84","-8.49%","3191.88","3388.36","334671776","35881888","-"],["2015/8/21","3609.96","3507.74","-156.55","-4.27%","3490.54","3652.84","369920480","45061648","-"],["2015/8/20","3754.57","3664.29","-129.82","-3.42%","3663.61","3788.01","390063072","50119500","-"],["2015/8/19","3646.8","3794.11","45.95","1.23%","3558.38","3811.43","475396224","59951332","-"],["2015/8/18","3999.13","3748.16","-245.5","-6.15%","3743.39","4006.34","543770816","72246720","-"],["2015/8/17","3947.84","3993.67","28.33","0.71%","3907.4","3994.54","460432064","62632768","-"],["2015/8/14","3976.41","3965.33","10.78","0.27%","3939.83","4000.68","467988224","64746644","-"],["2015/8/13","3869.91","3954.56","68.24","1.76%","3838.16","3955.79","430073280","57868552","-"],["2015/8/12","3881.23","3886.32","-41.59","-1.06%","3871.14","3937.77","442688256","59705028","-"],["2015/8/11","3928.81","3927.91","-0.51","-0.01%","3891.18","3970.34","538923456","71228992","-"],["2015/8/10","3786.03","3928.42","184.21","4.92%","3775.85","3943.62","497304320","65262204","-"],["2015/8/7","3692.61","3744.2","82.67","2.26%","3686.3","3756.74","340757184","44548504","-"],["2015/8/6","3625.5","3661.54","-33.03","-0.89%","3614.74","3710.57","274074656","35751512","-"],["2015/8/5","3745.65","3694.57","-61.97","-1.65%","3676.39","3782.35","366423008","48385028","-"],["2015/8/4","3621.85","3756.54","133.64","3.69%","3601.29","3757.03","362901664","46403624","-"],["2015/8/3","3614.99","3622.91","-40.82","-1.11%","3549.5","3648.94","363968704","44599160","-"],["2015/7/31","3655.67","3663.73","-42.04","-1.13%","3620.17","3729.51","350955712","46047224","-"],["2015/7/30","3773.79","3705.77","-83.4","-2.20%","3685.96","3844.37","457943232","61597792","-"],["2015/7/29","3689.82","3789.17","126.17","3.44%","3612.06","3792.07","434352096","55749196","-"],["2015/7/28","3573.14","3663","-62.56","-1.68%","3537.36","3762.53","563330048","68505752","-"],["2015/7/27","3985.57","3725.56","-345.35","-8.48%","3720.44","4051.16","556003264","72129808","-"],["2015/7/24","4124.75","4070.91","-53.02","-1.29%","4044.83","4184.45","627424896","84302208","-"],["2015/7/23","4022.27","4123.92","97.88","2.43%","4019.04","4132.61","563585984","74353184","-"],["2015/7/22","3996.43","4026.04","8.37","0.21%","3960.86","4042.34","520732224","67883192","-"],["2015/7/21","3939.9","4017.67","25.57","0.64%","3912.8","4041.82","504288000","64641684","-"],["2015/7/20","3948.42","3992.11","34.76","0.88%","3927.12","4021.33","539106688","68825560","-"],["2015/7/17","3831.42","3957.35","134.18","3.51%","3814.15","3994.48","481726272","59306700","-"],["2015/7/16","3758.5","3823.18","17.47","0.46%","3688.44","3877.51","492256224","56985892","-"],["2015/7/15","3874.97","3805.7","-118.78","-3.03%","3741.25","3914.27","601301312","70053656","-"],["2015/7/14","3958.37","3924.49","-45.9","-1.16%","3855.56","4035.43","670558784","83007464","-"],["2015/7/13","3918.99","3970.39","92.58","2.39%","3858.64","4030.19","643489024","78243056","-"],["2015/7/10","3707.46","3877.8","168.47","4.54%","3677.43","3959.22","586364288","68043416","-"],["2015/7/9","3432.45","3709.33","202.14","5.76%","3373.54","3748.48","656914624","67331096","-"],["2015/7/8","3467.4","3507.19","-219.93","-5.90%","3421.53","3599.25","680356928","70024832","-"],["2015/7/7","3654.78","3727.12","-48.79","-1.29%","3585.4","3750.57","698818752","77607256","-"],["2015/7/6","3975.21","3775.91","89","2.41%","3653.04","3975.21","831139264","94342040","-"],["2015/7/3","3793.71","3686.92","-225.85","-5.77%","3629.56","3927.13","548163072","64805412","-"],["2015/7/2","4058.62","3912.77","-140.93","-3.48%","3795.25","4080.39","586015616","73600680","-"],["2015/7/1","4214.15","4053.7","-223.52","-5.23%","4043.37","4317.05","598769408","83807088","-"],["2015/6/30","4006.75","4277.22","224.19","5.53%","3847.88","4279.97","709176576","94152464","-"],["2015/6/29","4289.77","4053.03","-139.84","-3.34%","3875.05","4297.47","673786368","90427136","-"],["2015/6/26","4399.93","4192.87","-334.91","-7.40%","4139.53","4456.9","565217920","78783568","-"],["2015/6/25","4711.76","4527.78","-162.37","-3.46%","4483.55","4720.7","572797568","86537976","-"],["2015/6/24","4604.58","4690.15","113.66","2.48%","4552.13","4691.77","543003712","81506272","-"],["2015/6/23","4471.61","4576.49","98.13","2.19%","4264.77","4577.94","473526112","69361720","-"],["2015/6/19","4689.93","4478.36","-306.99","-6.42%","4476.5","4744.08","452689632","68545816","-"],["2015/6/18","4942.52","4785.36","-182.54","-3.67%","4780.87","4966.77","507440896","78584504","-"],["2015/6/17","4890.55","4967.9","80.47","1.65%","4767.22","4983.66","537101120","83026672","-"],["2015/6/16","5004.41","4887.43","-175.56","-3.47%","4842.1","5029.68","550801408","89542056","-"],["2015/6/15","5174.42","5062.99","-103.36","-2.00%","5048.74","5176.79","637803968","106499200","-"],["2015/6/12","5143.34","5166.35","44.76","0.87%","5103.4","5178.19","625627904","106016744","-"],["2015/6/11","5101.44","5121.59","15.56","0.30%","5050.76","5122.46","563990528","97467056","-"],["2015/6/10","5049.2","5106.04","-7.5","-0.15%","5001.49","5164.16","596969024","100642824","-"],["2015/6/9","5145.98","5113.53","-18.35","-0.36%","5042.96","5147.45","729893824","115080864","-"],["2015/6/8","5045.69","5131.88","108.78","2.17%","4997.48","5146.95","855035072","130992456","-"],["2015/6/5","5016.09","5023.1","75.99","1.54%","4898.07","5051.63","772240832","123230064","-"],["2015/6/4","4912.95","4947.1","37.12","0.76%","4647.41","4947.96","674952384","105227024","-"],["2015/6/3","4924.38","4909.98","-0.55","-0.01%","4822.44","4942.06","611453824","101018000","-"],["2015/6/2","4844.7","4910.53","81.79","1.69%","4797.55","4911.57","623748096","99874576","-"],["2015/6/1","4633.1","4828.74","216.99","4.71%","4615.23","4829.5","593389056","93445544","-"],["2015/5/29","4603.47","4611.74","-8.52","-0.18%","4431.56","4698.19","611262400","95536560","-"],["2015/5/28","4943.74","4620.27","-321.45","-6.50%","4614.24","4986.5","782964544","124792600","-"],["2015/5/27","4932.85","4941.71","30.82","0.63%","4857.06","4958.16","681165376","111626184","-"],["2015/5/26","4854.85","4910.9","97.1","2.02%","4779.08","4911.69","704892864","113850936","-"],["2015/5/25","4660.08","4813.8","156.2","3.35%","4656.83","4814.67","682461376","107929560","-"],["2015/5/22","4584.98","4657.6","128.17","2.83%","4562.99","4658.27","655591296","100717320","-"],["2015/5/21","4456.44","4529.42","83.13","1.87%","4438.26","4530.48","464996512","72908056","-"],["2015/5/20","4434.98","4446.29","28.74","0.65%","4432.28","4520.54","514106208","80608056","-"],["2015/5/19","4285.78","4417.55","134.06","3.13%","4285.78","4418.4","436735232","69381256","-"],["2015/5/18","4277.9","4283.49","-25.2","-0.58%","4260.51","4324.83","380057440","59455952","-"],["2015/5/15","4366.82","4308.69","-69.62","-1.59%","4278.55","4366.82","439706208","66596564","-"],["2015/5/14","4372.82","4378.31","2.55","0.06%","4329.04","4397.75","449077952","66988224","-"],["2015/5/13","4402.38","4375.76","-25.46","-0.58%","4342.48","4415.63","510490464","78075496","-"],["2015/5/12","4342.37","4401.22","67.64","1.56%","4317.98","4402.31","521866400","79346376","-"],["2015/5/11","4231.27","4333.58","127.67","3.04%","4187.82","4334.88","488750528","71524664","-"],["2015/5/8","4152.98","4205.92","93.7","2.28%","4099.04","4206.86","397428096","55964868","-"],["2015/5/7","4197.9","4112.21","-117.05","-2.77%","4108.01","4213.76","394566656","54020632","-"],["2015/5/6","4311.64","4229.27","-69.44","-1.62%","4187.37","4376.35","481732992","71653624","-"],["2015/5/5","4479.85","4298.71","-181.76","-4.06%","4282.24","4488.87","572858624","80556608","-"],["2015/5/4","4441.34","4480.46","38.81","0.87%","4387.43","4487.57","494173376","71754080","-"],["2015/4/30","4483.01","4441.65","-34.96","-0.78%","4441.05","4507.34","526728000","77434920","-"],["2015/4/29","4446.12","4476.62","0.4","0.01%","4398.64","4499.94","519834208","75240176","-"],["2015/4/28","4527.63","4476.21","-51.18","-1.13%","4432.9","4572.39","767676416","106117216","-"],["2015/4/27","4441.93","4527.4","133.71","3.04%","4441.93","4529.73","671088512","97524208","-"],["2015/4/24","4355.95","4393.69","-20.82","-0.47%","4318.12","4416.38","628555008","91687296","-"],["2015/4/23","4414.48","4414.51","16.01","0.36%","4358.84","4444.41","667344640","96302488","-"],["2015/4/22","4304.6","4398.49","104.87","2.44%","4297.95","4400.19","680305088","97687696","-"],["2015/4/21","4212.19","4293.62","76.55","1.82%","4188.57","4294.38","634470656","86244776","-"],["2015/4/20","4301.35","4217.08","-70.22","-1.64%","4190.68","4356","857132800","100000000","-"],["2015/4/17","4254.72","4287.3","92.47","2.20%","4238.91","4317.22","701706240","91563304","-"],["2015/4/16","4055.92","4194.82","110.66","2.71%","4031.24","4195.31","551242944","71208248","-"],["2015/4/15","4135.65","4084.16","-51.4","-1.24%","4069.01","4175.49","613005824","77312592","-"],["2015/4/14","4125.78","4135.56","13.85","0.34%","4091.26","4168.35","610683520","81464520","-"],["2015/4/13","4072.72","4121.71","87.4","2.17%","4057.29","4128.07","589814208","78166736","-"],["2015/4/10","3947.49","4034.31","76.78","1.94%","3929.32","4040.35","484283648","66850416","-"],["2015/4/9","4006.13","3957.53","-37.28","-0.93%","3900.03","4016.4","585176832","81671088","-"],["2015/4/8","3976.53","3994.81","33.43","0.84%","3903.65","4000.22","618085440","83915928","-"],["2015/4/7","3899.42","3961.38","97.45","2.52%","3891.73","3961.67","570447552","74642400","-"],["2015/4/3","3803.38","3863.93","38.14","1.00%","3792.21","3864.41","473033312","63565136","-"],["2015/4/2","3827.69","3825.78","15.49","0.41%","3775.89","3835.45","479299680","63202892","-"],["2015/4/1","3748.34","3810.29","62.4","1.66%","3742.21","3817.08","447458304","59241832","-"],["2015/3/31","3822.99","3747.9","-38.67","-1.02%","3737.04","3835.57","561676032","72129488","-"],["2015/3/30","3710.61","3786.57","95.47","2.59%","3710.61","3795.94","564702400","69212536","-"],["2015/3/27","3686.13","3691.1","9","0.24%","3656.83","3710.48","408945184","50929848","-"],["2015/3/26","3641.94","3682.09","21.37","0.58%","3615.01","3707.32","488647200","61951560","-"],["2015/3/25","3680.95","3660.73","-30.68","-0.83%","3634.56","3693.15","521886336","64549892","-"],["2015/3/24","3692.57","3691.41","3.68","0.10%","3600.7","3715.87","639554688","75488472","-"],["2015/3/23","3640.1","3687.73","70.41","1.95%","3635.49","3688.25","536062816","66157464","-"],["2015/3/20","3587.08","3617.32","35.05","0.98%","3569.38","3632.34","516661664","65177196","-"],["2015/3/19","3576.02","3582.27","4.97","0.14%","3546.84","3600.68","537346624","61224968","-"],["2015/3/18","3510.5","3577.3","74.45","2.13%","3503.85","3577.66","545217152","61736700","-"],["2015/3/17","3469.6","3502.85","53.54","1.55%","3459.69","3504.12","520939520","60150068","-"],["2015/3/16","3391.16","3449.3","76.39","2.26%","3377.09","3449.3","399132416","47935532","-"],["2015/3/13","3359.49","3372.91","23.59","0.70%","3352.15","3391.25","328410144","37404140","-"],["2015/3/12","3314.81","3349.32","58.42","1.78%","3300.49","3360.05","357295104","40719240","-"],["2015/3/11","3289.59","3290.9","4.83","0.15%","3278.47","3325.05","282985536","32757308","-"],["2015/3/10","3289.08","3286.07","-16.34","-0.49%","3277.09","3309.92","285817568","32995596","-"],["2015/3/9","3224.31","3302.41","61.22","1.89%","3198.37","3307.7","321495456","35992752","-"],["2015/3/6","3248.04","3241.19","-7.29","-0.22%","3234.53","3266.93","282915808","32834414","-"],["2015/3/5","3264.08","3248.48","-31.06","-0.95%","3221.67","3266.64","320663584","37358000","-"],["2015/3/4","3264.18","3279.53","16.48","0.51%","3250.48","3286.59","293639520","34678976","-"],["2015/3/3","3317.7","3263.05","-73.23","-2.20%","3260.43","3317.7","382044608","44159348","-"],["2015/3/2","3332.72","3336.28","25.98","0.78%","3298.67","3336.76","346445664","41025956","-"],["2015/2/27","3296.83","3310.3","11.94","0.36%","3291.01","3324.55","299163712","33501958","-"],["2015/2/26","3222.15","3298.36","69.52","2.15%","3202.19","3300.62","301263872","33434746","-"],["2015/2/25","3256.48","3228.84","-18.06","-0.56%","3215.55","3257.22","233348096","26514336","-"],["2015/2/17","3230.88","3246.91","24.54","0.76%","3230.77","3255.73","228332624","26334004","-"],["2015/2/16","3206.14","3222.36","18.54","0.58%","3195.88","3228.85","223797440","26595070","-"],["2015/2/13","3186.81","3203.83","30.41","0.96%","3182.79","3237.16","261290432","29301768","-"],["2015/2/12","3157.96","3173.42","15.71","0.50%","3134.24","3181.77","194592320","22969158","-"],["2015/2/11","3145.76","3157.7","16.11","0.51%","3139.05","3166.42","172840096","21086256","-"],["2015/2/10","3090.49","3141.59","46.47","1.50%","3084.25","3142.1","193817136","22508492","-"],["2015/2/9","3063.51","3095.12","19.22","0.62%","3049.11","3119.03","206108384","24071968","-"],["2015/2/6","3120.09","3075.91","-60.62","-1.93%","3052.94","3129.54","246749680","26650278","-"],["2015/2/5","3251.21","3136.53","-37.6","-1.18%","3135.82","3251.21","306139296","34826696","-"],["2015/2/4","3212.82","3174.13","-30.78","-0.96%","3171.14","3238.98","249098080","29015516","-"],["2015/2/3","3156.09","3204.91","76.61","2.45%","3129.73","3207.94","248192160","28335594","-"],["2015/2/2","3148.14","3128.3","-82.06","-2.56%","3122.57","3175.13","250861632","26684996","-"],["2015/1/30","3273.75","3210.36","-51.94","-1.59%","3210.31","3288.5","258312544","28426564","-"],["2015/1/29","3259","3262.3","-43.43","-1.31%","3234.24","3286.79","274658624","29642450","-"],["2015/1/28","3325.72","3305.74","-47.22","-1.41%","3294.66","3354.8","301927104","34156428","-"],["2015/1/27","3389.85","3352.96","-30.22","-0.89%","3290.22","3390.22","374517568","41829884","-"],["2015/1/26","3347.26","3383.18","31.42","0.94%","3321.31","3384.8","317540992","35842744","-"],["2015/1/23","3357.1","3351.76","8.42","0.25%","3328.29","3406.79","366249248","42097952","-"],["2015/1/22","3327.32","3343.34","19.73","0.59%","3293.98","3352.38","353382976","40787408","-"],["2015/1/21","3189.08","3323.61","150.56","4.74%","3178.34","3337","410956032","47375868","-"],["2015/1/20","3114.56","3173.05","56.7","1.82%","3100.48","3190.25","357080800","41629524","-"],["2015/1/19","3189.73","3116.35","-260.14","-7.70%","3095.07","3262.21","401098784","40988600","-"],["2015/1/16","3343.6","3376.5","40.04","1.20%","3340.49","3400.32","339876768","39225388","-"],["2015/1/15","3224.07","3336.46","114.02","3.54%","3207.54","3337.08","282546240","33061054","-"],["2015/1/14","3242.34","3222.44","-12.86","-0.40%","3193.98","3268.48","240190752","26720452","-"],["2015/1/13","3223.54","3235.3","5.98","0.19%","3214.41","3259.39","230725760","27358878","-"],["2015/1/12","3258.21","3229.32","-56.1","-1.71%","3191.58","3275.19","322064672","36627308","-"],["2015/1/9","3276.97","3285.41","-8.04","-0.24%","3267.51","3404.83","410240864","45864804","-"],["2015/1/8","3371.96","3293.46","-80.5","-2.39%","3285.09","3381.57","371131200","39923032","-"],["2015/1/7","3326.65","3373.95","22.51","0.67%","3312.21","3374.9","391918880","43641672","-"],["2015/1/6","3330.8","3351.45","0.93","0.03%","3303.18","3394.22","501661696","53239848","-"],["2015/1/5","3258.63","3350.52","115.84","3.58%","3253.88","3369.28","531352384","54976008","-"],["","","","","","","","","",""],["","","","","","","","","",""]] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WEB打印,HTML转PDF工具。bookjs-eazy 2 | 3 | - Readme: [中文](./README.md) | [English](./README-en.md) 4 | - 仓库地址: [GITEE](https://gitee.com/wuxue107/bookjs-eazy) | [GITHUB](https://github.com/wuxue107/bookjs-eazy) 5 | - 主要解决,HTML生成PDF,分页可控的问题,从此生成高品质PDF不在是困难的事 6 | - 依赖js库:polyfill、jquery、lodash、bookjs-eazy 7 | - 优势: 8 | 9 | 1. 只需专注用H5构件你的PDF内容,而无需关心分页及内容截断问题,按规则自动分页。 10 | 2. 支持预览,所见即所得。支持WEB打印、支持自定义页码/目录/页眉/页脚。 11 | 3. 前后端皆可生成PDF,前端打印另存为PDF,后端可配套使用chrome headless和wkhtmltopdf命令行PDF生成工具。 12 | 4. docker镜像。可快速构件你的在线PDF的打印生成服务 13 | 5. 兼容主流浏览器及移动端 14 | 15 | 16 | - 缺陷提示: 17 | 18 | 1. 不支持现代js框架 VUE、React等单页面多路由场景,需要在html中用script标签直接引入,不能在import引入再经过编译 19 | 2. 不支持动态刷新,重新渲染需要刷新整个页面 20 | 3. PDF页面需要单独的html文件入口 21 | 4. 如果想嵌入应用网页内部,可使用iframe方式 22 | 23 | 24 | # 预览案例(./dist) 25 | 26 | - eazy-1.html 27 | 28 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-1-qrcode.png) 29 | 30 | - 另一个小说案例 31 | - JS : eazy-2.html 32 | - Lodash模板:eazy-4.html 33 | - Vue模板: eazy-3.html 34 | 35 | 36 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-2-qrcode.png) 37 | 38 | - 发票案例 39 | - eazy-5.html 40 | - **注意**:对于自定义纸张的页面,只有在web打印中只有在chrome“打印另存为PDF”或有安装并选择对应打印机和纸张时在能正确显示。否则有可能错乱。使用chrome headless和wkhtmltopdf不影响 41 | 42 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-5-qrcode.png) 43 | 44 | - 表格: 合并单元格 45 | - 参考实例:eazy-6.html 46 | 47 | 48 | # 使用docker快速体验(可以不使用docker,请参考,[PDF生成服务安装](#自建打印服务本机安装pdf生成服务)章节) 49 | 50 | - 下载或clone项目,命令行进入项目目录 51 | - 运行 ./docker-start.sh 或 docker-start.bat 52 | - 即可通过浏览器 http://127.0.0.1:3000/eazy-1.html 访问demo,打印并制作PDF 53 | - 在dist目录下可以尝试写自己的pdf页面。 54 | 55 | # 使用方式: 56 | 57 | 渲染机制: 58 | 1. 将PDF页面内容元素放置body>#content-box节点下(参考:PDF内容设计) 59 | 2. 程序会检查全局变量window.bookConfig.start 的值(参考:配置页面参数) 60 | 直到此值为true时,才开始渲染将 #content-box 节点的内容渲染为PDF样式。 61 | **重要**:如果你的页面是动态的,就先将默认值设为false,当内容准备好后,在将其设为true。 62 | 3. 高度页面溢出检测原理: 63 | 页面内容节点.nop-page-content,是一个弹性高度的容器节点。 64 | 在向页面加入内容时会引起容器节点的高度变化。 65 | 计算页面的是否溢出,就时通过计算它高度得到的。 66 | **注意**: 67 | a. display: float, position: absolute; overflow样式的元素的插入不会页面容器高度变化。可能造成页面溢出而检测不到。 68 | b. 因为 margin样式的元素 无法撑开.nop-page-content 大小,造成.nop-page-content位置偏移,很容易造成页面出现溢出的现象,所以控制相对位置尽量使用padding 69 | 70 | ## 配置页面参数: 71 | 72 | - 定义一个全局配置变量 bookConfig 73 | 74 | ```html 75 |
$' + '{PAGE} / $' + '{TOTAL_PAGE}
', 130 | }, 131 | 132 | // 目录/书签插件,可选(默认未开启),所列选项为开启时的默认值 133 | simpleCatalog : { 134 | // 当前版本,如果需要生成PDF书签,toolBar.serverPrint.wkHtmlToPdf 必须为true 135 | // titlesSelector不要修改,使用h1-h6标记书签 136 | titlesSelector : 'h1,h2,h3,h4,h5,h6', // 可选,作为目录标题的选择器,按目录级别依次 137 | 138 | 139 | /** 目录相关选项 **/ 140 | showCatalog : true, // 可选,是否在页面中插入目录,默认,插入目录到页面 141 | header : '
目 录
', // 可选,目录页Header部分,放入你想加入的一切 142 | itemFillChar : '…', // 可选,目录项填充字符, ""空字符串,不填充,使用自定义makeItem时,忽略该选项配置 143 | positionSelector : '.nop-page-item-pagenum-1', //可选,目录位置会插入在匹配页的之前,默认为第一个编号页前 144 | // 可选,自定义目录项。 145 | makeItem : function(itemEl,itemInfo) { 146 | /** 147 | * @var itemEl jQuery Element 148 | * @var object itemInfo PS: {title, pageNum, level,linkId} 149 | **/ 150 | return '
自定义的目录项html内容,根据itemInfo自己构造
'; 151 | }, 152 | 153 | /** 侧边栏(PDF书签)相关选项 **/ 154 | showSlide : true, // 可选,是否显示侧边栏,目录导航,工具栏按钮顺序index: 200, 在bookConfig.toolBar选项为false时无效 155 | slideOn : false, // 可选,目录导航,默认是否打开状态 156 | slideHeader : '
目  录
', // 可选,侧边栏标题 157 | slideClassName : '', // 可选,侧边栏自定义class 158 | slidePosition : 'left', // 可选,位置 left、right 159 | slideMakeContent : null, // 自定义侧边栏内容处理函数,为null时,默认行为:使用目录内容填充, function(){ return '侧边栏内容';} 160 | }, 161 | 162 | // 工具栏插件,可选(默认开启),object|false, false会不显示工具栏, 所列选项为开启时的默认值 163 | toolBar : { 164 | // Web打印按钮功能可选,默认true, 按钮顺序index: 100 165 | webPrint : true, 166 | 167 | /** 168 | * HTML保存按钮,可选,bool|object,默认false:禁用保存HTML功能,true:启用并使用默认选项 169 | * 按钮顺序index: 300 170 | * saveHtml : { 171 | * // 可选,保存的文件名,默认值: document.title + '.html' 172 | * fileName : 'output.html', 173 | * // 可选,自定义下载保存。可用于混合APP内下载时用 174 | * save : function(getStaticHtmlPromiseFunc,fileName){ 175 | * getStaticHtmlPromiseFunc().then(function(htmlBlob){ 176 | * ... 177 | * }) 178 | * } 179 | * } 180 | */ 181 | saveHtml : false, 182 | 183 | /** 184 | * 服务端打印下载按钮,按钮顺序index: 400 185 | * 可选,bool|object,默认false:不启用,true:启用并使用默认选项,object:使用自定义的服务端打印 186 | * true等效的object的配置:serverPrint : { serverUrl : '/' }, 187 | * 要使用serverPrint,必须server能访问到你的网页。网页不要使用登录状态授权,建议通过URL参数传递临时授权 188 | * 如果使用官方的server进行打印,则需公网上可正确访问你用bookjs-eazy构造的网页 189 | * 190 | * serverPrint : { 191 | * // 可选,打印服务器地址,按钮顺序index: 400 192 | * serverUrl : '/', 193 | * 194 | * // 可选,true时使用wkHtmlPdf制作,false:默认使用chrome headless 195 | * // **注意**:wkhtmltopdf不支持es6,缺失一些web新特性,好处在于可以生成PDF目录书签。 196 | * // 为了更好的调试发现问题:请下载QtWeb浏览器,其内核于wkhtmltopdf是一样的。 197 | * // 菜单->工具->启用网页检查器,右键页面内容,选择检查 进入debug工具栏 198 | * // 以便发现各种兼容问题 199 | * // 在QtWeb浏览器中默认为打印模式的样式。不显示页间隔,及工具栏 200 | * // 下载链接:http://www.qtweb.net/download.html 201 | * wkHtmlToPdf : false, 202 | * 203 | * // 可选,保存的文件名,默认值 document.title + '.pdf' 204 | * fileName : 'output.pdf', 205 | * // 可选,打印附属参数 206 | * params : { 207 | * // 打印超时时间 208 | * timeout : 30000, 209 | * // 页面渲染完成后,打印前延时 210 | * delay : 1000, 211 | * }, 212 | * // 可选,自定义下载。可用于混合APP内下载时用 213 | * save : function(pdfUrl, serverPrintOption){ 214 | * 215 | * } 216 | * } 217 | */ 218 | serverPrint : false, 219 | 220 | buttons : [ 221 | // 这里可以自定义工具栏按钮 222 | // { 223 | // id : 'cloudPrint', 224 | // index : 1, // 按钮位置顺序,小的显示在前面,系统内置按钮index值,见各配置项说明。 225 | // icon : 'https://xxxx.../aa.png' 226 | // onClick : function(){ console.log("...do some thing"); } 227 | // } 228 | ], 229 | 230 | className: '', // 额外自定义的class属性 231 | position : 'right',// 位置:right、left 232 | } 233 | } 234 | 235 | ``` 236 | 237 | ## PDF内容设计(约定页面内容分页方式) 238 | 239 | - 定义一个id为content-box节点内放入要插入到文档里的内容; 240 | - content-box下的每个一级子节点都需定义属性 data-op-type表示其在文档中的插入方式 241 | - 示例: 242 | 243 | ```html 244 | 245 |
246 |

Hello World!

247 |
248 | 249 | ``` 250 | 251 | - 除block和text可以嵌套在盒子类型(mix-box、table、block-box、text-box)的容器节点内内,其他类型并不支持相互嵌套。 252 | - 具体注意查看每种类型“使用在符合下列选择器规则的位置”说明 253 | 254 | ### block:块,不可分割(默认) 255 | 256 | - 如果当前页空间充足则整体插入,空间不足,则会自动创建新页,整体插入到下一页 257 | - **注意**:这里的块,仅是内容不跨页。与css中的display无关,也就可以display: inline样式。 258 | 前面有用户问到这个问题。从而限制了他对PDF内容设计的思维。 259 | - 例如:[块示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=4ELVR92Y) 260 | ```html 261 |
...
262 | ``` 263 | - 使用在符合下列选择器规则的位置之一: 264 | ``` 265 | #content-box> 下的一级节点 266 | [data-op-type=mix-box] .nop-fill-box> 混合盒子容器节点下的一级节点 267 | [data-op-type=table] tbody td> 表格的单元格的 268 | ``` 269 | 270 | ### text: 文本,可分割到不同页 271 | 272 | - 跨页内容自动分割,节点内直接放入文本内容。(内部只能为文本,如果包含子节点,子节点标签将被删除) 273 | - 例如:[文本示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=D8PBJHC5) 274 | ```html 275 |

long text...

276 |

long text2...

277 | ``` 278 | 279 | - 使用在符合下列选择器规则的位置之一: 280 | ``` 281 | #content-box> 下的一级节点 282 | [data-op-type=mix-box] .nop-fill-box> 混合盒子容器节点下的一级节点 283 | [data-op-type=table] tbody td> 表格的单元格的一级节点 284 | ``` 285 | 286 | 287 | ### new-page: 新页,手动控制添加新页 288 | - 在标记的节点后的内容,将从新的一页开始写入 289 | - 例如:[新页示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=R992XN88) 290 | ```html 291 |
仅仅是一个标记节点,这里的内容是不会渲染的
292 | ``` 293 | - 使用在符合下列选择器规则的位置之一: 294 | ``` 295 | #content-box> 下的一级节点 296 | [data-op-type=mix-box] .nop-fill-box> 混合盒子容器节点下的一级节点 297 | [data-op-type=table] tbody>tr 表格的tbody下的tr节点,(与被标记到其他位置不同,被标记的tr节点会保留不会从页面删除) 298 | 299 | ``` 300 | 301 | 302 | 303 | ### pendants: 页面部件,相对于页面位置固定的元素(页眉、页脚、页标签...) 304 | 305 | - pendants内部的子节点,会自动标记class:nop-page-pendants,在其定义后的每个页面都会显示,直到下一个pendants出现。 306 | - 部件nop-page-pendants包含css: {position: absolute}属性,相对页面纸张位置固定。 307 | - 在页面设计时需要为部件节点设置css: left/right/top/bottom/width/height等属性来控制部件位置和大小。 308 | - 使用在符合下列选择器规则的位置之一: 309 | ``` 310 | #content-box> 下的一级节点 311 | ``` 312 | - 例如: [部件示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=V86PPDPA) 313 | ```html 314 |
315 |
logo
316 |
页尾:章节:xxx
317 |
318 | ``` 319 | 320 | 321 | ### 盒子, 可差分,并携带布局样式 322 | - 包含mix-box、table、block-box、text-box 多种类型详见具体 323 | - **注意**:不要限定盒子及容器节点高度(如height、max-height样式),影响溢出检测,出现未知结果 324 | 325 | #### mix-box: 混合盒子(常用) 326 | - 盒子内部class:nop-fill-box标记的容器节点的可以包含多个[data-op-type="text"],[data-op-type="block"]元素 327 | - 盒子内的元素被超出一页时,会根据text/block的规则,自动分割到下一页,并会复制携带包裹元素的外部节点。 328 | - 例如: 见示例:[混合盒子示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=EM8ANL97) 329 | ```html 330 |
331 |
布局1
332 |
333 | 334 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 335 | 336 | BBBBBBBBBBBBBBBBBBBBBBB 337 | 文章链接... 338 |
339 |
布局2
340 |
布局3
341 |
342 | ``` 343 | - 使用在符合下列选择器规则的位置之一: 344 | ``` 345 | #content-box> 下的一级节点 346 | ``` 347 | 348 | #### table: 表格,也是一种特殊的盒子 349 | - 对表格遇到分页时,出现的一些显示问题,做了些优化处理(**注意**:列一定要固定宽度),(参考:ezay-6 示例) 350 | - 对于合并单元格:td上标记属性 data-split-repeat="true" ,在分页td里的文本会在在新页中也会显示。 351 | - td : td>直接子节点可以是[data-op-type="text"],[data-op-type="block"]元素 352 | - 使用在符合下列选择器规则的位置之一: 353 | ``` 354 | #content-box> 下的一级节点 355 | ``` 356 | 357 | - 例如: 见示例:[表格示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=J2QR8NGC) 358 | ```html 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 377 | 378 | 379 | 380 | 386 | 387 | 388 | 389 | 390 | 393 | 394 | 395 |
生物种类子类别详解介绍
动物爬行动物 372 |

long text1 ...

373 | 374 |

long text2 ...

375 |
...
376 |
哺乳动物 381 |

long text1 ...

382 | 383 |

long text2 ...

384 |
...
385 |
植物蕨类 391 |

long text...

392 |
396 | ``` 397 | 398 | #### block-box: 块盒子,(@deprecated 其功能已完全被mix-box替代) 399 | - 块盒子内部nop-fill-box标记的节点内部的一级子节点都被视作"块",盒子内的多个块被分割到多个页面时,都会复制包裹块的外部节点。 400 | - 以下一个示例中的简易表格为例: 401 | - table节点定义为块盒子 402 | - tbody节点定义为容纳块的容器节点(使用class: nop-fill-box标记) 403 | - 这样在填充行tr时,当前页空间不足时,换页并复制外部table(除去nop-fill-box标记的部分)继续填充。这样表头就得到复用 404 | - 使用在符合下列选择器规则的位置之一: 405 | ``` 406 | #content-box> 下的一级节点 407 | ``` 408 | 409 | - 例如:见示例:[块示例](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=6AYD2RET) 410 | ```html 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 |
IDname
1name1
2name2
......
421 | ``` 422 | 423 | #### text-box : 文本盒子(@deprecated 其功能已完全被mix-box替代) 424 | - 与块盒子类似,大文本内容跨多个页面时,会复制外部包裹文本的盒子的部分。 425 | - 文本盒子内部nop-fill-box标记的节点内部的一级子节点都被视作"文本" 426 | 427 | ### 示例 428 | 429 | - 使用样例 430 | 431 | ```html 432 | 471 | ``` 472 | 473 | # 在线体验 474 | 475 | - 在线模板编辑 476 | 477 | # 使用示例 478 | 479 | ## 页面背景图片 480 | 481 | - 页面背景图片示例 482 | 483 | ## 页面水印 484 | 485 | - 页面水印示例 486 | 487 | ## 不分页PDF 488 | 489 | - 不分页PDF,仅支持后端生成 490 | - 不分页PDF 491 | 492 | 493 | # 设计中的相关细节 494 | 495 | ## 字体相关 496 | 497 | - 如果是服务端生成PDF,为了保证生成的PDF和浏览器端预览的体验一致性,建议在生成PDF的服务器预先安装使用到的字体。 498 | - 如果是docker启动,可以将字体文件放入./dist/fonts下,字体文件会在docker启动时自动加载。 499 | - 为了加快截图或生成PDF速度,通常字体文件较大,下载耗时。防止渲染截图或PDF出现字体不一致情况,建议css设置字体时,优先使用字体原字体名,再使用网络字体别名,例如: 500 | 501 | ```html 502 | 515 | ``` 516 | 517 | ## 页面渲染完成前,事件回调 518 | ```javascript 519 | /** 520 | * BOOK渲染完成前 book.before-complete 521 | **/ 522 | $(document).on('book.before-complete',function (e,info) { 523 | /** 524 | * info: 525 | * { 526 | * "PAGE_BEGIN_INDEX": 0, // 开始页码标记的页面序号 527 | * "PAGE_END_INDEX": 2, // 结束页码标记的页面序号 528 | * "TOTAL_PAGE": 3 // 总页数 529 | * } 530 | **/ 531 | }); 532 | ``` 533 | 534 | ## 打印时不显示和强制打印背景 535 | 536 | class: nop-no-print 被标记的节点在打印时不显示 537 | class: nop-force-background 被标记的节点强制打印背景,在forcePrintBackground选项为false时可用 538 | 539 | ## 奇偶页实现 540 | 541 | - 在设置简易页码插件后,页面节点上会添加对应的class: nop-page-item-odd (奇数页)、 nop-page-item-even(偶数页) nop-page-item-pagenum-1(页编号) 542 | 543 | ## 文本、盒子被分割到不同页后,被差分部分特殊样式处理 544 | 545 | - 同一段落文本,被分到下一页的文本部分节点,会被class: nop-link-last 进行标记。可以根据此class,进行缩进特殊处理 546 | 547 | - text-box 、block-box、mix-box 内容被分割部分也同样会被class: nop-link-last 标记 548 | 549 | ## 浏览器类型标记 550 | 551 | - Book节点。上会标记浏览器类型。class: chrome、firefox、safari、ie、qq、wechat、wkhtmltopdf 552 | 553 | ## 打印和预览时样式差异处理 554 | 555 | - Book节点。在不同模式下,会使用class: nop-book-preview(预览)、nop-book-print(打印) 进行标记 556 | 557 | ## PDF的属性信息生成 558 | 559 | - 可以在页面中加入meta标签,bookjs-eazy会将其生成到pdf的属性信息中 560 | - 从1.12.0 版本开始,服务端生成有效。 561 | 562 | ```html 563 | 564 | 565 | 566 | ``` 567 | 568 | ## 辅助函数,见 [BookJsHelper.md](BookJsHelper.md) 569 | 570 | # 生成PDF及配套PDF生成命令行工具的使用 571 | 572 | ## 通过浏览器点击打印按钮,打印另存为PDF 573 | 574 | - 点击WEB打印按钮 打印选择“另存为PDF” 575 | 576 | ## 服务端打印 577 | - 参考 : bookConfig.toolBar.serverPrint 服务端打印选项 578 | - 可以配置值为 :true (和 {serverUrl : '/'}等效) 或 {serverUrl : '//your_screenshot_api_server_host[:WEB_PORT]/'} 579 | 580 | ### 自建打印服务(使用官网docker镜像) ,点击直接下载PDF(服务端打印、推荐) 581 | 582 | - 可使用 ./docker-start.sh 进行快速部署 583 | ```bash 584 | # 自己docker打印服务的命令 585 | # ./docker-start.sh [WEB端口,默认3000] 586 | 587 | ./docker-start.sh 588 | # 运行打印服务 589 | # 会以dist为根目录,创建一个web站点。可通过http://127.0.0.1:3000/eazy-1.html访问示例,并可使用服务端打印 590 | # 591 | # 你可以在dist根目录下用bookjs-eazy创建book.html(参考示例:eazy-1.html)。 592 | # 即可访问 http://127.0.0.1:3000/book.html 进行预览/打印下载 593 | # 生成的pdf会存在dist/pdf/ 目录下。 594 | ``` 595 | 596 | 详细内容见,wuxue107/screenshot-api-server项目 597 | 598 | ### 自建打印服务、本机安装PDF生成服务 599 | 600 | ```shell script 601 | # 需预先先安装nodejs 环境,并安装yarn 602 | git clone https://gitee.com/wuxue107/screenshot-api-server.git 603 | cd screenshot-api-server 604 | # 安装依赖 605 | yarn 606 | # 启动服务,默认服务端口号3000 607 | # 指定端口号启动 608 | # 启动时可指定的环境变量 609 | # MAX_BROWSER=1 最大的puppeteer实例数,忽略选项则默认值: [可用内存]/200M 610 | # PDF_KEEP_DAY=0 自动删除num天之前产生的文件目录,默认0: 不删除文件 611 | # PORT=3001 监听端口,默认:3000 612 | yarn start 613 | ``` 614 | 615 | 指定配置bookConfig.toolBar.serverPrint.serverUrl值为: '//your-screenshot-api-server[:PORT]/' 616 | 617 | 618 | 619 | ## 命令行打印,使用chrome headless方式渲染 620 | 621 | - 此插件适配了wkhtmltopdf和chrome headless。可使用本项目中配套封装的命令行工具,从后端生成精美PDF 622 | 623 | ```bash 624 | # 首次使用时,安装bin/html2pdf的依赖包 625 | yarn install 626 | ``` 627 | 628 | ```bash 629 | # 安装过后,执行命令 630 | # 示例: 631 | bin/html2pdf print --output eazy-2-1.pdf "https://bookjs.zhouwuxue.com/eazy-2.html" 632 | 633 | # 634 | # 命令行说明: 635 | # Usage: html2pdf print [options] 636 | # 637 | # Options: 638 | # -o --output [outputfile] 保存PDF文件的路径 (default: "output.pdf") 639 | # -t --timeout [type] 超时时间 (default: 60000) 640 | # -a --agent [agent] 指定转换引擎chrome-headless|puppeteer,默认:puppeteer (default: "puppeteer") 641 | # -d --printDelay [delay] 打印前等待延迟(毫秒) (default: 1000) 642 | # -c --checkJs [jsExpression] 检查是否渲染完成的js表达式 (default: "window.status === 'PDFComplete'") 643 | # "window.document.readyState === 'complete'" 这个表达式可以用作非bookjs-eazy构建的网页 644 | # -h, --help display help for command 645 | # 646 | # 647 | ``` 648 | 649 | ## 命令行打印,使用wkhtmltopdf渲染(会更据h1-h6生成PDF书签),需自己去下载命令行,放入PATH的环境变量所在目录下 650 | 651 | ```bash 652 | 653 | bin/pdf-a4-landscape "https://bookjs.zhouwuxue.com/eazy-2.html" eazy-2-2.pdf 654 | # 655 | # 在bin目录下,有数个同类脚本文件。 656 | # 657 | # bin/pdf-[纸张]-[纸张方向] [预览的链接] [输出文件] 658 | # 659 | # **注意**:如果使用wkhtmltopdf方式的自定义尺寸,不用担心,浏览器渲染完毕后,在Console上会输出wkhtmltopdf的PDF配套生成命令 660 | ``` 661 | 662 | # 生成常见问题(踩坑备忘录) 663 | 664 | - 服务端打印失效: 665 | - 启动的打印服务(screenshot-api-server) 必须要能够访问到你要打印的HTML制作的PDF预览页面。 666 | 667 | - 内容超出页面: 668 | - 一些如: display: float, position: absolute; overflow样式的元素可能不会页面容器高度变化。因而表现出超出页面。 669 | - 因为 margin样式的元素 无法撑开.nop-page-content 大小,造成.nop-page-content位置偏移,很容易造成页面出现溢出的现象,所以控制相对位置尽量使用padding 670 | - 在设置bookConfig.start = true ,之前#content-box下的页面内容没有经其他程序(Vue、React、Ajax..)加载完毕。导致bookjs重新分页后,其他程序在又去操作相应dom,导致节点原始大小发生改变,从而表现为内容溢出页面 671 | 672 | - 页面出现多余空白: 673 | - 不要手动对html、body、.nop-book、.nop-page、.nop-page-items、nop-page-item元素做任何的border/width/height/margin/padding等样式调整 674 | 675 | - 每页都多出一个空白页 676 | - 见bookConfig.pageFixedHeightOffset 选项,进行调节 677 | 678 | - 打印出来是空白页 679 | - 有用户反映,页面引入polyfill.min.js后出现空白页。引入此js是为了wkhtmltopdf,对部分js特性的兼容问题。 如果去除后测试发现对打印无影响,可将此js去除。 680 | 681 | - 字体无法显示: 682 | - 生成的PDF里全是框框或显示不出来,原因在于。在linux服务器环境下,通常没有安装所需字体。或使用web加载字体文件太大,加载超时 683 | 684 | - 生成的PDF与预览有一些差异 685 | - 对于服务端生成PDF,可能时由于字体原因,可以指定页面的的字体。并在生成服务器安装对应字体。见:设计中的相关细节->字体相关 686 | 687 | - iframe 嵌入网页失效:不能点击无法下载打印: 688 | - 需要在iframe上加入 sandbox="allow-downloads allow-top-navigation allow-scripts allow-modals" 属性 689 | 690 | - 页面事件绑定失效: 691 | - 经过bookjs-eazy渲染后,: 如果失效,原绑定可能被分割到不同页面,请尝试在PDF渲染完成事件后处理事件绑定。 692 | 693 | - 找不到wkhtmltopdf 694 | - 执行bin/pdf-xx-xx 相关命令,找不到wkhtmltopdf,需自己去下载wkhtmltopdf放置PATH目录下 695 | 696 | - 使用data-op-type="table" 表格合并单元格分页显示不正确。建议: 697 | - 将表格布局写好 先使用data-op-type="block" 表格不写任何东西,使保持在一个页面里,看看不经过拆分的表格是否布局正确。 如果不正确,就是你自己table写的有问题,和bookjs-eazy的无关。 698 | - 在将数据填充进去,改用data-op-type="table" ,此时如出现问题。可以在这里重现场景表格测试,保存并复制链接。提交issue 699 | - 下载PDF超时 700 | - 服务端制作PDF超时,你的页面可能需要token和session才能访问,后端程序无法正确访问你的页面 701 | - 如果使用wkhtmltopdf方式生成,可能你的页面使用了wkhtmltopdf不支持的特性,如es6 702 | 703 | - 页面卡死,CPU超高 704 | - bookjs-eazy 不能经过了import引入和再编译 解决: 需要在html中通过script标签引入。 705 | - 使用的block块元素,超出一页内容,即使换页也放置不下。 706 | 常见于“[data-op-type="table"] td>[data-op-type="block"]”中 707 | td里的下元素如果未指定data-op-type也会默认视为block 708 | 请合理的拆分,block块元素大小,使其可以在一页内放置。 709 | 710 | - 部件无法显示 711 | - 页边距 bookConfig.padding = "0 0 0 0" 时,在火狐浏览器的打印预览中,空白页部件无法显示。 712 | 调整bookConfig.padding = "1px 0 0 0" 713 | 或者可以尝试在页面中补一个```  ``` 的空文本节点。 714 | 715 | 723 | 724 | # QQ交流群 725 | 726 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/qq-group-1.png) 727 | 728 | 729 | - 仓库地址: [GITEE](https://gitee.com/wuxue107/bookjs-eazy) | [GITHUB](https://github.com/wuxue107/bookjs-eazy) 730 | -------------------------------------------------------------------------------- /README-en.md: -------------------------------------------------------------------------------- 1 | # WEB print, HTML to PDF tool. bookjs-eazy 2 | 3 | - Readme: [中文](./README.md) | [English](./README-en.md) 4 | - Repository: [GITEE](https://gitee.com/wuxue107/bookjs-eazy) | [GITHUB](https://github.com/wuxue107/bookjs-eazy) 5 | - Mainly solve the problem of HTML generating PDF and paging control. From then on, it is no longer difficult to generate high-quality PDF. 6 | - Dependent js libraries: polyfill, jquery, lodash, bookjs-eazy 7 | - Advantages: 8 | 9 | 1. Just focus on using H5 to construct your PDF content, without worrying about paging and content truncation, and automatically paging according to rules. 10 | 2. Support preview, WYSIWYG. Support WEB printing, support custom page number/directory/header/footer. 11 | 3. Both the front and back ends can generate PDF, the front end can print and save as PDF, and the back end can use chrome headless and wkhtmltopdf command line PDF generation tools. 12 | 4. Docker mirror. A print generation service that can quickly build your online PDF 13 | 5. Compatible with mainstream browsers and mobile terminals 14 | 15 | 16 | - Defect tips: 17 | 18 | 1. Modern js frameworks VUE, React and other single-page multi-routing scenarios are not supported. Script tags need to be directly introduced in html, and cannot be introduced in import and compiled again. 19 | 2. Dynamic refresh is not supported, and the entire page needs to be refreshed for re-rendering. 20 | 3. PDF pages require a separate html file entry. 21 | 4. If you want to embed inside the application web page, you can use the iframe method. 22 | 23 | 24 | # Preview Case (./dist) 25 | 26 | - eazy-1.html 27 | 28 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-1-qrcode.png) 29 | 30 | - Another novel case 31 | - JS : eazy-2.html 32 | - Lodash template:eazy-4.html 33 | - Vue template: eazy-3.html 34 | 35 | 36 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-2-qrcode.png) 37 | 38 | - Invoice case 39 | - eazy-5.html 40 | - **Note**: For pages with custom paper, it can be displayed correctly only when chrome "Print Save as PDF" or the corresponding printer and paper are installed and selected in web printing. Otherwise there may be confusion. Using chrome headless and wkhtmltopdf does not affect 41 | 42 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/eazy-5-qrcode.png) 43 | 44 | - Table: Merge Cells 45 | - Reference example:eazy-6.html 46 | 47 | 48 | # Use docker quick experience (you can not use docker, please refer to the chapter [PDF generation service installation](# self-built printing service native installation pdf generation service)) 49 | 50 | - Download or clone the project, the command line into the project directory. 51 | - Run./docker-start.sh or docker-start.bat 52 | - You can access demo through the browser http:// 127.0.0.1:3000/eazy-1.html, print and create PDF 53 | - You can try to write your own pdf page in the dist directory. 54 | 55 | # Usage: 56 | 57 | Rendering Mechanism: 58 | 1. place the PDF page content elements under the body>#content-box node (reference: PDF content design) 59 | 2. The program will check the value of the global variable window.bookConfig.start (reference: configuration page parameters) 60 | Rendering does not start until this value is true renders the contents of the #content-box node to PDF style. 61 | **Important**: If your page is dynamic, set the default value to false first, and set it to true when the content is ready. 62 | 3. Height page overflow detection principle: 63 | The page content node. nop-page-content is a container node with an elastic height. 64 | Adding content to the page causes the height of the container node to change. 65 | To calculate whether the page overflows, it is obtained by calculating its height. 66 | **NOTE * *: 67 | a. display: float, position: absolute; Insertion of overflow-style elements does not change the height of the page container. May cause page overflow to go undetected. 68 | B because margin style elements cannot be stretched out. nop-page-content size, resulting in. nop-page-content position offset, it is easy to cause page overflow phenomenon, so control the relative position as far as possible to use padding 69 | 70 | ## Configure page parameters: 71 | 72 | - Define a global configuration variable bookConfig 73 | 74 | ```html 75 | 236 | ``` 237 | 238 | ## PDF content design (page content paging method) 239 | 240 | - Define the content to be inserted into the document in an id content-box node; 241 | - Each first-level child node under the content-box needs to define attributes data-op-type indicate how it is inserted in the document. 242 | - Example: 243 | 244 | ```html 245 | 246 |
247 |

Hello World!

248 |
249 | 250 | ``` 251 | 252 | - Except that block and text can be nested in container nodes of box types (mix-box, table, block-box, text-box), other types do not support nesting each other. 253 | - Specific attention to view each type of "use in locations that meet the following selector rules" description 254 | 255 | ### block: block, indivisible (default) 256 | 257 | - If the current page has enough space, it will be inserted as a whole, and if the space is insufficient, a new page will be automatically created and inserted as a whole to the next page 258 | - **Note**: The block here is only the content and does not span pages. Regardless of the display in css, you can display the: inline style. 259 | A previous user asked this question. Thus limiting his thinking on PDF content design. 260 | - Example: [Block Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=4ELVR92Y) 261 | ```html 262 |
...
263 | ``` 264 | - Use in one of the positions that meet the following selector rules: 265 | ``` 266 | #content-box> next level node 267 | [data-op-type = mix-box] .nop-fill-box> Level 1 node under the mixed box container node 268 | [data-op-type = table] tbody td> Of the cells of the table 269 | ``` 270 | 271 | ### text: text, which can be split into different pages 272 | 273 | - Automatic splitting of cross-page content, with text content directly placed in nodes. (internal can only be text, if it contains child nodes, the child node label will be deleted) 274 | - Example: [Text Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=D8PBJHC5) 275 | ```html 276 |

long text...

277 |

long text2...

278 | ``` 279 | 280 | - Use in one of the positions that meet the following selector rules: 281 | ``` 282 | #content-box> next level node 283 | [data-op-type = mix-box] .nop-fill-box> Level 1 node under the mixed box container node 284 | [data-op-type = table] tbody td> The first-level node of the cell of the table 285 | ``` 286 | 287 | 288 | ### new-page: new page, manual control to add new page 289 | - The content after the marked node will be written starting from the new 1 page 290 | - Example: [New Page Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=R992XN88) 291 | ```html 292 |
is just a tag node, the content here is not rendered
293 | ``` 294 | - Use in one of the positions that meet the following selector rules: 295 | ``` 296 | #content-box> next level node 297 | [data-op-type = mix-box] .nop-fill-box> Level 1 node under the mixed box container node 298 | [data-op-type = table] tbody>tr nodes under tbody of tr table, (unlike marked to other positions, marked tr nodes will remain and will not be deleted from the page) 299 | 300 | ``` 301 | 302 | 303 | 304 | ### pendants: page parts, elements that are fixed relative to the page position (header, footer, page label,...) 305 | 306 | - The child node inside the pendants will be automatically marked with class:nop-page-pendants, and every page after its definition will be displayed until the next pendants appears. 307 | - The widget nop-page-pendants contains the css: {position: absolute} attribute, which is fixed relative to the page paper position. 308 | - When designing the page, you need to set css: left/right/top/bottom/width/height and other properties for the part node to control the position and size of the part. 309 | - Use in one of the positions that meet the following selector rules: 310 | ``` 311 | #content-box> next level node 312 | ``` 313 | - Example: [Part Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=V86PPDPA) 314 | ```html 315 |
316 |
logo
317 |
Footer: Chapter: xxx
318 |
319 | ``` 320 | 321 | 322 | ### Box, differential, and carry layout style 323 | - Includes mix-box, table, block-box, and text-box types. See details for details. 324 | - **Note**: Do not limit the height of the box and container nodes (such as height and max-height style), which affects overflow detection and causes unknown results. 325 | 326 | #### mix-box: mix box (commonly used) 327 | - box internal class:nop-fill-box marked container node can contain multiple [data-op-type="text"],[data-op-type="block"] elements 328 | - When the element in the box is beyond the 1 page, it will be automatically divided to the next page according to the rules of text/block, and the external node carrying the package element will be copied. 329 | - Example: See Example: [Mixed Box Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=EM8ANL97) 330 | ```html 331 |
332 |
Layout 1
333 |
334 | 335 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 336 | 337 | BBBBBBBBBBBBBBBBBBBBBBB 338 | Article link... 339 |
340 |
Layout 2
341 |
Layout 3
342 |
343 | ``` 344 | - Use in one of the positions that meet the following selector rules: 345 | ``` 346 | #content-box> next level node 347 | ``` 348 | 349 | #### table: table, also 1 kind of special box 350 | - some display problems occurred when paging was encountered in the table, and some optimization treatment was made (* * note * *: the column must have a fixed width),(reference: ezay-6 example) 351 | - For merged cells: the tag attribute data-split-repeat="true" on td, the text in the pagination td will also be displayed on the new page. 352 | - td : td> Direct child nodes can be [data-op-type="text"],[data-op-type="block"] elements 353 | - Use in one of the positions that meet the following selector rules: 354 | ``` 355 | #content-box> next level node 356 | ``` 357 | 358 | - Example: See Example: [Table Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=J2QR8NGC) 359 | ```html 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 378 | 379 | 380 | 381 | 387 | 388 | 389 | 390 | 391 | 394 | 395 | 396 |
Biological species Subcategories Detailed introduction
Animals Reptile 373 |

long text1 ...

374 | 375 |

long text2 ...

376 |
...
377 |
Mammals 382 |

long text1 ...

383 | 384 |

long text2 ...

385 |
...
386 |
Plants Ferns 392 |

long text...

393 |
397 | ``` 398 | 399 | #### block-box: block box,(@ deprecated its function has been completely replaced by mix-box) 400 | - The first-level child nodes inside the nop-fill-box marked nodes in the block box are all regarded as "blocks". When multiple blocks in the box are divided into multiple pages, the external nodes of the wrapped block are copied. 401 | - Take the simple table in the next example: 402 | - table node defined as a block box 403 | The-tbody node is defined as the container node that holds the block (using the class: nop-fill-box notation) 404 | - In this way, when filling the line tr, when the current page is short of space, page change and copy the external table (excluding the part marked by the nop-fill-box) to continue filling. In this way, the header is reused. 405 | - Use in one of the positions that meet the following selector rules: 406 | ``` 407 | #content-box> next level node 408 | ``` 409 | 410 | - Example: See Example: [Block Example](https://bookjs.zhouwuxue.com/static/book-tpl/editor.html?code=6AYD2RET) 411 | ```html 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 |
IDname
1name1
2name2
......
422 | ``` 423 | 424 | #### text-box: text box (@ deprecated its function has been completely replaced by mix-box) 425 | - Similar to block boxes, when large text content spans multiple pages, the part of the box that wraps the text outside is copied. 426 | - The first-level child nodes inside nop-fill-box marked nodes inside the text box are treated as "text" 427 | 428 | ### Example 429 | 430 | - Use sample 431 | 432 | ```html 433 | 472 | ``` 473 | 474 | # Online Experience 475 | 476 | - Online template editing 477 | - Try it: CodePen online test 478 | 479 | # Use Examples 480 | 481 | ## Page background image 482 | 483 | - Example of a page background image 484 | 485 | ## Page Watermark 486 | 487 | - Page Watermark Example 488 | 489 | ## No paging PDF 490 | 491 | - No paging PDF, only back-end generation is supported 492 | - Do not page PDF 493 | 494 | 495 | # Relevant details in the design 496 | 497 | ## Font Related 498 | 499 | - If the PDF is generated on the server, it is recommended that the fonts used be pre-installed on the server that generates the PDF to ensure the consistency of the experience between the generated PDF and the browser preview. 500 | - If docker starts, you can put the font file into./dist/fonts, and the font file will be automatically loaded when docker starts. 501 | - In order to speed up the screenshot or PDF generation, the font file is usually large and time-consuming to download. To prevent font inconsistency in rendered screenshots or PDF, it is recommended that when setting fonts in css, the original font name should be used first, and then the network font alias should be used. For example: 502 | 503 | ```html 504 | 517 | ``` 518 | 519 | ## Event callback before page rendering 520 | ```javascript 521 | /* * 522 | * book.before-complete before BOOK rendering 523 | * */ 524 | $(document).on('book.before-complete',function (e,info) { 525 | /* * 526 | * info: 527 | * { 528 | * "PAGE_BEGIN_INDEX": 0, // the page sequence number of the starting page number tag 529 | * "PAGE_END_INDEX": 2, // the page sequence number of the end page number tag 530 | * "TOTAL_PAGE": 3 // total pages 531 | *} 532 | * */ 533 | }); 534 | ``` 535 | 536 | ## Do not display and force printing background when printing 537 | 538 | class: nop-no-print marked nodes are not displayed when printing 539 | class: nop-force-background the marked node to force the printing background, available when the forcePrintBackground option is false 540 | 541 | ## parity page implementation 542 | 543 | - After setting the simple page number plug-in, the corresponding class: nop-page-item-odd (odd pages), nop-page-item-even (even pages) nop-page-item-pagenum-1 (page number) will be added to the page node. 544 | 545 | ## After the text and box are divided into different pages, they are processed by the special style of the differential part. 546 | 547 | - The same paragraph text, the text part node that is divided into the next page, will be marked by class: nop-link-last. Special indentation processing can be performed according to this class 548 | 549 | - text-box, block-box, and mix-box content will also be marked by class: nop-link-last 550 | 551 | ## Browser type tag 552 | 553 | - Book node. The browser type is marked on. class: chrome, firefox, safari, ie, qq, wechat, wkhtmltopdf 554 | 555 | ## Processing of style differences during printing and previewing 556 | 557 | - Book node. In different modes, will use class: nop-book-preview (preview), nop-book-print (print) for marking 558 | 559 | ## PDF attribute information generation 560 | 561 | - You can add meta tags to the page, and the bookjs-eazy will generate them into the attribute information of the pdf. 562 | - Starting from version 1.12.0, server generation is valid. 563 | 564 | ```html 565 | 566 | 567 | 568 | ``` 569 | 570 | ## Auxiliary function, see [BookJsHelper.md](BookJsHelper.md) 571 | 572 | # Use of PDF generation and supporting PDF generation command line tools 573 | 574 | ## Click the print button through the browser to print and save as PDF 575 | 576 | - Click the WEB print button to print and select "Save as PDF" 577 | 578 | ## Server-side printing 579 | - Reference: bookConfig.toolBar.serverPrint server-side printing options 580 | - can be configured as: true (and {serverUrl : '/'} equivalent) or {serverUrl : '// your_screenshot_api_server_host[:WEB_PORT]/'} 581 | 582 | ### Self-built printing service, use official website docker image, click to download PDF directly (server-side printing, recommended) 583 | 584 | - Can be quickly deployed using./docker-start.sh 585 | ```bash 586 | # Own command for the docker print service 587 | # ./docker-start.sh [WEB port, default 3000] 588 | 589 | ./docker-start.sh 590 | # Run the print service 591 | # will create a web site with dist as the root directory. The sample can be accessed at http:// 127.0.0.1:3000/eazy-1.html and printed on the server. 592 | # 593 | # You can create book.html with bookjs-eazy in the dist root directory (see example: eazy-1.html). 594 | # Access http:// 127.0.0.1:3000/book.html for preview/print download 595 | # The generated pdf will be in the dist/pdf/directory. 596 | ``` 597 | 598 | For more information, see the wuxue107/screenshot-api-server project 599 | 600 | ### Self-built printing service, local installation PDF generation service 601 | 602 | ```shell script 603 | # You need to pre-install the nodejs environment and install yarn 604 | git clone https://gitee.com/wuxue107/screenshot-api-server.git 605 | cd screenshot-api-server 606 | # Install dependencies 607 | yarn 608 | # Start the service. The default service port number is 3000 609 | # Specify the port number to start 610 | # Environment variables that can be specified at startup 611 | # MAX_BROWSER = 1 The maximum number of puppeteer instances. If the option is ignored, the default value is [Available Memory]/200M 612 | # PDF_KEEP_DAY = 0 Automatically delete the file directory generated num days ago, default 0: do not delete files 613 | # PORT = 3001 listening port, default: 3000 614 | yarn start 615 | ``` 616 | 617 | Specify the configuration bookConfig.toolBar.serverPrint.serverUrl value as: '// your-screenshot-api-server[:PORT]/' 618 | 619 | 620 | 621 | ## Command line printing, using chrome headless mode rendering 622 | 623 | - This plugin adapts wkhtmltopdf and chrome headless. You can use the command-line tools packaged in this project to generate beautiful PDFs from the back end. 624 | 625 | ```bash 626 | # When using for the first time, install the dependency package of bin/html2pdf 627 | yarn install 628 | ``` 629 | 630 | ```bash 631 | # After installation, execute the command 632 | # Example: 633 | bin/html2pdf print --output eazy-2-1.pdf "https://bookjs.zhouwuxue.com/eazy-2.html" 634 | 635 | # 636 | # Command line description: 637 | # Usage: html2pdf print [options] 638 | # 639 | # Options: 640 | # -o -- output [outputfile] Path to save the PDF file (default: "output.pdf") 641 | # -t -- timeout [type] timeout (default: 60000) 642 | # -a -- agent [agent] specifies the conversion engine chrome-headless | puppeteer, default: puppeteer (default: "puppeteer") 643 | # -d -- printDelay [delay] wait delay (ms) before printing (default: 1000) 644 | # -c -- checkJs [jsExpression] js expression to check whether rendering is completed (default: "window.status === 'PDFComplete'") 645 | # "window.document.readyState === 'complete'" This expression can be used as a non-bookjs-eazy built web page 646 | # -h, --help display help for command 647 | # 648 | # 649 | ``` 650 | 651 | ## Command line printing, using wkhtmltopdf rendering (PDF bookmarks will be generated according to h1-h6), you need to download the command line yourself and put it into the directory where the PATH environment variable is located. 652 | 653 | ```bash 654 | 655 | bin/pdf-a4-landscape "https://bookjs.zhouwuxue.com/eazy-2.html" eazy-2-2.pdf 656 | # 657 | # There are several similar script files in the bin directory. 658 | # 659 | # bin/pdf-[Paper]-[Paper Orientation] [Preview Link] [Output File] 660 | # 661 | # **Note**: If you use wkhtmltopdf custom size, don't worry, after the browser renders, the wkhtmltopdf PDF matching generation command will be output on the Console 662 | ``` 663 | 664 | # Generate FAQ (Pit Stamping Memo) 665 | 666 | - Server printing failure: 667 | -Starting the print service (screenshot-api-server) must be able to access the PDF preview page you want to print from HTML. 668 | 669 | - Content beyond the page: 670 | -Some such as: display: float, position: absolute; overflow style elements may not change the height of the page container. Thus showing beyond the page. 671 | -because margin style elements cannot be stretched out. nop-page-content size, resulting in. nop-page-content position offset, it is easy to cause page overflow phenomenon, so control the relative position as far as possible to use padding 672 | -Before setting bookConfig.start = true, the page content under #content-box has not been loaded by other programs (Vue, React, Ajax ..). After bookjs is re-paginated, other programs are operating the corresponding dom again, resulting in a change in the original size of the node, thus showing that the content overflows the page. 673 | 674 | - Extra blank space on the page: 675 | -do not manually make any border/width/height/margin/padding style adjustments to html, body,. nop-book,. nop-page,. nop-page-items, and nop-page-item elements 676 | 677 | - One more blank page per page 678 | -See bookConfig.pageFixedHeightOffset option for adjustment 679 | 680 | - Print out is a blank page 681 | -Some users reflected that a blank page appeared after the page was introduced into polyfill.min.js. The introduction of this js is to wkhtmltopdf the compatibility of some js features. If the test finds no effect on printing after removal, this js can be removed. 682 | 683 | - Font cannot be displayed: 684 | -The generated PDF is full of frames or cannot be displayed because. In linux server environments, the required fonts are usually not installed. Or use web load font file too large, load timeout 685 | 686 | - The generated PDF has some differences from the preview 687 | -For PDF generated by the server, the font of the page can be specified if possible due to the font. And install the corresponding font on the build server. See: Related Details in Design-> Font Related 688 | 689 | - iframe embedded web page invalid: cannot click cannot download print: 690 | -need to add sandbox="allow-downloads allow-top-navigation allow-scripts allow-modals" attribute to iframe 691 | 692 | - page event binding failure: 693 | -After bookjs-eazy rendering,: If it fails, the original binding may be split into different pages. Please try to post the event binding after the PDF rendering is completed. 694 | 695 | - Can't find wkhtmltopdf 696 | -Execute bin/pdf-xx-xx related commands. No wkhtmltopdf can be found. You need to download the wkhtmltopdf yourself and place it in the PATH directory. 697 | 698 | - Merged cells with data-op-type="table" are not displayed correctly. Recommendations: 699 | -Write the table layout well. First, use the data-op-type="block" table without writing anything. Keep it in one page and see if the table without splitting is correctly laid out. If it is not correct, there is something wrong with your own table, which has nothing to do with the bookjs-eazy. 700 | -When filling data in, use data-op-type="table" instead. If there is a problem at this time. You can reproduce the scene here table test , save and copy the link. Submit issue 701 | - Download PDF timeout 702 | -The server timed out making PDF, your page may need token and session to access, and the back-end program cannot access your page correctly. 703 | -If you use wkhtmltopdf method, your page may use wkhtmltopdf unsupported features, such as es6. 704 | 705 | - Page stuck, CPU super high 706 | -bookjs-eazy cannot be solved by import introduction and recompilation: it needs to be introduced through script tags in html. 707 | -The block element used exceeds the content of the 1 page and cannot be placed even if the page is changed. 708 | Common in "[data-op-type =" table "] td>[data-op-type =" block "]" 709 | The next element in td will be regarded as block by default if no data-op-type is specified. 710 | Please split the block element reasonably so that it can be placed in the 1 page. 711 | 712 | - Parts cannot be displayed 713 | -When the margin is bookConfig.padding="0 0 0 0", the blank page part cannot be displayed in the print preview of the Firefox browser. 714 | Adjustment bookConfig.padding="1px 0 0 0" 715 | Or you can try to fill an empty text node for ``` & nbsp``` in the page. 716 | 717 | 725 | 726 | # QQ communication group 727 | 728 | ![alt ](https://bookjs.zhouwuxue.com/static/js/bookjs/qq-group-1.png) 729 | 730 | 731 | - Repository: [GITEE](https://gitee.com/wuxue107/bookjs-eazy) | [GITHUB](https://github.com/wuxue107/bookjs-eazy) 732 | -------------------------------------------------------------------------------- /dist/eazy-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NOP BOOK TEST 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 59 | 219 | 243 | 654 | 655 | 656 | --------------------------------------------------------------------------------