Как визуализировать SVG без сглаживания в Qt / hook QPainter, чтобы избежать сглаживания? - PullRequest
2 голосов
/ 22 марта 2019

Мне нужно отрисовать только вектор SVG без сглаживания в Qt; в частности, я не хочу, чтобы полученное изображение содержало какие-либо цвета, которые не были точно такими, как указано в исходном файле.

При загрузке SVG в QImage, Qt по умолчанию использует сглаживание; даже при явном использовании QSvgRenderer::render подсказка рендеринга QPainter::Antialiasing игнорируется.

Это оказывается очевидным, поскольку QSVGTinyDocument::draw, который, похоже, является тем, кто фактически начинает рисование, заставляет его установить :

//sets default style on the painter
//### not the most optimal way
mapSourceToTarget(p, bounds);
QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin);
pen.setMiterLimit(4);
p->setPen(pen);
p->setBrush(Qt::black);
p->setRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::SmoothPixmapTransform);

Чтобы обойти это, я попытался создать пользовательский QPaintEngine, обертывающий стандартный по умолчанию (а затем подкласс даже QImage для возврата оболочки QPaintEngine в виртуальном методе paintEngine()), но я не смог найти ни одного чистый способ перехватить и изменить подсказку рендеринга на пути к фактическому QPaintEngine.

Метод QPaintEngine::update(), который, по-видимому, является способом, посредством которого QPaintEngine получает флаги, получает ссылку на QPaintEngineState, который является ужасным кладжем, который предоставляет только геттеры, которые, в свою очередь,

  • не virtual, поэтому вы не можете предоставить свою реализацию;
  • внутренне просто предполагает, что он на самом деле работает с экземпляром внутреннего подкласса (QPainterState) , жестоко приводя указатель this и получая доступ к его полям.

Кроме того, даже простое предоставление QPaintEngine привело к появлению ошибок в недрах кода QPainter, поэтому я быстро отказался.


Короче говоря:

  • есть ли способ принудительно отключить / перехватить и игнорировать / ... подсказку QPainter::Antialiasing рендеринга для QPainter? (переменная окружения QT_NO_ANTIALIASING не считается, поскольку она включена только в сборках без QT_NO_DEBUG);
  • В общем, как я могу отрисовать SVG на QImage без сглаживания?

1 Ответ

0 голосов
/ 23 марта 2019

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

Этот обходной путь, вероятно, нецелесообразен для рендеринга в реальном времени, но если вы только хотите создать QImage s вшаг предварительной обработки, он должен сделать работу.

QImage convertToAliased(const QImage& source)
{
  const auto mask = QPixmap::fromImage(source.createAlphaMask());

  QImage image(source.size(), QImage::Format_ARGB32);
  image.fill(Qt::transparent);

  QPainter p;
  p.begin(&image);
  p.setClipRegion(QRegion(mask));
  p.drawImage(QPoint(0, 0), source.convertToFormat(QImage::Format_RGB32));
  p.end();

  return image;
}

Код также можно найти здесь в GitHub.

...