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

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

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

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

着色器的外观如何?

说,给定 QBitArrayn*n 大小。

【问题讨论】:

    标签: qt shader opengl-es-2.0 qr-code qtquick2


    【解决方案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 更适合作为纹理。

    【讨论】:

    • 相反,着色器实际上将是一个非常普通和琐碎的着色器。
    猜你喜欢
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    相关资源
    最近更新 更多