如何使用jsPDF使图像适应页面宽度?

71

有没有办法解决这个问题? 我试过以毫米为单位设置宽度和高度。如何将其设置为全宽?


2
为什么不直接将宽度和高度以毫米为单位设置为与页面大小相同呢?标准纸张尺寸很容易获得,而且由于您知道页面的大小,因此您知道应该将图像制作多大。或者我可能漏掉了什么? - enhzflep
请查看此示例和使用 jsPDF 的自动宽度调整函数:http://www.freakyjolly.com/jspdf-multipage-example-generate-multipage-pdf-using-single-canvas-of-html-document-using-jspdf/ - Code Spy
19个回答

136

您可以像下面这样获得PDF文档的宽度和高度:

var doc = new jsPDF("p", "mm", "a4");

var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight();

那么你可以使用这个宽度和高度来使你的图像适合整个PDF文档。

var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJ......';

doc.addImage(imgData, 'JPEG', 0, 0, width, height);

请确保您的图像与PDF文档具有相同的尺寸(分辨率)。否则它会看起来变形(拉伸)。

如果您想将px转换为mm,请使用此链接:http://www.endmemo.com/sconvert/millimeterpixel.php


3
你如何保证你的图片始终与页面/PDF文档的大小/分辨率相同?更好的方法是计算图像的长宽比和页面的相对宽高比。请参见我在下面的回答:链接 - Weihui Guo
如果您想保持比例:var ratio = canvas.width/canvas.height; var width = doc.internal.pageSize.getWidth(); var height = width / ratio; doc.addImage(imgData, 'PNG', 0, 0, width, height); - Jared Chu
对于这个解决方案来说,即使它能够适用,但 PDF 页面最终也会变得扭曲。不管怎样还是谢谢您。 - Minh Kha
我曾经遇到过使用 html2canvas 方法缩放图像高度的问题,但是这个解决方案解决了它。为了使画布宽度适应 PDF,我使用了以下方法:html2canvas(pdfElement, { scrollY: -window.scrollY })。此外,通过 addImage() 方法中的 x、y 值,您可以设置 PDF 内容在页面中的位置。 - Falcon
2
doc.internal.pageSize.getWidth(); 出现错误,因为getWidth()不是一个函数。 - Karthic G
太棒了!我之前遇到了不同分辨率的问题,现在看来这就是解决方案。 - Ngima Sherpa

85
如果您需要获得PDF文件的100%宽度自动高度,则可以使用html2canvas库的getImageProperties属性。
html2canvas(input)
      .then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF({
          orientation: 'landscape',
        });
        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('download.pdf');
      });

13
嗯,我不记得在哪里听说过html2canvas。但是...让我们面对现实,这正是我们大多数人正在做的事情,所以谢谢! - IcedDante
1
如果我想要添加另一个页面该怎么办? - Yahya Rehman
1
只有这个解决方案对我有效,谢谢。 - Vinícius Cerqueira Bonifácio
2
这仍然剪切了图像的一部分。 - Yannick Mussche

27

我的回答涉及了一个更具体的情况,但我认为可以从中得出一些思路,以便更普遍地应用。此外,如果我能,我会将此作为评论发布到Purushoth的答案上(我的答案基于他的答案)。

好的,我的问题是如何将网页适配到PDF文档中,而不会失去宽高比。我使用了jsPDF和html2canvas,从我的div的宽度和高度计算了比例。我将该比例应用于PDF文档,页面完美地适合页面上,没有任何扭曲。

var divHeight = $('#div_id').height();
var divWidth = $('#div_id').width();
var ratio = divHeight / divWidth;
html2canvas(document.getElementById("div_id"), {
     height: divHeight,
     width: divWidth,
     onrendered: function(canvas) {
          var image = canvas.toDataURL("image/jpeg");
          var doc = new jsPDF(); // using defaults: orientation=portrait, unit=mm, size=A4
          var width = doc.internal.pageSize.getWidth();    
          var height = doc.internal.pageSize.getHeight();
          height = ratio * width;
          doc.addImage(image, 'JPEG', 0, 0, width-20, height-10);
          doc.save('myPage.pdf'); //Download the rendered PDF.
     }
});

这种方法解决了我将大型图像适配到信纸格式页面的问题。非常推荐。 - E-Bat

16

今天早上在尝试使用html2canvas时我发现了这个。虽然这不包括打印多页的设置,但它可以将图像缩放到页面宽度,并根据调整后的宽度重新调整高度比例:

html2canvas(document.getElementById('testdiv')).then(function(canvas){
        var wid: number
        var hgt: number
        var img = canvas.toDataURL("image/png", wid = canvas.width, hgt = canvas.height);
        var hratio = hgt/wid
        var doc = new jsPDF('p','pt','a4');
        var width = doc.internal.pageSize.width;    
        var height = width * hratio
        doc.addImage(img,'JPEG',20,20, width, height);
        doc.save('Test.pdf');
    });

1
最佳答案。将图像大小固定为比例大小。 - Gildonei
这个功能运行良好,但输出质量太低。 - Moxet Jan
@MoxetJan,您可以在选项对象中设置质量值,如下所示:html2canvas(element, { scale: 2, quality: 4, ... }).then(canvas => { // ... }) - Vinícius Cerqueira Bonifácio

11

自从这个提交以来,API已发生变化,使用版本1.4.1现在是这样的

var width = pdf.internal.pageSize.getWidth();
var height = pdf.internal.pageSize.getHeight();

11

针对所有屏幕尺寸和动态方向的解决方案:

import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'

export default async function downloadComponentInPDF(Component: HTMLElement) {
  await html2canvas(Component).then((canvas) => {
    const componentWidth = Component.offsetWidth
    const componentHeight = Component.offsetHeight

    const orientation = componentWidth >= componentHeight ? 'l' : 'p'

    const imgData = canvas.toDataURL('image/png')
    const pdf = new jsPDF({
    orientation,
    unit: 'px'
  })

    pdf.internal.pageSize.width = componentWidth
    pdf.internal.pageSize.height = componentHeight

    pdf.addImage(imgData, 'PNG', 0, 0, componentWidth, componentHeight)
    pdf.save('download.pdf')
  })
}

唯一可行的解决方案是导出整个可滚动页面。谢谢。 - lukeic
这是一个非常棒的解决方案,谢谢。 - mister_b

9
如果您想要一个动态大小的图像自动填满页面并仍然保持图像的宽高比,可以按以下方式操作:

let width = doc.internal.pageSize.getWidth()
let height = doc.internal.pageSize.getHeight()

let widthRatio = width / canvas.width
let heightRatio = height / canvas.height

let ratio = widthRatio > heightRatio ? heightRatio : widthRatio

doc.addImage(
  canvas.toDataURL('image/jpeg', 1.0),
  'JPEG',
  0,
  0,
  canvas.width * ratio,
  canvas.height * ratio,
)

但是在像 iPhone 这样的较小屏幕上,图像仍然看起来被拉伸了。我们能做些什么吗? - NoushadM

6
如果您只有一张图片,那么调整页面大小很容易。更具挑战性的任务是将不同大小的图像适应到pdf文件中。实现这一目标的关键在于计算图像的宽高比和页面的相对宽高比。以下代码是我用来在线转换多个图像为PDF文件的。它会根据图像/页面的方向旋转图像,并设置适当的边距。我的项目使用带有在线src的图像。您应该能够修改以满足您的需求。
至于图像旋转,如果旋转后看到空白页,可能仅仅是因为图像超出了范围。有关详细信息,请参见此answer
function exportPdf(urls) {
    let pdf = new jsPDF('l', 'mm', 'a4');
    const pageWidth = pdf.internal.pageSize.getWidth();
    const pageHeight = pdf.internal.pageSize.getHeight();
    const pageRatio = pageWidth / pageHeight;

    for (let i = 0; i < urls.length; i++) {
        let img = new Image();
        img.src = urls[i];
        img.onload = function () {
            const imgWidth = this.width;
            const imgHeight = this.height;
            const imgRatio = imgWidth / imgHeight;
            if (i > 0) { pdf.addPage(); }
            pdf.setPage(i + 1);
            if (imgRatio >= 1) {
                const wc = imgWidth / pageWidth;
                if (imgRatio >= pageRatio) {
                    pdf.addImage(img, 'JPEG', 0, (pageHeight - imgHeight / wc) / 2, pageWidth, imgHeight / wc, null, 'NONE');
                }
                else {
                    const pi = pageRatio / imgRatio;
                    pdf.addImage(img, 'JPEG', (pageWidth - pageWidth / pi) / 2, 0, pageWidth / pi, (imgHeight / pi) / wc, null, 'NONE');
                }
            }
            else {
                const wc = imgWidth / pageHeight;
                if (1 / imgRatio > pageRatio) {
                    const ip = (1 / imgRatio) / pageRatio;
                    const margin = (pageHeight - ((imgHeight / ip) / wc)) / 4;
                    pdf.addImage(img, 'JPEG', (pageWidth - (imgHeight / ip) / wc) / 2, -(((imgHeight / ip) / wc) + margin), pageHeight / ip, (imgHeight / ip) / wc, null, 'NONE', -90);
                }
                else {

                    pdf.addImage(img, 'JPEG', (pageWidth - imgHeight / wc) / 2, -(imgHeight / wc), pageHeight, imgHeight / wc, null, 'NONE', -90);
                }
            }
            if (i == urls.length - 1) {
                pdf.save('Photo.pdf');
            }
        }
    }
}

如果这有点难理解,你也可以使用 .addPage([imgWidth, imgHeight]),这更加直观。这种方法的缺点是第一页由 new jsPDF() 固定。有关详细信息,请参见 this answer

3

我的解决方案是检查pdf的方向和图片尺寸,根据比例(高度或宽度)应用需要的比例。注意:如果不需要边距,请将边距设置为0。

   const imgData = canvas.toDataURL("image/jpeg");

   const pdf = new jsPDF({
       orientation: "portrait", // landscape or portrait
       unit: "mm",
       format: "a4",
   });
   const imgProps = pdf.getImageProperties(imgData);
   const margin = 0.1;

   const pdfWidth = pdf.internal.pageSize.width * (1 - margin);
   const pdfHeight = pdf.internal.pageSize.height * (1 - margin);

   const x = pdf.internal.pageSize.width * (margin / 2);
   const y = pdf.internal.pageSize.height * (margin / 2);

   const widthRatio = pdfWidth / imgProps.width;
   const heightRatio = pdfHeight / imgProps.height;
   const ratio = Math.min(widthRatio, heightRatio);
   
   const w = imgProps.width * ratio;
   const h = imgProps.height * ratio;

   pdf.addImage(imgData, "JPEG", x, y, w, h);

3

有很多使用.addImage的解决方案,我尝试了很多,但都没有成功。所以我找到了.html()函数,并在一些尝试后找到了html2canvas-scale-option。这个解决方案不是通用的解决方案,你需要调整比例以适应你的PDF,但这是唯一适合我的解决方案。

var doc = new jspdf.jsPDF({
    orientation: 'p',
    unit: 'pt',
    format: 'a4'
});

doc.html(document.querySelector('#styledTable'), {
    callback: function (doc) {
        doc.save('file.pdf');
    },
    margin: [60, 60, 60, 60],
    x: 32,
    y: 32,
    html2canvas: {
        scale: 0.3, //this was my solution, you have to adjust to your size
        width: 1000 //for some reason width does nothing
    },
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接