Refactor: extract image processor

This commit is contained in:
Ming Ming 2023-09-01 02:34:48 +08:00
parent 70a234a9b4
commit dbea0e0a55
249 changed files with 5644 additions and 4139 deletions

View file

@ -121,6 +121,6 @@ dependencies {
// fix crash on sdk33, need investigation
implementation "androidx.window:window:1.0.0"
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation 'com.nkming.nc_photos.np_android_log:np_android_log'
implementation 'com.nkming.nc_photos.np_android_core:np_android_core'
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.3"
}

View file

@ -1,6 +1,6 @@
package com.nkming.nc_photos
import com.nkming.nc_photos.np_android_log.LogConfig
import com.nkming.nc_photos.np_android_core.LogConfig
import io.flutter.BuildConfig
import io.flutter.app.FlutterApplication

View file

@ -1,7 +1,7 @@
package com.nkming.nc_photos
import android.content.Context
import com.nkming.nc_photos.np_android_log.logI
import com.nkming.nc_photos.np_android_core.logI
import java.util.Locale
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.HttpsURLConnection
@ -13,9 +13,7 @@ class CustomHostnameVerifier(context: Context) : HostnameVerifier {
* behavior
*/
override fun verify(hostname: String, session: SSLSession): Boolean {
return if (allowedHosts.contains(
hostname.lowercase(Locale.getDefault())
)) {
return if (allowedHosts.contains(hostname.lowercase(Locale.getDefault()))) {
// good
logI(
"CustomHostnameVerifier::verify",

View file

@ -13,8 +13,9 @@ class CustomKeyStoresTrustManager(keyStore: KeyStore) : X509TrustManager {
* Delegate to the default trust manager.
*/
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate>,
authType: String) {
override fun checkClientTrusted(
chain: Array<X509Certificate>, authType: String
) {
val defaultX509TrustManager = x509TrustManagers[0]
defaultX509TrustManager.checkClientTrusted(chain, authType)
}
@ -23,8 +24,9 @@ class CustomKeyStoresTrustManager(keyStore: KeyStore) : X509TrustManager {
* Loop over the trustmanagers until we find one that accepts our server
*/
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate>,
authType: String) {
override fun checkServerTrusted(
chain: Array<X509Certificate>, authType: String
) {
var defaultException: Exception? = null
for (tm in x509TrustManagers) {
try {
@ -54,13 +56,15 @@ class CustomKeyStoresTrustManager(keyStore: KeyStore) : X509TrustManager {
val factories = ArrayList<TrustManagerFactory>()
// The default Trustmanager with default keystore
val original = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
TrustManagerFactory.getDefaultAlgorithm()
)
original.init(null as KeyStore?)
factories.add(original)
// with custom keystore
val custom = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
TrustManagerFactory.getDefaultAlgorithm()
)
custom.init(keyStore)
factories.add(custom)

View file

@ -29,10 +29,12 @@ class CustomSSLSocketFactory(context: Context) : SSLSocketFactory() {
}
@Throws(IOException::class)
override fun createSocket(s: Socket, host: String, port: Int,
autoClose: Boolean): Socket {
override fun createSocket(
s: Socket, host: String, port: Int, autoClose: Boolean
): Socket {
return enableProtocols(
sslSocketFactory.createSocket(s, host, port, autoClose))
sslSocketFactory.createSocket(s, host, port, autoClose)
)
}
@Throws(IOException::class)
@ -41,10 +43,12 @@ class CustomSSLSocketFactory(context: Context) : SSLSocketFactory() {
}
@Throws(IOException::class)
override fun createSocket(host: String, port: Int, localHost: InetAddress,
localPort: Int): Socket {
override fun createSocket(
host: String, port: Int, localHost: InetAddress, localPort: Int
): Socket {
return enableProtocols(
sslSocketFactory.createSocket(host, port, localHost, localPort))
sslSocketFactory.createSocket(host, port, localHost, localPort)
)
}
@Throws(IOException::class)
@ -53,11 +57,17 @@ class CustomSSLSocketFactory(context: Context) : SSLSocketFactory() {
}
@Throws(IOException::class)
override fun createSocket(address: InetAddress, port: Int,
localAddress: InetAddress, localPort: Int): Socket {
override fun createSocket(
address: InetAddress,
port: Int,
localAddress: InetAddress,
localPort: Int
): Socket {
return enableProtocols(
sslSocketFactory.createSocket(address, port, localAddress,
localPort))
sslSocketFactory.createSocket(
address, port, localAddress, localPort
)
)
}
fun reload(context: Context) {

View file

@ -1,6 +0,0 @@
package com.nkming.nc_photos
interface K {
companion object {
}
}

View file

@ -6,11 +6,11 @@ import android.os.Bundle
import androidx.annotation.NonNull
import com.google.android.gms.maps.MapsInitializer
import com.google.android.gms.maps.OnMapsSdkInitializedCallback
import com.nkming.nc_photos.np_android_log.logD
import com.nkming.nc_photos.np_android_log.logE
import com.nkming.nc_photos.np_android_log.logI
import com.nkming.nc_photos.plugin.NcPhotosPlugin
import com.nkming.nc_photos.plugin.UriUtil
import com.nkming.nc_photos.np_android_core.UriUtil
import com.nkming.nc_photos.np_android_core.logD
import com.nkming.nc_photos.np_android_core.logE
import com.nkming.nc_photos.np_android_core.logI
import com.nkming.nc_photos.np_platform_image_processor.NpPlatformImageProcessorPlugin
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
@ -28,7 +28,7 @@ class MainActivity : FlutterActivity(), MethodChannel.MethodCallHandler,
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (intent.action == NcPhotosPlugin.ACTION_SHOW_IMAGE_PROCESSOR_RESULT) {
if (intent.action == NpPlatformImageProcessorPlugin.ACTION_SHOW_IMAGE_PROCESSOR_RESULT) {
val route = getRouteFromImageProcessorResult(intent) ?: return
logI(TAG, "Initial route: $route")
_initialRoute = route
@ -66,7 +66,7 @@ class MainActivity : FlutterActivity(), MethodChannel.MethodCallHandler,
override fun onNewIntent(intent: Intent) {
when (intent.action) {
NcPhotosPlugin.ACTION_SHOW_IMAGE_PROCESSOR_RESULT -> {
NpPlatformImageProcessorPlugin.ACTION_SHOW_IMAGE_PROCESSOR_RESULT -> {
val route = getRouteFromImageProcessorResult(intent) ?: return
logI(TAG, "Navigate to route: $route")
flutterEngine?.navigationChannel?.pushRoute(route)
@ -109,7 +109,7 @@ class MainActivity : FlutterActivity(), MethodChannel.MethodCallHandler,
private fun getRouteFromImageProcessorResult(intent: Intent): String? {
val resultUri = intent.getParcelableExtra<Uri>(
NcPhotosPlugin.EXTRA_IMAGE_RESULT_URI
NpPlatformImageProcessorPlugin.EXTRA_IMAGE_RESULT_URI
)
if (resultUri == null) {
logE(TAG, "Image result uri == null")

View file

@ -1,7 +1,7 @@
package com.nkming.nc_photos
import android.app.Activity
import com.nkming.nc_photos.np_android_log.logE
import com.nkming.nc_photos.np_android_core.logE
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import javax.net.ssl.HttpsURLConnection

View file

@ -2,8 +2,8 @@ package com.nkming.nc_photos
import android.content.Context
import android.util.Pair
import com.nkming.nc_photos.np_android_log.logE
import com.nkming.nc_photos.np_android_log.logI
import com.nkming.nc_photos.np_android_core.logE
import com.nkming.nc_photos.np_android_core.logI
import org.json.JSONObject
import java.io.File
import java.io.FileInputStream
@ -13,15 +13,20 @@ import java.time.OffsetDateTime
// Modifications to this class must also reflect on dart side
data class CertInfo(
val host: String, val sha1: String, val subject: String,
val issuer: String, val startValidity: OffsetDateTime,
val host: String,
val sha1: String,
val subject: String,
val issuer: String,
val startValidity: OffsetDateTime,
val endValidity: OffsetDateTime
) {
companion object {
fun fromJson(json: JSONObject): CertInfo {
return CertInfo(
json.getString("host"), json.getString("sha1"),
json.getString("subject"), json.getString("issuer"),
json.getString("host"),
json.getString("sha1"),
json.getString("subject"),
json.getString("issuer"),
OffsetDateTime.parse(json.getString("startValidity")),
OffsetDateTime.parse(json.getString("endValidity"))
)
@ -58,7 +63,8 @@ class SelfSignedCertManager {
} catch (e: Exception) {
logE(
"SelfSignedCertManager::readAllCerts",
"Failed to read certificate file: ${f.name}", e
"Failed to read certificate file: ${f.name}",
e
)
}
}

View file

@ -19,7 +19,8 @@ class ShareChannelHandler(activity: Activity) :
try {
shareItems(
call.argument("fileUris")!!,
call.argument("mimeTypes")!!, result
call.argument("mimeTypes")!!,
result
)
} catch (e: Throwable) {
result.error("systemException", e.toString(), null)
@ -29,7 +30,8 @@ class ShareChannelHandler(activity: Activity) :
"shareText" -> {
try {
shareText(
call.argument("text")!!, call.argument("mimeType"),
call.argument("text")!!,
call.argument("mimeType"),
result
)
} catch (e: Throwable) {
@ -40,7 +42,8 @@ class ShareChannelHandler(activity: Activity) :
"shareAsAttachData" -> {
try {
shareAsAttachData(
call.argument("fileUri")!!, call.argument("mimeType"),
call.argument("fileUri")!!,
call.argument("mimeType"),
result
)
} catch (e: Throwable) {
@ -55,7 +58,8 @@ class ShareChannelHandler(activity: Activity) :
}
private fun shareItems(
fileUris: List<String>, mimeTypes: List<String?>,
fileUris: List<String>,
mimeTypes: List<String?>,
result: MethodChannel.Result
) {
assert(fileUris.isNotEmpty())

View file

@ -1,5 +1,5 @@
include ':app'
includeBuild '../../np_android_log'
includeBuild '../../np_android_core'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()

View file

@ -1,6 +1,6 @@
import 'package:logging/logging.dart';
import 'package:nc_photos/stream_extension.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_platform_permission/np_platform_permission.dart';
Future<Map<String, int>> requestPermissionsForResult(
List<String> permissions) async {

View file

@ -27,6 +27,7 @@ import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_async/np_async.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_collection/np_collection.dart';
import 'package:np_platform_permission/np_platform_permission.dart';
import 'package:np_platform_util/np_platform_util.dart';
part 'enhanced_photo_browser.g.dart';

View file

@ -4,7 +4,7 @@ import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/mobile/android/android_info.dart';
import 'package:nc_photos/mobile/android/permission_util.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_platform_permission/np_platform_permission.dart';
import 'package:np_platform_util/np_platform_util.dart';
/// Handle platform permissions

View file

@ -23,7 +23,8 @@ import 'package:nc_photos/widget/image_editor/color_toolbar.dart';
import 'package:nc_photos/widget/image_editor/crop_controller.dart';
import 'package:nc_photos/widget/image_editor/transform_toolbar.dart';
import 'package:nc_photos/widget/image_editor_persist_option_dialog.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_platform_image_processor/np_platform_image_processor.dart';
import 'package:np_platform_raw_image/np_platform_raw_image.dart';
import 'package:np_ui/np_ui.dart';
class ImageEditorArguments {

View file

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/widget/image_editor/toolbar_button.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_collection/np_collection.dart';
import 'package:np_platform_image_processor/np_platform_image_processor.dart';
import 'package:np_string/np_string.dart';
import 'package:np_ui/np_ui.dart';

View file

@ -4,8 +4,9 @@ import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/pixel_image_provider.dart';
import 'package:nc_photos/widget/image_editor/transform_toolbar.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_platform_image_processor/np_platform_image_processor.dart';
import 'package:np_platform_raw_image/np_platform_raw_image.dart';
part 'crop_controller.g.dart';

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/widget/image_editor/toolbar_button.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_platform_image_processor/np_platform_image_processor.dart';
enum TransformToolType {
crop,

View file

@ -28,8 +28,8 @@ import 'package:nc_photos/widget/handler/permission_handler.dart';
import 'package:nc_photos/widget/image_editor_persist_option_dialog.dart';
import 'package:nc_photos/widget/selectable.dart';
import 'package:nc_photos/widget/settings/enhancement_settings.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_platform_image_processor/np_platform_image_processor.dart';
import 'package:np_platform_util/np_platform_util.dart';
import 'package:np_ui/np_ui.dart';

View file

@ -17,7 +17,6 @@ import 'package:nc_photos/mobile/self_signed_cert_manager.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/widget/page_visibility_mixin.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_platform_lock/np_platform_lock.dart';
import 'package:np_platform_util/np_platform_util.dart';
import 'package:to_string/to_string.dart';

View file

@ -1011,6 +1011,13 @@ packages:
relative: true
source: path
version: "1.0.0"
np_platform_image_processor:
dependency: "direct main"
description:
path: "../np_platform_image_processor"
relative: true
source: path
version: "0.0.1"
np_platform_lock:
dependency: "direct main"
description:
@ -1018,6 +1025,20 @@ packages:
relative: true
source: path
version: "0.0.1"
np_platform_permission:
dependency: "direct main"
description:
path: "../np_platform_permission"
relative: true
source: path
version: "0.0.1"
np_platform_raw_image:
dependency: "direct main"
description:
path: "../np_platform_raw_image"
relative: true
source: path
version: "0.0.1"
np_platform_util:
dependency: "direct main"
description:

View file

@ -109,8 +109,14 @@ dependencies:
path: ../np_log
np_math:
path: ../np_math
np_platform_image_processor:
path: ../np_platform_image_processor
np_platform_lock:
path: ../np_platform_lock
np_platform_permission:
path: ../np_platform_permission
np_platform_raw_image:
path: ../np_platform_raw_image
np_platform_util:
path: ../np_platform_util
np_string:

View file

@ -1,4 +1,4 @@
group 'com.nkming.nc_photos.np_android_log'
group 'com.nkming.nc_photos.np_android_core'
version '1.0-SNAPSHOT'
buildscript {
@ -26,7 +26,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
namespace 'com.nkming.nc_photos.np_android_log'
namespace 'com.nkming.nc_photos.np_android_core'
compileSdk 31
defaultConfig {
@ -51,4 +51,7 @@ android {
}
dependencies {
implementation "androidx.annotation:annotation:1.6.0"
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.exifinterface:exifinterface:1.3.6"
}

View file

@ -0,0 +1 @@
rootProject.name = "np_android_core"

View file

@ -0,0 +1,244 @@
package com.nkming.nc_photos.np_android_core
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.net.Uri
import androidx.exifinterface.media.ExifInterface
import java.io.InputStream
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
fun Bitmap.aspectRatio() = width / height.toFloat()
/**
* Recycle the bitmap after @c block returns.
*
* @param block
* @return
*/
@OptIn(ExperimentalContracts::class)
inline fun <T> Bitmap.use(block: (Bitmap) -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
try {
return block(this)
} finally {
recycle()
}
}
enum class BitmapResizeMethod {
FIT, FILL,
}
interface BitmapUtil {
companion object {
fun loadImageFixed(
context: Context, uri: Uri, targetW: Int, targetH: Int
): Bitmap {
val opt = loadImageBounds(context, uri)
val subsample = calcBitmapSubsample(
opt.outWidth,
opt.outHeight,
targetW,
targetH,
BitmapResizeMethod.FILL
)
if (subsample > 1) {
logD(
TAG,
"Subsample image to fixed: $subsample ${opt.outWidth}x${opt.outHeight} -> ${targetW}x$targetH"
)
}
val outOpt = BitmapFactory.Options().apply {
inSampleSize = subsample
}
val bitmap = loadImage(context, uri, outOpt)
if (subsample > 1) {
logD(TAG, "Bitmap subsampled: ${bitmap.width}x${bitmap.height}")
}
return Bitmap.createScaledBitmap(bitmap, targetW, targetH, true)
}
/**
* Load a bitmap
*
* If @c resizeMethod == FIT, make sure the size of the bitmap can fit
* inside the bound defined by @c targetW and @c targetH, i.e.,
* bitmap.w <= @c targetW and bitmap.h <= @c targetH
*
* If @c resizeMethod == FILL, make sure the size of the bitmap can
* completely fill the bound defined by @c targetW and @c targetH, i.e.,
* bitmap.w >= @c targetW and bitmap.h >= @c targetH
*
* If bitmap is smaller than the bound and @c shouldUpscale == true, it
* will be upscaled
*
* @param context
* @param uri
* @param targetW
* @param targetH
* @param resizeMethod
* @param isAllowSwapSide
* @param shouldUpscale
* @return
*/
fun loadImage(
context: Context,
uri: Uri,
targetW: Int,
targetH: Int,
resizeMethod: BitmapResizeMethod,
isAllowSwapSide: Boolean = false,
shouldUpscale: Boolean = true,
shouldFixOrientation: Boolean = false,
): Bitmap {
val opt = loadImageBounds(context, uri)
val shouldSwapSide =
isAllowSwapSide && opt.outWidth != opt.outHeight && (opt.outWidth >= opt.outHeight) != (targetW >= targetH)
val dstW = if (shouldSwapSide) targetH else targetW
val dstH = if (shouldSwapSide) targetW else targetH
val subsample = calcBitmapSubsample(
opt.outWidth, opt.outHeight, dstW, dstH, resizeMethod
)
if (subsample > 1) {
logD(
TAG,
"Subsample image to ${resizeMethod.name}: $subsample ${opt.outWidth}x${opt.outHeight} -> ${dstW}x$dstH" + (if (shouldSwapSide) " (swapped)" else "")
)
}
val outOpt = BitmapFactory.Options().apply {
inSampleSize = subsample
}
val bitmap = loadImage(context, uri, outOpt)
if (subsample > 1) {
logD(TAG, "Bitmap subsampled: ${bitmap.width}x${bitmap.height}")
}
if (bitmap.width < dstW && bitmap.height < dstH && !shouldUpscale) {
return if (shouldFixOrientation) {
fixOrientation(context, uri, bitmap)
} else {
bitmap
}
}
val result = when (resizeMethod) {
BitmapResizeMethod.FIT -> Bitmap.createScaledBitmap(
bitmap,
minOf(dstW, (dstH * bitmap.aspectRatio()).toInt()),
minOf(dstH, (dstW / bitmap.aspectRatio()).toInt()),
true
)
BitmapResizeMethod.FILL -> Bitmap.createScaledBitmap(
bitmap,
maxOf(dstW, (dstH * bitmap.aspectRatio()).toInt()),
maxOf(dstH, (dstW / bitmap.aspectRatio()).toInt()),
true
)
}
return if (shouldFixOrientation) {
fixOrientation(context, uri, result)
} else {
result
}
}
/**
* Rotate the image to its visible orientation
*/
private fun fixOrientation(
context: Context, uri: Uri, bitmap: Bitmap
): Bitmap {
return try {
openUriInputStream(context, uri)!!.use {
val iExif = ExifInterface(it)
val orientation =
iExif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)
logI(
TAG,
"[fixOrientation] Input file orientation: $orientation"
)
val rotate = when (orientation) {
ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_TRANSPOSE -> 90f
ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_FLIP_VERTICAL -> 180f
ExifInterface.ORIENTATION_ROTATE_270, ExifInterface.ORIENTATION_TRANSVERSE -> 270f
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> 0f
else -> return bitmap
}
val mat = Matrix()
mat.postRotate(rotate)
if (orientation == ExifInterface.ORIENTATION_FLIP_HORIZONTAL || orientation == ExifInterface.ORIENTATION_TRANSVERSE || orientation == ExifInterface.ORIENTATION_FLIP_VERTICAL || orientation == ExifInterface.ORIENTATION_TRANSPOSE) {
mat.postScale(-1f, 1f)
}
Bitmap.createBitmap(
bitmap, 0, 0, bitmap.width, bitmap.height, mat, true
)
}
} catch (e: Throwable) {
logE(
TAG,
"[fixOrientation] Failed fixing, assume normal orientation",
e
)
bitmap
}
}
private fun openUriInputStream(
context: Context, uri: Uri
): InputStream? {
return if (UriUtil.isAssetUri(uri)) {
context.assets.open(UriUtil.getAssetUriPath(uri))
} else {
context.contentResolver.openInputStream(uri)
}
}
private fun loadImageBounds(
context: Context, uri: Uri
): BitmapFactory.Options {
openUriInputStream(context, uri)!!.use {
val opt = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeStream(it, null, opt)
return opt
}
}
private fun loadImage(
context: Context, uri: Uri, opt: BitmapFactory.Options
): Bitmap {
openUriInputStream(context, uri)!!.use {
return BitmapFactory.decodeStream(it, null, opt)!!
}
}
private fun calcBitmapSubsample(
originalW: Int,
originalH: Int,
targetW: Int,
targetH: Int,
resizeMethod: BitmapResizeMethod
): Int {
return when (resizeMethod) {
BitmapResizeMethod.FIT -> maxOf(
originalW / targetW, originalH / targetH
)
BitmapResizeMethod.FILL -> minOf(
originalW / targetW, originalH / targetH
)
}
}
private const val TAG = "BitmapUtil"
}
}

View file

@ -0,0 +1,3 @@
package com.nkming.nc_photos.np_android_core
class PermissionException(message: String) : Exception(message)

View file

@ -0,0 +1,7 @@
package com.nkming.nc_photos.np_android_core
internal interface K {
companion object {
const val PERMISSION_REQUEST_CODE = 11011
}
}

View file

@ -1,4 +1,4 @@
package com.nkming.nc_photos.np_android_log
package com.nkming.nc_photos.np_android_core
class LogConfig {
companion object {

View file

@ -1,4 +1,4 @@
package com.nkming.nc_photos.plugin
package com.nkming.nc_photos.np_android_core
import android.content.ContentValues
import android.content.Context

View file

@ -0,0 +1,42 @@
package com.nkming.nc_photos.np_android_core
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
interface PermissionUtil {
companion object {
const val REQUEST_CODE = K.PERMISSION_REQUEST_CODE
fun request(
activity: Activity, vararg permissions: String
) {
ActivityCompat.requestPermissions(
activity, permissions, REQUEST_CODE
)
}
fun hasReadExternalStorage(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context, Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
}
fun requestReadExternalStorage(activity: Activity) = request(
activity, Manifest.permission.READ_EXTERNAL_STORAGE
)
fun hasWriteExternalStorage(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context, Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
}
fun requestWriteExternalStorage(activity: Activity) = request(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
}

View file

@ -0,0 +1,44 @@
package com.nkming.nc_photos.np_android_core
import android.graphics.Bitmap
import java.nio.ByteBuffer
/**
* Container of pixel data stored in RGBA format
*/
class Rgba8Image(
val pixel: ByteArray, val width: Int, val height: Int
) {
companion object {
fun fromJson(json: Map<String, Any>) = Rgba8Image(
json["pixel"] as ByteArray,
json["width"] as Int,
json["height"] as Int
)
fun fromBitmap(src: Bitmap): Rgba8Image {
assert(src.config == Bitmap.Config.ARGB_8888)
val buffer = ByteBuffer.allocate(src.width * src.height * 4).also {
src.copyPixelsToBuffer(it)
}
return Rgba8Image(buffer.array(), src.width, src.height)
}
}
fun toJson() = mapOf<String, Any>(
"pixel" to pixel,
"width" to width,
"height" to height,
)
fun toBitmap(): Bitmap {
return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
.apply {
copyPixelsFromBuffer(ByteBuffer.wrap(pixel))
}
}
init {
assert(pixel.size == width * height * 4)
}
}

View file

@ -1,9 +1,8 @@
package com.nkming.nc_photos.plugin
package com.nkming.nc_photos.np_android_core
import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import com.nkming.nc_photos.np_android_log.logI
interface UriUtil {
companion object {

View file

@ -1,9 +1,8 @@
package com.nkming.nc_photos.plugin
package com.nkming.nc_photos.np_android_core
import android.app.PendingIntent
import android.os.Build
import android.os.Bundle
import com.nkming.nc_photos.np_android_log.logI
import java.io.Serializable
import java.net.HttpURLConnection

View file

@ -1,21 +0,0 @@
# 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

View file

@ -1 +0,0 @@
rootProject.name = "np_android_log"

30
np_platform_image_processor/.gitignore vendored Normal file
View file

@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/

View file

@ -0,0 +1,33 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: f72efea43c3013323d1b95cff571f3c1caa37583
channel: stable
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f72efea43c3013323d1b95cff571f3c1caa37583
base_revision: f72efea43c3013323d1b95cff571f3c1caa37583
- platform: android
create_revision: f72efea43c3013323d1b95cff571f3c1caa37583
base_revision: f72efea43c3013323d1b95cff571f3c1caa37583
- platform: ios
create_revision: f72efea43c3013323d1b95cff571f3c1caa37583
base_revision: f72efea43c3013323d1b95cff571f3c1caa37583
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View file

@ -0,0 +1 @@
include: package:np_lints/np.yaml

View file

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

View file

@ -0,0 +1,76 @@
group 'com.nkming.nc_photos.np_platform_image_processor'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.8.20'
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
namespace 'com.nkming.nc_photos.np_platform_image_processor'
compileSdk 31
ndkVersion "23.2.8568313"
defaultConfig {
minSdk 21
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86_64"
}
consumerProguardFiles "consumer-rules.pro"
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
lintOptions {
disable 'LongLogTag'
}
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.3"
implementation "androidx.annotation:annotation:1.6.0"
implementation "androidx.core:core-ktx:1.10.1"
implementation "androidx.exifinterface:exifinterface:1.3.6"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.nkming.nc_photos.np_android_core:np_android_core'
}

View file

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip

View file

@ -0,0 +1,2 @@
rootProject.name = 'np_platform_image_processor'
includeBuild '../../np_android_core'

View file

@ -0,0 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nkming.nc_photos.np_platform_image_processor">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
<service
android:name=".ImageProcessorService"
android:exported="false" />
</application>
</manifest>

View file

@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("plugin")
project("np_platform_image_processor")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
@ -27,7 +27,7 @@ set_target_properties( renderscript-intrinsics-replacement-toolkit PROPERTIES IM
${dependency_DIR}/renderscript-intrinsics-replacement-toolkit/jni/${ANDROID_ABI}/librenderscript-toolkit.so )
add_library( # Sets the name of the library.
plugin
np_platform_image_processor
# Sets the library as a shared library.
SHARED
@ -62,7 +62,7 @@ add_library( # Sets the name of the library.
util.cpp
zero_dce.cpp
)
set_target_properties( plugin PROPERTIES COMPILE_OPTIONS -fopenmp )
set_target_properties( np_platform_image_processor PROPERTIES COMPILE_OPTIONS -fopenmp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
@ -79,7 +79,7 @@ find_library( # Sets the name of the path variable.
find_library( android-lib android )
target_include_directories( plugin PRIVATE
target_include_directories( np_platform_image_processor PRIVATE
${dependency_DIR}/tensorflowlite/headers
${dependency_DIR}/renderscript-intrinsics-replacement-toolkit/headers )
@ -88,7 +88,7 @@ target_include_directories( plugin PRIVATE
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
plugin
np_platform_image_processor
# Links the target library to the log library
# included in the NDK.

View file

@ -15,7 +15,7 @@
#include "tflite_wrapper.h"
#include "util.h"
using namespace plugin;
using namespace im_proc;
using namespace std;
using namespace tflite;
@ -60,7 +60,7 @@ private:
} // namespace
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_ArbitraryStyleTransfer_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_ArbitraryStyleTransfer_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jbyteArray style, jfloat weight) {
try {

View file

@ -7,7 +7,7 @@ extern "C" {
#endif
JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_ArbitraryStyleTransfer_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_ArbitraryStyleTransfer_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jbyteArray style, jfloat weight);

View file

@ -18,7 +18,7 @@
#include "util.h"
using namespace core;
using namespace plugin;
using namespace im_proc;
using namespace renderscript;
using namespace std;
using namespace tflite;
@ -151,7 +151,7 @@ private:
} // namespace
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_DeepLab3Portrait_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_DeepLab3Portrait_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jint radius) {
try {
@ -176,7 +176,7 @@ Java_com_nkming_nc_1photos_plugin_image_1processor_DeepLab3Portrait_inferNative(
}
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_DeepLab3ColorPop_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_DeepLab3ColorPop_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jfloat weight) {
try {

View file

@ -7,12 +7,12 @@ extern "C" {
#endif
JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_DeepLab3Portrait_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_DeepLab3Portrait_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jint radius);
JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_DeepLab3ColorPop_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_DeepLab3ColorPop_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height, jfloat weight);

View file

@ -16,7 +16,7 @@
#include "tflite_wrapper.h"
#include "util.h"
using namespace plugin;
using namespace im_proc;
using namespace std;
using namespace tflite;
@ -47,7 +47,7 @@ private:
} // namespace
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_Esrgan_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_Esrgan_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height) {
try {

View file

@ -7,7 +7,7 @@ extern "C" {
#endif
JNIEXPORT jbyteArray JNICALL
Java_com_nkming_nc_1photos_plugin_image_1processor_Esrgan_inferNative(
Java_com_nkming_nc_1photos_np_1platform_1image_1processor_processor_Esrgan_inferNative(
JNIEnv *env, jobject *thiz, jobject assetManager, jbyteArray image,
jint width, jint height);

Some files were not shown because too many files have changed in this diff Show more