Permission to access file: /storage/emulated/0/tesseract/tessdata/kaz.traineddata is denied

40 views Asked by At

I am new in android developing and I am trying to integrate tess two (Tesseract Android Tools) with my kotlin app to implement text recognition on android app. I've tried several approaches but any of them work. I've encountered errors before this: related to subfolder tessdata and path doesn't exist. I've tried all approaches that i found to integrate tesseract with android but none of them work.I tried also to downgrade my sdk version to 27(one of the solution relating to permission denial) but I coudn't downgrade gradle dependencies versions and all of the dependencies demand sdk34.

My build.gradle file

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.chaquo.python'
}

android {
    namespace 'com.example.nogpt'
    compileSdk 34

    defaultConfig {
        applicationId "com.example.nogpt"
        minSdk 26
        targetSdk 34
        versionCode 1
        versionName "1.0"

        ndk {
            // On Apple silicon, you can omit x86_64.
            abiFilters "arm64-v8a", "x86_64"
        }

        python{
            version = "3.8"
        }

        python{
            pip {
                install "numpy"
                install "opencv-python"
                install "pytesseract"

            }
        }

        python {
            buildPython("C:/Users/User/AppData/Local/Programs/Python/Python38-32/python.exe")
        }




        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    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'
    }
    sourceSets {
        main {
            java.srcDir("src/main/python")
        }
    }

    buildFeatures {
        viewBinding true
    }

    dataBinding {
        enabled true
    }
}

dependencies {

    implementation 'com.rmtheis:tess-two:9.1.0'

    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.11.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

HomeFragment.kt file:

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    lateinit var selectBtn: Button
    lateinit var predBtn: Button
    lateinit var resView: TextView
    lateinit var imageView: ImageView
    lateinit var textView2: TextView

    lateinit var bitmap: Bitmap

    private val REQUEST_CODE_STORAGE_PERMISSION = 100


    @SuppressLint("SdCardPath")
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val root: View = binding.root


        val textView2 = binding.textView2
        selectBtn = binding.selectbtn
        predBtn = binding.predictbtn
        resView = binding.textView2
        imageView = binding.imageView

        selectBtn.setOnClickListener(){
            var intent: Intent = Intent()
            intent.setAction(Intent.ACTION_GET_CONTENT)
            intent.setType("image/*")
            startActivityForResult(intent, 100)
        }

        // Inside your predBtn.setOnClickListener()
        predBtn.setOnClickListener() {

            val drawable = imageView.drawable
            val bitmap = (drawable as BitmapDrawable).bitmap

            //-----------------


            try {

               // val datapath = context?.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).toString()
                //val tessBaseAPI = TessBaseAPI()
                //tessBaseAPI.init(datapath, "kaz")


                // Initialize Tesseract API with trained data file
                //val tessBaseAPI = TessBaseAPI()
                //val dataPath = "${Environment.getExternalStorageDirectory()}/tesseract/" 
                //val tessDataPath = "$dataPath/tessdata/" 
               // val language = "kaz"

               // val dataPath = context?.filesDir.toString() + "/tesseract/"
              //  val language = "kaz"

                val tessBaseAPI = TessBaseAPI()
                tessBaseAPI.init("sdcard/tesseract/", "kaz");

               // val dir: File = File(dataPath)
              //  if (!dir.exists()) dir.mkdirs()
               // tessBaseAPI.init(dataPath, language)
                if (isStoragePermissionGranted()) {
                    // Если разрешения на чтение и запись уже предоставлены, выполняем необходимые действия
                    // Например, инициируем процесс OCR
                    performOCR(tessBaseAPI, bitmap)
                } else {
                    // Если разрешения не предоставлены, запросите их у пользователя
                    requestStoragePermission()
                }

                // Perform OCR on the bitmap
                val recognizedText = performOCR(tessBaseAPI, bitmap)

                // Display the recognized text
                textView2.text = recognizedText

                // Release resources
                tessBaseAPI.end()
            } catch (e: IOException) {
                // Handle IOException
                Log.e("HomeFragment", "Error loading trained data file: ${e.message}")
            }

        }

        return root
    }

    private fun isStoragePermissionGranted(): Boolean {
        val writePermission = ContextCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED

        val readPermission = ContextCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED

        return writePermission && readPermission
    }

    private fun requestStoragePermission() {
        ActivityCompat.requestPermissions(
            requireActivity(),
            arrayOf(
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
            ),
            REQUEST_CODE_STORAGE_PERMISSION
        )
    }



    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == 100 && resultCode == Activity.RESULT_OK){
            val uri = data?.data
            uri?.let {
                try {
                    val bitmap = MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, uri)
                    imageView.setImageBitmap(bitmap)
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }



    fun performOCR(tessBaseAPI: TessBaseAPI, bitmap: Bitmap): String {
        tessBaseAPI.setImage(bitmap)
        return tessBaseAPI.utF8Text
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

build.gradle(Project)

buildscript {
    ext {
        agp_version = '4.2.2'
        agp_version1 = '7.0.0'
        agp_version2 = '8.1.0'
    }
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.0' apply false
    id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
    id 'com.chaquo.python' version '15.0.1' apply false
}

fragment_home.xml file:




<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.home.HomeFragment">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:src="@drawable/ex"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <LinearLayout
        android:id="@+id/linLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/imageView"
        android:layout_centerHorizontal="true"
        android:orientation="vertical"
        app:layout_constraintTop_toBottomOf="@id/imageView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <!-- Add your LinearLayout content here -->

    </LinearLayout>

    <Button
        android:id="@+id/selectbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="select"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/linLayout" />

    <Button
        android:id="@+id/predictbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="188dp"
        android:text="predict"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/selectbtn"
        app:layout_constraintTop_toBottomOf="@id/linLayout" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="prediction is"
        android:textSize="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

</androidx.constraintlayout.widget.ConstraintLayout>

I am new in android developing and I am trying to integrate tess two (Tesseract Android Tools) with my kotlin app to implement text recognition on android app. I've tried several approaches but any of them work.

0

There are 0 answers