Skip to content

Commit

Permalink
added v11.4.9
Browse files Browse the repository at this point in the history
  • Loading branch information
sMaltsevAcuant committed Dec 22, 2020
1 parent 3727b5a commit 27d96af
Show file tree
Hide file tree
Showing 26 changed files with 642 additions and 451 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Acuant Android SDK v11.4.8
# Acuant Android SDK v11.4.9
**December 2020**

See [https://github.com/Acuant/AndroidSDKV11/releases](https://github.com/Acuant/AndroidSDKV11/releases) for release notes.
Expand Down Expand Up @@ -189,18 +189,18 @@ The SDK includes the following modules:
- Add the following dependencies

implementation 'com.acuant:acuantcommon:11.4.8'
implementation 'com.acuant:acuantcamera:11.4.8'
implementation 'com.acuant:acuantimagepreparation:11.4.8'
implementation 'com.acuant:acuantdocumentprocessing:11.4.8'
implementation 'com.acuant:acuantechipreader:11.4.8'
implementation 'com.acuant:acuantfacematch:11.4.8'
implementation 'com.acuant:acuanthgliveness:11.4.8'
implementation ('com.acuant:acuantipliveness:11.4.8'){
implementation 'com.acuant:acuantcommon:11.4.9'
implementation 'com.acuant:acuantcamera:11.4.9'
implementation 'com.acuant:acuantimagepreparation:11.4.9'
implementation 'com.acuant:acuantdocumentprocessing:11.4.9'
implementation 'com.acuant:acuantechipreader:11.4.9'
implementation 'com.acuant:acuantfacematch:11.4.9'
implementation 'com.acuant:acuanthgliveness:11.4.9'
implementation ('com.acuant:acuantipliveness:11.4.9'){
transitive = true
}
implementation 'com.acuant:acuantfacecapture:11.4.8'
implementation 'com.acuant:acuantpassiveliveness:11.4.8'
implementation 'com.acuant:acuantfacecapture:11.4.9'
implementation 'com.acuant:acuantpassiveliveness:11.4.9'

- Acuant also relies on Google Play services dependencies, which are pre-installed on almost all Android devices.

Expand Down
2 changes: 1 addition & 1 deletion acuantcamera/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
android:screenOrientation="portrait" />

<activity
android:name="com.acuant.acuantcamera.camera.mrz.cameraone.DocumentCaptureActivity"
android:name="com.acuant.acuantcamera.camera.mrz.cameraone.MrzCaptureActivity"
android:screenOrientation="portrait" />
</application>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

abstract class AcuantBaseCameraFragment : Fragment() {

Expand All @@ -58,11 +60,12 @@ abstract class AcuantBaseCameraFragment : Fragment() {
protected lateinit var textView: TextView
protected lateinit var imageView: ImageView
protected lateinit var detectors: List<IAcuantDetector>
private val previewBoundThreshold = 10
protected var pointXOffset = 0
protected var pointYOffset = 0
private lateinit var orientationListener: AcuantOrientationListener
protected var oldPoints : Array<Point>? = null
private lateinit var displaySize: Point
internal var targetSmallDocDpi: Int = 0
internal var targetLargeDocDpi: Int = 0
internal var barCodeString: String? = null
internal var isCapturing = false
/**
Expand Down Expand Up @@ -141,8 +144,6 @@ abstract class AcuantBaseCameraFragment : Fragment() {
*/
private var sensorOrientation = 0

private val previewBoundThreshold = 25

protected abstract fun setTextFromState(state: CameraState)

override fun onCreate(savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -177,17 +178,23 @@ abstract class AcuantBaseCameraFragment : Fragment() {


internal fun isDocumentInFrame(points: Array<Point>?) : Boolean{
if(points != null){
val startY = 0 //textureView.width.toFloat() / 2 - previewSize.height.toFloat() / 2
val startX = 0 //textureView.height.toFloat() / 2 - previewSize.width.toFloat() / 2
val endY = startY + displaySize.x //textureView.width
val endX = startX + displaySize.y //textureView.height
if (points != null) {
val minOffset = 0.025f
val startY = displaySize.x * minOffset//textureView.width
val startX = displaySize.y * minOffset //textureView.height.toFloat() / 2 - previewSize.width.toFloat() / 2
val endY = displaySize.x * (1 - minOffset)//textureView.width
val endX = displaySize.y * (1 - minOffset)//textureView.height

// Log.d("WTF", "start: $startX,$startY\tend: $endX,$endY")
// if (previewSize.width.toFloat()/displaySize.y < previewSize.height.toFloat()/displaySize.x) {
// endX = (previewSize.width * displaySize.x/previewSize.height.toFloat()).toInt()
// } else {
// endY = (previewSize.height * displaySize.y/previewSize.width.toFloat()).toInt()
// }
// Log.d("WTF", "start: $startX,$startY\tend: $endX,$endY")

for (point in points) {
if( point.x < -previewBoundThreshold ||
point.x > endX + previewBoundThreshold ||
(textureView.width - point.y) < -previewBoundThreshold ||
(textureView.width - point.y) > endY + previewBoundThreshold) {
if (point.x < startX || point.y < startY || point.x > endX || point.y > endY) {
return false
}
}
Expand Down Expand Up @@ -284,6 +291,7 @@ abstract class AcuantBaseCameraFragment : Fragment() {

override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
configureTransform(width, height)
textureView.requestLayout()
}

override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
Expand Down Expand Up @@ -470,36 +478,49 @@ abstract class AcuantBaseCameraFragment : Fragment() {
val maxPreviewWidth = if (swappedDimensions) displaySize.y else displaySize.x
val maxPreviewHeight = if (swappedDimensions) displaySize.x else displaySize.y

val largestJpeg = Collections.max(
val bestJpeg = Collections.max(
listOf(*map.getOutputSizes(ImageFormat.JPEG)),
CompareSizesByArea())

// val bestJpeg = chooseBestCaptureSize(listOf(*map.getOutputSizes(ImageFormat.JPEG)), maxPreviewWidth, maxPreviewHeight)

// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java),
rotatedPreviewWidth, rotatedPreviewHeight,
maxPreviewWidth, maxPreviewHeight)

targetSmallDocDpi = (previewSize.width * SMALL_DOC_DPI_SCALE_VALUE).toInt()
targetLargeDocDpi = (previewSize.width * LARGE_DOC_DPI_SCALE_VALUE).toInt()
maxPreviewWidth, maxPreviewHeight, bestJpeg)

imageReader = ImageReader.newInstance(previewSize.width , previewSize.height,
ImageFormat.YUV_420_888, /*maxImages*/ 3).apply {
setOnImageAvailableListener(onFrameImageAvailableListener, backgroundHandler)
}

captureImageReader = ImageReader.newInstance(largestJpeg.width, largestJpeg.height,
captureImageReader = ImageReader.newInstance(bestJpeg.width, bestJpeg.height,
ImageFormat.JPEG, /*maxImages*/ 1).apply {
setOnImageAvailableListener(onCaptureImageAvailableListener, backgroundHandler)
}

val scaledWidth: Int
val scaledHeight: Int

if (rotatedPreviewWidth/previewSize.width.toFloat() < rotatedPreviewHeight/previewSize.height.toFloat()) {
scaledWidth = rotatedPreviewWidth
scaledHeight = (previewSize.height * rotatedPreviewWidth/previewSize.width.toFloat()).toInt()
} else {
scaledWidth = (previewSize.width * rotatedPreviewHeight/previewSize.height.toFloat()).toInt()
scaledHeight = rotatedPreviewHeight
}

pointXOffset = (rotatedPreviewWidth - scaledWidth)/2
pointYOffset = (rotatedPreviewHeight - scaledHeight)/2

// We fit the aspect ratio of TextureView to the size of preview we picked.
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
textureView.setMax(maxPreviewWidth, maxPreviewHeight)
//textureView.setMax(maxPreviewWidth, maxPreviewHeight)
textureView.setAspectRatio(previewSize.width, previewSize.height)
} else {
textureView.setMax(maxPreviewHeight, maxPreviewWidth)
//textureView.setMax(maxPreviewHeight, maxPreviewWidth)
textureView.setAspectRatio(previewSize.height, previewSize.width)
}

Expand Down Expand Up @@ -573,6 +594,7 @@ abstract class AcuantBaseCameraFragment : Fragment() {
throw RuntimeException("Time out waiting to lock camera opening.")
}
manager.openCamera(cameraId, stateCallback, backgroundHandler)
textureView.requestLayout()
} catch (e: CameraAccessException) {
Log.e(TAG, e.toString())
} catch (e: InterruptedException) {
Expand Down Expand Up @@ -606,7 +628,7 @@ abstract class AcuantBaseCameraFragment : Fragment() {
*/
private fun startBackgroundThread() {
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
backgroundHandler = Handler(backgroundThread?.looper)
backgroundHandler = Handler(backgroundThread?.looper ?: throw IllegalStateException("Background thread was null in a place where it can not/should not be null."))
}

/**
Expand Down Expand Up @@ -888,17 +910,30 @@ abstract class AcuantBaseCameraFragment : Fragment() {
*/
private const val STATE_PICTURE_TAKEN = 4

/**
* Target DPI for preview size 1920x1080 = 350
* SMALL_DOC_DPI_SCALE_VALUE = target_dpi/preview_size_width
*/
private const val SMALL_DOC_DPI_SCALE_VALUE = .18229
private const val RATIO_TOLERANCE = 0.1f

/**
* Target DPI for preview size 1920x1080 = 225
* LARGE_DOC_DPI_SCALE_VALUE = target_dpi/preview_size_width
*/
private const val LARGE_DOC_DPI_SCALE_VALUE = .11719
@Suppress("unused")
@JvmStatic private fun chooseBestCaptureSize(sizes: List<Size>, screenWidth: Int, screenHeight: Int) : Size {
val targetSmallSide = min(screenHeight, screenWidth)
val targetLargeSide = max(screenHeight, screenWidth)

val sortedSizes = sizes.sortedWith(CompareSizesByArea())

val minSize = sortedSizes[0].width * sortedSizes[0].height * 0.75f

for (option in sortedSizes) {

val currentSmallSide = min(option.height, option.width)
val currentLargeSide = max(option.height, option.width)

if (abs(currentLargeSide.toFloat()/currentSmallSide - targetLargeSide.toFloat()/targetSmallSide) < RATIO_TOLERANCE &&
currentLargeSide * currentSmallSide > minSize) {
return option
}
}

return sortedSizes[0]
}

/**
* Given `choices` of `Size`s supported by a camera, choose the smallest one that
Expand All @@ -920,28 +955,41 @@ abstract class AcuantBaseCameraFragment : Fragment() {
textureViewWidth: Int,
textureViewHeight: Int,
maxWidth: Int,
maxHeight: Int
maxHeight: Int,
captureSize: Size
): Size {

val targetRatio = captureSize.width.toFloat()/captureSize.height
// Collect the supported resolutions that are at least as big as the preview Surface
val bigEnough = ArrayList<Size>()
val bigEnoughGood = ArrayList<Size>()
val bigEnoughBad = ArrayList<Size>()
// Collect the supported resolutions that are smaller than the preview Surface
val notBigEnough = ArrayList<Size>()
val notBigEnoughGood = ArrayList<Size>()
val notBigEnoughBad = ArrayList<Size>()
for (option in choices) {
if (option.width <= maxWidth && option.height <= maxHeight ) {
if (option.width >= textureViewWidth && option.height >= textureViewHeight) {
bigEnough.add(option)
if (abs(option.width.toFloat()/option.height - targetRatio) < RATIO_TOLERANCE) {
bigEnoughGood.add(option)
} else {
bigEnoughBad.add(option)
}
} else {
notBigEnough.add(option)
if (abs(option.width.toFloat()/option.height - targetRatio) < RATIO_TOLERANCE) {
notBigEnoughGood.add(option)
} else {
notBigEnoughBad.add(option)
}
}
}
}

// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
return when {
bigEnough.size > 0 -> Collections.min(bigEnough, CompareSizesByArea())
notBigEnough.size > 0 -> Collections.max(notBigEnough, CompareSizesByArea())
bigEnoughGood.size > 0 -> Collections.min(bigEnoughGood, CompareSizesByArea())
notBigEnoughGood.size > 0 -> Collections.max(notBigEnoughGood, CompareSizesByArea())
bigEnoughBad.size > 0 -> Collections.min(bigEnoughBad, CompareSizesByArea())
notBigEnoughBad.size > 0 -> Collections.max(notBigEnoughBad, CompareSizesByArea())
else -> {
Log.e(TAG, "Couldn't find any suitable preview size")
choices[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class AcuantCameraActivity : AppCompatActivity(), ICameraActivityFinish {
} else {
val cameraIntent = Intent(
this@AcuantCameraActivity,
com.acuant.acuantcamera.camera.mrz.cameraone.DocumentCaptureActivity::class.java
com.acuant.acuantcamera.camera.mrz.cameraone.MrzCaptureActivity::class.java
)

cameraIntent.putExtra(ACUANT_EXTRA_CAMERA_OPTIONS, options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.graphics.*
import android.graphics.drawable.Drawable
import android.os.*
import android.support.v4.app.ActivityCompat
import android.util.Size
import android.util.SparseIntArray
import android.view.*
import com.acuant.acuantcamera.R
Expand All @@ -15,9 +16,7 @@ import com.acuant.acuantcamera.detector.barcode.AcuantBarcodeDetectorHandler
import com.acuant.acuantcamera.detector.document.AcuantDocumentDetectorHandler
import com.acuant.acuantcamera.detector.document.AcuantDocumentDetector
import com.acuant.acuantcamera.overlay.DocRectangleView
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.math.sqrt
import kotlin.math.*

class AcuantDocCameraFragment : AcuantBaseCameraFragment(),
ActivityCompat.OnRequestPermissionsResultCallback, AcuantDocumentDetectorHandler, AcuantBarcodeDetectorHandler {
Expand Down Expand Up @@ -52,31 +51,26 @@ class AcuantDocCameraFragment : AcuantBaseCameraFragment(),
holdTextDrawable = activity!!.getDrawable(R.drawable.camera_text_config_hold)
}

private fun getTargetDpi(isPassport : Boolean): Int{
return if(isPassport){
targetLargeDocDpi
}
else{
targetSmallDocDpi
}
}

private fun scalePoints(points: Array<Point>) : Array<Point> {
val scaledPoints = points.copyOf()
val scaledPointY = textureView.height.toFloat() / previewSize.width.toFloat()
val scaledPointX = textureView.width.toFloat() / previewSize.height.toFloat()
rectangleView.setWidth(textureView.width.toFloat())

scaledPoints.forEach {
it.x = (it.x * scaledPointY).toInt()
it.y = (it.y * scaledPointX).toInt()
points.apply {
this.forEach {
it.x = (it.x * scaledPointY).toInt()
it.y = (it.y * scaledPointX).toInt()
it.y -= pointYOffset
it.x += pointXOffset
}
}

return scaledPoints
}

private fun drawBorder(points: Array<Point>?){
if(points != null){
if(points != null) {
rectangleView.setAndDrawPoints(points)
}
else{
Expand Down Expand Up @@ -132,7 +126,7 @@ class AcuantDocCameraFragment : AcuantBaseCameraFragment(),
setTextFromState(CameraState.NotInFrame)
resetTimer()
}
croppedImage.dpi < getTargetDpi(croppedImage.isPassport) -> {
!isAcceptableDistance(detectedPoints, Size(textureView.width, textureView.height)) -> {
unlockFocus()
rectangleView.setViewFromState(CameraState.MoveCloser)
setTextFromState(CameraState.MoveCloser)
Expand Down Expand Up @@ -284,6 +278,24 @@ class AcuantDocCameraFragment : AcuantBaseCameraFragment(),

internal const val TOO_SLOW_FOR_AUTO_THRESHOLD: Long = 130

fun isAcceptableDistance(points: Array<Point>?, screenSize: Size): Boolean {
if (points != null) {
val shortSide = min(distance(points[0], points[1]), distance(points[0], points[3]))
val largeSide = max(distance(points[0], points[1]), distance(points[0], points[3]))
val screenShortSide = min(screenSize.width, screenSize.height).toFloat()
val screenLargeSide = max(screenSize.width, screenSize.height).toFloat()

if (shortSide > 0.75 * screenShortSide || largeSide > 0.75 * screenLargeSide) {
return true
}
}
return false
}

private fun distance(pointA: Point, pointB: Point): Float {
return sqrt( (pointA.x - pointB.x).toFloat().pow(2) + (pointA.y - pointB.y).toFloat().pow(2))
}

/**
* Conversion from screen rotation to JPEG orientation.
*/
Expand Down
Loading

0 comments on commit 27d96af

Please sign in to comment.