【问题标题】:Creating a gradient fill in a PDF file using reportlab使用reportlab在PDF文件中创建渐变填充
【发布时间】:2009-01-16 21:24:12
【问题描述】:

是否可以使用ReportLab (python) 在 PDF 中创建渐变填充?

【问题讨论】:

    标签: python pdf gradient reportlab


    【解决方案1】:

    ReportLab 现在支持 PDF 渐变。

    2012 年 8 月 6 日,Peter Johnson 的 posted to the ReportLab mailing list 是渐变支持补丁,第二天是 added to the source。我在the release notes for ReportLab 2.6 中看不到任何东西,但自从 2012 年 10 月 1 日发布以来,它大概就在那里。它肯定存在于 2.7 中。

    可以指定具有多个停靠点的线性和径向渐变。在文档中搜索术语 gradient 并没有发现任何东西。但是,message with the first version of the patch 有几个示例是some tests in the ReportLab source 的基础。基于此,我编写了一个快速演示脚本:

    from reportlab.pdfgen.canvas import Canvas
    from reportlab.lib.colors import red, yellow, green
    from reportlab.lib.units import mm
    
    c = Canvas("gradient.pdf")
    
    # Linear gradient with the endpoints extending over the page.
    c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow))
    c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow))")
    c.line(105*mm, 200*mm, 180*mm, 100*mm)
    c.showPage()
    
    # Linear gradient constrained within the endpoints.
    c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow), extend=False)
    c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow), extend=False)")
    c.line(105*mm, 200*mm, 180*mm, 100*mm)
    c.showPage()
    
    # Linear gradient with multiple stops.
    c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow, green), (0, 0.8, 1), extend=False)
    c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow, green), (0, 0.8, 1), extend=False)")
    c.line(105*mm, 200*mm, 180*mm, 100*mm)
    c.line(141*mm, 102*mm, 189*mm, 138*mm)
    c.showPage()
    
    # Radial gradient with the endpoint extending over the page.
    c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow))
    c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow))")
    c.circle(105*mm, 200*mm, 60*mm)
    c.showPage()
    
    # Radial gradient constrained within the circle.
    c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow), extend=False)
    c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow), extend=False)")
    c.circle(105*mm, 200*mm, 60*mm)
    c.showPage()
    
    # Radial gradient with multiple stops.
    c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow, green), (0, 0.8, 1))
    c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow, green), (0, 0.8, 1))")
    c.circle(105*mm, 200*mm, 48*mm)
    c.circle(105*mm, 200*mm, 60*mm)
    c.showPage()
    
    c.save()
    

    这会输出六个页面,其中包含各种渐变以及渐变方法调用和显示端点和停止位置的线条/圆圈:

    【讨论】:

    • 对于线性渐变,有没有办法限制渐变,使其不会在垂直于直线的方向上无限延伸?
    【解决方案2】:

    [我的答案不再正确,Reportlab 中现在可以使用渐变,详情请参阅此页面上的其他答案。]

    很抱歉重新提出这个问题,但我偶然发现它并没有得到正确回答。

    答案是否定的,截至今天,当前版本的 ReportLab 不支持渐变。但是,PDF 支持渐变。如果您查看 ReportLab 的 Canvas 类,您会发现它的许多方法都是围绕底层 PDF 代码生成的相对较小的包装器。要在 RL 中访问渐变,您需要扩展 Canvas 类并添加其他方法来生成正确的 PDF 代码。这是可行的,但显然不是微不足道的,这意味着您必须阅读 PDF 规范。

    有两种选择。首先将渐变生成为光栅图像并使用它,其次通过绘制一系列不同颜色的矩形来生成渐变。

    start_color = (1,0,0)
    end_color = (0,1,0)
    for i in range(100):
        p = i * 0.01
        canvas.setFillColorRGB(*[start_color[i]*(1.0-p)+end_color[i]*p for i in range(3)])
        canvas.rect(i, 0, 2, 100)
    

    例如。不幸的是,使渐变平滑需要很多矩形,这会导致 PDF 很大并且渲染缓慢。您最好使用光栅方法。

    最后,您可以考虑使用 PyCairo。这对许多图形元素有更好的支持,并且可以呈现为 PDF 或 PNG。但是,它缺少 reportlabs 更高层次的结构(例如页面布局)。

    【讨论】:

      【解决方案3】:

      您想用渐变填充矩形(或其他路径)而不是 纯色?

      没问题。使用剪辑将渐变绑定/限制到路径。只需记住在设置渐变之前设置剪辑路径。 (然后将其包裹在saveState()/restoreState() 中,以在之后重置剪辑和渐变。)

      c = canvas.Canvas (filename)
      #c.translate (8*cm, 8*cm)  # use this to move the rectangle
      p = c.beginPath()
      p.rect (0,0 , 5*cm,5*cm)
      c.clipPath (p, stroke=0)
      c.linearGradient (0,0 , 5*cm, 5*cm , (red, yellow))
      

      对于径向渐变,将 extend 关键字参数设置为 False 可能就足够了。

      【讨论】:

      • 虽然这里有有用的信息,但它应该解决实际问题,而不是另一个答案中提出的问题。
      • @ZAD-Man 好吧,除非你想用线性渐变填充整个页面,否则你必须使用剪切路径(AFAIK)。我很确定大多数用例都涉及填充页面区域。我不喜欢迂腐地解释人们所说/写的东西。我通常会回答我认为发帖人试图询问/做/弄清楚的事情。当我这样做的时候;我首先说明我是如何解释这个问题的。
      • 嗯,我指的是您的答案正在回答一个现在已删除的“答案”,而这应该是一个新问题。您在开头的报价取自已删除的答案。就像我说的,这里有很好的信息,但应该对其进行编辑以删除对另一个“答案”的引用,以减少潜在的混淆,尤其是在另一个已被删除的情况下。
      • @ZAD-Man 当然,有什么可以取悦你的 :) 我删除了你不喜欢的报价。
      • 哈哈,小心,如果你说任何东西,我可能会要贵重的礼物。 ;) 谢谢你逗我 - 这是清理的最后一部分。虽然没有太大关系,但我喜欢彻底。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多