Создание градиентной заливки в файле PDF с помощью reportlab

Можно ли создать градиентную заливку в PDF с помощью ReportLab (python)?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
12
0
3 655
3

Ответы 3

[Мой ответ больше неверен, градиенты теперь доступны в Reportlab, подробности см. В другом ответе на этой странице.]

Извините, что снова задаю этот вопрос, но я наткнулся на него, и на него не было дано правильного ответа.

Ответ - нет, на сегодняшний день текущая версия ReportLab не поддерживает градиенты. Однако градиенты поддерживаются PDF. Если вы посмотрите на класс Canvas ReportLab, вы увидите, что многие из его методов являются относительно небольшими оболочками для генерации базового кода 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. Однако в нем отсутствуют более высокие рычажные конструкции reportlab (например, макет страницы).

ReportLab теперь поддерживает градиенты PDF.

Патч для поддержки градиента был размещен в списке рассылки ReportLab Питера Джонсона 6 августа 2012 года и был добавлен в источник на следующий день. Я не могу найти ничего в примечания к выпуску ReportLab 2.6, но, поскольку он был выпущен 1 октября 2012 года, по-видимому, он там есть. Это определенно присутствует в 2.7.

Можно указать как линейный, так и радиальный градиенты с несколькими упорами. Поиск в документации по запросу градиент ничего не дает. Однако сообщение с первой версией патча имеет несколько примеров, которые являются основой некоторые тесты в источнике ReportLab. На основе этого я разработал небольшой демонстрационный скрипт:

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()

Это выводит шесть страниц с различными градиентами, а также вызов метода градиента и линии / круги, показывающие, где находятся конечные точки и остановки:

Basic linear gradient extending over pageLinear gradient constrained within endpointsLinear gradient with multiple stopsBasic radial gradient extending over pageRadial gradient constrained within radiusRadial gradient with multiple stops

Вы хотите заполнить прямоугольник (или другой путь) градиентом вместо сплошной цвет?

Без проблем. Используйте отсечение, чтобы привязать / ограничить градиент до контура. Просто не забудьте установить путь обрезки перед, задав градиент. (И оберните его внутрь 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 20.06.2014 00:32

@ ZAD-Man Ну, если вы не хотите заполнить всю страницу линейным градиентом, вы должны использовать обтравочный контур (AFAIK). Я почти уверен, что в большинстве случаев используется заполнение областей страницы. Я не любитель педантично интерпретировать то, что люди говорят / пишут. Я обычно отвечаю на то, что я считать пытается спросить / сделать / выяснить. И когда я это сделаю; Я начинаю свой ответ с описания того, как я истолковал вопрос.

Torkel Bjørnson-Langen 21.06.2014 22:43

Что ж, я имею в виду тот факт, что ваш ответ является ответом на теперь удаленный «ответ», который должен был быть новым вопросом. Ваша цитата в начале взята из удаленного ответа. Как я уже сказал, здесь есть хорошая информация, но ее следует отредактировать, чтобы удалить ссылки на другой «ответ», чтобы уменьшить потенциальную путаницу, особенно теперь, когда другой был удален.

ZAD-Man 23.06.2014 19:23

@ ZAD-Man Конечно, все, чтобы доставить вам удовольствие :) Я удалил цитату, которая вам не понравилась.

Torkel Bjørnson-Langen 23.06.2014 21:52

Ха-ха, осторожно, я могу попросить дорогие подарки, если ты скажешь что-нибудь. ;) Спасибо, что пошутил - это была последняя часть уборки. Хотя это не имело большого значения, мне нравится быть внимательным.

ZAD-Man 23.06.2014 23:19

Другие вопросы по теме