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-02-16 09:40:22 +0100
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
e7b185ee3c14dafd5d1cb2b0b44af50edd46f7d2
e7b185ee
2 parents
82a43ccb
dc7f855d
Merge branch 'master' into dependabot/gradle/android/com.android.tools.build-gradle-7.1.1
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
126 additions
and
104 deletions
example/lib/main.dart
example/lib/mobile_scanner_overlay.dart
example/test/widget_test.dart
ios/Classes/SwiftMobileScannerPlugin.swift
lib/mobile_scanner.dart
lib/src/mobile_scanner.dart
lib/src/mobile_scanner_arguments.dart
lib/src/mobile_scanner_controller.dart
lib/src/objects/barcode.dart
lib/src/objects/barcode_utility.dart
test/mobile_scanner_test.dart
example/lib/main.dart
View file @
e7b185e
import
'dart:ui'
;
import
'package:flutter/material.dart'
;
import
'package:mobile_scanner/mobile_scanner.dart'
;
...
...
@@ -18,8 +16,10 @@ class _AnalyzeViewState extends State<AnalyzeView>
with
SingleTickerProviderStateMixin
{
String
?
barcode
;
MobileScannerController
controller
=
MobileScannerController
(
torchEnabled:
true
,
facing:
CameraFacing
.
front
,);
MobileScannerController
controller
=
MobileScannerController
(
torchEnabled:
true
,
facing:
CameraFacing
.
front
,
);
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -60,9 +60,11 @@ class _AnalyzeViewState extends State<AnalyzeView>
builder:
(
context
,
state
,
child
)
{
switch
(
state
as
TorchState
)
{
case
TorchState
.
off
:
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
);
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
);
case
TorchState
.
on
:
return
const
Icon
(
Icons
.
flash_on
,
color:
Colors
.
yellow
);
return
const
Icon
(
Icons
.
flash_on
,
color:
Colors
.
yellow
);
}
},
),
...
...
example/lib/mobile_scanner_overlay.dart
View file @
e7b185e
...
...
@@ -20,7 +20,7 @@ class _AnalyzeViewState extends State<AnalyzeView>
// CameraController cameraController = CameraController(context, width: 320, height: 150);
String
?
barcode
=
null
;
String
?
barcode
;
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -37,20 +37,21 @@ class _AnalyzeViewState extends State<AnalyzeView>
this
.
barcode
=
barcode
.
rawValue
;
if
(
barcode
.
corners
!=
null
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
'
${barcode.rawValue}
'
),
content:
Text
(
barcode
.
rawValue
),
duration:
const
Duration
(
milliseconds:
200
),
animation:
null
,
));
setState
(()
{
final
List
<
Offset
>
points
=
[];
double
factorWidth
=
args
.
size
.
width
/
520
;
//
double factorWidth = args.size.width / 520;
// double factorHeight = wanted / args.size.height;
final
size
=
MediaQuery
.
of
(
context
).
devicePixelRatio
;
debugPrint
(
'Size:
${barcode.corners}
'
);
for
(
var
point
in
barcode
.
corners
!)
{
final
adjustedWith
=
point
.
dx
;
final
adjustedHeight
=
point
.
dy
;
points
.
add
(
Offset
(
adjustedWith
/
size
,
adjustedHeight
/
size
));
final
adjustedWith
=
point
.
dx
;
final
adjustedHeight
=
point
.
dy
;
points
.
add
(
Offset
(
adjustedWith
/
size
,
adjustedHeight
/
size
));
// points.add(Offset((point.dx ) / size,
// (point.dy) / size));
// final differenceWidth = (args.wantedSize!.width - args.size.width) / 2;
...
...
@@ -108,7 +109,7 @@ class OpenPainter extends CustomPainter {
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
var
paint1
=
Paint
()
..
color
=
Color
(
0xff63aa65
)
..
color
=
const
Color
(
0xff63aa65
)
..
strokeWidth
=
10
;
//draw points on canvas
canvas
.
drawPoints
(
PointMode
.
points
,
points
,
paint1
);
...
...
example/test/widget_test.dart
View file @
e7b185e
...
...
@@ -5,11 +5,8 @@
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:mobile_scanner_example/main.dart'
;
void
main
(
)
{
testWidgets
(
'Verify Platform version'
,
(
WidgetTester
tester
)
async
{
// Build our app and trigger a frame.
...
...
ios/Classes/SwiftMobileScannerPlugin.swift
View file @
e7b185e
...
...
@@ -53,11 +53,11 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
case
"start"
:
start
(
call
,
result
)
case
"torch"
:
torchNative
(
call
,
result
)
switchTorch
(
call
,
result
)
case
"analyze"
:
analyzeNativ
e
(
call
,
result
)
switchAnalyzeMod
e
(
call
,
result
)
case
"stop"
:
stop
Native
(
result
)
stop
(
result
)
default
:
result
(
FlutterMethodNotImplemented
)
}
...
...
@@ -83,58 +83,59 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
return
Unmanaged
<
CVPixelBuffer
>.
passRetained
(
latestBuffer
)
}
// public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
//
// latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
// registry.textureFrameAvailable(textureId)
//
// switch analyzeMode {
// case 1: // barcode
// if analyzing {
// break
// }
// analyzing = true
// let buffer = CMSampleBufferGetImageBuffer(sampleBuffer)
// let image = VisionImage(image: buffer!.image)
// image.orientation = imageOrientation(
// deviceOrientation: UIDevice.current.orientation,
// defaultOrientation: .portrait
// )
//
// let scanner = BarcodeScanner.barcodeScanner()
// scanner.process(image) { [self] barcodes, error in
// if error == nil && barcodes != nil {
// for barcode in barcodes! {
// let event: [String: Any?] = ["name": "barcode", "data": barcode.data]
// sink?(event)
// }
// }
// analyzing = false
// }
// default: // none
// break
// }
// }
// func imageOrientation(
// deviceOrientation: UIDeviceOrientation,
// defaultOrientation: UIDeviceOrientation
// ) -> UIImage.Orientation {
// switch deviceOrientation {
// case .portrait:
// return position == .front ? .leftMirrored : .right
// case .landscapeLeft:
// return position == .front ? .downMirrored : .up
// case .portraitUpsideDown:
// return position == .front ? .rightMirrored : .left
// case .landscapeRight:
// return position == .front ? .upMirrored : .down
// case .faceDown, .faceUp, .unknown:
// return .up
// @unknown default:
// return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait)
// }
// }
// Gets called when a new image is added to the buffer
public
func
captureOutput
(
_
output
:
AVCaptureOutput
,
didOutput
sampleBuffer
:
CMSampleBuffer
,
from
connection
:
AVCaptureConnection
)
{
latestBuffer
=
CMSampleBufferGetImageBuffer
(
sampleBuffer
)
registry
.
textureFrameAvailable
(
textureId
)
switch
analyzeMode
{
case
1
:
// barcode
if
analyzing
{
break
}
analyzing
=
true
let
buffer
=
CMSampleBufferGetImageBuffer
(
sampleBuffer
)
let
image
=
VisionImage
(
image
:
buffer
!.
image
)
image
.
orientation
=
imageOrientation
(
deviceOrientation
:
UIDevice
.
current
.
orientation
,
defaultOrientation
:
.
portrait
)
let
scanner
=
BarcodeScanner
.
barcodeScanner
()
scanner
.
process
(
image
)
{
[
self
]
barcodes
,
error
in
if
error
==
nil
&&
barcodes
!=
nil
{
for
barcode
in
barcodes
!
{
let
event
:
[
String
:
Any
?]
=
[
"name"
:
"barcode"
,
"data"
:
barcode
.
data
]
sink
?(
event
)
}
}
analyzing
=
false
}
default
:
// none
break
}
}
func
imageOrientation
(
deviceOrientation
:
UIDeviceOrientation
,
defaultOrientation
:
UIDeviceOrientation
)
->
UIImage
.
Orientation
{
switch
deviceOrientation
{
case
.
portrait
:
return
position
==
.
front
?
.
leftMirrored
:
.
right
case
.
landscapeLeft
:
return
position
==
.
front
?
.
downMirrored
:
.
up
case
.
portraitUpsideDown
:
return
position
==
.
front
?
.
rightMirrored
:
.
left
case
.
landscapeRight
:
return
position
==
.
front
?
.
upMirrored
:
.
down
case
.
faceDown
,
.
faceUp
,
.
unknown
:
return
.
up
@unknown
default
:
return
imageOrientation
(
deviceOrientation
:
defaultOrientation
,
defaultOrientation
:
.
portrait
)
}
}
func
checkPermission
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
let
status
=
AVCaptureDevice
.
authorizationStatus
(
for
:
.
video
)
...
...
@@ -158,22 +159,35 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
let
argReader
=
MapArgumentReader
(
call
.
arguments
as?
[
String
:
Any
])
guard
let
ratio
=
argReader
.
int
(
key
:
"ratio"
),
let
torch
=
argReader
.
int
(
key
:
"torch"
),
let
facing
=
argReader
.
int
(
key
:
"facing"
)
else
{
result
(
FlutterError
(
code
:
"INVALID_ARGUMENT"
,
message
:
"Missing a required argument"
,
details
:
"Expecting targetWidth, targetHeight, formats, and optionally heartbeatTimeout"
))
return
}
// let ratio: Int = argReader.int(key: "ratio")
let
torch
:
Bool
=
argReader
.
bool
(
key
:
"torch"
)
??
false
let
facing
:
Int
=
argReader
.
int
(
key
:
"facing"
)
??
1
// Set the camera to use
position
=
facing
==
0
?
AVCaptureDevice
.
Position
.
front
:
.
back
// Open the camera device
if
#available(iOS 10.0, *)
{
device
=
AVCaptureDevice
.
DiscoverySession
(
deviceTypes
:
[
.
builtInWideAngleCamera
],
mediaType
:
.
video
,
position
:
position
)
.
devices
.
first
}
else
{
device
=
AVCaptureDevice
.
devices
(
for
:
.
video
)
.
filter
({
$0
.
position
==
position
})
.
first
}
// Enable the torch if parameter is set and torch is available
if
(
device
.
hasTorch
&&
device
.
isTorchAvailable
)
{
do
{
try
device
.
lockForConfiguration
()
device
.
torchMode
=
torch
?
.
on
:
.
off
device
.
unlockForConfiguration
()
}
catch
{
error
.
throwNative
(
result
)
}
}
device
.
addObserver
(
self
,
forKeyPath
:
#
keyPath
(
AVCaptureDevice
.
torchMode
),
options
:
.
new
,
context
:
nil
)
captureSession
.
beginConfiguration
()
// Add device input.
// Add device input
do
{
let
input
=
try
AVCaptureDeviceInput
(
device
:
device
)
captureSession
.
addInput
(
input
)
...
...
@@ -205,7 +219,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
result
(
answer
)
}
func
torchNative
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
func
switchTorch
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
do
{
try
device
.
lockForConfiguration
()
device
.
torchMode
=
call
.
arguments
as!
Int
==
1
?
.
on
:
.
off
...
...
@@ -216,12 +230,12 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
}
}
func
analyzeNativ
e
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
func
switchAnalyzeMod
e
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
analyzeMode
=
call
.
arguments
as!
Int
result
(
nil
)
}
func
stop
Native
(
_
result
:
FlutterResult
)
{
func
stop
(
_
result
:
FlutterResult
)
{
captureSession
.
stopRunning
()
for
input
in
captureSession
.
inputs
{
captureSession
.
removeInput
(
input
)
...
...
@@ -241,6 +255,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
result
(
nil
)
}
// Observer for torch state
public
override
func
observeValue
(
forKeyPath
keyPath
:
String
?,
of
object
:
Any
?,
change
:
[
NSKeyValueChangeKey
:
Any
]?,
context
:
UnsafeMutableRawPointer
?)
{
switch
keyPath
{
case
"torchMode"
:
...
...
@@ -270,6 +285,10 @@ class MapArgumentReader {
return
(
args
?[
key
]
as?
NSNumber
)?
.
intValue
}
func
bool
(
key
:
String
)
->
Bool
?
{
return
(
args
?[
key
]
as?
NSNumber
)?
.
boolValue
}
func
stringArray
(
key
:
String
)
->
[
String
]?
{
return
args
?[
key
]
as?
[
String
]
}
...
...
lib/mobile_scanner.dart
View file @
e7b185e
lib/src/mobile_scanner.dart
View file @
e7b185e
...
...
@@ -3,10 +3,7 @@ import 'package:mobile_scanner/mobile_scanner.dart';
import
'mobile_scanner_arguments.dart'
;
enum
Ratio
{
ratio_4_3
,
ratio_16_9
}
enum
Ratio
{
ratio_4_3
,
ratio_16_9
}
/// A widget showing a live camera preview.
class
MobileScanner
extends
StatefulWidget
{
...
...
@@ -18,7 +15,8 @@ class MobileScanner extends StatefulWidget {
/// Create a [MobileScanner] with a [controller], the [controller] must has been initialized.
const
MobileScanner
(
{
Key
?
key
,
this
.
onDetect
,
this
.
controller
,
this
.
fit
=
BoxFit
.
cover
})
:
assert
((
controller
!=
null
)),
super
(
key:
key
);
:
assert
((
controller
!=
null
)),
super
(
key:
key
);
@override
State
<
MobileScanner
>
createState
()
=>
_MobileScannerState
();
...
...
lib/src/mobile_scanner_arguments.dart
View file @
e7b185e
...
...
@@ -11,5 +11,6 @@ class MobileScannerArguments {
final
bool
hasTorch
;
/// Create a [MobileScannerArguments].
MobileScannerArguments
({
required
this
.
textureId
,
required
this
.
size
,
required
this
.
hasTorch
});
MobileScannerArguments
(
{
required
this
.
textureId
,
required
this
.
size
,
required
this
.
hasTorch
});
}
...
...
lib/src/mobile_scanner_controller.dart
View file @
e7b185e
...
...
@@ -38,7 +38,6 @@ class MobileScannerController {
int
?
_controllerHashcode
;
StreamSubscription
?
events
;
final
ValueNotifier
<
MobileScannerArguments
?>
args
=
ValueNotifier
(
null
);
final
ValueNotifier
<
TorchState
>
torchState
=
ValueNotifier
(
TorchState
.
off
);
late
final
ValueNotifier
<
CameraFacing
>
cameraFacingState
;
...
...
@@ -107,7 +106,8 @@ class MobileScannerController {
setAnalyzeMode
(
AnalyzeMode
.
barcode
.
index
);
// Check authorization status
MobileScannerState
state
=
MobileScannerState
.
values
[
await
methodChannel
.
invokeMethod
(
'state'
)];
MobileScannerState
state
=
MobileScannerState
.
values
[
await
methodChannel
.
invokeMethod
(
'state'
)];
switch
(
state
)
{
case
MobileScannerState
.
undetermined
:
final
bool
result
=
await
methodChannel
.
invokeMethod
(
'request'
);
...
...
@@ -129,13 +129,18 @@ class MobileScannerController {
if
(
torchEnabled
!=
null
)
arguments
[
'torch'
]
=
torchEnabled
;
// Start the camera with arguments
final
Map
<
String
,
dynamic
>?
startResult
=
await
methodChannel
.
invokeMapMethod
<
String
,
dynamic
>(
'start'
,
arguments
);
final
Map
<
String
,
dynamic
>?
startResult
=
await
methodChannel
.
invokeMapMethod
<
String
,
dynamic
>(
'start'
,
arguments
);
if
(
startResult
==
null
)
throw
PlatformException
(
code:
'INITIALIZATION ERROR'
);
if
(
startResult
==
null
)
{
throw
PlatformException
(
code:
'INITIALIZATION ERROR'
);
}
hasTorch
=
startResult
[
'torchable'
];
args
.
value
=
MobileScannerArguments
(
textureId:
startResult
[
'textureId'
],
size:
toSize
(
startResult
[
'size'
]),
hasTorch:
hasTorch
);
args
.
value
=
MobileScannerArguments
(
textureId:
startResult
[
'textureId'
],
size:
toSize
(
startResult
[
'size'
]),
hasTorch:
hasTorch
);
}
Future
<
void
>
stop
()
async
=>
await
methodChannel
.
invokeMethod
(
'stop'
);
...
...
@@ -157,7 +162,8 @@ class MobileScannerController {
Future
<
void
>
switchCamera
()
async
{
ensure
(
'switchCamera'
);
await
stop
();
facing
=
facing
==
CameraFacing
.
back
?
CameraFacing
.
front
:
CameraFacing
.
back
;
facing
=
facing
==
CameraFacing
.
back
?
CameraFacing
.
front
:
CameraFacing
.
back
;
start
();
}
...
...
lib/src/objects/barcode.dart
View file @
e7b185e
...
...
@@ -490,7 +490,7 @@ enum BarcodeFormat {
/// Barcode format constant for Data Matrix.
///
/// Constant Value: 16
data
_m
atrix
,
data
M
atrix
,
/// Barcode format constant for EAN-13.
///
...
...
@@ -510,17 +510,17 @@ enum BarcodeFormat {
/// Barcode format constant for QR Code.
///
/// Constant Value: 256
qr
_c
ode
,
qr
C
ode
,
/// Barcode format constant for UPC-A.
///
/// Constant Value: 512
upc
_a
,
upc
A
,
/// Barcode format constant for UPC-E.
///
/// Constant Value: 1024
upc
_e
,
upc
E
,
/// Barcode format constant for PDF-417.
///
...
...
lib/src/objects/barcode_utility.dart
View file @
e7b185e
...
...
@@ -29,7 +29,7 @@ BarcodeFormat toFormat(int value) {
case
8
:
return
BarcodeFormat
.
codebar
;
case
16
:
return
BarcodeFormat
.
data
_m
atrix
;
return
BarcodeFormat
.
data
M
atrix
;
case
32
:
return
BarcodeFormat
.
ean13
;
case
64
:
...
...
@@ -37,11 +37,11 @@ BarcodeFormat toFormat(int value) {
case
128
:
return
BarcodeFormat
.
itf
;
case
256
:
return
BarcodeFormat
.
qr
_c
ode
;
return
BarcodeFormat
.
qr
C
ode
;
case
512
:
return
BarcodeFormat
.
upc
_a
;
return
BarcodeFormat
.
upc
A
;
case
1024
:
return
BarcodeFormat
.
upc
_e
;
return
BarcodeFormat
.
upc
E
;
case
2048
:
return
BarcodeFormat
.
pdf417
;
case
4096
:
...
...
test/mobile_scanner_test.dart
View file @
e7b185e
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:mobile_scanner/src/mobile_scanner.dart'
;
void
main
(
)
{
const
MethodChannel
channel
=
MethodChannel
(
'mobile_scanner'
);
...
...
@@ -16,5 +15,4 @@ void main() {
tearDown
(()
{
channel
.
setMockMethodCallHandler
(
null
);
});
}
...
...
Please
register
or
login
to post a comment