渲染二维码的着色器
Shader to render QR code
在 Qt Quick 应用程序中以图形方式表示 QR 码的最佳方式(从性能和内存消耗的角度来看)是什么?
我认为 QR 码位图可以使用一些着色器以图形方式表示为黑白单元格的方阵。这将是性能最优的解决方案。
目前我只能用一堆Rectangle创建一个GridView。它被认为是浪费内存来存储和 CPU/GPU 渲染时间。
着色器的外观如何?
比如说,给定 QBitArray
大小 n*n
。
如果您的应用程序中只有一个二维码,那么请节省您的时间并创建一个 GridView。
其他选项是:
- C++ 自定义
QQuickItem
:生成并加载纹理 (Qt SceneGraph API)
- C++ 自定义
QQuickFramebufferObject
:生成并加载纹理(主要是纯 OpenGL API)
- C++ 自定义
QQuickPaintedItem
(QPainter 2D API)
- QML-JS Canvas/Context2D (HTML 2D API)
- QML-JS Canvas3D/Context3D:生成并加载纹理 (WebGL API) - 与所有其他 C++ 选项一样,但在 OpenGL 的 JS 版本中
- C++ 自定义
QQuickImageProvider
:生成并加载纹理(ImageProvider 和 OpenGL API),同时将整个 QR 数据作为图像名称传递给您的自定义 QQuickImageProvider
(可能有点太聪明了)
使用 vertex-buffers/uniform-buffers 代替纹理可能有效,但它需要不寻常的着色器代码。我认为 QR 更适合作为纹理。
着色器本身是微不足道的,基本上你将片段位置x和y除以二维码大小和floor得到行和列,然后通过将两者相加找到1d索引,然后查找qt该索引处的数据数组,如果包含0,则片段颜色为白色,如果包含1,则颜色为黑色。
但是,QML 着色器目前不提供传递常规一维数组的工具。
您必须将数组转换为位图图像,并将其传递给数组,这意味着您还必须实现图像提供程序才能使 QImage
与 QML 一起工作,因为令人惊讶的是,默认情况下它仍然没有。
我不会太在意性能,那是过早的优化,在 99% 的情况下都是糟糕的。即使是微不足道的 100% QML 解决方案也足够快:
ApplicationWindow {
id: main
visible: true
width: 640
height: 480
color: "darkgray"
property var qrdata: []
MouseArea {
anchors.fill: parent
onClicked: {
qrdata = []
for (var i = 0; i < (100 * 100); ++i) qrdata.push(Math.round(Math.random()))
code.requestPaint()
}
}
Canvas {
id: code
width: 300
height: 300
onPaint: {
console.time("p")
var c = getContext("2d")
c.fillStyle = Qt.rgba(1, 1, 1, 1);
c.fillRect(0, 0, width, height)
c.fillStyle = Qt.rgba(0, 0, 0, 1);
var l = qrdata.length
var step = Math.sqrt(l)
var size = width / step
for (var i = 0; i < l; ++i) {
if (qrdata[i]) {
var rw = Math.floor(i / step), cl = i % step
c.fillRect(cl * size, rw * size, size, size)
}
}
console.timeEnd("p")
}
}
}
在我的系统上,绘制一个 100 x 100 的二维码大约需要 2 毫秒。 IMO 已经足够好了,不值得花时间来制作更复杂的低级解决方案。
然而,我个人会做的是实现一个 image provider,将二维码数据转换为图像,然后使用 smooth: false
将图像缩放到我想要的大小,这样可以避免模糊和保持清晰的结果。这是迄今为止最直接、最有效、最直接的解决方案。
在 Qt Quick 应用程序中以图形方式表示 QR 码的最佳方式(从性能和内存消耗的角度来看)是什么?
我认为 QR 码位图可以使用一些着色器以图形方式表示为黑白单元格的方阵。这将是性能最优的解决方案。
目前我只能用一堆Rectangle创建一个GridView。它被认为是浪费内存来存储和 CPU/GPU 渲染时间。
着色器的外观如何?
比如说,给定 QBitArray
大小 n*n
。
如果您的应用程序中只有一个二维码,那么请节省您的时间并创建一个 GridView。
其他选项是:
- C++ 自定义
QQuickItem
:生成并加载纹理 (Qt SceneGraph API) - C++ 自定义
QQuickFramebufferObject
:生成并加载纹理(主要是纯 OpenGL API) - C++ 自定义
QQuickPaintedItem
(QPainter 2D API) - QML-JS Canvas/Context2D (HTML 2D API)
- QML-JS Canvas3D/Context3D:生成并加载纹理 (WebGL API) - 与所有其他 C++ 选项一样,但在 OpenGL 的 JS 版本中
- C++ 自定义
QQuickImageProvider
:生成并加载纹理(ImageProvider 和 OpenGL API),同时将整个 QR 数据作为图像名称传递给您的自定义QQuickImageProvider
(可能有点太聪明了)
使用 vertex-buffers/uniform-buffers 代替纹理可能有效,但它需要不寻常的着色器代码。我认为 QR 更适合作为纹理。
着色器本身是微不足道的,基本上你将片段位置x和y除以二维码大小和floor得到行和列,然后通过将两者相加找到1d索引,然后查找qt该索引处的数据数组,如果包含0,则片段颜色为白色,如果包含1,则颜色为黑色。
但是,QML 着色器目前不提供传递常规一维数组的工具。
您必须将数组转换为位图图像,并将其传递给数组,这意味着您还必须实现图像提供程序才能使 QImage
与 QML 一起工作,因为令人惊讶的是,默认情况下它仍然没有。
我不会太在意性能,那是过早的优化,在 99% 的情况下都是糟糕的。即使是微不足道的 100% QML 解决方案也足够快:
ApplicationWindow {
id: main
visible: true
width: 640
height: 480
color: "darkgray"
property var qrdata: []
MouseArea {
anchors.fill: parent
onClicked: {
qrdata = []
for (var i = 0; i < (100 * 100); ++i) qrdata.push(Math.round(Math.random()))
code.requestPaint()
}
}
Canvas {
id: code
width: 300
height: 300
onPaint: {
console.time("p")
var c = getContext("2d")
c.fillStyle = Qt.rgba(1, 1, 1, 1);
c.fillRect(0, 0, width, height)
c.fillStyle = Qt.rgba(0, 0, 0, 1);
var l = qrdata.length
var step = Math.sqrt(l)
var size = width / step
for (var i = 0; i < l; ++i) {
if (qrdata[i]) {
var rw = Math.floor(i / step), cl = i % step
c.fillRect(cl * size, rw * size, size, size)
}
}
console.timeEnd("p")
}
}
}
在我的系统上,绘制一个 100 x 100 的二维码大约需要 2 毫秒。 IMO 已经足够好了,不值得花时间来制作更复杂的低级解决方案。
然而,我个人会做的是实现一个 image provider,将二维码数据转换为图像,然后使用 smooth: false
将图像缩放到我想要的大小,这样可以避免模糊和保持清晰的结果。这是迄今为止最直接、最有效、最直接的解决方案。