【问题标题】:Qt text size in pointsQt 文本大小(以磅为单位)
【发布时间】:2018-10-08 14:37:54
【问题描述】:

我正在尝试在 A4 上以毫米而不是默认设备单位打印发票文档。除了将单位更改为毫米时,打印文档上的文本点大小不再与 Word 或 Adob​​e Illustrator 中的点大小匹配。我尝试将点大小转换为相应的像素大小,但他们遇到了问题。

QFont::SetPixelSize 只接受一个 int,因此如果计算值低于 1,它将截断为 0

font.setPixelSize((9.0 * 72.0) / printer.resolution());

另一种方法使文本的垂直大小正确,但存在一些伪像:

int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);


您可以在其中看到某些字符之间异常大的间隙。 (也许 Qt 的文本绘制代码内部存在一些精度问题?)


这是一个显示问题的最小示例:

QPrinter printer(QPrinter::HighResolution);
printer.setPageSize(QPrinter::A4);
printer.setOrientation(QPrinter::Portrait);
printer.setFullPage(true);
printer.setPageMargins(QMarginsF(0, 0, 0, 0));

printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName("invoice.pdf");

QPainter painter(&printer);

auto page_size = printer.pageRect(QPrinter::Unit::Millimeter);
painter.setWindow(page_size.toRect());

QFont font = painter.font();

// Either this
font.setPixelSize((9.0 * 72.0) / printer.resolution());

// or this
int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);

painter.setFont(font);
painter.drawText(35, 46, "John Doe");

如何以毫米(或任何任意单位)为单位进行定位,并使文本大小以点为单位正确(或某些正确的重新计算)?

这是在 Qt 5.10.0 和 Windows 10 上。

编辑 最后,我选择增加 10 倍的比例(即十分之一毫米),这解决了 setPointSizeF 可见的字距调整问题。现在我遇到的最后一个问题是设置线的宽度和其他形状(QPen::setWidth),我找不到计算,所以它以毫米为单位。

编辑 最后线宽不需要任何重新计算。最终代码如下:

QPrinter printer(QPrinter::HighResolution);
printer.setPageSize(QPrinter::A4);
printer.setOrientation(QPrinter::Portrait);
printer.setFullPage(true);
printer.setPageMargins(QMarginsF(0, 0, 0, 0));

printer.setOutputFormat(QPrinter::NativeFormat);

QPainter painter(&printer);
painter.setWindow(0, 0, 2100, 2970);
painter.setViewport(0, 0, printer.width(), printer.height());

QFont font(fontFamily, 0, weight, italic);
font.setPointSizeF(static_cast<float>(pixelSize) / printer.width() * 2100);

【问题讨论】:

  • 你能澄清一下 9.0 , 210.0, 72.0 值代表什么吗?
  • 9.0 是以磅为单位的随机字体大小。 210 是 A4 纸的宽度,单位为毫米,72.0 是 DPI。

标签: c++ qt text


【解决方案1】:

我认为您在应该相乘的地方进行划分,反之亦然。看看明确写出的单位:

9 点 *(1 英寸/72 点)*(printer.res 像素/英寸)

乘以单位,分子得到 (points * inch * pixels) ,分母得到 (points * inch) 。取消类似的单位,你会得到分子中的像素。所以计算应该是:

font.setPixelSize(9.0 / 72.0 * printer.resolution());

第二个问题,

QPen::setWidthF(w*printer.resolution()/25.4);

其中 w 是您想​​要的宽度,以 mm 为单位。

【讨论】:

  • 啊,是的,这确实是错误的。我似乎已经解决了文本缩放的问题,并用最后一个小问题更新了我的主帖。
  • 好的,我用你的第二个问题的答案更新了我的答案
  • 这似乎不太对劲。如果我的打印机分辨率是 1200 并且我选择 2 毫米然后选择 20(毫米的十分之一)* 1200 / 25.4 那么它会给出 944 这是巨大的
  • 不,应该是 2mm * 1200 / 25.4。如果你想从十分位开始,除以 254。
  • (简化) lineNormal.setWidth(20.0 * 1200.0 / 254.0);画线(100、0、100、200);给出:g2f.nl/0f847sx 超过 2 毫米
【解决方案2】:

通过详细观察(打印一个长句子),注意到字符之间的这些间隙与字符本身直接相关,宽字符和大写字母会吃掉间隙(J,s,r,c),而窄字符留下更多gap (i , l , t) .. 这只是说它不是 随机 行为。

通常这被称为 kerning 很好地解释了here。为了尽量减少这种情况,Qt 将 QFont kerning 设置为 true (默认)QFont Kerning ...但问题是 kerning 在很大程度上取决于使用的字体和像素,并且启用 Qt kerning 有时不会像 this post 那样起作用,可能因为将 Kerning 设置为 true

(将在相邻字形之间应用字距调整。请注意,OpenType GPOS 目前不支持基于字距调整 QRawFont::LayoutFlags

这意味着某些字体 Ascent / Descent 仍然会限制如何控制间隙。 下面考虑两种解决方案,第一种是仍然坚持默认的画家字体,但您可以拉伸字符以强制执行合理的 gab:

font.setStretch(70); // value is experimental 

我不认为这是一个稳健的解决方案,除非仅限于使用特定字体,而字体本身对于发票打印并不重要,第二种有吸引力的方法是找出符合要求的最佳字体 要求:在设定的分辨率下渲染良好/绘制为 PDF(来自 Qt)时损失很小/最重要的是对字距调整有效! 例如,“MS Gothic”(ttf)在这种设置中表现良好,这里是它的表现(没有拉伸)

painter.setFont(QFont("MS Gothic"));
QFont font = painter.font();
int phys_w = printer.width();
font.setPointSizeF((9.0 / phys_w) * 210.0);
//font.setStretch(70);
painter.setFont(font);

选择合适字体的好处是可以进行更多控制(特别是对于小空间很有价值的发票打印)。

例如,通过减少字母之间的间距,可以用更少的空间打印相同的内容:

font.setLetterSpacing(QFont::PercentageSpacing,65); // 65% gap of default

甚至可以在不丢失视觉间隙的情况下使用较小的字体。


在尝试阐明打印小字体如何影响字母之间的间隙时分享以下一些工作。想法是在 QRect 内分别绘制每个字符,同时在同一区域绘制等效的 QRectF。

这是为了查看当字体大小较大时 QRectF 被绘制成彼此相邻,因此每个字符也是如此……而当字体大小变小时,相邻的 QRectF 将严重重叠并且字符之间的间隙开始变得混乱。

QPen pen=painter.pen();
pen.setWidth(0.1);
painter.setPen(pen);
QString td("John Doe");
auto spacer = font.pointSizeF(); // font size used to set width of QRect of each character.
spacer *=30.0; // large Rect width.
auto b = 35.0;

for (int i=0; i < td.length() ;i++ )
{
    QRectF rectf(b+=spacer,47.0,4.0,4.0);
    QRect rect(b, 47.0,4.0,4.0);
    QString ch = td.at(i);
    //painter.drawText(b+=spacer,46,ch);
    painter.drawText(rect,Qt::AlignCenter,ch);
    painter.drawRect(rectf);
}
painter.end();

大字体的结果:

接下来让QRectF重叠:

spacer *=10.0;

结果,字母之间的间隙变小,相邻的宽字符间隙变窄。

【讨论】:

  • 感谢您的详尽解释!我最终将精度提高了十倍以抵消奇怪的字距调整,但我还有最后一个小问题。我已经更新了主帖。
  • pen.setWidthF(0.05); 怎么样?
  • @Mohammad-Kanan 你能看看这个问题吗:stackoverflow.com/questions/61697971/… 它只与字体有关......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
  • 2020-12-14
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
相关资源
最近更新 更多