迁移到Maven,更新文档,升级到1.5.1

pull/34/head
Jason 4 years ago
parent 0317d3e8de
commit 1780380bc9
  1. 1
      .gitignore
  2. 100
      README.md
  3. 2
      app/build.gradle
  4. 24
      app/src/androidTest/java/com/zww/sample/ExampleInstrumentedTest.kt
  5. 7
      app/src/main/AndroidManifest.xml
  6. 32
      app/src/main/java/com/zww/sample/JavaApp.java
  7. 23
      app/src/main/java/com/zww/sample/KtApp.kt
  8. 7
      app/src/main/java/com/zww/sample/MainActivity.kt
  9. 30
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  10. 5
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  11. 5
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  12. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  13. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  14. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  15. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  16. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  17. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  18. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  19. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  20. 4
      app/src/main/res/xml/network_security_config.xml
  21. 17
      app/src/test/java/com/zww/sample/ExampleUnitTest.kt
  22. 10
      build.gradle
  23. 5
      gradle.properties
  24. 179
      nsfw/build.gradle
  25. 2
      nsfw/src/main/AndroidManifest.xml
  26. 55
      nsfw/src/main/java/io/github/devzwy/nsfw/NSFWHelper.kt
  27. 2
      nsfw/src/main/java/io/github/devzwy/nsfw/utils.kt

1
.gitignore vendored

@ -1,5 +1,6 @@
*.iml *.iml
.gradle .gradle
/gradle.properties
/local.properties /local.properties
/.idea/caches /.idea/caches
/.idea/libraries /.idea/libraries

@ -18,57 +18,107 @@
![图片](https://github.com/devzwy/open_nsfw_android/blob/dev/img/demopic.png) ![图片](https://github.com/devzwy/open_nsfw_android/blob/dev/img/demopic.png)
### 开始使用(从1.3.9版本开始,依赖从JetPack移动到Maven仓库,可直接在项目中依赖,无需添加jetpack支持) ### 开始使用 (已从jCenter仓库迁移到Maven,注:新版本需要手动下载[nsfw.tflite](https://github.com/devzwy/open_nsfw_android/blob/dev/app/src/main/assets/nsfw.tflite)模型初始化使用)
- 开启tflite文件支持 - [下载模型文件,并放入assets目录下](https://github.com/devzwy/open_nsfw_android/blob/dev/app/src/main/assets/nsfw.tflite)
- 开启tflite文件读取支持(解决模型放在assets目录下无法读取的问题。如果模型不放在assets目录下可跳过该步骤)
``` ```
android { android {
...
aaptOptions { aaptOptions {
noCompress "tflite" noCompress "tflite"
} }
} }
``` ```
- 引入依赖(lastVersion更换为最新版本,最新版本为右边图片中的数字👉[ ![Download](https://api.bintray.com/packages/devzwy/maven/nsfw/images/download.svg) ](https://bintray.com/devzwy/maven/nsfw/_latestVersion)) - 引入依赖
``` ```
//可选 快速初始化扫描器,可免去初始化代码 dependencies {
implementation 'com.zwy.nsfw:nsfw_initializer:lastVersion' ...
//必须 扫描器核心文件 implementation 'io.github.devzwy:nsfw:1.5.1'
implementation 'com.zwy.nsfw:nsfw:lastVersion' }
//必须 tensorflow 支持库
implementation 'org.tensorflow:tensorflow-lite:2.1.0'
implementation 'org.tensorflow:tensorflow-lite-gpu:2.1.0'
```
- 初始化 ```
[模型下载](https://github.com/devzwy/open_nsfw_android/blob/dev/app/src/main/assets/nsfw.tflite) - 初始化(建议在Application中进行)
``` ```
//方式一,将模型文件放在Assets根目录下并命名为nsfw.tflite class KtApp : Application() {
NSFWHelper.init(context = this@Application) override fun onCreate() {
super.onCreate()
//开启日志输出,可选
NSFWHelper.openDebugLog()
//扫描前必须初始化
NSFWHelper.initHelper(
context = this)
//初始化api原型
/* NSFW初始化函数 内部日志默认关闭,调试环境可使用openDebugLog()开启日志*/
fun initHelper(
context: Context, //建议传入application,传入activity可能会有内存泄漏
modelPath: String? = null,//模型文件路径,为空时将默认从Assets下读取
isOpenGPU: Boolean = true, //是否开启GPU扫描加速,部分机型兼容不友好的可关闭。默认开启
numThreads: Int = 4 //扫描数据时内部分配的线程 默认4
)
//方式二,适用于产品对apk大小控制严格,无法将模型文件直接放在apk中,可在用户打开Apk后台静默下载后指定模型路径进行初始化 }
NSFWHelper.init(modelPath = "模型文件存放路径") }
```
//方式三,将模型文件放在Assets根目录下并命名为nsfw.tflite,引用该库可免去初始化代码 - 支持的api列表,带返回值的为同步,传入函数的为异步:
implementation 'com.zwy.nsfw:nsfw_initializer:lastVersion'
``` >> [NSFWHelper.getNSFWScore(file: File): NSFWScoreBean]()
- 使用: >> [getNSFWScore(file: File, onResult: ((NSFWScoreBean) -> Unit))]()
>> [getNSFWScore(filePath: String): NSFWScoreBean]()
>> [getNSFWScore(filePath: String, onResult: ((NSFWScoreBean) -> Unit))]()
>> [getNSFWScore(bitmap: Bitmap): NSFWScoreBean]()
>> [getNSFWScore(bitmap: Bitmap, onResult: ((NSFWScoreBean) -> Unit))]()
- 识别结果说明
``` ```
//val mNSFWScoreBean:NSFWScoreBean = File.getNSFWScore()
//val mNSFWScoreBean:NSFWScoreBean = Bitmap.getNSFWScore()
//val mNSFWScoreBean:NSFWScoreBean = NSFWHelper.getNSFWScore(bitmap)
mNSFWScoreBean.sfw ... 非涉黄数值 数值越大约安全 mNSFWScoreBean.sfw ... 非涉黄数值 数值越大约安全
mNSFWScoreBean.nsfw ... 涉黄数值 数值越大约危险 mNSFWScoreBean.nsfw ... 涉黄数值 数值越大约危险
mNSFWScoreBean.timeConsumingToLoadData ... 装载数据耗时 单位ms mNSFWScoreBean.timeConsumingToLoadData ... 装载数据耗时 单位ms
mNSFWScoreBean.timeConsumingToScanData ... 扫描图片耗时 单位ms mNSFWScoreBean.timeConsumingToScanData ... 扫描图片耗时 单位ms
``` ```
- 调用参考
```
//异步方式
NSFWHelper.getNSFWScore(item.bitmap) {
this.text =
"nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms"
if (it.nsfwScore > 0.7) {
this.setBackgroundColor(Color.parseColor("#C1FF0000"))
} else if (it.nsfwScore > 0.5) {
this.setBackgroundColor(Color.parseColor("#C1FF9800"))
} else {
this.setBackgroundColor(Color.parseColor("#803700B3"))
}
}
//同步方式
NSFWHelper.getNSFWScore(item.bitmap).let {
this.text =
"nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms"
if (it.nsfwScore > 0.7) {
this.setBackgroundColor(Color.parseColor("#C1FF0000"))
} else if (it.nsfwScore > 0.5) {
this.setBackgroundColor(Color.parseColor("#C1FF9800"))
} else {
this.setBackgroundColor(Color.parseColor("#803700B3"))
}
}
```
### 安卓手机直接[点我安装](http://d.6short.com/q9cv) ### 安卓手机直接[点我安装](http://d.6short.com/q9cv)
### 扫码下载 ### 扫码下载

@ -27,6 +27,7 @@ android {
} }
} }
aaptOptions { aaptOptions {
noCompress "tflite" noCompress "tflite"
} }
@ -61,4 +62,5 @@ dependencies {
// implementation project(path: ':nsfw_initializer') // implementation project(path: ':nsfw_initializer')
implementation project(path: ':nsfw') implementation project(path: ':nsfw')
// implementation 'io.github.devzwy:nsfw:1.5.0'
} }

@ -1,24 +0,0 @@
package com.zww.sample
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.zww.sample", appContext.packageName)
}
}

@ -2,17 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zww.sample"> package="com.zww.sample">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:name=".KtApp" android:name=".KtApp"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"

@ -1,32 +0,0 @@
package com.zww.sample;
import android.annotation.SuppressLint;
import android.app.Application;
import android.widget.Toast;
import io.github.devzwy.nsfw.NSFWHelper;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
public class JavaApp extends Application {
@SuppressLint("NewApi")
@Override
public void onCreate() {
super.onCreate();
NSFWHelper.INSTANCE.initHelper(this, this.getFilesDir().getPath() + "/nsfw.tflite", true, 4, new Function0<Unit>() {
@Override
public Unit invoke() {
Toast.makeText(JavaApp.this, "初始化成功", Toast.LENGTH_SHORT).show();
return null;
}
}, new Function1<String, Unit>() {
@Override
public Unit invoke(String s) {
Toast.makeText(JavaApp.this, s, Toast.LENGTH_SHORT).show();
return null;
}
});
}
}

@ -7,16 +7,21 @@ import io.github.devzwy.nsfw.NSFWHelper
class KtApp : Application() { class KtApp : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
//开启日志输出,可选
NSFWHelper.openDebugLog() NSFWHelper.openDebugLog()
//扫描前必须初始化
NSFWHelper.initHelper( NSFWHelper.initHelper(
context = this, context = this)
modelPath = "${this.filesDir.path}/nsfw.tflite",
isOpenGPU = true, //初始化api原型
onInitError = { /* NSFW初始化函数 内部日志默认关闭,调试环境可使用openDebugLog()开启日志*/
Toast.makeText(this, it, Toast.LENGTH_SHORT).show() // fun initHelper(
}, // context: Context, //建议传入application,传入activity可能会有内存泄漏
onInitSuccess = { // modelPath: String? = null,//模型文件路径,为空时将默认从Assets下读取
Toast.makeText(this, "初始化成功", Toast.LENGTH_SHORT).show() // isOpenGPU: Boolean = true, //是否开启GPU扫描加速,部分机型兼容不友好的可关闭。默认开启
}) // numThreads: Int = 4 //扫描数据时内部分配的线程 默认4
// )
} }
} }

@ -26,6 +26,8 @@ class MainActivity : BaseActivity() {
.diskCacheStrategy(DiskCacheStrategy.ALL) .diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.getView(R.id.iv)) .into(holder.getView(R.id.iv))
holder.getView<TextView>(R.id.tv).apply { holder.getView<TextView>(R.id.tv).apply {
//异步方式
NSFWHelper.getNSFWScore(item.bitmap) { NSFWHelper.getNSFWScore(item.bitmap) {
this.text = this.text =
"nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms" "nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms"
@ -38,8 +40,8 @@ class MainActivity : BaseActivity() {
} }
} }
// //同步方式
// item.nsfwScoreBean.let { // NSFWHelper.getNSFWScore(item.bitmap).let {
// this.text = // this.text =
// "nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms" // "nsfw:${it.nsfwScore}\nsfw:${it.sfwScore}\n扫描耗时:${it.timeConsumingToScanData} ms"
// if (it.nsfwScore > 0.7) { // if (it.nsfwScore > 0.7) {
@ -50,6 +52,7 @@ class MainActivity : BaseActivity() {
// this.setBackgroundColor(Color.parseColor("#803700B3")) // this.setBackgroundColor(Color.parseColor("#803700B3"))
// } // }
// } // }
} }
} }

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>

@ -1,17 +0,0 @@
package com.zww.sample
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

@ -1,16 +1,14 @@
buildscript { buildscript {
ext.kotlin_version = '1.3.72' ext.kotlin_version = '1.4.32'
ext.libVersion = '1.5.0' ext.libVersion = '1.5.1'
repositories { repositories {
mavenCentral()
jcenter() jcenter()
google() google()
mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.18" classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.18"
} }
} }

@ -3,3 +3,8 @@ kotlin.code.style=official
kotlin.coroutines=enable kotlin.coroutines=enable
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
signing.keyId=EFDF121D
### 创建密钥时的密码
signing.password=Aa112211....
### .gpg文件的路径
signing.secretKeyRingFile=/Users/zhaowenwen/.gnupg/secring.gpg

@ -1,23 +1,18 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
//apply plugin: 'com.github.dcendents.android-maven'
//apply plugin: 'com.jfrog.bintray'
apply plugin: 'org.jetbrains.dokka' apply plugin: 'org.jetbrains.dokka'
apply plugin: 'maven-publish' apply plugin: 'maven'
apply plugin: 'signing'
group 'com.zwy.nsfw'
version "$libVersion"
android { android {
compileSdkVersion 30 compileSdkVersion 30
buildToolsVersion "30.0.2" buildToolsVersion "30.0.2"
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 16
targetSdkVersion 30 targetSdkVersion 30
versionCode 139 versionCode 151
versionName "$libVersion" versionName "$libVersion"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -31,14 +26,14 @@ android {
} }
} }
sourceSets { // sourceSets {
main { // main {
java { // java {
include '**/*.java' // include '**/*.java'
include '**/*.kt' // include '**/*.kt'
} // }
} // }
} // }
} }
dependencies { dependencies {
@ -55,132 +50,60 @@ dependencies {
} }
//version = "$libVersion"
//group = "com.zwy.nsfw"
//publish {
// userOrg = 'devzwy'
// repoName = 'maven'
// artifactId = 'nsfw'
// desc = 'android端离线鉴黄库'
// website = 'https://github.com/devzwy'
//}
//
//tasks.withType(Javadoc) {//
// options.addStringOption('Xdoclint:none', '-quiet')
// options.addStringOption('encoding', 'UTF-8')
// options.addStringOption('charSet', 'UTF-8')
//}
def siteUrl = 'https://github.com/devzwy/open_nsfw_android' // (GitHub地址)
def gitUrl = 'https://github.com/devzwy/open_nsfw_android.git' // Git仓库的url
group = "io.github.devzwy" // ****groupId , com.squareup.okhttp3:okhttp:3.4.1com.squareup.okhttp3部分
Properties properties = new Properties() Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream()) properties.load(project.rootProject.file('local.properties').newDataInputStream())
def lUsername = properties.getProperty("username") def lUsername = properties.getProperty("username")
def lPassword = properties.getProperty("password") def lPassword = properties.getProperty("password")
publishing { group="io.github.devzwy"
version="$libVersion"
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: lUsername, password: lPassword)
}
pom.project {
name 'nsfw'
packaging 'jar'
description 'android端离线鉴黄库'
url 'https://github.com/devzwy/open_nsfw_android'
scm {
connection 'scm:git:https://github.com/devzwy/open_nsfw_android.git'
developerConnection 'scm:git:https://github.com/devzwy/open_nsfw_android.git'
url 'https://github.com/devzwy/open_nsfw_android'
}
publications {
//
publishMyProjectMiniexcel(MavenPublication) {
// jar包
// from components.java
// //
// artifact generateSourcesJar
// // javadoc
// artifact generateJavadoc
pom {
name = "nsfw"
description = "android端离线鉴黄库"
url = "https://github.com/devzwy/open_nsfw_android"
licenses { licenses {
license { license {
name = "The Apache License, Version 2.0" name 'The Apache License, Version 2.0'
url = "http://www.apache.org/licenses/LICENSE-2.0.txt" url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
} }
} }
developers { developers {
developer { developer {
id = "devzwy" id 'nsfw'
name = "devzwy" name 'dev_zwy'
email = "dev_zwy@aliyun.com" email 'dev_zwy@aliyun.com'
} }
} }
scm {
connection = gitUrl
developerConnection = gitUrl
url = siteUrl
} }
} }
} }
} }
// https://oss.sonatype.org/#nexus-search;
//Properties properties = new Properties()
//properties.load(project.rootProject.file('local.properties').newDataInputStream())
//bintray {
// user = properties.getProperty("bintray.username") // local.properties bintray.user
// key = properties.getProperty("bintray.password") // local.properties bintray.apikey
// configurations = ['archives']
signing {
repositories { sign configurations.archives
//configurations = ['archives']
// Release版本可在版本号后面带上'-RELEASE'
maven {
name 'Release'
url 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
credentials {
username = lUsername
password = lPassword
}
} }
// Snapshot快照版本必须在版本号后面加上'-SNAPSHOT'
// maven {
// name = 'Snapshot'
// url = 'https://oss.sonatype.org/content/repositories/snapshots'
// credentials {
// username = "${NEXUS_USERNAME}"
// password = "${NEXUS_PASSWORD}"
// }
// }
}
}
//install {
// repositories.mavenInstaller {
// pom {
// project {
// packaging 'aar'
// name 'nsfw' //
// url siteUrl
// licenses {
// license {
// name = 'The Apache Software License, Version 2.0'
// url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
// }
// }
// developers {
// developer {
// id 'z' //
// name 'Jason' //
// email 'dev_zwy@aliyun.com' //
// }
// }
// scm {
// connection gitUrl
// developerConnection gitUrl
// url siteUrl
// }
// }
// }
// }
//}
task generateSourcesJar(type: Jar) { task generateSourcesJar(type: Jar) {
group = 'jar' group = 'jar'
from android.sourceSets.main.java.srcDirs from android.sourceSets.main.java.srcDirs
@ -215,19 +138,3 @@ artifacts {
archives generateSourcesJar //sourcesJar archives generateSourcesJar //sourcesJar
} }
//Properties properties = new Properties()
//properties.load(project.rootProject.file('local.properties').newDataInputStream())
//bintray {
// user = properties.getProperty("bintray.user") // local.properties bintray.user
// key = properties.getProperty("bintray.apikey") // local.properties bintray.apikey
// configurations = ['archives']
// pkg {
// repo = "maven" //(****)bintray中自己新建仓库的名字
// name = "nsfw" //****JCenter上的项目名字com.squareup.okhttp3:okhttp:3.4.1okhttp
// websiteUrl = siteUrl
// vcsUrl = gitUrl
// licenses = ["Apache-2.0"]
// publish = true
// desc = 'android端离线鉴黄库'
// }
//}

@ -1,3 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zwy.nsfw"> package="io.github.devzwy.nsfw">
</manifest> </manifest>

@ -1,6 +1,7 @@
package io.github.devzwy.nsfw package io.github.devzwy.nsfw
import android.app.Application import android.content.Context
import android.content.res.AssetFileDescriptor
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color import android.graphics.Color
@ -13,16 +14,16 @@ import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.lang.Exception
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
import java.text.DecimalFormat import java.text.DecimalFormat
object NSFWHelper { object NSFWHelper {
/*为空时表示未初始化SDK*/ /*为空时表示未初始化SDK*/
private var nsfwApplication: Application? = null private var nsfwApplication: Context? = null
/*扫描器*/ /*扫描器*/
private lateinit var mInterpreter: Interpreter private lateinit var mInterpreter: Interpreter
@ -43,22 +44,17 @@ object NSFWHelper {
* [modelPath] 模型文件路径为空时将默认从Assets下读取 * [modelPath] 模型文件路径为空时将默认从Assets下读取
* [isOpenGPU] 是否开启GPU扫描加速部分机型兼容不友好的可关闭默认开启 * [isOpenGPU] 是否开启GPU扫描加速部分机型兼容不友好的可关闭默认开启
* [numThreads] 扫描数据时内部分配的线程 默认4 * [numThreads] 扫描数据时内部分配的线程 默认4
* [onInitSuccess] 初始化成功的回调
* [onInitError] 初始化失败的回调携带一个string
*/ */
fun initHelper( fun initHelper(
context: Application, context: Context,
modelPath: String? = null, modelPath: String? = null,
isOpenGPU: Boolean = true, isOpenGPU: Boolean = true,
numThreads: Int = 4, numThreads: Int = 4
onInitSuccess: (() -> Unit)? = null,
onInitError: ((String) -> Unit)? = null
) { ) {
nsfwApplication?.let { nsfwApplication?.let {
logD("NSFWHelper已初始化,自动跳过本次初始化!") logD("NSFWHelper已初始化,自动跳过本次初始化!")
onInitError?.let { it1 -> it1("请勿重复初始化") }
return return
} }
@ -72,6 +68,7 @@ object NSFWHelper {
logD("未传入模型路径,尝试从Assets下读取'nsfw.tflite'模型文件") logD("未传入模型路径,尝试从Assets下读取'nsfw.tflite'模型文件")
//指定模型为空时默认寻找assets目录下名称为nsfw.tflite的模型 //指定模型为空时默认寻找assets目录下名称为nsfw.tflite的模型
try { try {
mInterpreter = Interpreter( mInterpreter = Interpreter(
nsfwApplication!!.assets.openFd("nsfw.tflite") nsfwApplication!!.assets.openFd("nsfw.tflite")
.let { fileDescriptor -> .let { fileDescriptor ->
@ -82,15 +79,13 @@ object NSFWHelper {
) )
}, options }, options
) )
} catch (e: Exception) { } catch (mFileNotFoundException: FileNotFoundException) {
nsfwApplication = null nsfwApplication = null
logE("未从Assets下成功读取'nsfw.tflite'模型") logE("未从Assets下成功读取'nsfw.tflite'模型")
onInitError?.let { it("未从Assets下成功读取'nsfw.tflite'模型") }
throw NSFWException("未从Assets下成功读取'nsfw.tflite'模型")
return
} }
logD("从Assets下加载模型文件成功!") logD("从Assets下加载模型文件成功!")
@ -121,17 +116,13 @@ object NSFWHelper {
nsfwApplication = null nsfwApplication = null
logE("模型配置错误,读取失败") logE("模型配置错误,读取失败")
onInitError?.let { it("未能正确读取到模型文件 '${modelPath}'") } throw NSFWException("未能正确读取到模型文件 '${modelPath}'")
return
} }
} }
} }
logD("NSFWHelper初始化成功!${if (isOpenGPU) "GPU加速已成功开启" else "GPU加速未开启"}") logD("NSFWHelper初始化成功!${if (isOpenGPU) "GPU加速已成功开启" else "GPU加速未开启"}")
onInitSuccess?.let { it() }
} }
@ -169,24 +160,15 @@ object NSFWHelper {
* 同步扫描文件NSFW数值 * 同步扫描文件NSFW数值
*/ */
fun getNSFWScore(file: File): NSFWScoreBean { fun getNSFWScore(file: File): NSFWScoreBean {
nsfwApplication?.let {
return getNSFWScore(BitmapFactory.decodeFile(file.path)) return getNSFWScore(BitmapFactory.decodeFile(file.path))
} }
throw NSFWUnInitException()
}
/** /**
* 异步扫描文件NSFW数值 * 异步扫描文件NSFW数值
*/ */
fun getNSFWScore(file: File, onResult: ((NSFWScoreBean) -> Unit)) { fun getNSFWScore(file: File, onResult: ((NSFWScoreBean) -> Unit)) {
if (nsfwApplication == null) {
throw NSFWUnInitException()
}
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
getNSFWScore(BitmapFactory.decodeFile(file.path)).let { result -> getNSFWScore(BitmapFactory.decodeFile(file.path)).let { result ->
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -194,19 +176,15 @@ object NSFWHelper {
} }
} }
} }
} }
/** /**
* 同步扫描文件NSFW数值 * 同步扫描文件NSFW数值
*/ */
fun getNSFWScore(filePath: String): NSFWScoreBean { fun getNSFWScore(filePath: String): NSFWScoreBean {
nsfwApplication?.let {
return getNSFWScore(BitmapFactory.decodeFile(filePath)) return getNSFWScore(BitmapFactory.decodeFile(filePath))
} }
throw NSFWUnInitException()
}
/** /**
@ -214,10 +192,6 @@ object NSFWHelper {
*/ */
fun getNSFWScore(filePath: String, onResult: ((NSFWScoreBean) -> Unit)) { fun getNSFWScore(filePath: String, onResult: ((NSFWScoreBean) -> Unit)) {
if (nsfwApplication == null) {
throw NSFWUnInitException()
}
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
getNSFWScore(BitmapFactory.decodeFile(filePath)).let { result -> getNSFWScore(BitmapFactory.decodeFile(filePath)).let { result ->
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -225,6 +199,7 @@ object NSFWHelper {
} }
} }
} }
} }
/** /**
@ -268,7 +243,7 @@ object NSFWHelper {
} }
} }
} }
throw NSFWUnInitException() throw NSFWException("请调用NSFWHelper.init(...)函数后再试!")
} }
@ -289,10 +264,6 @@ object NSFWHelper {
// # 使用index关键字喂入模型 // # 使用index关键字喂入模型
// # 删除所有单维度的条目 // # 删除所有单维度的条目
// # 输出扫描结果 // # 输出扫描结果
if (nsfwApplication == null) {
logE("未初始化")
throw NSFWUnInitException()
}
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
getNSFWScore(bitmap).let { result -> getNSFWScore(bitmap).let { result ->

@ -24,6 +24,6 @@ fun Boolean.assetBoolean(onTrue: ()-> Unit,onFalse: ()-> Unit){
if (this) onTrue() else onFalse() if (this) onTrue() else onFalse()
} }
class NSFWUnInitException:Exception("请调用NSFWHelper.init(...)函数后再试!") class NSFWException(str:String):Exception(str)
data class CovertBitmapResultBean(val imgData: ByteBuffer,val exceTime:Long) data class CovertBitmapResultBean(val imgData: ByteBuffer,val exceTime:Long)

Loading…
Cancel
Save