Хорошо, я понял:
Мне нужно создать QTextLayout и создать строку в этом макете (без переноса). GlyphRuns, которые я получаю из этого макета, существуют для каждой буквы текста в макете, поэтому мне просто нужно перебрать каждую букву, взять глиф этой буквы, убедиться, что его положение не совпадает с положением предыдущей буквы (в случае он был объединен с предыдущей буквой) и нарисуйте его.
Вот мой рабочий код радуги:
#include <QPainter>
#include <QImage>
#include <QGuiApplication>
#include <QTextLayout>
QColor get_color(float position, uint8_t alpha) {
if (position < 0.2)
return QColor(255 - 255 * position / 0.2, 0, 255, alpha);
if (position < 0.4)
return QColor( 0, 255 * (position - 0.2) / 0.2, 255, alpha);
if (position < 0.6)
return QColor( 0, 255, 255 - 255 * (position - 0.4) / 0.2, alpha);
if (position < 0.8)
return QColor(255 * (position - 0.6) / 0.2, 255, 0, alpha);
return QColor( 255, 255 - 255 * (position - 0.8) / 0.2, 0, alpha);
}
QImage draw_letters(const QString & text, const QFont & font) {
QFontMetrics metric(font);
auto bbox = metric.boundingRect(text);
QImage img(bbox.width(), bbox.height(), QImage::Format_ARGB32);
QPainter painter;
painter.begin(&img);
painter.setBrush(QBrush(QColor(0, 0, 0, 255)));
painter.drawRect(0, 0, img.width()+1, img.height()+1);
QTextLayout layout(text, font);
QTextOption option;
option.setWrapMode(QTextOption::NoWrap);
layout.setTextOption(option);
layout.beginLayout();
auto line = layout.createLine();
layout.endLayout();
QPointF prev_position(-1, -1);
int num_letters = text.length();
for (int i = 0; i < num_letters; ++i) {
auto glyph = layout.glyphRuns(i, 1)[0];
painter.setPen(get_color(static_cast<float>(i) / (num_letters - 1), 255));
if (prev_position != glyph.positions()[0])
painter.drawGlyphRun(QPointF(0, 0), glyph);
prev_position = glyph.positions()[0];
}
painter.end();
return img;
}
int main(int argc, char *argv[])
{
QString text("I can see the rainbow!");
QGuiApplication a(argc, argv);
QFont font("Dancing Script", 100);
draw_letters(text, font).save("txt.png");
return 0;
}
Использование цветных вертикальных полос с визуализированным шрифтом в качестве альфа-маски согласно предложению Джармана может быть легко достигнуто путем рисования прямоугольников с помощью glyph.boundingRect()
, но это приводит к проблеме с буквами, такими как W
в моем выбранном шрифте, поскольку он перекрывает прямоугольник следующей буквы, поэтому при использовании этого метода эта буква W будет нарисована двумя цветами .
Также обратите внимание, что на самом деле я вообще не использую альфа-смешение, оказывается, это выглядит лучше, когда следующая буква полностью перезаписывает предыдущую вместо альфа-смешения. Вид линейного смешивания (с изменением веса по оси x) может быть лучше, но это выходит за рамки этого вопроса.