diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4c3a57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +/.idea/ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..9623f2c --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,56 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.kbyai.idcardrecognition' + compileSdk 34 + + defaultConfig { + applicationId "com.kbyai.idcardrecognition" + minSdk 24 + targetSdk 34 + versionCode 5 + versionName "1.4" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + ndk { + abiFilters 'arm64-v8a', 'armeabi-v7a' + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.9.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + + implementation project(path: ':libidsdk') + + implementation 'com.itextpdf:itextpdf:5.5.10' + + // PDF library + implementation 'io.fotoapparat:fotoapparat:2.7.0' + + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/app/idcard.jks b/app/idcard.jks new file mode 100644 index 0000000..acdc3c1 Binary files /dev/null and b/app/idcard.jks differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/kbyai/idcardrecognition/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/kbyai/idcardrecognition/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..a729d63 --- /dev/null +++ b/app/src/androidTest/java/com/kbyai/idcardrecognition/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.kbyai.idcardrecognition + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.kbyai.idcardrecognition", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..af42416 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/kbyai/idcardrecognition/AboutActivity.kt b/app/src/main/java/com/kbyai/idcardrecognition/AboutActivity.kt new file mode 100644 index 0000000..1453be0 --- /dev/null +++ b/app/src/main/java/com/kbyai/idcardrecognition/AboutActivity.kt @@ -0,0 +1,150 @@ +package com.kbyai.idcardrecognition + +import android.content.Intent +import android.content.pm.ResolveInfo +import android.net.Uri +import android.os.Bundle +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import com.kbyai.idcardrecognition.R + + +class AboutActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_about) + + findViewById(R.id.txtMail).setOnClickListener { + val intent = Intent(Intent.ACTION_SEND) + intent.type = "plain/text" + intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("contact@kby-ai.com")) + intent.putExtra(Intent.EXTRA_SUBJECT, "License Request") + intent.putExtra(Intent.EXTRA_TEXT, "") + startActivity(Intent.createChooser(intent, "")) + } + + findViewById(R.id.txtWhatsapp).setOnClickListener { + val general = Intent(Intent.ACTION_VIEW, Uri.parse("https://com.whatsapp/kbyai")) + val generalResolvers: HashSet = HashSet() + val generalResolveInfo: List = packageManager.queryIntentActivities(general, 0) + for (info in generalResolveInfo) { + if (info.activityInfo.packageName != null) { + generalResolvers.add(info.activityInfo.packageName) + } + } + + val telegram = Intent(Intent.ACTION_VIEW, Uri.parse("https://wa.me/19092802609")) + var goodResolver = 0 + + val resInfo: List = packageManager.queryIntentActivities(telegram, 0) + if (!resInfo.isEmpty()) { + for (info in resInfo) { + if (info.activityInfo.packageName != null && !generalResolvers.contains(info.activityInfo.packageName)) { + goodResolver++ + telegram.setPackage(info.activityInfo.packageName) + } + } + } + + if (goodResolver != 1) { + telegram.setPackage(null) + } + if (telegram.resolveActivity(packageManager) != null) { + startActivity(telegram) + } + } + + findViewById(R.id.txtTelegram).setOnClickListener { + val general = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.com/kbyai")) + val generalResolvers: HashSet = HashSet() + val generalResolveInfo: List = packageManager.queryIntentActivities(general, 0) + for (info in generalResolveInfo) { + if (info.activityInfo.packageName != null) { + generalResolvers.add(info.activityInfo.packageName) + } + } + + val telegram = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/kbyai")) + var goodResolver = 0 + + val resInfo: List = packageManager.queryIntentActivities(telegram, 0) + if (!resInfo.isEmpty()) { + for (info in resInfo) { + if (info.activityInfo.packageName != null && !generalResolvers.contains(info.activityInfo.packageName)) { + goodResolver++ + telegram.setPackage(info.activityInfo.packageName) + } + } + } + + if (goodResolver != 1) { + telegram.setPackage(null) + } + if (telegram.resolveActivity(packageManager) != null) { + startActivity(telegram) + } + } + + findViewById(R.id.txtSkype).setOnClickListener { + val general = Intent(Intent.ACTION_VIEW, Uri.parse("https://com.skype/kbyai")) + val generalResolvers: HashSet = HashSet() + val generalResolveInfo: List = packageManager.queryIntentActivities(general, 0) + for (info in generalResolveInfo) { + if (info.activityInfo.packageName != null) { + generalResolvers.add(info.activityInfo.packageName) + } + } + + val telegram = Intent(Intent.ACTION_VIEW, Uri.parse("https://join.skype.com/invite/OffY2r1NUFev")) + var goodResolver = 0 + + val resInfo: List = packageManager.queryIntentActivities(telegram, 0) + if (!resInfo.isEmpty()) { + for (info in resInfo) { + if (info.activityInfo.packageName != null && !generalResolvers.contains(info.activityInfo.packageName)) { + goodResolver++ + telegram.setPackage(info.activityInfo.packageName) + } + } + } + + if (goodResolver != 1) { + telegram.setPackage(null) + } + if (telegram.resolveActivity(packageManager) != null) { + startActivity(telegram) + } + } + + findViewById(R.id.txtGitHub).setOnClickListener { + val general = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/kby-ai")) + val generalResolvers: HashSet = HashSet() + val generalResolveInfo: List = packageManager.queryIntentActivities(general, 0) + for (info in generalResolveInfo) { + if (info.activityInfo.packageName != null) { + generalResolvers.add(info.activityInfo.packageName) + } + } + + val telegram = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/kby-ai")) + var goodResolver = 0 + + val resInfo: List = packageManager.queryIntentActivities(telegram, 0) + if (!resInfo.isEmpty()) { + for (info in resInfo) { + if (info.activityInfo.packageName != null && !generalResolvers.contains(info.activityInfo.packageName)) { + goodResolver++ + telegram.setPackage(info.activityInfo.packageName) + } + } + } + + if (goodResolver != 1) { + telegram.setPackage(null) + } + if (telegram.resolveActivity(packageManager) != null) { + startActivity(telegram) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kbyai/idcardrecognition/CameraActivityKt.kt b/app/src/main/java/com/kbyai/idcardrecognition/CameraActivityKt.kt new file mode 100644 index 0000000..51496bb --- /dev/null +++ b/app/src/main/java/com/kbyai/idcardrecognition/CameraActivityKt.kt @@ -0,0 +1,141 @@ +package com.kbyai.idcardrecognition; + +import android.Manifest +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.graphics.Rect +import android.os.Bundle +import android.util.Log +import android.util.Size +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import com.kbyai.idsdk.IDSDK +import io.fotoapparat.Fotoapparat +import io.fotoapparat.parameter.Resolution +import io.fotoapparat.preview.Frame +import io.fotoapparat.preview.FrameProcessor +import io.fotoapparat.selector.back +import io.fotoapparat.view.CameraView +import org.json.JSONObject + +class CameraActivityKt : AppCompatActivity() { + + val TAG = CameraActivityKt::class.java.simpleName + val PREVIEW_WIDTH = 720 + val PREVIEW_HEIGHT = 1280 + + private lateinit var cameraView: CameraView + private lateinit var faceView: FaceView + private lateinit var fotoapparat: Fotoapparat + private lateinit var context: Context + private var documenName: String = "" + private var positionRect: Rect = Rect() + + private var recognized = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_camera_kt) + + context = this + cameraView = findViewById(R.id.preview) + faceView = findViewById(R.id.faceView) + + fotoapparat = Fotoapparat.with(this) + .into(cameraView) + .lensPosition(back()) + .frameProcessor(FaceFrameProcessor()) + .previewResolution { Resolution(PREVIEW_HEIGHT,PREVIEW_WIDTH) } + .build() + + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_DENIED + ) { + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1) + } else { + fotoapparat.start() + } + } + + override fun onResume() { + super.onResume() + recognized = false + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED + ) { + fotoapparat.start() + } + } + + override fun onPause() { + super.onPause() + fotoapparat.stop() + faceView.setDocumentInfos(null, "") + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == 1) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED + ) { + fotoapparat.start() + } + } + } + + inner class FaceFrameProcessor : FrameProcessor { + + override fun process(frame: Frame) { + + if(recognized == true) { + return + } + + val bitmap = IDSDK.yuv2Bitmap(frame.image, frame.size.width, frame.size.height, 6) + val result = IDSDK.idcardRecognition(bitmap) + + try { + val jsonResult = JSONObject(result) + val positionObj = jsonResult["Position"] as JSONObject + val hasMrz = jsonResult.has("MRZ") + documenName = jsonResult["Document Name"] as String + val quality = jsonResult["Quality"] as Int + val x1 = positionObj["x1"] as Int + val y1 = positionObj["y1"] as Int + val x2 = positionObj["x2"] as Int + val y2 = positionObj["y2"] as Int + positionRect = Rect(x1, y1, x2, y2) + if (quality > 86 && (documenName != "Unknown" || hasMrz == true)) { + recognized = true + + runOnUiThread { + faceView.setFrameSize(Size(bitmap.width, bitmap.height)) + faceView.setDocumentInfos(positionRect, documenName) + } + + runOnUiThread { + ResultActivity.resultString = jsonResult.toString() + val intent = Intent(context, ResultActivity::class.java) + startActivity(intent) + } + } + documenName = documenName + " " + quality + } catch (e1: Exception) { + documenName = "" + positionRect = Rect() + } + + runOnUiThread { + faceView.setFrameSize(Size(bitmap.width, bitmap.height)) + faceView.setDocumentInfos(positionRect, documenName) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kbyai/idcardrecognition/FaceView.java b/app/src/main/java/com/kbyai/idcardrecognition/FaceView.java new file mode 100644 index 0000000..77d1616 --- /dev/null +++ b/app/src/main/java/com/kbyai/idcardrecognition/FaceView.java @@ -0,0 +1,92 @@ +package com.kbyai.idcardrecognition; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Size; +import android.view.View; + +import androidx.annotation.Nullable; + +import java.util.List; + +public class FaceView extends View { + + private Context context; + private Paint realPaint; + private Paint spoofPaint; + + private Size frameSize; + + private Rect position; + + private String documentName; + + public FaceView(Context context) { + this(context, null); + + this.context = context; + init(); + } + + public FaceView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + + init(); + } + + public void init() { + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + + realPaint = new Paint(); + realPaint.setStyle(Paint.Style.STROKE); + realPaint.setStrokeWidth(3); + realPaint.setColor(Color.GREEN); + realPaint.setAntiAlias(true); + realPaint.setTextSize(50); + + spoofPaint = new Paint(); + spoofPaint.setStyle(Paint.Style.STROKE); + spoofPaint.setStrokeWidth(3); + spoofPaint.setColor(Color.RED); + spoofPaint.setAntiAlias(true); + spoofPaint.setTextSize(50); + } + + public void setFrameSize(Size frameSize) + { + this.frameSize = frameSize; + } + + public void setDocumentInfos(Rect position, String documentName) + { + this.position = position; + this.documentName = documentName; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if(position != null && !position.isEmpty()) { + float x_scale = this.frameSize.getWidth() / (float)canvas.getWidth(); + float y_scale = this.frameSize.getHeight() / (float)canvas.getHeight(); + + realPaint.setStrokeWidth(3); + realPaint.setStyle(Paint.Style.FILL_AND_STROKE); + canvas.drawText(documentName, (position.left / x_scale) + 10, (position.top / y_scale) - 30, realPaint); + + realPaint.setStyle(Paint.Style.STROKE); + realPaint.setStrokeWidth(5); + + canvas.drawRect(new Rect((int)(position.left / x_scale), (int)(position.top / y_scale), + (int)(position.right / x_scale), (int)(position.bottom / y_scale)), realPaint); + } + } +} diff --git a/app/src/main/java/com/kbyai/idcardrecognition/MainActivity.kt b/app/src/main/java/com/kbyai/idcardrecognition/MainActivity.kt new file mode 100644 index 0000000..7021b1f --- /dev/null +++ b/app/src/main/java/com/kbyai/idcardrecognition/MainActivity.kt @@ -0,0 +1,76 @@ +package com.kbyai.idcardrecognition + +import android.content.Intent +import android.graphics.Bitmap +import android.os.Bundle +import android.util.Log +import android.widget.Button +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import com.kbyai.idsdk.IDSDK +import org.json.JSONObject +import android.widget.Toast + +class MainActivity : AppCompatActivity() { + companion object { + private val SELECT_PHOTO_REQUEST_CODE = 1 + private val IDCARD_RECOGNITION_REQUEST_CODE = 2 + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + var ret = IDSDK.setActivation( + "ItbU8EMHg1dFLQgkk7h4IP+Zu/CkrfVWGEEmOY5IjiAmxvcEU1fqJ3C76+CoZ2zit816tchptZDn\n" + + "61TCAtHBKVV6Fub3tmoyHl8kJz4pOMX4OQ2qUEhyvI2WzRN8/FUZ6ZAdUGw/4I3SJfTxdxD55MJ3\n" + + "/rOt5C8OLJvR8sBTx+ltt9J2hGMO+T5Jf1ndrj00djN6/v5PtcQqFJiDQTbVdFyCm6E4w66Mgx63\n" + + "FWtYRgBd1qC3f9FFeFvICppd2BvEsuaw2n/8/6qDj6X1kTdYgYRtRD5VKPTnmAV04sV90EA/3Hm5\n" + + "xLeVxrn4C9SiQJ5t9T1g0EX0pOrY7SPlfLUocg==" + ) + if(ret == IDSDK.SDK_SUCCESS) { + ret = IDSDK.init(this) + } + + findViewById