ZXingQt6CamReader.qml 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright 2022 Axel Waggershauser
  3. */
  4. // SPDX-License-Identifier: Apache-2.0
  5. import QtQuick
  6. import QtQuick.Window
  7. import QtQuick.Controls
  8. import QtQuick.Layouts
  9. import QtQuick.Shapes
  10. import QtMultimedia
  11. import ZXing
  12. Window {
  13. visible: true
  14. width: 640
  15. height: 480
  16. title: Qt.application.name
  17. property var nullPoints: [Qt.point(0,0), Qt.point(0,0), Qt.point(0,0), Qt.point(0,0)]
  18. property var points: nullPoints
  19. Timer {
  20. id: resetInfo
  21. interval: 1000
  22. }
  23. BarcodeReader {
  24. id: barcodeReader
  25. videoSink: videoOutput.videoSink
  26. formats: (linearSwitch.checked ? (ZXing.LinearCodes) : ZXing.None) | (matrixSwitch.checked ? (ZXing.MatrixCodes) : ZXing.None)
  27. tryRotate: tryRotateSwitch.checked
  28. tryHarder: tryHarderSwitch.checked
  29. tryInvert: tryInvertSwitch.checked
  30. tryDownscale: tryDownscaleSwitch.checked
  31. textMode: ZXing.TextMode.HRI
  32. // callback with parameter 'barcode', called for every successfully processed frame
  33. onFoundBarcode: (barcode)=> {
  34. points = [barcode.position.topLeft, barcode.position.topRight, barcode.position.bottomRight, barcode.position.bottomLeft]
  35. info.text = qsTr("Format: \t %1 \nText: \t %2 \nType: \t %3 \nTime: \t %4 ms").arg(barcode.formatName).arg(barcode.text).arg(barcode.contentTypeName).arg(runTime)
  36. resetInfo.restart()
  37. // console.log(barcode)
  38. }
  39. // called for every processed frame where no barcode was detected
  40. onFailedRead: ()=> {
  41. points = nullPoints
  42. if (!resetInfo.running)
  43. info.text = "No barcode found (in %1 ms)".arg(runTime)
  44. }
  45. }
  46. MediaDevices {
  47. id: devices
  48. }
  49. Camera {
  50. id: camera
  51. cameraDevice: devices.videoInputs[camerasComboBox.currentIndex] ? devices.videoInputs[camerasComboBox.currentIndex] : devices.defaultVideoInput
  52. focusMode: Camera.FocusModeAutoNear
  53. onErrorOccurred: console.log("camera error:" + errorString)
  54. active: true
  55. }
  56. CaptureSession {
  57. id: captureSession
  58. camera: camera
  59. videoOutput: videoOutput
  60. }
  61. ColumnLayout {
  62. anchors.fill: parent
  63. RowLayout {
  64. Layout.fillWidth: true
  65. Layout.fillHeight: false
  66. visible: devices.videoInputs.length > 1
  67. Label {
  68. text: qsTr("Camera: ")
  69. Layout.fillWidth: false
  70. }
  71. ComboBox {
  72. id: camerasComboBox
  73. Layout.fillWidth: true
  74. model: devices.videoInputs
  75. textRole: "description"
  76. currentIndex: 0
  77. }
  78. }
  79. VideoOutput {
  80. id: videoOutput
  81. Layout.fillHeight: true
  82. Layout.fillWidth: true
  83. function mapPointToItem(point)
  84. {
  85. if (videoOutput.sourceRect.width === 0 || videoOutput.sourceRect.height === 0)
  86. return Qt.point(0, 0);
  87. let dx = point.x;
  88. let dy = point.y;
  89. if ((videoOutput.orientation % 180) == 0)
  90. {
  91. dx = dx * videoOutput.contentRect.width / videoOutput.sourceRect.width;
  92. dy = dy * videoOutput.contentRect.height / videoOutput.sourceRect.height;
  93. }
  94. else
  95. {
  96. dx = dx * videoOutput.contentRect.height / videoOutput.sourceRect.height;
  97. dy = dx * videoOutput.contentRect.width / videoOutput.sourceRect.width;
  98. }
  99. switch ((videoOutput.orientation + 360) % 360)
  100. {
  101. case 0:
  102. default:
  103. return Qt.point(videoOutput.contentRect.x + dx, videoOutput.contentRect.y + dy);
  104. case 90:
  105. return Qt.point(videoOutput.contentRect.x + dy, videoOutput.contentRect.y + videoOutput.contentRect.height - dx);
  106. case 180:
  107. return Qt.point(videoOutput.contentRect.x + videoOutput.contentRect.width - dx, videoOutput.contentRect.y + videoOutput.contentRect.height -dy);
  108. case 270:
  109. return Qt.point(videoOutput.contentRect.x + videoOutput.contentRect.width - dy, videoOutput.contentRect.y + dx);
  110. }
  111. }
  112. Shape {
  113. id: polygon
  114. anchors.fill: parent
  115. visible: points.length === 4
  116. ShapePath {
  117. strokeWidth: 3
  118. strokeColor: "red"
  119. strokeStyle: ShapePath.SolidLine
  120. fillColor: "transparent"
  121. //TODO: really? I don't know qml...
  122. startX: videoOutput.mapPointToItem(points[3]).x
  123. startY: videoOutput.mapPointToItem(points[3]).y
  124. PathLine {
  125. x: videoOutput.mapPointToItem(points[0]).x
  126. y: videoOutput.mapPointToItem(points[0]).y
  127. }
  128. PathLine {
  129. x: videoOutput.mapPointToItem(points[1]).x
  130. y: videoOutput.mapPointToItem(points[1]).y
  131. }
  132. PathLine {
  133. x: videoOutput.mapPointToItem(points[2]).x
  134. y: videoOutput.mapPointToItem(points[2]).y
  135. }
  136. PathLine {
  137. x: videoOutput.mapPointToItem(points[3]).x
  138. y: videoOutput.mapPointToItem(points[3]).y
  139. }
  140. }
  141. }
  142. Label {
  143. id: info
  144. color: "white"
  145. padding: 10
  146. background: Rectangle { color: "#80808080" }
  147. }
  148. ColumnLayout {
  149. anchors.right: parent.right
  150. anchors.bottom: parent.bottom
  151. Switch {id: tryRotateSwitch; text: qsTr("Try Rotate"); checked: true }
  152. Switch {id: tryHarderSwitch; text: qsTr("Try Harder"); checked: true }
  153. Switch {id: tryInvertSwitch; text: qsTr("Try Invert"); checked: true }
  154. Switch {id: tryDownscaleSwitch; text: qsTr("Try Downscale"); checked: true }
  155. Switch {id: linearSwitch; text: qsTr("Linear Codes"); checked: true }
  156. Switch {id: matrixSwitch; text: qsTr("Matrix Codes"); checked: true }
  157. }
  158. }
  159. }
  160. }