首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QRawFont/QPainterPath再现图标

QRawFont/QPainterPath再现图标
EN

Stack Overflow用户
提问于 2022-07-19 06:12:06
回答 1查看 61关注 0票数 1

我正在尝试复制FontAwesome上的一个图标。

首先,我加载字体并得到点:

代码语言:javascript
复制
int fa = QFontDatabase::addApplicationFont(":/fonts/fa-solid-900.ttf");
auto fas = QFontDatabase::applicationFontFamilies(fa).at(0);

QRawFont rfont = QRawFont::fromFont(fas);

qDebug() << rfont.pathForGlyph(0);

其结果是:

代码语言:javascript
复制
QPainterPath: Element count=45
 -> MoveTo(x=10.5, y=-14)
 -> LineTo(x=1.5, y=-14)
 -> CurveTo(x=1.08333, y=-13.9792)
 -> CurveToData(x=0.729167, y=-13.8333)
 -> CurveToData(x=0.4375, y=-13.5625)
 -> CurveTo(x=0.166667, y=-13.2708)
 -> CurveToData(x=0.0208333, y=-12.9167)
 -> CurveToData(x=0, y=-12.5)
 -> LineTo(x=0, y=0.5)
 -> CurveTo(x=0.0208333, y=0.916667)
 -> CurveToData(x=0.166667, y=1.27083)
 -> CurveToData(x=0.4375, y=1.5625)
 -> CurveTo(x=0.729167, y=1.83333)
 -> CurveToData(x=1.08333, y=1.97917)
 -> CurveToData(x=1.5, y=2)
 -> LineTo(x=10.5, y=2)
 -> CurveTo(x=10.9167, y=1.97917)
 -> CurveToData(x=11.2708, y=1.83333)
 -> CurveToData(x=11.5625, y=1.5625)
 -> CurveTo(x=11.8333, y=1.27083)
 -> CurveToData(x=11.9792, y=0.916667)
 -> CurveToData(x=12, y=0.5)
 -> LineTo(x=12, y=-12.5)
 -> CurveTo(x=11.9792, y=-12.9167)
 -> CurveToData(x=11.8333, y=-13.2708)
 -> CurveToData(x=11.5625, y=-13.5625)
 -> CurveTo(x=11.2708, y=-13.8333)
 -> CurveToData(x=10.9167, y=-13.9792)
 -> CurveToData(x=10.5, y=-14)
 -> MoveTo(x=8.8125, y=-12)
 -> LineTo(x=6, y=-7.8125)
 -> LineTo(x=3.21875, y=-12)
 -> LineTo(x=8.8125, y=-12)
 -> MoveTo(x=2, y=-10.1875)
 -> LineTo(x=4.8125, y=-6)
 -> LineTo(x=2, y=-1.8125)
 -> LineTo(x=2, y=-10.1875)
 -> MoveTo(x=3.21875, y=0)
 -> LineTo(x=6, y=-4.1875)
 -> LineTo(x=8.8125, y=0)
 -> LineTo(x=3.21875, y=0)
 -> MoveTo(x=10, y=-1.8125)
 -> LineTo(x=7.21875, y=-6)
 -> LineTo(x=10, y=-10.1875)
 -> LineTo(x=10, y=-1.8125)

然后我试着复制它:

代码语言:javascript
复制
QPainterPath* polygonPath = new QPainterPath();

polygonPath->moveTo(10.5, -14);
polygonPath->lineTo(1.5, -14);
polygonPath->CurveTo(1.08333, -13.9792);
polygonPath->CurveToData(0.729167, -13.8333);
polygonPath->CurveToData(0.4375, -13.5625);
polygonPath->CurveTo(0.166667, -13.2708);
polygonPath->CurveToData(0.0208333, -12.9167);
polygonPath->CurveToData(0, -12.5);
polygonPath->lineTo(0, 0.5);
polygonPath->CurveTo(0.0208333, 0.916667);
polygonPath->CurveToData(0.166667, 1.27083);
polygonPath->CurveToData(0.4375, 1.5625);
polygonPath->CurveTo(0.729167, 1.83333);
polygonPath->CurveToData(1.08333, 1.97917);
polygonPath->CurveToData(1.5, 2);
polygonPath->lineTo(10.5, 2);
polygonPath->CurveTo(10.9167, 1.97917);
polygonPath->CurveToData(11.2708, 1.83333);
polygonPath->CurveToData(11.5625, 1.5625);
polygonPath->CurveTo(11.8333, 1.27083);
polygonPath->CurveToData(11.9792, 0.916667);
polygonPath->CurveToData(12, 0.5);
polygonPath->lineTo(12, -12.5);
polygonPath->CurveTo(11.9792, -12.9167);
polygonPath->CurveToData(11.8333, -13.2708);
polygonPath->CurveToData(11.5625, -13.5625);
polygonPath->CurveTo(11.2708, -13.8333);
polygonPath->CurveToData(10.9167, -13.9792);
polygonPath->CurveToData(10.5, -14);
polygonPath->moveTo(8.8125, -12);
polygonPath->lineTo(6, -7.8125);
polygonPath->lineTo(3.21875, -12);
polygonPath->lineTo(8.8125, -12);
polygonPath->moveTo(2, -10.1875);
polygonPath->lineTo(4.8125, -6);
polygonPath->lineTo(2, -1.8125);
polygonPath->lineTo(2, -10.1875);
polygonPath->moveTo(3.21875, 0);
polygonPath->lineTo(6, -4.1875);
polygonPath->lineTo(8.8125, 0);
polygonPath->lineTo(3.21875, 0);
polygonPath->moveTo(10, -1.8125);
polygonPath->lineTo(7.21875, -6);
polygonPath->lineTo(10, -10.1875);
polygonPath->lineTo(10, -1.8125);
polygonPath->closeSubpath();

不幸的是,我不知道用什么代替CurveTo和CurveToData。我一直在看医生,但我就是不明白。

我想要实现的是获得图标点,以便我可以画它作为一个多边形。与此类似:

代码语言:javascript
复制
QPolygon symbol;

symbol << QPoint(0.65, -9.75)
    << QPoint(5.85, -9.75)
    << QPoint(5.85, 0)
    << QPoint(0.65, 0);

painter.drawPolygon(symbol);

如果有人能这么好地提供一个解决方案,那就太棒了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-19 10:34:47

对于关于QPainterPath的另一个答案,我得到的反馈是,OP的实际问题似乎是为预期的字形检索油漆工路径。

因此,我修改了MCVE以绘制选定字符的画家路径。

首先,我使用MS字符表选择了一个很好的字符:

相关信息是在底部状态行:U+2620中显示的Unicode代码点。

然后,我修改了makeSample()以使用该字符检索相应的画家路径:

代码语言:javascript
复制
QPainterPath makeSample()
{
  // get a font which should be able to provide most of the Unicode code points
  QFont qFont("Arial Unicode MS");
  // transform font into a raw font
  QRawFont qRawFont = QRawFont::fromFont(qFont);
  // build a Qt string with the intended character
  QString qText(1, QChar(0x2620)); // 0x2620 is the Unicode code point for Skull
  // retrieve the glyph index for the character
  QVector<quint32> qGlyphIndices = qRawFont.glyphIndexesForString(qText);
  // build the Qt painter path
  QPainterPath qPainterPath;
  for (quint32 qGlyphIndex : qGlyphIndices) {
    qPainterPath += qRawFont.pathForGlyph(qGlyphIndex);
  }
  // done
  return qPainterPath;
}

第一个结果是中文字形,直到我意识到字形索引与Unicode代码点无关。(我使用了0x2620 ( Unicode代码点)作为字形索引。)因此,我介绍了QRawFont::glyphIndexesForString()的转换。

与OP所描述的类似,接下来我得到的是左上角的一些线条。浏览一下转储列表,我就意识到转储中存在y坐标,其负数即呈现在我的Canvas小部件的顶部边框之外。

因此,我稍微调整了渲染,直到我发现它可以接受为止。

整个MCVE:

代码语言:javascript
复制
#include <QtWidgets>

class Canvas: public QWidget {

  private:
    QPainterPath *_pQPainterPath;

  public:
    explicit Canvas(QPainterPath* pQPainterPath, QWidget* pQParent = nullptr):
      QWidget(pQParent),
      _pQPainterPath(pQPainterPath)
    { }

  protected:
    virtual void paintEvent(QPaintEvent* pQEvent) override;
};

void Canvas::paintEvent(QPaintEvent* pQEvent)
{
  if (!_pQPainterPath) return;
  const QRectF qRect = _pQPainterPath->boundingRect();
  const qreal scale
    = std::min(width() / qRect.width(), height() / qRect.height());
  const QPointF center(0.5 * width(), 0.5 * height());
  QPainter qPainter(this);
  QPen qPen(Qt::blue);
  qPen.setCosmetic(true);
  qPainter.setPen(qPen);
  qPainter.translate(center);
  qPainter.scale(scale, scale);
  qPainter.translate(-qRect.center());
  qPainter.drawPath(*_pQPainterPath);
}

const char* toText(QPainterPath::ElementType type)
{
  static const char* const texts[] = {
    "MoveTo", "LineTo", "CurveTo", "CurveToData"
  };
  const size_t n = std::size(texts);
  return type < n ? texts[type] : "???";
}

QString list(const QPainterPath& qPainterPath)
{
  QString qText;
  QTextStream qOut(&qText);
  for (int i = 0, n = qPainterPath.elementCount(); i < n; ++i) {
    const QPainterPath::Element& qPPElem = qPainterPath.elementAt(i);
    qOut << toText(qPPElem.type) << "(x=" << qPPElem.x << ", y=" << qPPElem.y << ")\n";
  }
  return qText;
}

QString listSrc(const QPainterPath& qPainterPath)
{
  QString qText;
  QTextStream qOut(&qText);
  qOut << "QPainterPath qPainterPath;\n";
  for (int i = 0, n = qPainterPath.elementCount(); i < n; ++i) {
    const QPainterPath::Element& qPPElem = qPainterPath.elementAt(i);
    switch (qPPElem.type) {
      case QPainterPath::MoveToElement:
        qOut << "qPainterPath.moveTo(" << qPPElem.x << ", " << qPPElem.y << ");\n";
        break;
      case QPainterPath::LineToElement:
        qOut << "qPainterPath.lineTo(" << qPPElem.x << ", " << qPPElem.y << ");\n";
        break;
      case QPainterPath::CurveToElement: {
        if (i + 2 >= n
          || qPainterPath.elementAt(i + 1).type != QPainterPath::CurveToDataElement
          || qPainterPath.elementAt(i + 2).type != QPainterPath::CurveToDataElement) {
          qOut << "// BROKEN qPainterPath.cubicTo();\n";
          break; // ERROR!
        }
        const QPainterPath::Element& qPPElem1 = qPainterPath.elementAt(++i);
        const QPainterPath::Element& qPPElem2 = qPainterPath.elementAt(++i);
        qOut << "qPainterPath.cubicTo(" << qPPElem.x << ", " << qPPElem.y << ", "
           << qPPElem1.x << ", " << qPPElem1.y << ", "
           << qPPElem2.x << ", " << qPPElem2.y << ");\n";
      } break;
    }
  }
  return qText;
}

QPainterPath makeSample()
{
  QFont qFont("Arial Unicode MS");
  QRawFont qRawFont = QRawFont::fromFont(qFont);
  QString qText(1, QChar(0x2620)); // 0x2620 is the Unicode code point for Skull
  QVector<quint32> qGlyphIndices = qRawFont.glyphIndexesForString(qText);
  QPainterPath qPainterPath;
  for (quint32 qGlyphIndex : qGlyphIndices) {
    qPainterPath += qRawFont.pathForGlyph(qGlyphIndex);
  }
  return qPainterPath;
}

int main(int argc, char** argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup data
  QPainterPath qPainterPath = makeSample();
  qDebug() << qPainterPath;
  // setup GUI
  QMainWindow qWinMain;
  qWinMain.setWindowTitle("Test QRawFont - QPainterPath");
  qWinMain.resize(480, 280);
  QSplitter qVSplit(Qt::Vertical);
  Canvas canvas(&qPainterPath);
  qVSplit.addWidget(&canvas);
  QSplitter qHSplit(Qt::Horizontal);
  QPlainTextEdit qEditCode;
  qEditCode.setPlainText(listSrc(qPainterPath));
  qHSplit.addWidget(&qEditCode);
  QPlainTextEdit qEditPath;
  qEditPath.setPlainText(list(qPainterPath));
  qHSplit.addWidget(&qEditPath);
  qVSplit.addWidget(&qHSplit);
  qVSplit.setSizes({ 100, 180 });
  qWinMain.setCentralWidget(&qVSplit);
  qWinMain.show();
  // runtime loop
  return app.exec();
}

输出:

虽然渲染可能并不完美,但确实有相似之处。

这是它的样子,如果一个黄色的刷子是与蓝色的笔。(在添加qPen.setCosmetic(true);之前,我删除了画笔,而结果却不符合我的预期。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73031944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档