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-08 10:35:34 +0100
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
6b0d799f7986de22896999bd6e593b57161f3080
6b0d799f
1 parent
7cd37530
feat: add zoomScale api for android and iOS
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
288 additions
and
0 deletions
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerPlugin.kt
example/lib/barcode_scanner_zoom.dart
example/lib/main.dart
ios/Classes/MobileScanner.swift
ios/Classes/MobileScannerError.swift
ios/Classes/SwiftMobileScannerPlugin.swift
lib/src/mobile_scanner_controller.dart
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt
View file @
6b0d799
...
...
@@ -33,6 +33,8 @@ class AlreadyStopped : Exception()
class TorchError : Exception()
class CameraError : Exception()
class TorchWhenStopped : Exception()
class ZoomWhenStopped : Exception()
class ZoomNotInRange : Exception()
class MobileScanner(
private val activity: Activity,
...
...
@@ -312,4 +314,13 @@ class MobileScanner(
}
}
/**
* Set the zoom rate of the camera.
*/
fun setScale(scale: Double) {
if (camera == null) throw ZoomWhenStopped()
if (scale > 1.0 || scale < 0) throw ZoomNotInRange()
camera!!.cameraControl.setLinearZoom(scale.toFloat())
}
}
...
...
android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerPlugin.kt
View file @
6b0d799
...
...
@@ -83,6 +83,7 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa
"torch" -> toggleTorch(call, result)
"stop" -> stop(result)
"analyzeImage" -> analyzeImage(call, result)
"setScale" -> setScale(call, result)
else -> result.notImplemented()
}
}
...
...
@@ -226,4 +227,15 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa
result.error("MobileScanner", "Called toggleTorch() while stopped!", null)
}
}
private fun setScale(call: MethodCall, result: MethodChannel.Result) {
try {
handler!!.setScale(call.arguments as Double)
result.success(null)
} catch (e: ZoomWhenStopped) {
result.error("MobileScanner", "Called setScale() while stopped!", null)
} catch (e: ZoomNotInRange) {
result.error("MobileScanner", "Scale should be within 0 and 1", null)
}
}
}
...
...
example/lib/barcode_scanner_zoom.dart
0 → 100644
View file @
6b0d799
import
'package:flutter/material.dart'
;
import
'package:image_picker/image_picker.dart'
;
import
'package:mobile_scanner/mobile_scanner.dart'
;
class
BarcodeScannerWithZoom
extends
StatefulWidget
{
const
BarcodeScannerWithZoom
({
Key
?
key
})
:
super
(
key:
key
);
@override
_BarcodeScannerWithZoomState
createState
()
=>
_BarcodeScannerWithZoomState
();
}
class
_BarcodeScannerWithZoomState
extends
State
<
BarcodeScannerWithZoom
>
with
SingleTickerProviderStateMixin
{
BarcodeCapture
?
barcode
;
MobileScannerController
controller
=
MobileScannerController
(
torchEnabled:
true
,
onPermissionSet:
(
hasPermission
)
{
// Do something with permission callback
},
);
bool
isStarted
=
true
;
double
_zoomFactor
=
0.0
;
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
backgroundColor:
Colors
.
black
,
body:
Builder
(
builder:
(
context
)
{
return
Stack
(
children:
[
MobileScanner
(
controller:
controller
,
fit:
BoxFit
.
contain
,
onDetect:
(
barcode
)
{
setState
(()
{
this
.
barcode
=
barcode
;
});
},
),
Align
(
alignment:
Alignment
.
bottomCenter
,
child:
Container
(
alignment:
Alignment
.
bottomCenter
,
height:
100
,
color:
Colors
.
black
.
withOpacity
(
0.4
),
child:
Column
(
children:
[
Slider
(
value:
_zoomFactor
,
onChanged:
(
value
)
{
setState
(()
{
_zoomFactor
=
value
;
controller
.
setZoomScale
(
value
);
});
},
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
[
IconButton
(
color:
Colors
.
white
,
icon:
ValueListenableBuilder
(
valueListenable:
controller
.
torchState
,
builder:
(
context
,
state
,
child
)
{
if
(
state
==
null
)
{
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
}
switch
(
state
as
TorchState
)
{
case
TorchState
.
off
:
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
case
TorchState
.
on
:
return
const
Icon
(
Icons
.
flash_on
,
color:
Colors
.
yellow
,
);
}
},
),
iconSize:
32.0
,
onPressed:
()
=>
controller
.
toggleTorch
(),
),
IconButton
(
color:
Colors
.
white
,
icon:
isStarted
?
const
Icon
(
Icons
.
stop
)
:
const
Icon
(
Icons
.
play_arrow
),
iconSize:
32.0
,
onPressed:
()
=>
setState
(()
{
isStarted
?
controller
.
stop
()
:
controller
.
start
();
isStarted
=
!
isStarted
;
}),
),
Center
(
child:
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
-
200
,
height:
50
,
child:
FittedBox
(
child:
Text
(
barcode
?.
barcodes
.
first
.
rawValue
??
'Scan something!'
,
overflow:
TextOverflow
.
fade
,
style:
Theme
.
of
(
context
)
.
textTheme
.
headline4
!
.
copyWith
(
color:
Colors
.
white
),
),
),
),
),
IconButton
(
color:
Colors
.
white
,
icon:
ValueListenableBuilder
(
valueListenable:
controller
.
cameraFacingState
,
builder:
(
context
,
state
,
child
)
{
if
(
state
==
null
)
{
return
const
Icon
(
Icons
.
camera_front
);
}
switch
(
state
as
CameraFacing
)
{
case
CameraFacing
.
front
:
return
const
Icon
(
Icons
.
camera_front
);
case
CameraFacing
.
back
:
return
const
Icon
(
Icons
.
camera_rear
);
}
},
),
iconSize:
32.0
,
onPressed:
()
=>
controller
.
switchCamera
(),
),
IconButton
(
color:
Colors
.
white
,
icon:
const
Icon
(
Icons
.
image
),
iconSize:
32.0
,
onPressed:
()
async
{
final
ImagePicker
picker
=
ImagePicker
();
// Pick an image
final
XFile
?
image
=
await
picker
.
pickImage
(
source
:
ImageSource
.
gallery
,
);
if
(
image
!=
null
)
{
if
(
await
controller
.
analyzeImage
(
image
.
path
))
{
if
(!
mounted
)
return
;
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
'Barcode found!'
),
backgroundColor:
Colors
.
green
,
),
);
}
else
{
if
(!
mounted
)
return
;
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
'No barcode found!'
),
backgroundColor:
Colors
.
red
,
),
);
}
}
},
),
],
),
],
),
),
),
],
);
},
),
);
}
}
...
...
example/lib/main.dart
View file @
6b0d799
...
...
@@ -3,6 +3,7 @@ import 'package:mobile_scanner_example/barcode_list_scanner_controller.dart';
import
'package:mobile_scanner_example/barcode_scanner_controller.dart'
;
import
'package:mobile_scanner_example/barcode_scanner_returning_image.dart'
;
import
'package:mobile_scanner_example/barcode_scanner_without_controller.dart'
;
import
'package:mobile_scanner_example/barcode_scanner_zoom.dart'
;
void
main
(
)
=>
runApp
(
const
MaterialApp
(
home:
MyHome
()));
...
...
@@ -62,6 +63,16 @@ class MyHome extends StatelessWidget {
},
child:
const
Text
(
'MobileScanner without Controller'
),
),
ElevatedButton
(
onPressed:
()
{
Navigator
.
of
(
context
).
push
(
MaterialPageRoute
(
builder:
(
context
)
=>
const
BarcodeScannerWithZoom
(),
),
);
},
child:
const
Text
(
'MobileScanner with zoom slider'
),
),
],
),
),
...
...
ios/Classes/MobileScanner.swift
View file @
6b0d799
...
...
@@ -207,6 +207,33 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
}
}
/// Set the zoom factor of the camera
func
setScale
(
_
scale
:
CGFloat
)
throws
{
if
(
device
==
nil
)
{
throw
MobileScannerError
.
torchWhenStopped
}
do
{
try
device
.
lockForConfiguration
()
var
maxZoomFactor
=
device
.
activeFormat
.
videoMaxZoomFactor
var
actualScale
=
(
scale
*
4
)
+
1
// Set maximum zoomrate of 5x
actualScale
=
min
(
5.0
,
actualScale
)
// Limit to max rate of camera
actualScale
=
min
(
maxZoomFactor
,
actualScale
)
// Limit to 1.0 scale
device
.
ramp
(
toVideoZoomFactor
:
actualScale
,
withRate
:
5
)
device
.
unlockForConfiguration
()
}
catch
{
throw
MobileScannerError
.
zoomError
(
error
)
}
}
/// Analyze a single image
func
analyzeImage
(
image
:
UIImage
,
position
:
AVCaptureDevice
.
Position
,
callback
:
@escaping
BarcodeScanningCallback
)
{
let
image
=
VisionImage
(
image
:
image
)
...
...
ios/Classes/MobileScannerError.swift
View file @
6b0d799
...
...
@@ -13,5 +13,7 @@ enum MobileScannerError: Error {
case
torchError
(
_
error
:
Error
)
case
cameraError
(
_
error
:
Error
)
case
torchWhenStopped
case
zoomWhenStopped
case
zoomError
(
_
error
:
Error
)
case
analyzerError
(
_
error
:
Error
)
}
...
...
ios/Classes/SwiftMobileScannerPlugin.swift
View file @
6b0d799
...
...
@@ -49,6 +49,8 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
toggleTorch
(
call
,
result
)
case
"analyzeImage"
:
analyzeImage
(
call
,
result
)
case
"setScale"
:
setScale
(
call
,
result
)
default
:
result
(
FlutterMethodNotImplemented
)
}
...
...
@@ -127,6 +129,33 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
result
(
nil
)
}
/// Toggles the zoomScale
private
func
setScale
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
var
scale
=
call
.
arguments
as?
CGFloat
if
(
scale
==
nil
)
{
result
(
FlutterError
(
code
:
"MobileScanner"
,
message
:
"You must provide a scale when calling setScale!"
,
details
:
nil
))
return
}
do
{
try
mobileScanner
.
setScale
(
scale
!
)
}
catch
MobileScannerError
.
zoomWhenStopped
{
result
(
FlutterError
(
code
:
"MobileScanner"
,
message
:
"Called setScale() while stopped!"
,
details
:
nil
))
}
catch
MobileScannerError
.
zoomError
(
let
error
)
{
result
(
FlutterError
(
code
:
"MobileScanner"
,
message
:
"Error while zooming."
,
details
:
error
))
}
catch
{
result
(
FlutterError
(
code
:
"MobileScanner"
,
message
:
"Error while zooming."
,
details
:
nil
))
}
result
(
nil
)
}
/// Analyzes a single image
private
func
analyzeImage
(
_
call
:
FlutterMethodCall
,
_
result
:
@escaping
FlutterResult
)
{
let
uiImage
=
UIImage
(
contentsOfFile
:
call
.
arguments
as?
String
??
""
)
...
...
lib/src/mobile_scanner_controller.dart
View file @
6b0d799
...
...
@@ -249,6 +249,19 @@ class MobileScannerController {
.
then
<
bool
>((
bool
?
value
)
=>
value
??
false
);
}
/// Set the zoomScale of the camera.
///
/// [zoomScale] must be within 0.0 and 1.0, where 1.0 is the max zoom, and 0.0
/// is zoomed out.
Future
<
void
>
setZoomScale
(
double
zoomScale
)
async
{
if
(
zoomScale
<
0
||
zoomScale
>
1
)
{
throw
MobileScannerException
(
'The zoomScale must be between 0 and 1.'
,
);
}
await
_methodChannel
.
invokeMethod
(
'setScale'
,
zoomScale
);
}
/// Disposes the MobileScannerController and closes all listeners.
///
/// If you call this, you cannot use this controller object anymore.
...
...
Please
register
or
login
to post a comment