Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
mobile_scanner
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Julian Steenbakker
2022-12-09 14:46:06 +0100
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
5df6814ba458771935a05b72ff72119f83b998c0
5df6814b
1 parent
c0cf90d0
imp: fixed window on android
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
117 additions
and
50 deletions
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerPlugin.kt
example/ios/Runner.xcodeproj/project.pbxproj
example/lib/barcode_scanner_window.dart
lib/src/mobile_scanner.dart
lib/src/mobile_scanner_controller.dart
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt
View file @
5df6814
...
...
@@ -3,12 +3,11 @@ package dev.steenbakker.mobile_scanner
import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.graphics.Point
import android.graphics.Rect
import android.graphics.RectF
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.Surface
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
...
...
@@ -17,19 +16,22 @@ import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import dev.steenbakker.mobile_scanner.objects.DetectionSpeed
import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import io.flutter.view.TextureRegistry
import kotlin.math.roundToInt
typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?) -> Unit
typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit
typealias MobileScannerErrorCallback = (error: String) -> Unit
typealias TorchStateCallback = (state: Int) -> Unit
typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit
import java.io.File
import kotlin.math.roundToInt
class NoCamera : Exception()
class AlreadyStarted : Exception()
...
...
@@ -58,7 +60,7 @@ class MobileScanner(
private var pendingPermissionResult: MethodChannel.Result? = null
private var preview: Preview? = null
private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null
private var scanWindow: List<Float>? = null;
var scanWindow: List<Float>? = null
private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES
private var detectionTimeout: Long = 250
...
...
@@ -144,13 +146,19 @@ class MobileScanner(
lastScanned = newScannedBarcodes
}
val barcodeMap
= barcodes.map { barcode -> barcode.data }
val barcodeMap
: MutableList<Map<String, Any?>> = mutableListOf()
for ( barcode in barcodes) {
if(scanWindow != null) {
val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy)
if(!match) continue
}
Log.d("mobile_scanner: ", "width: ${inputImage.width}, height: ${inputImage.height}")
barcodeMap.add(barcode.data)
}
if (barcodeMap.isNotEmpty()) {
mobileScannerCallback(
barcodeMap,
if (returnImage) mediaImage.toByteArray() else null
...
...
@@ -172,18 +180,13 @@ class MobileScanner(
}
}
private fun updateScanWindow(call: MethodCall) {
scanWindow = call.argument<List<Float>>("rect")
}
// scales the scanWindow to the provided inputImage and checks if that scaled
// scanWindow contains the barcode
private fun isbarCodeInScanWindow(scanWindow: List<Float>, barcode: Barcode, inputImage: ImageProxy): Boolean {
val barcodeBoundingBox = barcode.getBoundingBox()
if(barcodeBoundingBox == null) return false
val barcodeBoundingBox = barcode.boundingBox ?: return false
val imageWidth = inputImage.getHeight();
val imageHeight = inputImage.getWidth();
val imageWidth = inputImage.height
val imageHeight = inputImage.width
val left = (scanWindow[0] * imageWidth).roundToInt()
val top = (scanWindow[1] * imageHeight).roundToInt()
...
...
@@ -192,9 +195,11 @@ class MobileScanner(
val scaledScanWindow = Rect(left, top, right, bottom)
print("scanWindow: ")
println(scaledScanWindow)
return scaledScanWindow.contains(barcodeBoundingBox)
// Log.d("mobile_scanner: ", "scanWindow: $scaledScanWindow")
// Log.d("mobile_scanner: ", "bounding box: $barcodeBoundingBox")
// Log.d("mobile_scanner: ", "contains: ${scaledScanWindow.contains(barcodeBoundingBox)}")
return true
// return scaledScanWindow.contains(barcodeBoundingBox)
}
/**
...
...
@@ -279,7 +284,7 @@ class MobileScanner(
// Enable torch if provided
camera!!.cameraControl.enableTorch(torch)
val resolution =
preview!!
.resolutionInfo!!.resolution
val resolution =
analysis
.resolutionInfo!!.resolution
val portrait = camera!!.cameraInfo.sensorRotationDegrees % 180 == 0
val width = resolution.width.toDouble()
val height = resolution.height.toDouble()
...
...
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerPlugin.kt
View file @
5df6814
...
...
@@ -77,6 +77,7 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa
"torch" -> toggleTorch(call, result)
"stop" -> stop(result)
"analyzeImage" -> analyzeImage(call, result)
"updateScanWindow" -> updateScanWindow(call)
else -> result.notImplemented()
}
}
...
...
@@ -215,4 +216,8 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa
result.error("MobileScanner", "Called toggleTorch() while stopped!", null)
}
}
private fun updateScanWindow(call: MethodCall) {
handler!!.scanWindow = call.argument<List<Float>>("rect")
}
}
...
...
example/ios/Runner.xcodeproj/project.pbxproj
View file @
5df6814
...
...
@@ -357,7 +357,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM =
QAJQ4586J2
;
DEVELOPMENT_TEAM =
75Y2P2WSQQ
;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
...
...
@@ -489,7 +489,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM =
QAJQ4586J2
;
DEVELOPMENT_TEAM =
75Y2P2WSQQ
;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
...
...
@@ -515,7 +515,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM =
QAJQ4586J2
;
DEVELOPMENT_TEAM =
75Y2P2WSQQ
;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
...
...
example/lib/barcode_scanner_window.dart
View file @
5df6814
...
...
@@ -11,35 +11,23 @@ class BarcodeScannerWithScanWindow extends StatefulWidget {
class
_BarcodeScannerWithScanWindowState
extends
State
<
BarcodeScannerWithScanWindow
>
{
late
MobileScannerController
controller
;
String
?
barcode
;
late
MobileScannerController
controller
=
MobileScannerController
();
Barcode
?
barcode
;
@override
void
initState
()
{
super
.
initState
();
controller
=
MobileScannerController
();
restart
();
Future
<
void
>
onDetect
(
BarcodeCapture
barcode
)
async
{
setState
(()
=>
this
.
barcode
=
barcode
.
barcodes
.
first
);
}
Future
<
void
>
restart
()
async
{
// await controller.stop();
await
controller
.
start
();
}
Future
<
void
>
onDetect
(
Barcode
barcode
,
MobileScannerArguments
?
_
)
async
{
setState
(()
=>
this
.
barcode
=
barcode
.
rawValue
);
await
Future
.
delayed
(
const
Duration
(
seconds:
1
));
setState
(()
=>
this
.
barcode
=
''
);
}
MobileScannerArguments
?
arguments
;
@override
Widget
build
(
BuildContext
context
)
{
final
query
=
MediaQuery
.
of
(
context
);
final
scanWindow
=
Rect
.
fromCenter
(
center:
MediaQuery
.
of
(
context
).
size
.
center
(
Offset
.
zero
),
width:
200
,
height:
200
,
);
return
Scaffold
(
backgroundColor:
Colors
.
black
,
body:
Builder
(
...
...
@@ -51,8 +39,18 @@ class _BarcodeScannerWithScanWindowState
fit:
BoxFit
.
contain
,
scanWindow:
scanWindow
,
controller:
controller
,
onScannerStarted:
(
arguments
)
{
setState
(()
{
this
.
arguments
=
arguments
;
});
},
onDetect:
onDetect
,
allowDuplicates:
true
,
),
if
(
barcode
!=
null
&&
barcode
?.
corners
!=
null
&&
arguments
!=
null
)
CustomPaint
(
painter:
BarcodeOverlay
(
barcode
!,
arguments
!,
BoxFit
.
contain
,
MediaQuery
.
of
(
context
).
devicePixelRatio
),
),
CustomPaint
(
painter:
ScannerOverlay
(
scanWindow
),
...
...
@@ -72,7 +70,7 @@ class _BarcodeScannerWithScanWindowState
height:
50
,
child:
FittedBox
(
child:
Text
(
barcode
??
'Scan something!'
,
barcode
?.
displayValue
??
'Scan something!'
,
overflow:
TextOverflow
.
fade
,
style:
Theme
.
of
(
context
)
.
textTheme
...
...
@@ -122,3 +120,57 @@ class ScannerOverlay extends CustomPainter {
return
false
;
}
}
class
BarcodeOverlay
extends
CustomPainter
{
BarcodeOverlay
(
this
.
barcode
,
this
.
arguments
,
this
.
boxFit
,
this
.
devicePixelRatio
);
final
Barcode
barcode
;
final
MobileScannerArguments
arguments
;
final
BoxFit
boxFit
;
final
double
devicePixelRatio
;
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
if
(
barcode
.
corners
==
null
)
return
;
// final realsize = Size(arguments.size.width * devicePixelRatio, arguments.size.height * devicePixelRatio);
final
adjustedSize
=
applyBoxFit
(
boxFit
,
arguments
.
size
,
size
);
double
verticalPadding
=
size
.
height
-
adjustedSize
.
destination
.
height
;
double
horizontalPadding
=
size
.
width
-
adjustedSize
.
destination
.
width
;
if
(
verticalPadding
>
0
)
{
verticalPadding
=
verticalPadding
/
2
;
}
else
{
verticalPadding
=
0
;
}
if
(
horizontalPadding
>
0
)
{
horizontalPadding
=
horizontalPadding
/
2
;
}
else
{
horizontalPadding
=
0
;
}
final
ratioWidth
=
arguments
.
size
.
width
/
adjustedSize
.
destination
.
width
;
final
ratioHeight
=
arguments
.
size
.
height
/
adjustedSize
.
destination
.
height
;
final
List
<
Offset
>
adjustedOffset
=
[];
for
(
final
offset
in
barcode
.
corners
!)
{
adjustedOffset
.
add
(
Offset
(
offset
.
dx
/
ratioWidth
+
horizontalPadding
,
offset
.
dy
/
ratioHeight
+
verticalPadding
));
}
final
cutoutPath
=
Path
()..
addPolygon
(
adjustedOffset
,
true
);
final
backgroundPaint
=
Paint
()
..
color
=
Colors
.
red
.
withOpacity
(
0.3
)
..
style
=
PaintingStyle
.
fill
..
blendMode
=
BlendMode
.
dstOut
;
canvas
.
drawPath
(
cutoutPath
,
backgroundPaint
);
}
@override
bool
shouldRepaint
(
covariant
CustomPainter
oldDelegate
)
{
return
false
;
}
}
...
...
lib/src/mobile_scanner.dart
View file @
5df6814
...
...
@@ -2,6 +2,7 @@ import 'dart:async';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
hide
applyBoxFit
;
import
'package:flutter/material.dart'
;
import
'package:mobile_scanner/src/mobile_scanner_controller.dart'
;
import
'package:mobile_scanner/src/objects/barcode_capture.dart'
;
import
'package:mobile_scanner/src/objects/mobile_scanner_arguments.dart'
;
...
...
@@ -143,9 +144,9 @@ class _MobileScannerState extends State<MobileScanner>
final
fittedTextureSize
=
applyBoxFit
(
fit
,
textureSize
,
widgetSize
);
/// create a new rectangle that represents the texture on the screen
final
minX
=
widgetSize
.
width
/
2
-
fittedTextureSize
.
width
/
2
;
final
minY
=
widgetSize
.
height
/
2
-
fittedTextureSize
.
height
/
2
;
final
textureWindow
=
Offset
(
minX
,
minY
)
&
fittedTextureSize
;
final
minX
=
widgetSize
.
width
/
2
-
fittedTextureSize
.
destination
.
width
/
2
;
final
minY
=
widgetSize
.
height
/
2
-
fittedTextureSize
.
destination
.
height
/
2
;
final
textureWindow
=
Offset
(
minX
,
minY
)
&
fittedTextureSize
.
destination
;
/// create a new scan window and with only the area of the rect intersecting the texture window
final
scanWindowInTexture
=
scanWindow
.
intersect
(
textureWindow
);
...
...
@@ -160,10 +161,10 @@ class _MobileScannerState extends State<MobileScanner>
final
windowInTexture
=
Rect
.
fromLTWH
(
newLeft
,
newTop
,
newWidth
,
newHeight
);
/// get the scanWindow as a percentage of the texture
final
percentageLeft
=
windowInTexture
.
left
/
fittedTextureSize
.
width
;
final
percentageTop
=
windowInTexture
.
top
/
fittedTextureSize
.
height
;
final
percentageRight
=
windowInTexture
.
right
/
fittedTextureSize
.
width
;
final
percentagebottom
=
windowInTexture
.
bottom
/
fittedTextureSize
.
height
;
final
percentageLeft
=
windowInTexture
.
left
/
fittedTextureSize
.
destination
.
width
;
final
percentageTop
=
windowInTexture
.
top
/
fittedTextureSize
.
destination
.
height
;
final
percentageRight
=
windowInTexture
.
right
/
fittedTextureSize
.
destination
.
width
;
final
percentagebottom
=
windowInTexture
.
bottom
/
fittedTextureSize
.
destination
.
height
;
/// this rectangle can be send to native code and used to cut out a rectangle of the scan image
return
Rect
.
fromLTRB
(
...
...
@@ -176,6 +177,8 @@ class _MobileScannerState extends State<MobileScanner>
@override
Widget
build
(
BuildContext
context
)
{
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
return
ValueListenableBuilder
<
MobileScannerArguments
?>(
valueListenable:
_controller
.
startArguments
,
builder:
(
context
,
value
,
child
)
{
...
...
@@ -191,7 +194,7 @@ class _MobileScannerState extends State<MobileScanner>
value
.
size
,
Size
(
constraints
.
maxWidth
,
constraints
.
maxHeight
),
);
controller
.
updateScanWindow
(
window
);
_
controller
.
updateScanWindow
(
window
);
}
...
...
@@ -217,6 +220,8 @@ class _MobileScannerState extends State<MobileScanner>
},
);
}
);
}
@override
void
dispose
()
{
...
...
lib/src/mobile_scanner_controller.dart
View file @
5df6814
...
...
@@ -363,6 +363,6 @@ class MobileScannerController {
/// updates the native scanwindow
Future
<
void
>
updateScanWindow
(
Rect
window
)
async
{
final
data
=
[
window
.
left
,
window
.
top
,
window
.
right
,
window
.
bottom
];
await
methodChannel
.
invokeMethod
(
'updateScanWindow'
,
{
'rect'
:
data
});
await
_
methodChannel
.
invokeMethod
(
'updateScanWindow'
,
{
'rect'
:
data
});
}
}
...
...
Please
register
or
login
to post a comment