html2canvas.js+itext+pdf.js将网页转化成图片,利用itext将图片转化成pdf保存

本文介绍了一种使用前端技术将网页内容截图并转换为PDF的方法。通过html2canvas库捕获网页区域,将其转换为图像,再利用jsPDF库生成PDF文件。提供了两种实现方案:一种是将生成的数据发送到服务器进行处理;另一种是完全在前端完成PDF的生成与下载。

直接上代码了

前端代码:

<html>
<head>
    <title>Title</title>
</head>
<body>
<input type="button" value="截图" onclick="takeScreenshot()">
<div id="view">
    <div id="mycanvas">

    </div>
</div>
</body></html>

引用得js
<script type="text/javascript" src="application/career/explore/js/html2canvas.js"></script>
<script type="text/javascript" src="application/career/explore/js/jsPdf.debug.js"></script>

<script>
    jQuery(document).ready(function() {
       jQuery.get(contextPath + "/application/career/selfWork/myInterest/new_detail.jsp",function(html){
            jQuery("#mycanvas").html(html);
        });
    });
    function takeScreenshot() {
        html2canvas(document.getElementById("mycanvas")).then(function(canvas) {
           document.body.appendChild(canvas);
            canvas.id = "mycanvas";
            // 生成base64图片数据
            var dataUrl = canvas.toDataURL('image/png'); //指定格式,也可不带参数
            var formData = new FormData(); //模拟表单对象
            formData.append("imgData", convertBase64UrlToBlob(dataUrl)); //写入数据
            var xhr = new XMLHttpRequest(); //数据传输方法
            xhr.open("POST", "./exportPdf.do"); //配置传输方式及地址
            xhr.send(formData);
            xhr.onreadystatechange = function() { //回调函数
                if(xhr.readyState == 4) {
                    if(xhr.status == 200) {
                        var back = JSON.parse(xhr.responseText);
                        if(back.success == true) {
                            alertBox({ content: 'Pdf导出成功!', lock: true, drag: false, ok: true });
                        } else {
                            alertBox({ content: 'Pdf导出失败!', lock: true, drag: false, ok: true });
                        }
                    }
                }
            }
        });
    }
    function downpdf(){
        html2canvas(document.getElementById("mycanvas"), {
            onrendered:function(canvas) {

                var contentWidth = canvas.width;
                var contentHeight = canvas.height;
                //一页pdf显示html页面生成的canvas高度;
                var pageHeight = contentWidth / 595.28 * 841.89;
                //未生成pdf的html页面高度
                var leftHeight = contentHeight;
                //pdf页面偏移
                var position = 0;
                //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
                var imgWidth = 555.28;
                var imgHeight = 555.28/contentWidth * contentHeight;

                var pageData = canvas.toDataURL('image/jpg', 1.0);

                var pdf = new jsPDF('', 'pt', 'a4');
                //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
                //当内容未超过pdf一页显示的范围,无需分页
                if (leftHeight < pageHeight) {
                    pdf.addImage(pageData, 'JPG', 20, 0, imgWidth, imgHeight );
                } else {
                    while(leftHeight > 0) {
                        pdf.addImage(pageData, 'JPG', 20, position, imgWidth, imgHeight)
                        leftHeight -= pageHeight;
                        position -= 841.89;
                        //避免添加空白页
                        if(leftHeight > 0) {
                            pdf.addPage();
                        }
                    }
                }

                pdf.save('content.pdf');
            }
        })
    }
    //将以base64的图片url数据转换为Blob
    function convertBase64UrlToBlob(urlData) {
        //去掉url的头,并转换为byte
        var bytes = window.atob(urlData.split(',')[1]);
        //处理异常,将ascii码小于0的转换为大于0
        var ab = new ArrayBuffer(bytes.length);
        var ia = new Uint8Array(ab);
        for(var i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i);
        }
        return new Blob([ab], { type: 'image/png' });
    }
</script>
 第一个方法是将数据传到后台保存起来

第二个方法是在前端利用pdf.js将网页直接下载为pdf


下面粘贴出后台得代码:

@Controller
public class TestController2 extends CommonController{
    @RequestMapping("/exportPdf")
    public  void exportPdf(MultipartHttpServletRequest request, HttpServletResponse response) throws Exception {
        ResultData result = new ResultData(); //自定义结果格式
        String filePath = "e:\\111.pdf";
        String imagePath = "e:\\111.bmp";
        Document document = new Document();
       // Document document = new Document(PageSize.A4, 20, 20, 20, 20);
        try{
            Map getMap = request.getFileMap();
            MultipartFile mfile = (MultipartFile) getMap.get("imgData"); //获取数据
            InputStream file = mfile.getInputStream();
            byte[] fileByte = FileCopyUtils.copyToByteArray(file);

            FileImageOutputStream imageOutput = new FileImageOutputStream(new File(imagePath));//打开输入流
            imageOutput.write(fileByte, 0, fileByte.length);//生成本地图片文件
            imageOutput.close();
            FileOutputStream fileOutputStream = new FileOutputStream(filePath);
            PdfWriter.getInstance(document,fileOutputStream); //itextpdf文件
          // document.setPageSize(PageSize.A4);
            document.setPageCount(2);
            Rectangle pageSize = new Rectangle(595.0F, 842.0F*4);
            document.setPageSize(pageSize);
            document.open();
           // document.add(new Paragraph("JUST TEST ..."));
            Image image = Image.getInstance(imagePath); //itext-pdf-image
            float heigth = image.getHeight();
            float width = image.getWidth();
           int percent = getPercent2(heigth, width);  //按比例缩小图片
            image.setAlignment(Image.MIDDLE);
           // image.scaleAbsolute(mmTopx(150), mmTopx(500));// 直接设定显示尺寸
            image.scalePercent(percent+3);
            document.add(image);
            document.close();

            result.setSuccess(true);
        }catch (DocumentException de) {
            System.err.println(de.getMessage());
        }
        catch (Exception e) {
            e.printStackTrace();
            result.setSuccess(false);
        }
        sendJsonMessage(response,result);
    }

    private static int getPercent2(float h, float w) {
        int p = 0;
        float p2 = 0.0f;
        p2 = 530 / w * 100;
        p = Math.round(p2);
        return p;
    }

    public static int getPercent(float h, float w) {
        int p = 0;
        float p2 = 0.0f;
        if (h > w) {
            p2 = 297 / h * 100;
        } else {
            p2 = 210 / w * 100;
        }
        p = Math.round(p2);
        return p;
    }

    public static float mmTopx(float mm){
        mm = (float) (mm *3.33) ;
        return mm ;
    }
}

后台代码得内容主要是将图片转化为pdf。需要引入得包有:iText-2.1.7.jar,iTextAsian.jar ,这里关键是让图片以什么样得缩放比例转化成pdf,这里还需要自己去调试,我也找不到一个完美得方法。

Rectangle pageSize = new Rectangle(595.0F, 842.0F*4);
image.scalePercent(percent+3);

核心就是选择纸张大小,和图片得缩放比例了

// image.scaleAbsolute(mmTopx(150), mmTopx(500));// 直接设定显示尺寸
也可以直接设定尺寸

<think>我们有一个需求:在Java后端支持下,使用Vue.js开发的网页中,将网页内容转换为图片PDF。 根据引用内容,我们可以总结出两种主要方式: 1. 前端主导:Vue.js生成内容,然后使用前端库(如html2canvas)将网页内容转换为图片,再发送给后端或直接在前端导出。 2. 后端主导:前端将需要导出的内容(可能是HTML结构或数据)发送给后端,后端使用工具(如iTextPDF、JFreeChart等)生成PDF图片,然后返回给前端下载。 但是,根据引用[1]和引用[3],我们看到了两种不同的实现: 引用[1]展示了前端通过axios请求后端,后端返回一个blob(二进制流),然后前端创建a标签触发下载。这种方式适用于后端生成文件(如Excel、PDF)的情况。 引用[3]则展示了后端使用itextpdf和JFreeChart生成PDF(其中包含图表)并导出。 对于我们的需求,我们可以分别考虑图片PDF的导出。 方案一:导出为图片前端主导) 步骤: 1. 在Vue.js使用html2canvas库将DOM元素转换为canvas,然后转换为图片。 2.图片数据发送到后端保存,或者直接在前端触发下载。 方案二:导出为PDF(可以前端主导,也可以后端主导) 前端主导:使用jsPDF库,结合html2canvas,将网页内容转换为图片,然后插入到PDF中。 后端主导:将需要导出的数据(或HTML内容)发送到后端,后端使用PDF生成库(如iText)生成PDF,然后返回给前端下载。 根据引用[3],后端生成PDF可以包含复杂的图表(由JFreeChart生成),所以如果我们的网页内容包含图表,并且已经在后端有生成图表的能力,那么后端生成PDF可能是更好的选择。 下面,我们分别给出两种导出的实现思路: 一、导出为图片前端实现) 1. 安装html2canvas:`npm install html2canvas --save` 2. 在Vue组件中使用: ```javascript import html2canvas from 'html2canvas'; methods: { exportAsImage() { const element = document.getElementById('content-to-export'); // 要导出的元素 html2canvas(element).then(canvas => { const image = canvas.toDataURL('image/png'); // 创建下载链接 const link = document.createElement('a'); link.href = image; link.download = 'image.png'; link.click(); }); } } ``` 这种方式完全在前端完成,不需要后端参与。 二、导出为PDF 有两种方式: 方式1:前端生成PDF使用jsPDF) 1. 安装jsPDFhtml2canvas:`npm install jspdf html2canvas --save` 2. 在Vue组件中使用: ```javascript import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; methods: { exportAsPDF() { const element = document.getElementById('content-to-export'); html2canvas(element).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF(); const imgProps = pdf.getImageProperties(imgData); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight); pdf.save('document.pdf'); }); } } ``` 这种方式也是前端完成,但生成的PDF实际上是图片形式的PDF,文字不可选。 方式2:后端生成PDF(适合需要后端处理数据生成复杂PDF,或者需要文字可选的PDF) 步骤: 1. 前端将需要导出的数据(或整个HTML内容)通过API发送给后端。 2. 后端接收到数据后,使用PDF生成库(如iTextPDF)生成PDF文件。 3. 后端将生成的PDF以流的形式返回给前端。 4. 前端接收到流之后,将其转换为Blob,然后触发下载(类似引用[1]中的方法)。 后端生成PDF的代码示例(Java): 我们可以使用iTextPDF来将HTML转换为PDF,或者使用Flying Saucer(基于iText)来将HTML转换为PDF,这样可以得到文字可选的PDF。 但是,如果网页内容包含图表,且图表是前端绘制的,那么后端可能无法直接渲染。此时,我们可以: - 方案A:将图表在前端生成后,转换为图片(base64),然后将图片数据一起发送给后端,后端将图片嵌入PDF。 - 方案B:后端根据数据重新绘制图表(如使用JFreeChart),然后生成PDF。 根据引用[3],后端使用JFreeChart生成图表,然后嵌入PDF。因此,如果我们的图表数据可以发送到后端,后端可以重新生成图表并嵌入PDF。 步骤: 1. 前端收集需要导出的数据(包括图表的配置和数据)发送给后端。 2. 后端使用JFreeChart生成图表(图片),然后使用iTextPDF将数据和图表组合成PDF。 3. 后端返回PDF文件流。 前端代码(Vue.js): ```javascript // 假设我们有一个函数,用于收集数据并调用后端API exportPDF() { const dataToExport = { // 包含需要导出的文本内容、图表数据等 title: '报表标题', content: '...', charts: [ { type: 'bar', data: [...] }, // ... 其他图表 ] }; this.axios.post('/api/export-pdf', dataToExport, { responseType: 'blob' }) .then(res => { const blob = new Blob([res.data], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'report.pdf'; link.click(); URL.revokeObjectURL(link.href); // 释放内存 }) .catch(error => { console.error('导出失败', error); }); } ``` 后端代码(Java)示例(简化): ```java @PostMapping("/api/export-pdf") public void exportPdf(@RequestBody ExportData exportData, HttpServletResponse response) throws Exception { // 设置响应类型 response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=\"report.pdf\""); // 创建PDF文档 Document document = new Document(); PdfWriter.getInstance(document, response.getOutputStream()); document.open(); // 添加标题 document.add(new Paragraph(exportData.getTitle())); // 添加内容 document.add(new Paragraph(exportData.getContent())); // 处理图表:根据exportData中的图表数据生成图片 for (ChartData chart : exportData.getCharts()) { // 使用JFreeChart生成图表图片 JFreeChart jfreeChart = createChart(chart); // 自定义方法 // 将图表转换为图片 BufferedImage bufferedImage = jfreeChart.createBufferedImage(600, 400); // 将BufferedImage转换为iText的Image Image image = Image.getInstance(bufferedImage, null); document.add(image); } document.close(); } ``` 注意:实际生成PDF时,可能需要更复杂的布局和样式控制。 总结: - 如果导出的内容不需要文字可选,且对样式要求不高,可以选择前端生成图片图片形式的PDF。 - 如果需要高质量的PDF,包含文字可选、格式精确控制,并且有后端支持,那么后端生成PDF是更好的选择。 根据实际需求选择合适的方式。 相关问题: 1. 如何在前端使用Vue.js网页内容导出为图片? 2. 如何在前端使用Vue.js网页内容导出为PDF使用jsPDF)? 3. 如何使用Java后端生成PDF(包含图表)并提供下载? 4. 在导出PDF时,如何保证前端样式和后端生成的样式一致? 5. 如何实现导出PDF时包含分页和页眉页脚?</think>在 Java 后端支持下实现 Vue.js 网页内容导出为图片PDF,可通过以下两种方案实现: --- ### 方案一:前端主导导出(Vue.js 实现) **适用场景**:纯前端操作,无需后端支持 #### 1. 导出为图片使用 html2canvas) ```javascript npm install html2canvas ``` ```vue <template> <div id="export-content"> <!-- 需要导出的内容 --> </div> <button @click="exportToImage">导出图片</button> </template> <script> import html2canvas from 'html2canvas'; export default { methods: { exportToImage() { html2canvas(document.getElementById('export-content')).then(canvas => { const link = document.createElement('a'); link.href = canvas.toDataURL('image/png'); link.download = '网页截图.png'; link.click(); }); } } }; </script> ``` #### 2. 导出为 PDF使用 jsPDF + html2canvas) ```javascript npm install jspdf ``` ```vue <script> import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; export default { methods: { exportToPDF() { html2canvas(document.getElementById('export-content')).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF('p', 'mm', 'a4'); const imgProps = pdf.getImageProperties(imgData); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight); pdf.save('网页导出.pdf'); }); } } }; </script> ``` --- ### 方案二:后端主导导出(Java 生成 PDF) **适用场景**:需要精确控制 PDF 格式/样式或包含动态数据 #### 后端实现步骤(Spring Boot + iTextPDF) 1. **添加依赖** ```xml <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.3</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> ``` 2. **创建 PDF 服务类** ```java @Service public class PdfExportService { public void generatePdf(String htmlContent, HttpServletResponse response) throws IOException { response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=export.pdf"); try (OutputStream os = response.getOutputStream()) { ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(htmlContent); renderer.layout(); renderer.createPDF(os); } catch (DocumentException e) { throw new IOException("PDF生成失败", e); } } } ``` 3. **前端调用(Vue.js)** ```vue <script> export default { methods: { async exportPDF() { const htmlContent = document.getElementById('export-content').innerHTML; try { const res = await this.$axios.post('/api/export-pdf', { html: htmlContent }, { responseType: 'blob' } ); const blob = new Blob([res.data], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = '后端导出.pdf'; link.click(); } catch (error) { console.error('导出失败', error); } } } }; </script> ``` 4. **后端控制器** ```java @RestController public class ExportController { @Autowired private PdfExportService pdfService; @PostMapping("/api/export-pdf") public void exportPdf(@RequestBody Map<String, String> request, HttpServletResponse response) throws IOException { pdfService.generatePdf(request.get("html"), response); } } ``` --- ### 关键注意事项 1. **样式一致性** - 后端生成 PDF 时需内联 CSS 样式(如使用 `juicy-cssom` 处理 HTML) - 避免使用前端框架特有样式(如 Vue 的 scoped CSS) 2. **性能优化** - 大文件导出:后端分页生成 PDF使用 `PdfWriter` 分页) - 前端导出:对复杂 DOM 使用 `{ scale: 2 }` 提高清晰度 3. **跨域问题** 后端需配置 CORS: ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://your-vue-domain.com") .allowedMethods("POST"); } } ``` --- ### 方案对比 | **特性** | 前端导出方案 | 后端导出方案 | |------------------|----------------------------------|----------------------------------| | 复杂度 | ⭐⭐ (简单) | ⭐⭐⭐⭐ (需前后端协作) | | 样式控制 | ⭐⭐ (依赖浏览器渲染) | ⭐⭐⭐⭐ (精确控制) | | 大文件支持 | ⭐ (可能内存溢出) | ⭐⭐⭐⭐ (流式生成) | | 图表支持 | ✅ (直接截图) | ✅ (需后端重绘图表[^3]) | | 文字可复制性 | ❌ (图片PDF) | ✅ (矢量PDF) | > 推荐选择: > - 简单内容 → **前端导出**(快速实现) > - 企业级报表 → **后端导出**(精确控制格式) --- ### 相关问题 1. 如何解决 html2canvas 截图模糊问题? 2. 后端生成 PDF 时如何处理 Vue 的动态绑定内容? 3. 如何实现 PDF 分页和页眉页脚? 4. 导出 Excel 和 PDF 方案有何异同? 5. 如何优化大体积 PDF 的生成速度? [^1]: 参考前端导出方案实现 [^2]: 电子签名/合同管理场景参考 [^3]: 后端图表生成参考 JFreeChart 集成方案
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值