【问题标题】:Qt QPainter in millimetres instead of inchesQt QPainter 以毫米而不是英寸为单位
【发布时间】:2018-05-23 21:23:07
【问题描述】:

我有一台 QPrinter,可以直接将 A4 打印到物理打印机或 PDF。现在我想使用 QPainter 以毫米为单位进行绘制,但当前坐标系似乎是 A4 的宽度和高度(以英寸为单位)乘以打印机的分辨率。

8.26 英寸 x 1200 分辨率 = 9912
11.69 英寸 x 1200 分辨率 = 14028

我尝试了以下内容,但文本最终变得很大。

auto page = printer.pageRect(QPrinter::Unit::Millimeter);
painter.setWindow(QRect(0, 0, page.width(), page.height()));

如何更改此设置,以便我的 QPainter 可以绘制到 210 x 297 毫米而不是上述系统?

这是在 Windows 10 和 Qt 5.10 上。

【问题讨论】:

    标签: c++ qt printing transform


    【解决方案1】:

    我在X11(ubuntu linux)PDF打印上测试了这个方法,使用ScreenResolution打印机模式:

    painter.begin(printer);
    
    int log_w  = 210;
    int log_h  = 297;
    painter.setWindow(0, 0, log_w, log_h);
    
    int phys_w  = printer->width();
    int phys_h = printer->height();
    painter.setViewport(0, 0, phys_w, phys_h);
    

    基本上,使用画家窗口以毫米为单位设置逻辑尺寸,并为画家的视口提供打印机的物理尺寸。 此行应在页面周围打印一个边框为 10 毫米的矩形:

    painter.drawRect(10, 10, log_w - 20, log_h -20);
    

    文本应该相应地工作。此代码应在矩形的左上角打印单词 Ok

      QFont font = painter.font();
      font.setPointSize(10); //1 cm height
      painter.setFont(font);
      painter.drawText(10, 20, "Ok");
    
      painter.end();
    

    使用HighResolution打印模式,字体大小必须使用

    font.setPixelSize(10); //1 cm height
    

    并且必须将QPen 设置为painter:

    QPen pen(Qt::black);
    pen.setWidthF(0.2);
    painter.setPen(pen);
    painter.drawRect(10, 10, log_w - 20, log_h - 20);
    

    关于使用setPixelSize 丢失设备依赖,我知道here 已声明:

    可以将屏幕上显示的字符高度设置为 使用 setPixelSize() 指定数量的像素;但是使用 setPointSize() 具有类似的效果并提供设备独立性。

    但我认为它仅指屏幕,因为声明了here

    在 QPrinter 设备上渲染文本时,重要的是要实现 当以磅为单位指定时,文本的大小与 为设备本身指定的分辨率。因此,它可能是 在将文本与 图形以确保它们的相对大小符合您的预期。

    【讨论】:

    • 您好,此方法部分适用于矩形而不适用于文本。这是最小的代码示例:pastebin.com/tT0ZLa87 会导致问题。输出到 NativeFormat (Windows 10) 时,矩形是正确的,但文本严重膨胀。当输出到 pdf 时,两者都是错误的。 PDFFormat 输出:g2f.nl/0o2if42 和 NativeFormat 输出:g2f.nl/0che686
    • 以高分辨率打印时(本机打印机)尝试使用设置字体大小。 setPixelSize。关于PDF,我真的不知道,我用的是ScreenResolution作为打印机模式。
    • 但这将是一种依赖于设备 (dpi) 的方式。似乎字体没有正确转换。我觉得这很困难,因为这似乎是您在打印时想要做的基本事情。
    • 我编辑了解决 PDF 问题的答案并解决了设备依赖性问题。
    • 好的,现在我可以在两者上绘制相同大小的文本,它现在非常大。如何将 Adob​​e Illustrator 中设置的点大小转换为在绘图代码中的 A4 上具有相同大小。对于原始窗口和视口大小,它是 1:1 映射。还有我的 QSvgRenderer 渲染器(“路径”);现在调用 renderer.render() 时将不显示任何输出
    【解决方案2】:

    你的方法是正确的。以下是如何设置打印机/画家对的示例。我不会摆弄转换矩阵,因为它足以指定一个窗口/视口对。我什至没有明确指定视口,因为它会自动设置为绘图设备的指标(在本例中为 QPrinter 对象)。

    #include <QPrinter>
    #include <QPainter>
    
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
    
        QPrinter printer(QPrinter::PrinterResolution);
        printer.setOrientation(QPrinter::Portrait);
        printer.setPageSize(QPageSize(QPageSize::A4));
        printer.setResolution(300 /*dpi*/);
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName("ellipse.pdf");
    
        QPainter painter(&printer);
    
        auto page = printer.pageRect(QPrinter::Unit::Millimeter);
        painter.setWindow(page.toRect());
    
        // Draw a 5mm thick ellipse across the whole page.
        painter.setPen(QPen(Qt::black, 5.0));
        painter.drawEllipse(0, 0, 210, 297);
    
        return 0;
    }
    

    如果不查看其余代码,很难判断您的情况出了什么问题

    【讨论】:

    • 您好,当使用您发布的示例代码时,椭圆确实被拉伸到了整个页面,但是在绘制一些文本时,它变得过大。这是代码:pastebin.com/CFDWghKi,这是输出 pdf:g2f.nl/0e905rh
    • 试试 setPixelSize() 代替 setPointSize() 应该没问题。
    • 但这将是一种依赖于设备 (dpi) 的方式。似乎字体没有正确转换。我觉得这很困难,因为这似乎是您在打印时想要做的基本事情。
    • 这是相当令人困惑的东西,有所有新的不同方式来实现 HiDPI 等,但 setPixelSize 对我有用,与文档的 DPI 无关。点大小总是非常依赖于平台。
    【解决方案3】:

    根据官方文档,我认为您正在寻找 QTransform 类:

    QTransform 类指定坐标的二维变换 系统。转换指定如何平移、缩放、剪切、 旋转或投影坐标系,通常用于 渲染图形。

    您可以初始化您的自定义转换类:

    QTransform transform = QTransform::fromScale(painter.device()->physicalDpiX() / scale, painter.device()->physicalDpiY() / scale);
    

    认为这可能会有所帮助,每米的点数:

    const int dot_per_millimeter = qRound(qApp->primaryScreen()->physicalDotsPerInch() / 25.40);
    

    然后自定义您的比例并使用 QPainter 应用它:

    QPainter painter(parent);
    painter.setWorldTransform(transform, false);
    

    【讨论】:

    • 使用 QTransform::fromScale(1.f/painter.device()->physicalDpiX(), 1.f/painter.device()->physicalDpiY());只是让一切都变得非常小。我可以稍后再放大它,但它会是像素级的,因为它是以如此低的分辨率绘制的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    相关资源
    最近更新 更多