渲染二维码的着色器

Posted

技术标签:

【中文标题】渲染二维码的着色器【英文标题】:Shader to render QR code 【发布时间】:2017-09-04 07:12:53 【问题描述】:

Qt Quick 应用程序中以图形方式表示 QR 码的最佳(就性能和内存消耗而言)方法是什么?

我认为 QR 码位图可以使用一些着色器以图形方式表示为黑白单元格的方阵。这将是性能最佳的解决方案。

目前我只能用一堆矩形创建一个GridView。这被认为是浪费内存来存储和 CPU/GPU 时间来渲染。

着色器的外观如何?

说,给定 QBitArrayn*n 大小。

【问题讨论】:

【参考方案1】:

着色器本身是微不足道的,基本上你将片段位置 x 和 y 除以 qr 代码大小和得到行和列的地板,然后通过将两者相加找到 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 将图像缩放到我想要的任意大小,这将避免模糊并保持清晰的结果。这是迄今为止最直接、最有效和最直接的解决方案。

【讨论】:

是否可以生成非光栅图像?比如说,SVG xml? @Orient - 没有意义,因为 SVG 仍然被光栅化以呈现特定大小。 SVG QR 码将比位图占用更多空间。如果禁用平滑,位图将无限放大。【参考方案2】:

如果您的应用程序中只有一个 QR 码,那么请节省您的时间并使用 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++ 选项一样,但在 JS 版本的 OpenGL 中 C++ 自定义 QQuickImageProvider:生成并加载纹理(ImageProvider 和 OpenGL API),同时将整个 QR 数据作为图像名称传递给您的自定义 QQuickImageProvider(可能有点太聪明了)

使用 vertex-buffers/uniform-b​​uffers 代替纹理可能有效,但它需要一个不寻常的着色器代码。我认为 QR 更适合作为纹理。

【讨论】:

相反,着色器实际上将是一个非常普通和琐碎的着色器。

以上是关于渲染二维码的着色器的主要内容,如果未能解决你的问题,请参考以下文章

《Unity Shader入门精要》读书笔记

着色器的简单理解

HLSL效果框架-多光源效果

渲染管道光栅阶段一“总览”

渲染管道光栅阶段一“总览”

oc渲染器提示着色器失败