diff --git a/harbour-barcode.pro b/harbour-barcode.pro index d64a5af..53ff8e5 100644 --- a/harbour-barcode.pro +++ b/harbour-barcode.pro @@ -115,6 +115,7 @@ HARBOUR_QML_COMPONENTS = \ $${HARBOUR_LIB_QML}/HarbourHighlightIcon.qml \ $${HARBOUR_LIB_QML}/HarbourHintIconButton.qml \ $${HARBOUR_LIB_QML}/HarbourHorizontalSwipeHint.qml \ + $${HARBOUR_LIB_QML}/HarbourInvertEffect.qml \ $${HARBOUR_LIB_QML}/HarbourPressEffect.qml OTHER_FILES += $${HARBOUR_QML_COMPONENTS} diff --git a/harbour-lib b/harbour-lib index 323fc6b..070dc9e 160000 --- a/harbour-lib +++ b/harbour-lib @@ -1 +1 @@ -Subproject commit 323fc6b6c98f85265e55425c22d617991178cc44 +Subproject commit 070dc9ede17b99ca748ac414a0256f2d96be2a77 diff --git a/qml/components/GalleryImage.qml b/qml/components/GalleryImage.qml index 185e447..24920c5 100644 --- a/qml/components/GalleryImage.qml +++ b/qml/components/GalleryImage.qml @@ -1,7 +1,7 @@ /* The MIT License (MIT) -Copyright (c) 2020-2021 Slava Monich +Copyright (c) 2020-2022 Slava Monich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,8 @@ THE SOFTWARE. import QtQuick 2.0 import Sailfish.Silica 1.0 +import "../harbour" + SilicaFlickable { id: galleryImage @@ -33,6 +35,7 @@ SilicaFlickable { property real orientation property bool isLandscape property alias source: image.source + property bool invert readonly property real minZoomX: (implicitWidth > width) ? width/implicitWidth : 0.1 readonly property real minZoomY: (implicitHeight > height) ? height/implicitHeight : 0.1 @@ -105,6 +108,11 @@ SilicaFlickable { readonly property real xSize: d * Math.max(Math.abs(Math.cos(r - a)), Math.abs(Math.cos(r + a))) readonly property real ySize: d * Math.max(Math.abs(Math.sin(r - a)), Math.abs(Math.sin(r + a))) + layer.enabled: invert + layer.effect: HarbourInvertEffect { + source: image + } + anchors.centerIn: parent scale: actualZoom smooth: true diff --git a/qml/components/ViewFinder.qml b/qml/components/ViewFinder.qml index bbafc87..cdf6114 100644 --- a/qml/components/ViewFinder.qml +++ b/qml/components/ViewFinder.qml @@ -2,21 +2,21 @@ import QtQuick 2.0 import QtMultimedia 5.4 import Sailfish.Silica 1.0 +import "../harbour" + VideoOutput { id: viewFinder - layer.enabled: true anchors.fill: parent fillMode: VideoOutput.Stretch property alias beepSource: beep.source property size viewfinderResolution - property bool completed property bool showFocusArea: true property real digitalZoom: 1.0 + property bool invert readonly property bool cameraActive: camera.cameraState === Camera.ActiveState - readonly property bool tapFocusActive: focusTimer.running readonly property bool flashOn: camera.flash.mode !== Camera.FlashOff // Not sure why not just camera.orientation but this makes the camera // behave similar to what it does for Jolla Camera @@ -26,6 +26,15 @@ VideoOutput { // Camera.ActiveStatus and doesn't emit maximumDigitalZoomChanged signal signal maximumDigitalZoom(var value) + // Internal properties + readonly property bool _tapFocusActive: focusTimer.running + property bool _completed + + layer.enabled: invert + layer.effect: HarbourInvertEffect { + source: viewFinder + } + onOrientationChanged: { if (camera.cameraState !== Camera.UnloadedState) { reloadTimer.restart() @@ -52,7 +61,7 @@ VideoOutput { if (viewfinderResolution) { camera.viewfinder.resolution = viewfinderResolution } - completed = true + _completed = true } function turnFlashOn() { @@ -131,15 +140,15 @@ VideoOutput { imageProcessing.whiteBalanceMode: flashOn ? CameraImageProcessing.WhiteBalanceFlash : CameraImageProcessing.WhiteBalanceTungsten - cameraState: (completed && !reloadTimer.running) ? + cameraState: (_completed && !reloadTimer.running) ? Camera.ActiveState : Camera.UnloadedState exposure { exposureCompensation: 1.0 exposureMode: Camera.ExposureAuto } focus { - focusMode: tapFocusActive ? Camera.FocusAuto : Camera.FocusContinuous - focusPointMode: tapFocusActive ? Camera.FocusPointCustom : Camera.FocusPointAuto + focusMode: _tapFocusActive ? Camera.FocusAuto : Camera.FocusContinuous + focusPointMode: _tapFocusActive ? Camera.FocusPointCustom : Camera.FocusPointAuto } onCameraStatusChanged: { if (cameraStatus === Camera.ActiveStatus) { diff --git a/qml/pages/ScanPage.qml b/qml/pages/ScanPage.qml index 6e166a1..b7edad9 100644 --- a/qml/pages/ScanPage.qml +++ b/qml/pages/ScanPage.qml @@ -34,27 +34,30 @@ import "../components" import "../harbour" Page { - id: scanPage + id: thisPage allowedOrientations: window.allowedOrientations + property bool autoScan + readonly property bool cameraActive: viewFinder && viewFinder.cameraActive + + // Internal properties property Item galleryImage property Item viewFinder property Item hint - property bool showMarker - property bool autoScan - property int scanTimeout: 60 + property bool showMarker + readonly property bool mustShowViewFinder: (thisPage.status === PageStatus.Active) && Qt.application.active && !scanningGalleryImage && !showMarker readonly property bool hintActive: hint && hint.visible - readonly property bool cameraActive: viewFinder && viewFinder.cameraActive readonly property bool landscapeLayout: width > height - readonly property bool mustShowViewFinder: (scanPage.status === PageStatus.Active) && Qt.application.active && !scanningGalleryImage && !showMarker readonly property bool scanningGalleryImage: galleryImage && galleryImage.visible - readonly property bool useVolumeKeys: AppSettings.volumeZoom && (scanPage.status === PageStatus.Active) && Qt.application.active + readonly property bool useVolumeKeys: AppSettings.volumeZoom && (thisPage.status === PageStatus.Active) && Qt.application.active + readonly property int toolIconFadeDuration: 64 + readonly property int scanTimeout: 60 - readonly property var volumeUp: Qt.createQmlObject(BarcodeUtils.mediaKeyQml, scanPage, "VolumeKey") - readonly property var volumeDown: Qt.createQmlObject(BarcodeUtils.mediaKeyQml, scanPage, "VolumeKey") - readonly property var permissions: Qt.createQmlObject(BarcodeUtils.permissionsQml, scanPage, "Permissions") + readonly property var volumeUp: Qt.createQmlObject(BarcodeUtils.mediaKeyQml, thisPage, "VolumeKey") + readonly property var volumeDown: Qt.createQmlObject(BarcodeUtils.mediaKeyQml, thisPage, "VolumeKey") + readonly property var permissions: Qt.createQmlObject(BarcodeUtils.permissionsQml, thisPage, "Permissions") Binding { target: permissions; property: "enabled"; value: useVolumeKeys } Binding { target: volumeUp; property: "enabled"; value: useVolumeKeys } @@ -173,7 +176,7 @@ Page { function showHint(text) { if (!hint) { - hint = hintComponent.createObject(scanPage) + hint = hintComponent.createObject(thisPage) } hint.text = text hint.opacity = 1.0 @@ -215,7 +218,7 @@ Page { } onStatusChanged: { - if (scanPage.status === PageStatus.Inactive) { + if (thisPage.status === PageStatus.Inactive) { console.log("Page is INACTIVE") // stop scanning if page is not active destroyScanner() @@ -267,6 +270,7 @@ Page { markerColor: AppSettings.markerColor rotation: orientationAngle() canGrab: (!galleryImage || !galleryImage.moving) && !galleryScanTimer.running + inverted: invertButton.down decodingHints: AppSettings.decodingHints onDecodingFinished: { @@ -274,7 +278,7 @@ Page { statusText.text = "" applyResult(image, result) if (AppSettings.resultViewDuration > 0) { - scanPage.showMarker = true + thisPage.showMarker = true resultViewTimer.restart() } if (buzzLoader.item) { @@ -318,7 +322,7 @@ Page { id: resultViewTimer interval: AppSettings.resultViewDuration * 1000 - onTriggered: scanPage.showMarker = false + onTriggered: thisPage.showMarker = false } Component { @@ -336,7 +340,7 @@ Page { GalleryImage { visible: false - isLandscape: scanPage.isLandscape + isLandscape: thisPage.isLandscape z: 1 } } @@ -345,6 +349,7 @@ Page { id: scanPageFlickable anchors.fill: parent + interactive: !(invertButton.visible && invertButton.down) PullDownMenu { enabled: scanner.idle && !hintActive @@ -366,7 +371,7 @@ Page { //: Page header //% "Select image" title: qsTrId("gallery-title"), - allowedOrientations: scanPage.allowedOrientations + allowedOrientations: thisPage.allowedOrientations }) var imageUrl, imageOrientation picker.imageSelected.connect(function(url, orientation) { @@ -493,8 +498,8 @@ Page { readonly property int landscapeHeight: Math.floor((parent.width/parent.height > ratio) ? parent.height : (parent.width / ratio)) anchors.centerIn: parent - width: scanningGalleryImage ? parent.width : (scanPage.isPortrait ? portraitWidth : landscapeWidth) - height: scanningGalleryImage ? parent.height : (scanPage.isPortrait ? portraitHeight : landscapeHeight) + width: scanningGalleryImage ? parent.width : (thisPage.isPortrait ? portraitWidth : landscapeWidth) + height: scanningGalleryImage ? parent.height : (thisPage.isPortrait ? portraitHeight : landscapeHeight) color: "#20000000" opacity: markerImage.visible ? 0 : 1 Behavior on opacity { FadeAnimation { } } @@ -520,7 +525,7 @@ Page { anchors.centerIn: viewFinderContainer z: 2 - source: scanPage.showMarker ? markerImageProvider.source : "" + source: thisPage.showMarker ? markerImageProvider.source : "" visible: status === Image.Ready cache: false } @@ -547,7 +552,7 @@ Page { } opacity: (TorchSupported && !scanningGalleryImage) ? 1.0 : 0.0 visible: TorchSupported && opacity > 0.0 - Behavior on opacity { FadeAnimation { } } + Behavior on opacity { FadeAnimation { duration: toolIconFadeDuration } } icon.source: viewFinder && viewFinder.flashOn ? Qt.resolvedUrl("img/flash-on.svg") : Qt.resolvedUrl("img/flash-off.svg") @@ -555,8 +560,8 @@ Page { //: Hint label //% "Toggle flashlight" hint: qsTrId("hint-toggle-flash") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() } Slider { @@ -632,6 +637,7 @@ Page { readonly property url icon_16_9: Qt.resolvedUrl("img/resolution_16_9.svg") readonly property url icon_4_3: Qt.resolvedUrl("img/resolution_4_3.svg") + readonly property bool isNeeded: viewFinderContainer.canSwitchResolutions && scanner.scanState !== BarcodeScanner.Scanning anchors { right: parent.right verticalCenter: parent.verticalCenter @@ -641,9 +647,9 @@ Page { sourceSize: Qt.size(Theme.iconSizeMedium, Theme.iconSizeMedium) rotation: isLandscape ? 90 : 0 } - opacity: (scanningGalleryImage || !viewFinderContainer.canSwitchResolutions)? 0.0 : 1.0 + opacity: isNeeded ? 1.0 : 0.0 visible: opacity > 0.0 - Behavior on opacity { FadeAnimation { } } + Behavior on opacity { FadeAnimation { duration: toolIconFadeDuration } } onClicked: AppSettings.wideMode = !AppSettings.wideMode hint: isLandscape ? //: Hint label @@ -652,8 +658,27 @@ Page { //: Hint label //% "Switch the aspect ratio between 9:16 and 3:4" qsTrId("hint-aspect-ratio") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() + } + + HarbourHintIconButton { + id: invertButton + + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + icon { + source: Qt.resolvedUrl("img/invert.svg") + sourceSize: Qt.size(Theme.iconSizeMedium, Theme.iconSizeMedium) + rotation: invertButton.down ? 180 : 0 + } + opacity: ((viewFinder || galleryImage) && !ratioButton.isNeeded) ? 1.0 : 0.0 + visible: opacity > 0.0 + Behavior on opacity { FadeAnimation { duration: toolIconFadeDuration } } + Binding { target: viewFinder; property: "invert"; value: invertButton.down } + Binding { target: galleryImage; property: "invert"; value: invertButton.down } } } @@ -725,7 +750,7 @@ Page { } else { var component = Qt.createComponent("../components/VCard.qml") if (component.status === Component.Ready) { - vcard = component.createObject(scanPage, { content: vcardText }) + vcard = component.createObject(thisPage, { content: vcardText }) } } } else { @@ -783,11 +808,11 @@ Page { //: Hint label //% "Show EU digital COVID certificate" hint: qsTrId("hint-covid_certificate") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() onClicked: { pageStack.push("CovidPage.qml", { - allowedOrientations: scanPage.allowedOrientations, + allowedOrientations: thisPage.allowedOrientations, text: dgCert.text }) } @@ -802,11 +827,11 @@ Page { //: Hint label //% "Open contact card" hint: qsTrId("hint-open_contact_card") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() onClicked: { pageStack.push("VCardPage.qml", { - allowedOrientations: scanPage.allowedOrientations, + allowedOrientations: thisPage.allowedOrientations, contact: clickableResult.vcard.contact(), }).saveContact.connect(function() { pageStack.pop() @@ -832,8 +857,8 @@ Page { //: Hint label //% "Add event to calendar" hint: qsTrId("hint-add_to_calendar") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() } HarbourHintIconButton { @@ -855,8 +880,8 @@ Page { //: Hint label //% "Open URL in default application" qsTrId("hint-open_url") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() onClicked: { console.log("opening", clickableResult.text) Qt.openUrlExternally(clickableResult.text) @@ -875,8 +900,8 @@ Page { //: Hint label //% "Copy to clipboard" hint: qsTrId("hint-copy-clipboard") - onShowHint: scanPage.showHint(hint) - onHideHint: scanPage.hideHint() + onShowHint: thisPage.showHint(hint) + onHideHint: thisPage.hideHint() } Timer { @@ -902,7 +927,7 @@ Page { remorse.execute(resultItem, qsTrId("history-menu-delete_remorse"), function() { HistoryModel.remove(0) - if (scanPage.status === PageStatus.Active) { + if (thisPage.status === PageStatus.Active) { HistoryModel.commitChanges() } remorse.destroy() @@ -933,7 +958,7 @@ Page { onClicked: { pageStack.push("TextPage.qml", { - allowedOrientations: scanPage.allowedOrientations, + allowedOrientations: thisPage.allowedOrientations, hasImage: AppSettings.saveImages, recordId: clickableResult.recordId, text: clickableResult.text, diff --git a/qml/pages/img/invert.svg b/qml/pages/img/invert.svg new file mode 100644 index 0000000..052f09d --- /dev/null +++ b/qml/pages/img/invert.svg @@ -0,0 +1,27 @@ + + + + + + diff --git a/src/scanner/BarcodeScanner.cpp b/src/scanner/BarcodeScanner.cpp index 11d1100..731ff9e 100644 --- a/src/scanner/BarcodeScanner.cpp +++ b/src/scanner/BarcodeScanner.cpp @@ -37,12 +37,23 @@ THE SOFTWARE. #include #include -#if HARBOUR_DEBUG +#define HARBOUR_BARCODE_DEBUG_IMAGES +#ifdef HARBOUR_BARCODE_DEBUG_IMAGES +// In debug build saving debug images is enabled by default, in release +// if HARBOUR_BARCODE_DEBUG_IMAGES environment is set 1 (or anything +// non-zero, actually) +# if HARBOUR_DEBUG +# define HARBOUR_BARCODE_DEBUG_IMAGES_ENABLED true +# else +# define HARBOUR_BARCODE_DEBUG_IMAGES_ENABLED \ + (qgetenv("HARBOUR_BARCODE_DEBUG_IMAGES").toInt() > 0) +# endif // HARBOUR_DEBUG #include static const QDir debugImageDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/codereader"); +static const bool debugImageEnabled = HARBOUR_BARCODE_DEBUG_IMAGES_ENABLED; static void saveDebugImage(const QImage& aImage, const QString& aFileName) { - if (!aImage.isNull()) { + if (debugImageEnabled && debugImageDir.exists() && !aImage.isNull()) { QString path = debugImageDir.filePath(aFileName); if (aImage.save(path)) { HDEBUG("image saved:" << qPrintable(path)); @@ -57,7 +68,9 @@ static void saveDebugImage(const QImage& aImage, const QString& aFileName) // BarcodeScanner::Private // ========================================================================== -class BarcodeScanner::Private : public QObject { +class BarcodeScanner::Private : + public QObject +{ Q_OBJECT public: Private(BarcodeScanner* aParent); @@ -65,11 +78,11 @@ class BarcodeScanner::Private : public QObject { BarcodeScanner* scanner(); - bool setViewFinderRect(const QRect& aRect); - bool setViewFinderItem(QObject* aValue); - bool setMarkerColor(QString aValue); - bool setRotation(int aDegrees); - void startScanning(int aTimeout); + bool setViewFinderRect(const QRect&); + bool setViewFinderItem(QObject*); + bool setMarkerColor(QString); + bool setRotation(int); + void startScanning(int); void stopScanning(); void grabImage(); void decodingThread(); @@ -77,15 +90,16 @@ class BarcodeScanner::Private : public QObject { Q_SIGNALS: void needImage(); - void decodingDone(QImage image, Decoder::Result result); + void decodingDone(QImage, Decoder::Result); public Q_SLOTS: void onScanningTimeout(); - void onDecodingDone(QImage aImage, Decoder::Result aResult); + void onDecodingDone(QImage, Decoder::Result); void onGrabImage(); public: bool iCanGrab; + bool iInverted; bool iGrabbing; bool iScanning; bool iNeedImage; @@ -95,6 +109,7 @@ public Q_SLOTS: ScanState iLastKnownState; QImage iCaptureImage; + bool iCaptureImageInverted; QQuickItem* iViewFinderItem; QTimer* iScanTimeout; @@ -110,6 +125,7 @@ public Q_SLOTS: BarcodeScanner::Private::Private(BarcodeScanner* aParent) : QObject(aParent), iCanGrab(true), + iInverted(false), iGrabbing(false), iScanning(false), iNeedImage(false), @@ -117,6 +133,7 @@ BarcodeScanner::Private::Private(BarcodeScanner* aParent) : iTimedOut(false), iRotation(0), iLastKnownState(Idle), + iCaptureImageInverted(false), iViewFinderItem(NULL), iScanTimeout(new QTimer(this)), iMarkerColor(QColor(0, 255, 0)), // default green @@ -142,12 +159,16 @@ BarcodeScanner::Private::~Private() iDecodingFuture.waitForFinished(); } -inline BarcodeScanner* BarcodeScanner::Private::scanner() +inline +BarcodeScanner* +BarcodeScanner::Private::scanner() { return qobject_cast(parent()); } -bool BarcodeScanner::Private::setViewFinderRect(const QRect& aRect) +bool +BarcodeScanner::Private::setViewFinderRect( + const QRect& aRect) { if (iViewFinderRect != aRect) { // iViewFinderRect is accessed by decodingThread() thread @@ -159,7 +180,9 @@ bool BarcodeScanner::Private::setViewFinderRect(const QRect& aRect) return false; } -bool BarcodeScanner::Private::setViewFinderItem(QObject* aItem) +bool +BarcodeScanner::Private::setViewFinderItem( + QObject* aItem) { QQuickItem* item = qobject_cast(aItem); if (iViewFinderItem != item) { @@ -169,7 +192,9 @@ bool BarcodeScanner::Private::setViewFinderItem(QObject* aItem) return false; } -bool BarcodeScanner::Private::setMarkerColor(QString aValue) +bool +BarcodeScanner::Private::setMarkerColor( + QString aValue) { if (QColor::isValidColor(aValue)) { QColor color(aValue); @@ -181,7 +206,9 @@ bool BarcodeScanner::Private::setMarkerColor(QString aValue) return false; } -bool BarcodeScanner::Private::setRotation(int aDegrees) +bool +BarcodeScanner::Private::setRotation( + int aDegrees) { if (iRotation != aDegrees) { iDecodingMutex.lock(); @@ -192,7 +219,9 @@ bool BarcodeScanner::Private::setRotation(int aDegrees) return false; } -void BarcodeScanner::Private::startScanning(int aTimeout) +void +BarcodeScanner::Private::startScanning( + int aTimeout) { if (!iScanning) { iScanning = true; @@ -210,7 +239,8 @@ void BarcodeScanner::Private::startScanning(int aTimeout) } } -void BarcodeScanner::Private::stopScanning() +void +BarcodeScanner::Private::stopScanning() { // stopping a running scanning process iDecodingMutex.lock(); @@ -223,7 +253,8 @@ void BarcodeScanner::Private::stopScanning() updateScanState(); } -void BarcodeScanner::Private::grabImage() +void +BarcodeScanner::Private::grabImage() { QQuickWindow* window = iViewFinderItem->window(); if (window) { @@ -239,13 +270,15 @@ void BarcodeScanner::Private::grabImage() HDEBUG(image); iDecodingMutex.lock(); iCaptureImage = image; + iCaptureImageInverted = iInverted; iDecodingEvent.wakeAll(); iDecodingMutex.unlock(); } } } -void BarcodeScanner::Private::onGrabImage() +void +BarcodeScanner::Private::onGrabImage() { if (iViewFinderItem && iScanning) { if (iCanGrab) { @@ -257,7 +290,8 @@ void BarcodeScanner::Private::onGrabImage() } } -void BarcodeScanner::Private::decodingThread() +void +BarcodeScanner::Private::decodingThread() { HDEBUG("decodingThread() is called from " << QThread::currentThread()); @@ -266,6 +300,7 @@ void BarcodeScanner::Private::decodingThread() QImage image; qreal scale = 1; bool rotated = false; + bool inverted = false; int scaledWidth = 0; const int maxSize = 800; @@ -282,8 +317,10 @@ void BarcodeScanner::Private::decodingThread() } if (iAbortScan) { image = QImage(); + inverted = false; } else { image = iCaptureImage; + inverted = iCaptureImageInverted; iCaptureImage = QImage(); } viewFinderRect = iViewFinderRect; @@ -341,7 +378,7 @@ void BarcodeScanner::Private::decodingThread() HDEBUG("extracted" << image); saveDebugImage(image, "debug_cropped.bmp"); -#if HARBOUR_DEBUG +#ifdef HARBOUR_BARCODE_DEBUG_IMAGES // In debug build, ~/Pictures/codereader/debug_input.bmp gets // processed instead of the actual captured and cropped image, // if such file exists. Normally it doesn't exist. If you need @@ -350,7 +387,7 @@ void BarcodeScanner::Private::decodingThread() // // $ mkdir ~/Pictures/codereader // - // try debuging the image, abort/finish the decoding the then + // try debuging the image, abort/finish the decoding, then // // $ cd ~/Pictures/codereader // $ cp debug_cropped.bmp debug_input.bmp @@ -358,7 +395,7 @@ void BarcodeScanner::Private::decodingThread() // And then whenever you start capture this file will be picked // up instead of the actual input. // - if (debugImageDir.exists()) { + if (debugImageEnabled && debugImageDir.exists()) { QImage debugImage; QString filePath = debugImageDir.filePath("debug_input.bmp"); if (debugImage.load(filePath)) { @@ -366,7 +403,7 @@ void BarcodeScanner::Private::decodingThread() image = debugImage; } } -#endif // HARBOUR_DEBUG +#endif // HARBOUR_BARCODE_DEBUG_IMAGES QImage scaledImage; if (image.width() > maxSize && image.height() > maxSize) { @@ -426,6 +463,9 @@ void BarcodeScanner::Private::decodingThread() if (result.isValid()) { HDEBUG("decoding succeeded:" << result.getText() << result.getPoints()); + if (inverted) { + image.invertPixels(); + } if (scale > 1 || rotated) { // The image could be a) scaled and b) rotated. Convert // points to the original coordinate system @@ -613,11 +653,29 @@ void BarcodeScanner::setCanGrab(bool aCanGrab) } } -bool BarcodeScanner::grabbing() const +bool +BarcodeScanner::grabbing() const { return iPrivate->iGrabbing; } +bool +BarcodeScanner::inverted() const +{ + return iPrivate->iInverted; +} + +void +BarcodeScanner::setInverted( + bool aInverted) +{ + if (iPrivate->iInverted != aInverted) { + HDEBUG(aInverted); + iPrivate->iInverted = aInverted; + Q_EMIT invertedChanged(); + } +} + uint BarcodeScanner::decodingHints() const { return iPrivate->iDecodingHints; diff --git a/src/scanner/BarcodeScanner.h b/src/scanner/BarcodeScanner.h index a5b9096..e61c3db 100644 --- a/src/scanner/BarcodeScanner.h +++ b/src/scanner/BarcodeScanner.h @@ -32,7 +32,8 @@ THE SOFTWARE. #include #include -class BarcodeScanner : public QObject { +class BarcodeScanner : public QObject +{ Q_OBJECT Q_PROPERTY(QObject* viewFinderItem READ viewFinderItem WRITE setViewFinderItem NOTIFY viewFinderItemChanged) Q_PROPERTY(QRect viewFinderRect READ viewFinderRect WRITE setViewFinderRect NOTIFY viewFinderRectChanged) @@ -41,6 +42,7 @@ class BarcodeScanner : public QObject { Q_PROPERTY(ScanState scanState READ scanState NOTIFY scanStateChanged) Q_PROPERTY(bool canGrab READ canGrab WRITE setCanGrab NOTIFY canGrabChanged) Q_PROPERTY(bool grabbing READ grabbing NOTIFY grabbingChanged) + Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged) Q_PROPERTY(uint decodingHints READ decodingHints WRITE setDecodingHints NOTIFY decodingHintsChanged) Q_ENUMS(ScanState) @@ -57,30 +59,33 @@ class BarcodeScanner : public QObject { BarcodeScanner(QObject* aParent = Q_NULLPTR); virtual ~BarcodeScanner(); - Q_INVOKABLE void startScanning(int aTimeout); + Q_INVOKABLE void startScanning(int); Q_INVOKABLE void stopScanning(); QObject* viewFinderItem() const; - void setViewFinderItem(QObject* aItem); + void setViewFinderItem(QObject*); const QRect& viewFinderRect() const; - void setViewFinderRect(const QRect& aRect); + void setViewFinderRect(const QRect&); QString markerColor() const; - void setMarkerColor(QString aValue); + void setMarkerColor(QString); int rotation() const; - void setRotation(int aDegrees); + void setRotation(int); ScanState scanState() const; bool canGrab() const; - void setCanGrab(bool aValue); + void setCanGrab(bool); bool grabbing() const; + bool inverted() const; + void setInverted(bool); + uint decodingHints() const; - void setDecodingHints(uint aValue); + void setDecodingHints(uint); Q_SIGNALS: void decodingFinished(QImage image, QVariantMap result); @@ -91,6 +96,7 @@ class BarcodeScanner : public QObject { void scanStateChanged(); void canGrabChanged(); void grabbingChanged(); + void invertedChanged(); void decodingHintsChanged(); private: