Qt ,mac osx ios x11 高清屏,视网膜的支持

Qt 5.0中添加了对于retina显示的基本支持。即将到来的Qt 5.1中提供了新的API和缺陷修复,对于这一问题进行了改进。Qt 4.8也获得了良好的支持,我们反向移植了一些Qt 5的补丁。

尽管这些实现的努力和Mac以及iOS程序员最为相关,但是来看一看其它平台是如何处理高DPI显示这一问题,也是很有趣的。这里主要有两种方式:

  • 基于DPI缩放——Win32 GDIKDE。在这种方式中,应用程序在全物理设备分辨率下工作,使用系统提供的一个DPI设定或者缩放因子,用于缩放布局。字体通常会被操作系统自动缩放(只要您使用点数(point)而不是像素(pixel)来指定字体大小)
  • 另一种意义的像素。在这种方式中,应用程序并不知道物理解析度(在任何程度上)。物理像素被逻辑像素替代:
平台/API 逻辑的 物理的
HTML CSS像素 设备像素
Apple 像素
Android 密度无关像素(dp) (屏幕)像素
Direct2D 设备无关像素(DIP) 物理像素
Qt(过去) 像素 像素
Qt(现在) 设备无关像素 设备像素

在历史上,Qt已经支持基于DPI缩放的物理像素这一方式。在2009年时,对于Windows上的高DPI值的支持已经有所改进。Qt布局对于增加的DPI并没有考虑。现在Qt 5添加了对于“新增像素”这一缩放类型的支持。

(还有其它的高DPI实现么?欢迎大家在评论中进行指正。)

Mac OS X的高DPI支持

OS X上高DPI模式的关键是,以前绝大多数几何信息都是通过物理像素给定的,现在却是设备无关点。这包括桌面几何信息(例如15英寸的Retina MacBook Pro是1440x900而不是全分辨率2880×1800)、窗口几何信息和事件坐标。CoreGraphics绘制引擎知道全分辨率并且针对这一解析度生成输出。例如,对于普通屏幕和高DPI屏幕(其它参数都相同的情况下),一个100x100的窗口在屏幕上占用的区域是一样的。在高DPI屏幕的窗口后端存储包含了200x200像素。

这种模式的主要收益是向后兼容性以及自由的高DPI矢量图形。对于底层情况不了解的应用程序可以简单地像以前一样工作在相同的几何情况下,并且保留写死的像素值。同时,他们还可以使用如文本这样的矢量图形,而不用做任何修改。光栅图形引擎不能获得自动改进,但这是可以实现的。不好的一点是在代码中使用点和像素的时候,有不可避免的坐标系统混淆。

点到像素的缩放因子总是2x。在改变屏幕分辨率的时候,这一情况也是真的——点和像素总是被一个值同时缩放。当使用“More Space”进行缩放的时候,应用程序将会被渲染到一个大的后端存储,这个后端存储会被再缩小到物理屏幕解析度上。

在Mac OS上缩放用户界面解析度

如果您手里没有Retina硬件,在使用外部显示器的时候,有一种仿真模式还是很有用的。打开显示器(Displays)属性并且选择一种HiDPI模式。(如果没有,请查看stackoverflow上的这个问题。)

为OS X应用程序启用高DPI

高DPI模式是通过Info.Plist文件中的这些键值控制的:

<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>

qmake将会为您添加这些内容。(严格意义上说,它将会只添加NSPrincipalClass,NSHighResolutionCapable是可选的并且默认值为true)。

如果NSHighResolutionCapable被设置为false,或者缺少这些键值,那么应用程序将会被按“普通”解析度渲染然后放大。这样的结果看起来很糟糕并且应该避免,特别是因为高DPI模式是非常向后兼容的,并且应用程序可以获得很多高DPI支持而不用做任何修改。

缩放的Qt Creator

高DPI的Qt Creator

(除了一个更新“模式”图标的补丁之外,没有其它修改了。)

Qt的实现细节

Mac OS 10.8(10.7是非正式的?)添加了对高DPI的Retina显示的支持。Qt 4免费获得这一支持,因为它使用的是CoreGraphics绘制引擎。

Qt 5使用的是光栅绘制引擎并且Qt通过缩放绘图器变换(transform)实现了高DPI矢量的绘制。HITheme同时为Qt 4和5提供了高DPI的Mac风格。在Qt 5的Fusion风格中,对于高DPI模式的支持也已经修改好了。

OpenGL是一种基于设备像素的API并且对于高DPI模式也仍然如此。在NSView中有一个flag可以用来开启或者禁用2x缩放——Qt在所有情况下都可以设置它。Shaders运行在设备像素中。

Qt Quick 1是构建于QGraphicsView之上的,它是一个QWidget并且通过QPainter获得对于高DPI的支持。

Qt Quick 2是基于Scene Graph(和OpenGL),已经更新了高DPI的支持。Qt Quick控件(也就是以前的Desktop Component)也已经更新了在高DPI模式下的渲染,其中包括距离场(distance field)文本渲染。(译者注:关于距离场,可以参考Yoann Lopes – Text Rendering in the QML Scene Graph以及iKDE上的译文。)

这里的卖点是应用程序开发人员不需要关心这些,您只需要在设备无关像素的空间里舒适地开发,Qt和/或OS会为您处理那些复杂的事情。但有一个例外,光栅内容(raster content)——需要提供高DPI光栅内容,并且应用程序代码需要正确处理这些内容。

窗口部件和绘图器

QPainter代码绝大多数情况下都和原来一样。我们来看看绘制渐变(gradient)的代码:

QRect destinationRect = ...
QGradient gradient = ...
painter.fillRect(rect, QBrush(gradient));

在高DPI显示器上,这个渐变在屏幕上的大小还是一样的,但是被填充了更多的(设备)像素。

绘制一个像素映射(pixmap)也是类似的:

QRect destinationRect = ...
QPixmap pixmap = ...
painter.drawPixmap(destinationRect, pixmap);

为了避免在高DPI显示器上出现缩放失真,像素映射必须包含足够的像素:两倍于destinationRect的宽和高。应用程序可以直接提供它们,也可以使用QIcon来管理不同的解析度:

QRect destinationRect = ...
QIcon icon = ...
painter.drawPixmap(destinationRect, icon.pixmap(destinationRect.size()));

QIcon::pixmap()已经被修改了,可以在高DPI系统中返回一个更大的像素映射。这种行为的改变会破坏现有的代码,所以它是由AA_UseHighDpiPixmaps这个应用程序属性来控制的:

qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);

在Qt 5.1中这个属性默认值是关闭的,但在未来的Qt发布中它很有可能默认为打开。

极端情况和devicePixelRatio

Qt的窗口部件有一些极端情况。在理想情况下,它一直使用QIcon,并且在绘制的时候会使用正确的像素映射,但是实际情况是Qt API经常直接生成和使用像素映射。当像素映射的大小被用来计算布局的几何信息时,会发生错误——如果一个像素映射已经是高分辨率的,那么在屏幕上它就不应该再占用更多的空间。

通过使用QPixmap::devicePixelRatio(),就能让200x200的像素映射实际占据100x100的设备无关像素。由QIcon::pixmap()返回的像素映射中devicePixelRatio已经设置好了。

例如QLabel就是一个“像素映射消费者”:

QPixmap pixmap2x = ...
pixmap2x.setDevicePixelRatio(2.0);
QLabel *label = ...
label->setPixmap(pixmap2x);

然后QLabel会除以devicePixelRatio来获得布局的大小:

QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();

与此类似的几种情况在Qt中都已经修复,并且应用程序代码在启用AA_UseHighDpiPixmaps之前也需要做类似处理。

下面几个Qt类中都提供了devicePixelRatio()的读写函数:

注释
QWindow::devicePixelRatio() 推荐使用的读写函数
QScreen::devicePixelRatio()
QGuiApplication::devicePixelRatio() 如果没有QWindow指针,请使用这个
QImage::[set]devicePixelRatio()
QPixmap::[set]devicePixelRatio()

文本

字体大小还可以和原来一样,会在高DPI显示中产生类似的大小(但会有一点小问题)。字体的像素大小是设备无关的像素大小。您在高DPI显示中永远不会得到太小的文本。

QGLWidget

OpenGL是在设备像素空间中工作的。例如,传递给glViewport的宽和高应该是设备像素。QGLWidget::resizeGL()中的宽和高也是设备像素的。

不管怎样,QGLWidget::width()实际上就是QWidget::width(),它返回的是设备无关像素的值。如果需要,用它来乘以widget->windowHandle()->devicePixelRatio()可以解决很多问题。

Qt Quick 2和控件

Qt Quick 2和Qt Quick控件可以直接使用。因为窗口部件的坐标是设备无关像素的。Qt Quick也有几个和光栅相关的极端情况,因为QML的Image元素是通过URL来指定图像源的,这样就避免了像素映射的传递。

Qt Quick控件

还有一个例外是OpenGL着色器(shader),它运行在设备像素空间中并且可以看到全分辨率。在通常情况下这没有什么问题,我们应该知道的一件重要的事情是,鼠标坐标是设备无关像素的,也许需要被转换成设备像素。

运行中的着色器效果实例

管理高解析度的光栅内容

正如我们所看到的,在缩放的情况下,光栅内容看起来会不够好,所以必须提供高解析度的内容。作为应用程序开发人员,您有两个选项:(请忽略“什么都不做”选项)

  • 使用高解析度版本替换现有光栅内容
  • 另外提供一份高解析度内容

第一个选项很简单,因为每个资源只有一个版本。可是您也许会发现(或者您的设计师会告诉您)像图标这样的资源只有在它被创建的那个特定解析度下看起来才最好。为了解决这个问题,Qt沿用了“@2x”这种图像文件名的方案:

foo.png
[email protected]

这样高解析度的内容和原来的一一对应。在需要的时候,“@2x”的版本会被QML的Image元素以及QIcon自动加载。

Image { source = “foo.png” }
QIcon icon(“foo.png”)

(对于QIcon请记住使用AA_UseHighDpiPixmaps)

试验性的跨平台的高解析度支持

QPA允许我们相对容易的完成跨平台的实现。Qt现在把这一问题分为三层:

  • 应用程序层(应用程序代码和使用QPA类的Qt代码)
  • QPA层(QWindow、QScreen、QBackingStore)
  • 平台插件层(QPlatform*子类)

简化一下,应用程序层是在设备无关像素空间中工作的,并不知道设备像素。平台插件是在设备像素空间中工作的,并不知道设备无关像素。QPA层在两者之间,基于一个由环境变量QT_HIGHDPI_SCALE_FACTOR指定的缩放因子进行转换。

实际上,这个情况还会更复杂一些,各层之间会有泄露的事情发生,并且在Mac和iOS下还会有一些例外情况。

代码在github上。最后是XCB下的Qt Creator的截屏:

DPI缩放的Qt Creator

Qt ,mac osx ios x11 高清屏,视网膜的支持

时间: 2024-10-12 12:13:39

Qt ,mac osx ios x11 高清屏,视网膜的支持的相关文章

Cocos2D iOS之旅:如何写一个敲地鼠游戏(一):高清屏显示和UIKit

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流之用,请勿进行商业用途.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作! 原文由Ray Wunderlich写成,地址在: http://www.raywenderlich.com/2560/cocos2d-tutorial-for-ios-how

移动端,多屏幕尺寸高清屏retina屏适配的解决方案

移动端高清.多屏适配方案 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页面高清的效果,视觉稿的规范往往会遵循以下两点: 首先,选取一款手机的屏幕宽高作为基准(以前是iphone4的320×480,现在更多的是iphone6的375×667). 对于retina屏幕(如: dpr=2),为了达到高清效果,视觉稿的画布大小会是基准的2倍,也就是说像素点个数是原来的4倍(对i

移动端高清屏适配方案

结论: 用户体验要求很高的页面,如UV较高的页面,活动页这些应该以用户体验优先,应用flexiable方案 在其它页面,固定视口,不缩放,使用rem做布局适配,js添加屏幕标识以便调整字体大小(即布局使用rem,字体使用百分比),使用@2x图片,只做ios8+的1px处理 面临的问题: 在不同大小和高清的屏幕下: 如何保证 界面布局 一致性:不错乱,不变形 如何保证 字体大小 一致性:大屏显示更大,小屏显示更小或更多 如何保证 1px边框 一致性:不同的高清屏也在正常显示1px的高度大小 如何保

高清屏及适配不同设备的方案总结

关于一些Retina,设备像素,移动适配的知识,网上一搜也是一大把,但是基本的东西并没有变化太多.下面就我看过的一些有关于这方面的知识做一些总结(仅以个人的角度出发,所以有不全的地方还请大家谅解).后面会有不定期的更新~每个知识点我都会在开关写出引用地址,所以大家有不懂的可以看原文章~ 一.关于设备像素比(devicePixelRatio) 出处:高清屏概念解析与检测设备像素比的方法 所谓设备像素比(devicePixelRatio)指的就是设备上物理像素和设备独立像素(device-indep

【转】解决 canvas 在高清屏中绘制模糊的问题

来源: http://www.css88.com/archives/9297 使用 canvas 绘制图片或者是文字在 Retina 屏中会非常模糊.如图: 因为 canvas 不是矢量图,而是像图片一样是位图模式的.高 dpi 显示设备意味着每平方英寸有更多的像素.也就是说二倍屏,浏览器就会以2个像素点的宽度来渲染一个像素,该 canvas 在 Retina 屏幕下相当于占据了2倍的空间,相当于图片被放大了一倍,因此绘制出来的图片文字等会变模糊. 因此,要做 Retina 屏适配,关键是知道当

高清屏下canvas重置尺寸引发的问题

我们知道,清空canvas画布内容有以下两个方法. 第一种方法是cearRect函数: context.cearRect(0,0,canvas.width,canvas.height) 第二种方法就是用原值重新设置一下canvas的宽(或者高) canvas.width = canvas.width // or canvas.height = canvas.height 第二种方法可以起作用,是因为canvas的一个特点: 每当画布的高度或宽度被重设时,画布内容就会被清空.相关内容可以参考htt

Mac OSX 下的快捷锁屏畅想曲

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 熟练使用 Windows 后,很容易就能想到 Win + L 刷屏,拿鼠标能干的活都是细致活,键盘虽然粗犷,确快捷得很. 那么 Mac 系统下,首

iOS 超大高清图展示策略 TileLayer 及 levelsOfDetailBias 分析

本次分析针对当下流行的中国地图图片处理,1亿像素,就是下面这张: 原图尺寸:11935x8554 文件大小:22.1MB 原始加载方式 首先,我们尝试一下直接加载的方式,看看效果会有多恐怖 效果请看下面的Gif动画展示: 直接加载原图内存占用 可以看到加载时内存的瞬间峰值达到了481M,毫无疑问,内存暴增,直接崩溃(视机型而定,好一点的机器比如iphone7可以正常展示~) 代码很简单,一个UIImageView,直接设置image: dispatch_async(dispatch_get_gl

[Tools] Kali Linux 高清屏扩大系统字体、软件字体

系统检索 Setting Manager,Appearance -> Settings,选择 Window Scaling:2x Terminal fonts: linux terminal 快捷键与 item2 的区别: item2 的轴心键是 command,linux terminal 的是 ctrl + shift. 所以打开新 tab,在 mac 上是 command + t, 在 linux 上是 ctrl + shift + t Software fonts,比如 BurpSuit