Каир (с Python): возможно ли заполнить многоугольник прозрачной линией? - PullRequest
0 голосов
/ 23 марта 2011

Вот код, который я сейчас использую:

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *image.size)
context = cairo.Context(surface)
context.set_source_rgba(1, 1, 1, 1)
context.new_path()
for i in xrange(len(points)):
    context.line_to(*points[i])

context.close_path()
context.fill()

Проблема в том, что он заполняет многоугольник тем же цветом, который я рисую.Я попытался нарисовать новый многоугольник поверх этого и сделал просто context.stroke() вместо fill(), но это работает, только если я использую другой цвет, так как в противном случае белый цвет будет ниже.Я пробовал с (0,0,0,0), чтобы он был прозрачным, но тогда белый цвет находится ниже него.

Я могу нарисовать цветную линию (скажем, (0.5,0.5,0.5,1)), сохранить ее на изображении с write_to_png, загрузитьс помощью PIL, преобразуйте его в numpy.array и замените каждый пиксель нужным цветом на цвет фона (0, 0, 0, 0), но это неэффективно.

Я также попытался установить ширину линии равной 0, но это неработать либо.

Кроме того, я в порядке с другими методами, которые позволяют мне делать это, которые не являются Каиром.Я попробовал polygon в ImageDraw, но он не рисует точную форму (я не знаю, как объяснить, но он рисует некоторые дополнительные пиксели за пределами полигона, где это не должно), поэтому ImageDraw победил 'мне не поможет.

Ответы [ 2 ]

1 голос
/ 08 июня 2012
fill_preserve()
context.set_source_rgba(0, .6, 1, .7) #line color
context.set_line_width(2.35)
context.stroke()
0 голосов
/ 23 марта 2011

Я понял это сейчас.Таким образом, нет никакого способа сделать это - все API 2D-рисования в стиле Каира предполагают, что «заливка» включает границу.Он работает таким образом на большинстве бэкэндов, к которым рендерится Cairo, например Postscript и SVG, поэтому трудно представить, как они могут отличаться.

«Чистый» способ сделать это - выполнить итерации по полигону так, чтобывы генерируете точки, которые разграничивают только область, которую вы хотите заполнить, т.е. вы должны сами рассчитать площадь линии.

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

http://doswa.com/blog/2010/03/29/using-cairo-in-pygame/ http://www.pygame.org/wiki/CairoPygame

(На самом деле, я пытался придумать рабочий процесс с использованием Pyagame и не смог - возможности манипулирования альфа-пикселями и копирования / вставки на нем довольно ограничены).

Последнее предложение для вас: не используйте для этого pycairo - проверьте, подходит ли вам использование GIMP Python API.GIMP - это полнофункциональная программа для рисования 2D с полным API, которую можно использовать из Python.Вы можете рисовать свои полигоны с помощью объектов GIMP «Векторы», и хотя «заливка» также будет включать в себя линию многоугольника, есть «gimp_selection_shrink», которую вы можете вызвать, например, jsut перед заполнением.Или вы можете использовать слои, чтобы получить нужный эффект.

Внутри GIMP вы можете проверить весь API в меню Справка-> Процедура.

Как только ваш скриптготово, можно запускать GIMP со строкой coomand для запуска вашей программы, без необходимости графического отображения.

Вот рабочий процесс, который вам необходим с помощью pygimp:

  • СоздатьОбъекты векторов GIMP с вашими полигонными точками: pdb.gimp_image_add_vectors, pdb.gimp_vectors_stroke_new_from_points
  • Создайте новый слой (над слоем с изображением, которое вы хотите сохранить вдоль линии) pdb.gimp_layer_new (есть некоторые другие функции, которыедолжны быть вызваны для привязки слоя к изображению)
  • Преобразование полигона в выделение - pdb.gimp_vectors_to_selection
  • Заполните новый слой нужным цветом pdb.gimp_edit_bucket_fill
  • Преобразовать выделение в "толстое" выделение с помощью pdb.gimp_selection_border
  • Вырезать пиксели из слоя - pdb.gimp_Edit_cut
  • Объединить новый слой с вашим предыдущим изображением - pdb.gimp_image_merge_down
...