【问题标题】:Canvas charts is blurry when download as PDF以 PDF 格式下载时,画布图表模糊不清
【发布时间】:2019-04-14 20:16:42
【问题描述】:

第二次更新:

再次感谢所有评论/回答我的问题的人

问题已解决: 我无法在生成的 PDF 上使画布图像看起来更好,并且项目的截止日期即将结束,最后,我决定将“PDF 报告”功能从前端(Angular)移到后端(python) ,我已经发布了一个答案(不是我自己的问题的真正答案,而更像是一个解决方案

搜索几天后更新:

我已将 Chart.js 替换为 Echarts,但仍然存在模糊问题。网上查了很多jsPDF和Canvas blurry,好像canvas设置需要自定义,可惜不知道怎么实现。

在浏览器中的外观:

下载为 PDF 时:

原问题:

我有一个 Angular 项目,需要下载 PDF 以获取图形数据。我选择 Chart.js 和 jspdf 效果很好。当我在一页中打印 2 个图表时,分辨率还可以,但是当我尝试在同一页上打印 3 个图表时,文本模糊。我已阅读此similar question,但不知道如何在拥有多个图表时提高分辨率。

HTML 代码:

  <div class="col-md-4">
    <div class="card card-chart">
      <div class="card-header">
        <h5 class="card-title">Cervical Lateral Flexion</h5>
        <!--<p class="card-category">Line Chart</p>-->
      </div>
      <div class="card-body">
        <canvas id="cervicalLateralFlexion"></canvas>
      </div>
    </div>
  </div>

打字稿代码:

  public static buildChart(doc, selector, title, yHeight) {
    let height = yHeight;
    const canvas = document.querySelector(selector) as HTMLCanvasElement;
    doc.setFontSize(h5);
    doc.text(leftMargin, yHeight, title);
    const canvasImage = canvas.toDataURL('image/png');
    height += margin;
    doc.addImage(canvasImage, 'PNG', leftMargin, height);
  }

有人可以帮忙吗?如何解决这个问题?提前致谢! 图 1 是它在网页上的样子,图 2 是 PDF 文件。

【问题讨论】:

  • 看起来图像尺寸在第二张图像中发生了变化。模糊可能是因为图像被拉伸了。
  • 你使用的是哪个jspdf版本?
  • 问题是图像的 PDF 副本上的双线性过滤,因为其大小设置与图像像素大小不匹配。您对doc.addImage 的调用看起来像是错误的论点。 doc.addImage(img, format, xPos, yPos, width, height, alias) 确保画布分辨率与 PDF 文档中的显示尺寸相匹配。试试doc.addImage(canvasImage, 'PNG', leftMargin, yPos, canvas.width, canvas.height, "graph") 你必须创建yPos

标签: angular pdf canvas html5-canvas jspdf


【解决方案1】:

需要在addImage中设置高度和宽度

doc.addImage(canvasImage, 'PNG', leftMargin, height, "IMAGE-WIDTH-HERE", "IMAGE-HEIGHT-HERE");

如果您不知道图像尺寸,请尝试以下方法。

function getImageDimensions(file) {
  return new Promise (function (resolved, rejected) {
    var i = new Image()
    i.onload = function(){
      resolved({w: i.width, h: i.height})
    };
    i.src = file
  })
}

public static buildChart(doc, selector, title, yHeight) {
    let height = yHeight;
    const canvas = document.querySelector(selector) as HTMLCanvasElement;
    doc.setFontSize(h5);
    doc.text(leftMargin, yHeight, title);

    const canvasImage = canvas.toDataURL('image/png, 1.0');

    let dimensions = await getImageDimensions(canvasImage);

    height += margin;
    doc.addImage(canvasImage, 'PNG', leftMargin, height, dimensions.w, dimensions.h);
  }

getImageDimensions 函数从 here 复制而来,此函数使用 Promises,因为我们需要在您的场景中进行同步行为。

【讨论】:

  • 感谢您的回复!在问问题之前我已经尝试过了,但它没有帮助......
  • 我在网上搜了一下,好像是Chart.js的问题。我明天将用 Echarts 替换它,看看它是否有帮助。再次感谢
  • 试试html2pdf,它内部使用jsPDF。我用它来将 D3 图表转换为 pdf。非常好github.com/eKoopmans/html2pdf
  • 我已尝试您的最新更新,但保存为 PDF 时没有图表。
  • 你能分享一下代码吗?我已经将它用于反应,而不是角度,但这不应该是一个问题。 html2pdf 从 DOM 中提取内容
【解决方案2】:

这是一种变通方法,而不是对所描述的 jsPDF 问题的直接解决方案。我面临着完全相同的问题:jsPDF,图表模​​糊和角度。

希望我不会偏离主题太远,但我认为这对某些人来说很有价值。

解决方法:node + puppeteer

puppeteer 是一款无头 chrome 浏览器,可以在任何环境(甚至是 linux 终端)下工作,并且可以将网页渲染为图像或 PDF。

    import * as puppeteer from "puppeteer";

    const browser = await puppeteer.launch({});
    const page = await browser.newPage();

    await page.goto("https://google.com", { waitUntil: 'networkidle2' });
    await page.setViewport({ width: 1250, height: 3950 });
    await page.screenshot({ path: 'hourly_report.png' });
    await browser.close();

【讨论】:

    【解决方案3】:

    2020 年 5 月 10 日更新 我已经录制了一些关于如何使用 Wea​​syprint 和 Plotly 构建 PDF 报告的视频,您可以在此处找到详细信息:https://www.youtube.com/watch?v=hjWTCYPy7oU&t=1s

    2020 年 2 月 3 日更新:

    我发现Plotly在导出静态图片时真的很棒,强烈推荐。查看我构建的图像,您可以将其与我的原始问题帖子图像进行比较: 几个特点:

    • 图像可以保存为 SVG 或 PNG。再也不用担心模糊的问题了!
    • 自定义主题/样式很容易
    • 您可以在图表上添加任何形状,见蓝色垂直线,您可以绘制三角形、矩形(见填充的灰色区域)和任何其他您想要的形状。
    • 它支持多种语言:JS、Python 和 R。

    2019年原帖:

    感谢所有回答我问题的人,非常感谢您的帮助 我在 jsPDF + Chart.js 上花了两个多星期,但仍然没有弄清楚如何正确打印带有画布图像的 PDF。

    此项目是新项目,语言/工具/依赖项不受限制。为了使项目按时完成,我将 PDF 报告从前端(Angular)切换到后端(Python)。 现在我花了 2 天时间完成 PDF。

    我用来生成 PDF 报告和图表的来源:

    非常感谢 Weasyprint 让使用 HTML 和 CSS 生成 PDF 文档变得高效! 这是我生成的 PDF:

    【讨论】:

      【解决方案4】:

      如果您使用puppeteer 截取图像或pdf 格式的屏幕截图,则需要使用deviceScaleFactor 选项缩放图像,默认设置为1。其最小值为1,最大值为5 . 通过设置它,图像和 pdf 的质量都会被放大。查看issue 了解更多详情。附上以下代码:

      const page = await browser.newPage();
      await page.setViewport({ width: 800, height: 800, deviceScaleFactor: 3 });
      

      附:将 widthheight 设置为视口不会对图像/pdf 的大小产生任何影响。

      【讨论】:

        猜你喜欢
        • 2011-08-26
        • 1970-01-01
        • 2016-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-25
        • 1970-01-01
        相关资源
        最近更新 更多