import java.security.MessageDigest /** * PaddleOCR (https://github.com/PaddlePaddle/PaddleOCR) build script (Groovy). * * Created by TonyJiangWJ (https://github.com/TonyJiangWJ) on Aug 7, 2023. * Modified by TonyJiangWJ (https://github.com/TonyJiangWJ) as of Aug 11, 2023. * Modified by SuperMonster003 as of Sep 4, 2023. */ plugins { id "com.android.library" } def versions = new Versions("$rootDir/version.properties") def versionNdk = versions.ndk def versionCmake = versions.cmake def deployer = new LibDeployer(versions.opencv) android { namespace = "com.baidu.paddle.lite.ocr" ndkVersion versionNdk compileSdk 34 defaultConfig { /* minSdk 默认为 23,这里修改为与 AutoJs6 最低 SDK 版本一致的 24. */ minSdk 24 targetSdk 34 externalNativeBuild { cmake { cppFlags(([ "-std": "c++11", ].collect { "$it.key=$it.value" } + [ "-f": ["rtti", "exceptions"], "-W": "no-format", ].collect { it.value instanceof List ? it.value.collect { opt -> (it.key + opt) }.join("\u0020") : it.key + it.value }).join("\u0020")) arguments(*[ // @Hint by LZX284 on Sep 30, 2023. // ! "ANDROID_PLATFORM" 默认为 "android-23", 这里修改为与 AutoJs6 最低 SDK 版本一致的 24. ANDROID_PLATFORM: "android-24", ANDROID_STL : "c++_shared", ANDROID_ARM_NEON: "TRUE", ].collect { // @Hint by SuperMonster003 on Nov 12, 2023. // ! Do not add a space (nbsp) after "-D". // ! Reference: https://stackoverflow.com/questions/14887438/spacing-in-d-option-in-cmake "-D$it.key=$it.value" }) } } ndk { // noinspection ChromeOsAbiSupport abiFilters "arm64-v8a", "armeabi-v7a" ldLibs "jnigraphics" } } buildTypes { release { minifyEnabled false } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" version versionCmake } } } dependencies { implementation fileTree(include: ["*.jar"], dir: "libs") implementation project(path: ":libs:org.opencv-${versions.opencv}") implementation "androidx.core:core-ktx:1.12.0" implementation "androidx.preference:preference-ktx:1.2.1" } ext { versions.showInfo() deployer.deploy(project) } class LibDeployer { String version LinkedHashMap archive LibDeployer(String version) { this.version = version // @Hint by TonyJiangWJ on Aug 7, 2023. // ! 下载 OpenCV 源码包 (默认为 4.2.0). // ! 和 Auto.js 中的版本 (如 4.8.0) 不匹配会产生冲突, // ! 可按需修改 version.properties 中对应内容. this.archive = [ "src" : "https://github.com/opencv/opencv/releases/download" + "/$version/opencv-$version-android-sdk.zip", "dest": "OpenCV", ] } void deploy(Project project) { // Prepare cache folder for archives String cachePath = "cache" if (!project.file(cachePath).exists()) { project.mkdir(cachePath) } def messageDigest = MessageDigest.getInstance("MD5") messageDigest.update(archive.src.bytes) String cacheName = new BigInteger(1, messageDigest.digest()).toString(32) def cacheSrc = archive.src def cacheDest = project.file(new File(cachePath, "${cacheName}.zip")) def libDest = archive.dest def versionNameFileName = "opencv-${version}.version" def versionNameFile = project.file(new File(libDest, versionNameFileName)) boolean copyFiles = false if (cacheDest.exists()) { println("No need to download the OpenCV archive as the cache exists") if (versionNameFile.exists()) { println("No need to extract OpenCV cached archive as the version name file exists") } else { println("OpenCV cached archive needs to be extracted as the version name file doesn't exist") copyFiles = true } println("") } else if (versionNameFile.exists()) { println("No need to download files as the version name file exists") } else { def title = "Downloading the OpenCV archive file including libs and models..." def srcInfo = "Source: ${cacheSrc}" def destInfo = "Destination: ${cacheDest}" def hintInfo = [ "If the download gets stuck and won't finish,", "try downloading the source file with tools like IDM (Internet Download Manager),", "then renaming it into the destination path above.", ] def maxLength = [ [title, srcInfo, destInfo].max { it.length() }, hintInfo.max { it.length() }, ].max { it.length() }.length() def infoList = [ "=".repeat(maxLength), title, "-".repeat(maxLength), srcInfo, destInfo, "-".repeat(maxLength), hintInfo.join("\n"), "=".repeat(maxLength), "", ] infoList.forEach { println(it) } project.ant.get(src: cacheSrc, dest: cacheDest) // Force to copy files from the latest archive files copyFiles = true } // Extract the target archive if its dest path does not exists if (copyFiles) { if (project.file(libDest).exists()) { println("Delete old files in \"${project.file(libDest)}\"") project.delete(libDest) } project.copy { from project.zipTree("${cachePath}${File.separator}${cacheName}.zip") into libDest } println("All libs and models extracted into \"${project.file(libDest)}\"") if (!versionNameFile.exists()) { versionNameFile.createNewFile() println("Version name file \"${versionNameFileName}\" created") } println() } } } class Versions { String opencv String ndk String cmake Versions(String filePath) { File file = new File(filePath) if (!file.canRead()) { throw FileNotFoundException("Can't read file '$filePath'") } Properties properties = new Properties() properties.load(new FileInputStream(file)) opencv = properties["OPENCV_VERSION"] as String ndk = properties["NDK_VERSION"] as String cmake = properties["CMAKE_VERSION"] as String } void showInfo() { def title = "Version information for paddleocr library" def infoOpencv = "OpenCV version: $opencv" def infoNdk = "NDK version: $ndk" def infoCmake = "CMake version: $cmake" def maxLength = maxOf([title, infoOpencv, infoNdk, infoCmake].collect { it.length() }) [ "=".repeat(maxLength), title, "-".repeat(maxLength), infoOpencv, infoNdk, infoCmake, "=".repeat(maxLength), "", ].each { println(it) } } private static int maxOf(List integers) { int max = 0 integers.each { max = Math.max(max, it) } return max } }