简体   繁体   English

为什么增加 devicePixelRatio 会减小我的 QImage 的大小?

[英]Why does increasing the devicePixelRatio decrease the size of my QImage?

The devicePixelRatio is used to translate the device independent pixels into the actual physical pixels on the device. devicePixelRatio 用于将设备独立像素转换为设备上的实际物理像素。 Therefore taking the example from the Qt Summit 2015 if I had a 300 x 200 QWidget with a devicePixelRatio of 2, it will render a 600 x 400 QWidget to the screen.因此,以2015 年 Qt 峰会为例,如果我有一个 300 x 200 QWidget 且 devicePixelRatio 为 2,它将在屏幕上呈现 600 x 400 QWidget。

I have beneath me some code that I created, however I feel as though the opposite behaviour is happening.我在我下面有一些我创建的代码,但是我觉得好像正在发生相反的行为。 When I set self.image.setDevicePixelRatio(2) my QImage actually halves in size, however with a devicePixelRatio of 2, I interpret this as, for each device independent pixel, now occupy 2 pixels on my physical device, therefore doubling the size of my QImage (or atleast doubling when comparing to the before devicePixelRatio value of 1).当我设置self.image.setDevicePixelRatio(2)时,我的QImage实际上大小减半,但是 devicePixelRatio 为 2,我将其解释为,对于每个设备独立像素,现在在我的物理设备上占用 2 个像素,因此大小加倍我的QImage (或与之前的 devicePixelRatio 值 1 相比至少翻倍)。 Could someone explain why it is instead halving the size?有人可以解释为什么它反而将尺寸减半吗?

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QImage, QPainter
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget

DEFAULT_WIDTH = DEFAULT_HEIGHT = 250


class QPainterWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.image = QImage(DEFAULT_WIDTH, DEFAULT_HEIGHT, QImage.Format_RGB32)
        self.image.fill(Qt.green)
        self.image.setDevicePixelRatio(2)
        painter = QPainter(self.image)
        painter.end()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawImage(0, 0, self.image)
        painter.end()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(DEFAULT_WIDTH, DEFAULT_HEIGHT)
        self.setCentralWidget(QPainterWidget())


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

在此处输入图像描述

This is very logical but a bit complicated at the first sight from the library users' perspective.从图书馆用户的角度来看,这是非常合乎逻辑的,但乍一看有点复杂。 And very complicated considering all implementation details in Qt library.考虑到 Qt 库中的所有实现细节,非常复杂。 But you do not need to care about most of the details, fortunately.但幸运的是,您不需要关心大部分细节。

With widgets it is easy: you specify the logical size and the physical size on screen is derived from the logical size multiplied by the application DPR.使用小部件很容易:您指定逻辑大小,屏幕上的物理大小是从逻辑大小乘以应用程序 DPR 得出的。

widget_physical_size_on_screen = widget_logical_size * application_dpr

But with images (and also icons and pixmaps) you need to distinguish between the image physical resolution and the physical size on screen.但是对于图像(以及图标和像素图),您需要区分图像的物理分辨率和屏幕上的物理尺寸 They can differ.它们可以不同。 And you also need to distinguish between the application DPR and the image DPR .并且您还需要区分应用程序 DPR图像 DPR They can also differ.它们也可以不同。 The final physical size on screen is calculated using logical size as an intermediary step.屏幕上的最终物理尺寸是使用逻辑尺寸作为中间步骤计算的。

So with images you first specify the physical resolution in the constructor QImage(width, height) , the parameters width and height represent physical pixels of your image resolution.因此,对于图像,您首先在构造函数QImage(width, height)中指定物理分辨率,参数widthheight表示图像分辨率的物理像素。 Then you can specify image DPR (as you did in your code).然后您可以指定图像 DPR (就像您在代码中所做的那样)。 Then your image logical pixel size is derived from its physical resolution by dividing with the image DPR.然后,您的图像逻辑像素大小是通过除以图像 DPR 从其物理分辨率得出的。 And when the image is displayed in application, it is then resized to physical size by multiplying with the application DPR (not the image DPR).并且当图像在应用程序中显示时,然后通过乘以应用程序 DPR (而不是图像 DPR)将其调整为物理大小

image_logical_size = physical_image_resolution / image_dpr
image_physical_size_on_screen = image_logical_size * application_dpr

Therefore if you display image with physical resolution 600x400 with image DPR 2 (then it has logical size 300x200) in application which has DPR 1, then it will have physical size 300x200 pixels, because in application with DPR 1, one logical pixel translates to one physical pixel on screen.因此,如果您在具有 DPR 1 的应用程序中显示物理分辨率为 600x400 的图像和图像 DPR 2(然后它的逻辑大小为 300x200),那么它将具有 300x200 像素的物理大小,因为在具有 DPR 1 的应用程序中,一个逻辑像素转换为一个屏幕上的物理像素。 This is exactly what hapenned in your case - increasing DPR to 2 leads to smaller image on screen because your application still has DPR 1. Eg image with resolution 600x400 with image DPR 2 appears as 300x200 on screen.这正是您的情况所发生的 - 将 DPR 增加到 2 会导致屏幕上的图像更小,因为您的应用程序仍然具有 DPR 1。例如,分辨率为 600x400 的图像和图像 DPR 2 在屏幕上显示为 300x200。

If you display the same image in application with application DPR 2, then the image will have 600x400 physical pixels.如果您在应用程序中使用应用程序 DPR 2 显示相同的图像,则该图像将具有 600x400 物理像素。 Because in application with DPR 2, one logical pixel translates to 2 physical pixels.因为在使用 DPR 2 的应用程序中,一个逻辑像素转换为 2 个物理像素。 Ie your image will have its original size if and only if your application has the same DPR as is the image DPR.即,当且仅当您的应用程序具有与图像 DPR 相同的 DPR 时,您的图像才会具有其原始大小。

If you display this image in application with DPR 3 (eg if you have really large 8k HighDPI display), then the image will have 900x600 physical pixels.如果您在使用 DPR 3 的应用程序中显示此图像(例如,如果您有非常大的 8k HighDPI 显示器),则该图像将具有 900x600 物理像素。 And it will scale up badly (if you get a closer look on your fancy 8k display, the image will be slightly pixelated) because the original image does not have such a big resolution.而且它的放大率会很差(如果你仔细观察你花哨的 8k 显示器,图像会稍微像素化),因为原始图像没有这么大的分辨率。

Actually setting DPR for images is not strictly needed, you can leave it with default value, which is DPR 1. But then you will need to do some more size recalculations and image resizings yourself.实际上,并不一定需要为图像设置 DPR,您可以将其保留为默认值,即 DPR 1。但是您需要自己进行更多的尺寸重新计算和图像大小调整。 So if you want image with logical pixel size 300x200 then for application with DPR 1 you would need to create image with resolution 300x200, for application with DPR 2 you would need image with resolution 600x400 etc. Otherwise if you display image with physical resolution 300x200 and DPR 1 (ie it has logical size 300x200) in application with DPR 2, the image will be scaled-up to physical size 600x400 but it will be pixelated because the actual physical resolution of the image is still just 300x200.因此,如果您想要逻辑像素大小为 300x200 的图像,那么对于 DPR 1 的应用程序,您需要创建分辨率为 300x200 的图像,对于 DPR 2 的应用程序,您需要分辨率为 600x400 等的图像。否则,如果您显示物理分辨率为 300x200 的图像和DPR 1(即它的逻辑尺寸为 300x200)在使用 DPR 2 的应用程序中,图像将被放大到物理尺寸 600x400 但它会被像素化,因为图像的实际物理分辨率仍然只有 300x200。

So keeping images with DPR 1 can actually save some memory in some cases since you will allocate smaller images, only as big as you really need.因此,在某些情况下,使用 DPR 1 保存图像实际上可以节省一些 memory,因为您将分配较小的图像,仅与您真正需要的一样大。 But the drawback is doing more calculations in code yourself.但缺点是自己在代码中做更多的计算。 It may be tempting to do these calculations yourself at the first sight.乍一看,您可能很想自己进行这些计算。 But I should warn you, in the text above I left out one important detail.但我应该警告你,在上面的文字中,我遗漏了一个重要的细节。 In general case there is not a single application-wide DPR.在一般情况下,没有单个应用程序范围的 DPR。 In multiscreen set up the application can occupy more screens, each with different DPR.在多屏设置中,应用程序可以占用更多屏幕,每个屏幕都有不同的 DPR。 So it is not the application which specifies the DPR but DPR is specified for each widget individually.因此,指定 DPR 的不是应用程序,而是为每个小部件单独指定 DPR。 And widgets can move from screen to screen if you move your window and hence their DPR can change.如果您移动 window,小部件可以在屏幕之间移动,因此它们的 DPR 可以改变。 And believe, then you do not want to recalculate the size of your images yourself in your code.相信,那么您不想在代码中自己重新计算图像的大小。

But if you are 100 % sure you do not want to support multiscreen mixed DPR scenario, then you can leave your images with DPR 1 (the default) and resize your images yourself.但是,如果您 100% 确定不想支持多屏混合 DPR 场景,那么您可以将图像保留为 DPR 1(默认值)并自行调整图像大小。 It can save you save memory and processing power in some cases because you can avoid allocating unneccessarily big images and avoid scaling down if the big resoltion is not needed.在某些情况下,它可以为您节省 memory 和处理能力,因为您可以避免分配不必要的大图像并避免在不需要大分辨率时按比例缩小。 But I would probably not recommend going this way.但我可能不建议这样做。

And one last very important note: always test your application in low-DPI scenarion with DPR == 1 and high-DPI scenario with DPR = 2. And ideally test your application also with fractional DPR, ie when DPR is a floating point number such as 1.25 or 1.5.最后一个非常重要的注意事项:始终在 DPR == 1 的低 DPI 场景和 DPR = 2 的高 DPI 场景中测试您的应用程序。理想情况下,也使用小数 DPR 测试您的应用程序,即当 DPR 是浮点数时为 1.25 或 1.5。 Your application should work well in all these cases.您的应用程序应该在所有这些情况下都能正常工作。 If not, then fix it.如果没有,那么修复它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM