kotlin 2.0.21, coil3

This commit is contained in:
T8RIN
2024-11-15 01:13:31 +03:00
parent e839f10346
commit a7e22d9add
48 changed files with 257 additions and 527 deletions

View File

@ -17,7 +17,7 @@
@file:Suppress("UnstableApiUsage")
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
id("com.android.application")
@ -28,6 +28,7 @@ plugins {
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
id("com.mikepenz.aboutlibraries.plugin")
id("org.jetbrains.kotlin.plugin.compose")
}
android {
@ -38,14 +39,14 @@ android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
applicationId = "ru.tech.imageresizershrinker"
minSdk = libs.versions.androidMinSdk.get().toIntOrNull()
targetSdk = libs.versions.androidTargetSdk.get().toIntOrNull()
versionCode = libs.versions.versionCode.get().toIntOrNull()
versionName = System.getenv("VERSION_NAME") ?: libs.versions.versionName.get()
archivesName.set("image-toolbox-$versionName${if (isFoss) "-foss" else ""}")
setProperty("archivesBaseName", "image-toolbox-$versionName${if (isFoss) "-foss" else ""}")
}
androidResources {
@ -92,12 +93,10 @@ android {
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = javaVersion.toString()
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.fromTarget(libs.versions.jvmTarget.get()))
}
}
buildFeatures {

View File

@ -17,6 +17,9 @@
@file:Suppress("UnstableApiUsage")
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
id("com.android.test")
id("org.jetbrains.kotlin.android")
@ -39,8 +42,10 @@ android {
targetCompatibility = JavaVersion.toVersion(libs.versions.jvmTarget.get())
}
kotlinOptions {
jvmTarget = libs.versions.jvmTarget.get()
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.fromTarget(libs.versions.jvmTarget.get()))
}
}
buildTypes {

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@ -30,8 +31,8 @@ java {
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
@ -39,6 +40,7 @@ dependencies {
compileOnly(libs.agp.gradle)
compileOnly(libs.kotlin.gradle)
compileOnly(libs.detekt.gradle)
compileOnly(libs.compose.compiler.gradle)
}
gradlePlugin {

View File

@ -17,35 +17,19 @@
import com.android.build.api.dsl.LibraryExtension
import com.t8rin.imagetoolbox.configureCompose
import com.t8rin.imagetoolbox.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType
@Suppress("UNUSED")
class ImageToolboxLibraryComposePlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
dependencies {
"implementation"(libs.findLibrary("androidx.material3").get())
"implementation"(libs.findLibrary("androidx.material3.window.sizeclass").get())
"implementation"(libs.findLibrary("androidx.material").get())
"implementation"(libs.findLibrary("androidx.material.icons.extended").get())
}
apply(plugin = "com.android.library")
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
extensions.configure<LibraryExtension> {
configureCompose(this)
}
tasks.withType<KotlinCompile> {
compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:strongSkipping=true",
)
}
configureCompose(extensions.getByType<LibraryExtension>())
}
}
}

View File

@ -19,6 +19,11 @@ package com.t8rin.imagetoolbox
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag
internal fun Project.configureCompose(
commonExtension: CommonExtension<*, *, *, *, *, *>,
@ -28,15 +33,20 @@ internal fun Project.configureCompose(
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.findVersion("compose.compiler").get().toString()
}
kotlinOptions {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
"${project.rootProject.projectDir.absolutePath}/compose_compiler_config.conf"
)
dependencies {
"implementation"(libs.findLibrary("androidx.material3").get())
"implementation"(libs.findLibrary("androidx.material3.window.sizeclass").get())
"implementation"(libs.findLibrary("androidx.material").get())
"implementation"(libs.findLibrary("androidx.material.icons.extended").get())
}
}
extensions.configure<ComposeCompilerGradlePluginExtension> {
featureFlags = setOf(
ComposeFeatureFlag.OptimizeNonSkippingGroups
)
stabilityConfigurationFile =
rootProject.layout.projectDirectory.file("compose_compiler_config.conf")
}
}

View File

@ -20,11 +20,14 @@ package com.t8rin.imagetoolbox
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.gradle.kotlin.dsl.provideDelegate
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *, *, *>,
@ -72,26 +75,9 @@ internal fun Project.configureKotlinAndroid(
disable += "UsingMaterialAndMaterial3Libraries"
disable += "ModifierParameter"
}
kotlinOptions {
freeCompilerArgs += listOf(
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.ui.unit.ExperimentalUnitApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
)
jvmTarget = javaVersion.toString()
}
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = javaVersion.toString()
}
}
configureKotlin<KotlinAndroidProjectExtension>()
dependencies {
add("coreLibraryDesugaring", libs.findLibrary("desugaring").get())
@ -103,6 +89,28 @@ val Project.javaVersion: JavaVersion
libs.findVersion("jvmTarget").get().toString()
)
fun CommonExtension<*, *, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) {
(this as ExtensionAware).extensions.configure("kotlinOptions", block)
}
/**
* Configure base Kotlin options
*/
private inline fun <reified T : KotlinTopLevelExtension> Project.configureKotlin() = configure<T> {
// Treat all Kotlin warnings as errors (disabled by default)
// Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
val warningsAsErrors: String? by project
when (this) {
is KotlinAndroidProjectExtension -> compilerOptions
is KotlinJvmProjectExtension -> compilerOptions
else -> TODO("Unsupported project extension $this ${T::class}")
}.apply {
jvmTarget = JvmTarget.fromTarget(libs.findVersion("jvmTarget").get().toString())
allWarningsAsErrors = warningsAsErrors.toBoolean()
freeCompilerArgs.addAll(
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.ui.unit.ExperimentalUnitApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
)
}
}

View File

@ -34,6 +34,7 @@ buildscript {
classpath(libs.baselineprofile.gradle)
classpath(libs.detekt.gradle)
classpath(libs.aboutlibraries.gradle)
classpath(libs.compose.compiler.gradle)
}
}

View File

@ -24,10 +24,13 @@ android.namespace = "ru.tech.imageresizershrinker.core.data"
dependencies {
api(libs.coil)
api(libs.coilCompose)
api(libs.coilNetwork)
api(libs.ktor)
implementation(libs.coilGif)
implementation(libs.coilSvg)
implementation(libs.androidx.compose.ui.graphics)
api(libs.datastore.preferences.android)
implementation(libs.avif.coder.coil) {

View File

@ -1,177 +0,0 @@
/*
* ImageToolbox is an image editor for android
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* You should have received a copy of the Apache License
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package ru.tech.imageresizershrinker.core.data.coil
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import coil.ImageLoader
import coil.decode.DecodeResult
import coil.decode.Decoder
import coil.fetch.SourceResult
import coil.request.Options
import coil.size.Scale
import coil.size.Size
import coil.size.pxOrElse
import com.awxkee.jxlcoder.JxlAnimatedImage
import com.awxkee.jxlcoder.JxlResizeFilter
import com.awxkee.jxlcoder.PreferredColorConfig
import com.awxkee.jxlcoder.ScaleMode
import com.awxkee.jxlcoder.animation.AnimatedDrawable
import com.awxkee.jxlcoder.animation.JxlAnimatedStore
import kotlinx.coroutines.runInterruptible
import okio.BufferedSource
import okio.ByteString.Companion.toByteString
internal class AnimatedJxlDecoderCoil2(
private val source: SourceResult,
private val options: Options,
private val context: Context,
private val preheatFrames: Int,
private val exceptionLogger: ((Exception) -> Unit)? = null,
) : Decoder {
override suspend fun decode(): DecodeResult? = runInterruptible {
try {
// ColorSpace is preferred to be ignored due to lib is trying to handle all color profile by itself
val sourceData = source.source.source().readByteArray()
var mPreferredColorConfig: PreferredColorConfig = when (options.config) {
Bitmap.Config.ALPHA_8 -> PreferredColorConfig.RGBA_8888
Bitmap.Config.RGB_565 -> if (options.allowRgb565) PreferredColorConfig.RGB_565 else PreferredColorConfig.DEFAULT
Bitmap.Config.ARGB_8888 -> PreferredColorConfig.RGBA_8888
else -> PreferredColorConfig.DEFAULT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && options.config == Bitmap.Config.RGBA_F16) {
mPreferredColorConfig = PreferredColorConfig.RGBA_F16
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && options.config == Bitmap.Config.HARDWARE) {
mPreferredColorConfig = PreferredColorConfig.HARDWARE
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && options.config == Bitmap.Config.RGBA_1010102) {
mPreferredColorConfig = PreferredColorConfig.RGBA_1010102
}
if (options.size == Size.ORIGINAL) {
val originalImage = JxlAnimatedImage(
byteArray = sourceData,
preferredColorConfig = mPreferredColorConfig
)
return@runInterruptible DecodeResult(
drawable = originalImage.drawable(),
isSampled = false
)
}
val dstWidth = options.size.width.pxOrElse { 0 }
val dstHeight = options.size.height.pxOrElse { 0 }
val scaleMode = when (options.scale) {
Scale.FILL -> ScaleMode.FILL
Scale.FIT -> ScaleMode.FIT
}
val originalImage = JxlAnimatedImage(
byteArray = sourceData,
preferredColorConfig = mPreferredColorConfig,
scaleMode = scaleMode,
jxlResizeFilter = JxlResizeFilter.BILINEAR
)
DecodeResult(
drawable = originalImage.drawable(
dstWidth = dstWidth,
dstHeight = dstHeight
),
isSampled = true
)
} catch (e: Exception) {
exceptionLogger?.invoke(e)
return@runInterruptible null
}
}
private fun JxlAnimatedImage.drawable(
dstWidth: Int = 0,
dstHeight: Int = 0
): Drawable = if (numberOfFrames > 1) {
AnimatedDrawable(
frameStore = JxlAnimatedStore(
jxlAnimatedImage = this,
targetWidth = dstWidth,
targetHeight = dstHeight
),
preheatFrames = preheatFrames,
firstFrameAsPlaceholder = true
)
} else {
BitmapDrawable(
context.resources,
getFrame(
frame = 0,
scaleWidth = dstWidth,
scaleHeight = dstHeight
)
)
}
class Factory(
private val context: Context,
private val preheatFrames: Int = 6,
private val exceptionLogger: ((Exception) -> Unit)? = null,
) : Decoder.Factory {
override fun create(
result: SourceResult,
options: Options,
imageLoader: ImageLoader,
) = if (isJXL(result.source.source())) {
AnimatedJxlDecoderCoil2(
source = result,
options = options,
context = context,
preheatFrames = preheatFrames,
exceptionLogger = exceptionLogger,
)
} else null
companion object {
private val MAGIC_1 = byteArrayOf(0xFF.toByte(), 0x0A).toByteString()
private val MAGIC_2 = byteArrayOf(
0x0.toByte(),
0x0.toByte(),
0x0.toByte(),
0x0C.toByte(),
0x4A,
0x58,
0x4C,
0x20,
0x0D,
0x0A,
0x87.toByte(),
0x0A
).toByteString()
private fun isJXL(source: BufferedSource): Boolean {
return source.rangeEquals(0, MAGIC_1) || source.rangeEquals(
0,
MAGIC_2
)
}
}
}
}

View File

@ -1,128 +0,0 @@
/*
* ImageToolbox is an image editor for android
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* You should have received a copy of the Apache License
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package ru.tech.imageresizershrinker.core.data.coil
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import coil.ImageLoader
import coil.decode.DecodeResult
import coil.decode.Decoder
import coil.fetch.SourceResult
import coil.request.Options
import coil.size.Scale
import coil.size.pxOrElse
import com.radzivon.bartoshyk.avif.coder.HeifCoder
import com.radzivon.bartoshyk.avif.coder.PreferredColorConfig
import com.radzivon.bartoshyk.avif.coder.ScaleMode
import kotlinx.coroutines.runInterruptible
import okio.ByteString.Companion.encodeUtf8
internal class HeifDecoderCoil2(
private val source: SourceResult,
private val options: Options,
private val exceptionLogger: ((Exception) -> Unit)? = null,
) : Decoder {
private val coder = HeifCoder()
override suspend fun decode(): DecodeResult? = runInterruptible {
try {
// ColorSpace is preferred to be ignored due to lib is trying to handle all color profile by itself
val sourceData = source.source.source().readByteArray()
var mPreferredColorConfig: PreferredColorConfig = when (options.config) {
Bitmap.Config.ALPHA_8 -> PreferredColorConfig.RGBA_8888
Bitmap.Config.RGB_565 -> if (options.allowRgb565) PreferredColorConfig.RGB_565 else PreferredColorConfig.DEFAULT
Bitmap.Config.ARGB_8888 -> PreferredColorConfig.RGBA_8888
else -> PreferredColorConfig.DEFAULT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && options.config == Bitmap.Config.RGBA_F16) {
mPreferredColorConfig = PreferredColorConfig.RGBA_F16
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && options.config == Bitmap.Config.HARDWARE) {
mPreferredColorConfig = PreferredColorConfig.HARDWARE
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && options.config == Bitmap.Config.RGBA_1010102) {
mPreferredColorConfig = PreferredColorConfig.RGBA_1010102
}
if (options.size == coil.size.Size.ORIGINAL) {
val originalImage =
coder.decode(
sourceData,
preferredColorConfig = mPreferredColorConfig
)
return@runInterruptible DecodeResult(
BitmapDrawable(
options.context.resources,
originalImage
), false
)
}
val dstWidth = options.size.width.pxOrElse { 0 }
val dstHeight = options.size.height.pxOrElse { 0 }
val scaleMode = when (options.scale) {
Scale.FILL -> ScaleMode.FILL
Scale.FIT -> ScaleMode.FIT
}
val originalImage =
coder.decodeSampled(
sourceData,
dstWidth,
dstHeight,
preferredColorConfig = mPreferredColorConfig,
scaleMode,
)
return@runInterruptible DecodeResult(
BitmapDrawable(
options.context.resources,
originalImage
), true
)
} catch (e: Exception) {
exceptionLogger?.invoke(e)
return@runInterruptible null
}
}
class Factory : Decoder.Factory {
override fun create(
result: SourceResult,
options: Options,
imageLoader: ImageLoader
): Decoder? {
return if (AVAILABLE_BRANDS.any {
result.source.source().rangeEquals(4, it)
}) HeifDecoderCoil2(result, options) else null
}
companion object {
private val MIF = "ftypmif1".encodeUtf8()
private val MSF = "ftypmsf1".encodeUtf8()
private val HEIC = "ftypheic".encodeUtf8()
private val HEIX = "ftypheix".encodeUtf8()
private val HEVC = "ftyphevc".encodeUtf8()
private val HEVX = "ftyphevx".encodeUtf8()
private val AVIF = "ftypavif".encodeUtf8()
private val AVIS = "ftypavis".encodeUtf8()
private val AVAILABLE_BRANDS = listOf(MIF, MSF, HEIC, HEIX, HEVC, HEVX, AVIF, AVIS)
}
}
}

View File

@ -17,8 +17,9 @@
package ru.tech.imageresizershrinker.core.data.coil
import coil.intercept.Interceptor
import coil.request.ImageResult
import coil3.intercept.Interceptor
import coil3.request.ImageResult
import coil3.request.transformations
import com.t8rin.logger.makeLog
import javax.inject.Inject
@ -28,7 +29,7 @@ internal class TimeMeasureInterceptor @Inject constructor() : Interceptor {
chain: Interceptor.Chain
): ImageResult {
val time = System.currentTimeMillis()
val result = chain.proceed(chain.request)
val result = chain.proceed()
val endTime = System.currentTimeMillis()
val delta = endTime - time

View File

@ -19,16 +19,20 @@ package ru.tech.imageresizershrinker.core.data.di
import android.content.Context
import android.os.Build
import coil.Coil
import coil.ComponentRegistry
import coil.ImageLoader
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.decode.SvgDecoder
import coil.imageLoader
import coil.util.DebugLogger
import coil.util.Logger
import coil3.ComponentRegistry
import coil3.ImageLoader
import coil3.SingletonImageLoader
import coil3.annotation.DelicateCoilApi
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.imageLoader
import coil3.request.allowHardware
import coil3.svg.SvgDecoder
import coil3.util.DebugLogger
import coil3.util.Logger
import com.awxkee.jxlcoder.coil.AnimatedJxlDecoder
import com.gemalto.jp2.coil.Jpeg2000Decoder
import com.github.awxkee.avifcoil.decoder.HeifDecoder
import com.t8rin.awebp.coil.AnimatedWebPDecoder
import com.t8rin.djvu_coder.coil.DjvuDecoder
import com.t8rin.psd.coil.PsdDecoder
@ -40,8 +44,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import oupson.apng.coil.AnimatedPngDecoder
import ru.tech.imageresizershrinker.core.data.coil.AnimatedJxlDecoderCoil2
import ru.tech.imageresizershrinker.core.data.coil.HeifDecoderCoil2
import ru.tech.imageresizershrinker.core.data.coil.TimeMeasureInterceptor
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.core.resources.BuildConfig
@ -50,6 +52,7 @@ import ru.tech.imageresizershrinker.core.resources.BuildConfig
@InstallIn(SingletonComponent::class)
internal object ImageLoaderModule {
@OptIn(DelicateCoilApi::class)
@Provides
fun provideImageLoader(
@ApplicationContext context: Context,
@ -58,13 +61,13 @@ internal object ImageLoaderModule {
dispatchersHolder: DispatchersHolder
): ImageLoader = context.imageLoader.newBuilder()
.components(componentRegistry)
.decoderDispatcher(dispatchersHolder.decodingDispatcher)
.fetcherDispatcher(dispatchersHolder.ioDispatcher)
.transformationDispatcher(dispatchersHolder.defaultDispatcher)
.coroutineContext(dispatchersHolder.defaultDispatcher)
.decoderCoroutineContext(dispatchersHolder.decodingDispatcher)
.fetcherCoroutineContext(dispatchersHolder.ioDispatcher)
.allowHardware(false)
.logger(logger)
.build()
.also(Coil::setImageLoader)
.also(SingletonImageLoader::setUnsafe)
@Provides
fun provideCoilLogger(): Logger? = if (BuildConfig.DEBUG) DebugLogger()
@ -72,21 +75,20 @@ internal object ImageLoaderModule {
@Provides
fun provideComponentRegistry(
@ApplicationContext context: Context,
interceptor: TimeMeasureInterceptor
): ComponentRegistry = ComponentRegistry.Builder()
.apply {
add(AnimatedPngDecoder.Factory())
if (Build.VERSION.SDK_INT >= 28) add(ImageDecoderDecoder.Factory())
if (Build.VERSION.SDK_INT >= 28) add(AnimatedImageDecoder.Factory())
else {
add(GifDecoder.Factory())
add(AnimatedWebPDecoder.Factory())
}
add(SvgDecoder.Factory())
if (Build.VERSION.SDK_INT >= 24) {
add(HeifDecoderCoil2.Factory())
add(HeifDecoder.Factory())
}
add(AnimatedJxlDecoderCoil2.Factory(context))
add(AnimatedJxlDecoder.Factory())
add(Jpeg2000Decoder.Factory())
add(TiffDecoder.Factory())
add(QoiDecoder.Factory())

View File

@ -26,15 +26,16 @@ import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.core.net.toUri
import androidx.exifinterface.media.ExifInterface
import coil.ImageLoader
import coil.request.ImageRequest
import coil.size.Size
import coil3.ImageLoader
import coil3.request.ImageRequest
import coil3.request.transformations
import coil3.size.Size
import coil3.toBitmap
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import ru.tech.imageresizershrinker.core.data.utils.toBitmap
import ru.tech.imageresizershrinker.core.data.utils.toCoil
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.core.domain.image.ImageGetter
@ -106,7 +107,7 @@ internal class AndroidImageGetter @Inject constructor(
if (originalSize) size(Size.ORIGINAL)
}
.build()
).drawable?.toBitmap()
).image?.toBitmap()
}.getOrNull()
}
@ -127,7 +128,7 @@ internal class AndroidImageGetter @Inject constructor(
)
}
.build()
).drawable?.toBitmap()
).image?.toBitmap()
}.getOrNull()
}
@ -146,7 +147,7 @@ internal class AndroidImageGetter @Inject constructor(
} ?: size(Size.ORIGINAL)
}
.build()
).drawable?.toBitmap()
).image?.toBitmap()
}.getOrNull()
}
@ -167,7 +168,7 @@ internal class AndroidImageGetter @Inject constructor(
.build()
runCatching {
imageLoader.execute(request).drawable?.toBitmap()?.let { bitmap ->
imageLoader.execute(request).image?.toBitmap()?.let { bitmap ->
val newUri = uri.toUri().tryGetLocation(context)
val fd = context.contentResolver.openFileDescriptor(newUri, "r")
val exif = fd?.fileDescriptor?.let { ExifInterface(it) }
@ -205,7 +206,7 @@ internal class AndroidImageGetter @Inject constructor(
.build()
runCatching {
imageLoader.execute(request).drawable?.toBitmap()
imageLoader.execute(request).image?.toBitmap()
}.getOrNull()
}

View File

@ -18,9 +18,8 @@
package ru.tech.imageresizershrinker.core.data.image
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.PorterDuff
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.core.graphics.BitmapCompat
import androidx.core.graphics.applyCanvas
import com.awxkee.aire.Aire
@ -234,7 +233,7 @@ internal class AndroidImageScaler @Inject constructor(
).apply {
setHasAlpha(true)
}.applyCanvas {
drawColor(Color.Transparent.toArgb(), PorterDuff.Mode.CLEAR)
drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
canvasColor?.let {
drawColor(it)
} ?: blurredBitmap?.let {
@ -320,7 +319,7 @@ internal class AndroidImageScaler @Inject constructor(
).apply {
setHasAlpha(true)
}.applyCanvas {
drawColor(Color.Transparent.toArgb(), PorterDuff.Mode.CLEAR)
drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
canvasColor?.let {
drawColor(it)
} ?: blurredBitmap?.let {

View File

@ -20,12 +20,13 @@ package ru.tech.imageresizershrinker.core.data.image
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Matrix
import coil.ImageLoader
import coil.request.ImageRequest
import coil.size.Size
import coil3.ImageLoader
import coil3.request.ImageRequest
import coil3.request.transformations
import coil3.size.Size
import coil3.toBitmap
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.withContext
import ru.tech.imageresizershrinker.core.data.utils.toBitmap
import ru.tech.imageresizershrinker.core.data.utils.toCoil
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.core.domain.image.ImageTransformer
@ -68,7 +69,7 @@ internal class AndroidImageTransformer @Inject constructor(
}
.build()
return@withContext imageLoader.execute(request).drawable?.toBitmap()
return@withContext imageLoader.execute(request).image?.toBitmap()
}
override suspend fun transform(
@ -89,7 +90,7 @@ internal class AndroidImageTransformer @Inject constructor(
.size(size.width, size.height)
.build()
return@withContext imageLoader.execute(request).drawable?.toBitmap()
return@withContext imageLoader.execute(request).image?.toBitmap()
}
override suspend fun applyPresetBy(
@ -105,7 +106,7 @@ internal class AndroidImageTransformer @Inject constructor(
.data(it)
.size(Size.ORIGINAL)
.build()
).drawable?.run { intrinsicWidth sizeTo intrinsicHeight }
).image?.run { width sizeTo height }
} ?: IntegerSize(image.width, image.height)
val rotated = abs(currentInfo.rotationDegrees) % 180 != 0f

View File

@ -19,7 +19,6 @@ package ru.tech.imageresizershrinker.core.data.image.utils
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.BlendMode
import ru.tech.imageresizershrinker.core.domain.image.model.BlendingMode
import android.graphics.BlendMode as AndroidBlendMode
import android.graphics.PorterDuff.Mode as PorterDuffMode
@ -52,7 +51,7 @@ fun BlendingMode.toPorterDuffMode(): PorterDuffMode = when (this) {
}
/**
* Convert the compose [BlendMode] to the underlying Android platform [AndroidBlendMode]
* Convert the domain [BlendingMode] to the underlying Android platform [AndroidBlendMode]
*/
@RequiresApi(Build.VERSION_CODES.Q)
fun BlendingMode.toAndroidBlendMode(): AndroidBlendMode = when (this) {

View File

@ -20,7 +20,6 @@ package ru.tech.imageresizershrinker.core.data.utils
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.compose.ui.graphics.ImageBitmap
import androidx.core.graphics.drawable.toBitmap
import java.io.ByteArrayOutputStream
@ -45,8 +44,6 @@ fun Bitmap.toSoftware(): Bitmap = copy(getSuitableConfig(this), false) ?: this
val Bitmap.aspectRatio: Float get() = width / height.toFloat()
val ImageBitmap.aspectRatio: Float get() = width / height.toFloat()
val Drawable.aspectRatio: Float get() = intrinsicWidth / intrinsicHeight.toFloat()
val Bitmap.safeAspectRatio: Float
@ -57,11 +54,6 @@ val Bitmap.safeAspectRatio: Float
val Bitmap.safeConfig: Bitmap.Config
get() = config ?: getSuitableConfig(this)
val ImageBitmap.safeAspectRatio: Float
get() = aspectRatio
.coerceAtLeast(0.005f)
.coerceAtMost(1000f)
val Drawable.safeAspectRatio: Float
get() = aspectRatio
.coerceAtLeast(0.005f)

View File

@ -18,11 +18,11 @@
package ru.tech.imageresizershrinker.core.data.utils
import android.graphics.Bitmap
import coil.size.Size
import coil.size.pxOrElse
import coil3.size.Size
import coil3.size.pxOrElse
import ru.tech.imageresizershrinker.core.domain.model.IntegerSize
import ru.tech.imageresizershrinker.core.domain.transformation.Transformation
import coil.transform.Transformation as CoilTransformation
import coil3.transform.Transformation as CoilTransformation
fun Size.asDomain(): IntegerSize = if (this == Size.ORIGINAL) IntegerSize.Undefined
else IntegerSize(width.pxOrElse { 1 }, height.pxOrElse { 1 })
@ -30,7 +30,7 @@ else IntegerSize(width.pxOrElse { 1 }, height.pxOrElse { 1 })
fun IntegerSize.asCoil(): Size = if (this == IntegerSize.Undefined) Size.ORIGINAL
else Size(width, height)
fun Transformation<Bitmap>.toCoil(): CoilTransformation = object : CoilTransformation {
fun Transformation<Bitmap>.toCoil(): CoilTransformation = object : CoilTransformation() {
private val instance = this@toCoil
override fun toString(): String = instance::class.simpleName.toString()

View File

@ -115,7 +115,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.net.toUri
import androidx.exifinterface.media.ExifInterface
import coil.transform.Transformation
import coil3.transform.Transformation
import com.arkivanov.decompose.ComponentContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory

View File

@ -89,9 +89,12 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.transform.Transformation
import coil3.compose.rememberAsyncImagePainter
import coil3.request.ImageRequest
import coil3.request.error
import coil3.request.transformations
import coil3.toBitmap
import coil3.transform.Transformation
import kotlinx.coroutines.launch
import ru.tech.imageresizershrinker.core.domain.model.FileModel
import ru.tech.imageresizershrinker.core.domain.model.ImageModel
@ -106,7 +109,6 @@ import ru.tech.imageresizershrinker.core.ui.theme.StrongBlack
import ru.tech.imageresizershrinker.core.ui.theme.White
import ru.tech.imageresizershrinker.core.ui.theme.outlineVariant
import ru.tech.imageresizershrinker.core.ui.utils.helper.ContextUtils.isNetworkAvailable
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.toImageModel
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedAlertDialog
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton
@ -172,7 +174,7 @@ internal fun FilterSelectionItem(
onSuccess = {
loading = false
scope.launch {
isBitmapDark = calculateBrightnessEstimate(it.result.drawable.toBitmap()) < 110
isBitmapDark = calculateBrightnessEstimate(it.result.image.toBitmap()) < 110
}
}
)

View File

@ -73,9 +73,11 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.min
import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.transform.Transformation
import coil3.compose.rememberAsyncImagePainter
import coil3.request.ImageRequest
import coil3.request.error
import coil3.request.transformations
import coil3.transform.Transformation
import dev.shreyaspatil.capturable.capturable
import dev.shreyaspatil.capturable.controller.rememberCaptureController
import kotlinx.coroutines.launch

View File

@ -51,9 +51,12 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.transform.Transformation
import coil3.compose.rememberAsyncImagePainter
import coil3.request.ImageRequest
import coil3.request.error
import coil3.request.transformations
import coil3.toBitmap
import coil3.transform.Transformation
import kotlinx.coroutines.launch
import ru.tech.imageresizershrinker.core.domain.model.ImageModel
import ru.tech.imageresizershrinker.core.filters.domain.model.TemplateFilter
@ -63,7 +66,6 @@ import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.ui.theme.StrongBlack
import ru.tech.imageresizershrinker.core.ui.theme.White
import ru.tech.imageresizershrinker.core.ui.theme.outlineVariant
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.toImageModel
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
import ru.tech.imageresizershrinker.core.ui.widget.modifier.shimmer
@ -108,7 +110,7 @@ internal fun TemplateFilterSelectionItem(
onSuccess = {
loading = false
scope.launch {
isBitmapDark = calculateBrightnessEstimate(it.result.drawable.toBitmap()) < 110
isBitmapDark = calculateBrightnessEstimate(it.result.image.toBitmap()) < 110
}
}
)

View File

@ -49,6 +49,8 @@ dependencies {
api(libs.coilCompose)
api(libs.coilGif)
api(libs.coilSvg)
api(libs.coilNetwork)
api(libs.ktor)
//Modules
api(libs.toolbox.uCrop)
@ -71,7 +73,7 @@ dependencies {
api(libs.reorderable)
api(libs.compose)
api(libs.shadowGadgets)
api(libs.shadowsPlus)
api(libs.kotlinx.collections.immutable)

View File

@ -18,8 +18,8 @@
package ru.tech.imageresizershrinker.core.ui.transformation
import android.graphics.Bitmap
import coil.size.Size
import coil.size.pxOrElse
import coil3.size.Size
import coil3.size.pxOrElse
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -35,7 +35,7 @@ import ru.tech.imageresizershrinker.core.domain.model.IntegerSize
import ru.tech.imageresizershrinker.core.domain.transformation.Transformation
import ru.tech.imageresizershrinker.core.ui.utils.helper.asCoil
import kotlin.math.roundToInt
import coil.transform.Transformation as CoilTransformation
import coil3.transform.Transformation as CoilTransformation
class ImageInfoTransformation @AssistedInject internal constructor(
@Assisted private val imageInfo: ImageInfo,
@ -45,7 +45,7 @@ class ImageInfoTransformation @AssistedInject internal constructor(
private val imageScaler: ImageScaler<Bitmap>,
private val imagePreviewCreator: ImagePreviewCreator<Bitmap>,
private val shareProvider: ShareProvider<Bitmap>
) : CoilTransformation, Transformation<Bitmap> {
) : CoilTransformation(), Transformation<Bitmap> {
override val cacheKey: String
get() = Triple(imageInfo, preset, transformations).hashCode().toString()

View File

@ -18,11 +18,11 @@
package ru.tech.imageresizershrinker.core.ui.utils.helper
import android.graphics.Bitmap
import coil.size.Size
import coil.size.pxOrElse
import coil3.size.Size
import coil3.size.pxOrElse
import ru.tech.imageresizershrinker.core.domain.model.IntegerSize
import ru.tech.imageresizershrinker.core.domain.transformation.Transformation
import coil.transform.Transformation as CoilTransformation
import coil3.transform.Transformation as CoilTransformation
fun Size.asDomain(): IntegerSize = if (this == Size.ORIGINAL) IntegerSize.Undefined
else IntegerSize(width.pxOrElse { 1 }, height.pxOrElse { 1 })
@ -30,7 +30,7 @@ else IntegerSize(width.pxOrElse { 1 }, height.pxOrElse { 1 })
fun IntegerSize.asCoil(): Size = if (this == IntegerSize.Undefined) Size.ORIGINAL
else Size(width, height)
fun Transformation<Bitmap>.toCoil(): CoilTransformation = object : CoilTransformation {
fun Transformation<Bitmap>.toCoil(): CoilTransformation = object : CoilTransformation() {
private val instance = this@toCoil
override fun toString(): String = instance::class.simpleName.toString()

View File

@ -18,6 +18,6 @@
package ru.tech.imageresizershrinker.core.ui.utils.provider
import androidx.compose.runtime.compositionLocalOf
import coil.ImageLoader
import coil3.ImageLoader
val LocalImageLoader = compositionLocalOf<ImageLoader> { error("No ImageLoader provided") }

View File

@ -39,13 +39,16 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.core.graphics.drawable.toBitmapOrNull
import coil.ImageLoader
import coil.compose.AsyncImagePainter
import coil.compose.SubcomposeAsyncImage
import coil.compose.SubcomposeAsyncImageScope
import coil.request.ImageRequest
import coil.transform.Transformation
import coil3.ImageLoader
import coil3.compose.AsyncImagePainter
import coil3.compose.SubcomposeAsyncImage
import coil3.compose.SubcomposeAsyncImageScope
import coil3.request.ImageRequest
import coil3.request.allowHardware
import coil3.request.crossfade
import coil3.request.transformations
import coil3.toBitmap
import coil3.transform.Transformation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
@ -155,7 +158,7 @@ fun Picture(
onSuccess = {
if (model is ImageRequest && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && enableUltraHDRSupport) {
activity.window.colorMode =
if (it.result.drawable.toBitmapOrNull(400, 400)?.hasGainmap() == true) {
if (it.result.image.toBitmap(400, 400).hasGainmap()) {
ActivityInfo.COLOR_MODE_HDR
} else ActivityInfo.COLOR_MODE_DEFAULT
}

View File

@ -44,7 +44,9 @@ import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import coil.request.ImageRequest
import coil3.asDrawable
import coil3.request.ImageRequest
import coil3.request.crossfade
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.safeAspectRatio
import ru.tech.imageresizershrinker.core.ui.widget.modifier.container
import kotlin.math.roundToInt
@ -100,7 +102,7 @@ internal fun UrisCarousel(uris: List<Uri>) {
.build()
},
onSuccess = {
aspectRatio = it.result.drawable.safeAspectRatio
aspectRatio = it.result.image.asDrawable(context.resources).safeAspectRatio
},
modifier = Modifier
.animateContentSize()

View File

@ -46,8 +46,9 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil3.compose.rememberAsyncImagePainter
import coil3.request.ImageRequest
import coil3.request.crossfade
import ru.tech.imageresizershrinker.core.ui.shapes.CloverShape
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalImageLoader
import ru.tech.imageresizershrinker.core.ui.widget.modifier.shimmer

View File

@ -52,7 +52,7 @@ import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.transform.Transformation
import coil3.transform.Transformation
import ru.tech.imageresizershrinker.core.domain.utils.notNullAnd
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton

View File

@ -17,6 +17,7 @@
package ru.tech.imageresizershrinker.core.ui.widget.sheets
import android.content.res.Resources
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
@ -50,7 +51,8 @@ import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.transform.Transformation
import coil3.asDrawable
import coil3.transform.Transformation
import com.smarttoolfactory.colordetector.util.ColorUtil.roundToTwoDigits
import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable
@ -107,7 +109,8 @@ fun ZoomModalSheet(
model = data,
contentDescription = null,
onSuccess = {
aspectRatio = it.result.drawable.safeAspectRatio
aspectRatio =
it.result.image.asDrawable(Resources.getSystem()).safeAspectRatio
},
contentScale = ContentScale.FillBounds,
showTransparencyChecker = false,

View File

@ -57,12 +57,12 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.applyCanvas
import coil.request.ImageRequest
import coil3.request.ImageRequest
import coil3.toBitmap
import ru.tech.imageresizershrinker.core.data.utils.safeConfig
import ru.tech.imageresizershrinker.core.domain.model.IntegerSize
import ru.tech.imageresizershrinker.core.domain.model.Pt
import ru.tech.imageresizershrinker.core.ui.shapes.MaterialStarShape
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.provider.LocalImageLoader
import ru.tech.imageresizershrinker.feature.draw.domain.DrawLineStyle
import ru.tech.imageresizershrinker.feature.draw.domain.DrawMode
@ -347,7 +347,7 @@ fun NativeCanvas.drawRepeatedImageOnPath(
.data(drawMode.imageData)
.size(strokeWidth.toPx(canvasSize).roundToInt())
.build()
).drawable?.toBitmap()
).image?.toBitmap()
}
}
pathImage?.let { bitmap ->

View File

@ -19,8 +19,8 @@ package ru.tech.imageresizershrinker.feature.filters.data.model
import android.content.Context
import android.graphics.Bitmap
import coil.size.Size
import coil.size.pxOrElse
import coil3.size.Size
import coil3.size.pxOrElse
import jp.co.cyberagent.android.gpuimage.GPUImage
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter
import ru.tech.imageresizershrinker.core.data.utils.asCoil
@ -28,11 +28,11 @@ import ru.tech.imageresizershrinker.core.data.utils.aspectRatio
import ru.tech.imageresizershrinker.core.domain.model.IntegerSize
import ru.tech.imageresizershrinker.core.domain.transformation.Transformation
import java.lang.Integer.max
import coil.transform.Transformation as CoilTransformation
import coil3.transform.Transformation as CoilTransformation
internal abstract class GPUFilterTransformation(
private val context: Context,
) : CoilTransformation, Transformation<Bitmap> {
) : CoilTransformation(), Transformation<Bitmap> {
/**
* Create the [GPUImageFilter] to apply to this [Transformation]

View File

@ -31,7 +31,7 @@ import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.graphics.TileMode
import androidx.core.net.toUri
import androidx.exifinterface.media.ExifInterface
import coil.transform.Transformation
import coil3.transform.Transformation
import com.arkivanov.decompose.ComponentContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory

View File

@ -47,11 +47,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import coil.request.ImageRequest
import coil3.request.ImageRequest
import coil3.toBitmap
import com.t8rin.modalsheet.FullscreenPopup
import ru.tech.imageresizershrinker.core.domain.image.model.ImageFrames
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.Picker
import ru.tech.imageresizershrinker.core.ui.utils.helper.rememberImagePicker
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
@ -191,7 +191,7 @@ internal fun ImagePreviewGrid(
ImageRequest.Builder(context)
.data(uri.toUri())
.build()
).drawable?.toBitmap()
).image?.toBitmap()
}
)
}

View File

@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil3.toBitmap
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.safeAspectRatio
import ru.tech.imageresizershrinker.core.ui.utils.helper.Picker
@ -119,7 +120,7 @@ fun ImageSplitterContent(
.padding(4.dp)
.clip(MaterialTheme.shapes.medium),
onSuccess = {
aspectRatio = it.result.drawable.safeAspectRatio
aspectRatio = it.result.image.toBitmap().safeAspectRatio
}
)
} else {

View File

@ -48,11 +48,11 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImagePainter
import coil3.compose.AsyncImagePainter
import coil3.toBitmap
import ru.tech.imageresizershrinker.core.domain.image.model.ImageInfo
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.resources.icons.ImageEdit
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.asClip
import ru.tech.imageresizershrinker.core.ui.utils.helper.isLandscapeOrientationAsState
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
@ -212,7 +212,7 @@ fun LoadNetImageContent(
if (it is AsyncImagePainter.State.Error) {
component.updateBitmap(null)
} else if (it is AsyncImagePainter.State.Success) {
component.updateBitmap(it.result.drawable.toBitmap())
component.updateBitmap(it.result.image.toBitmap())
}
imageState = it
},

View File

@ -21,7 +21,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.exifinterface.media.ExifInterface
import coil.ImageLoader
import coil3.ImageLoader
import com.arkivanov.decompose.ComponentContext
import com.t8rin.dynamic.theme.ColorTuple
import com.t8rin.dynamic.theme.extractPrimaryColor

View File

@ -26,9 +26,10 @@ import android.graphics.pdf.PdfRenderer
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.core.net.toUri
import coil.ImageLoader
import coil.request.ImageRequest
import coil.size.Size
import coil3.ImageLoader
import coil3.request.ImageRequest
import coil3.size.Size
import coil3.toBitmap
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@ -36,7 +37,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import ru.tech.imageresizershrinker.core.data.utils.aspectRatio
import ru.tech.imageresizershrinker.core.data.utils.getSuitableConfig
import ru.tech.imageresizershrinker.core.data.utils.toBitmap
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.core.domain.image.ImageScaler
import ru.tech.imageresizershrinker.core.domain.image.model.ImageScaleMode
@ -186,12 +186,12 @@ internal class AndroidPdfManager @Inject constructor(
val r = PdfRenderer(fileDescriptor)
List(r.pageCount) {
val page = r.openPage(it)
page?.run {
page.run {
IntegerSize(width, height)
}.also {
page.close()
}
}.filterNotNull().also {
}.also {
pagesBuf[uri] = it
}
}
@ -217,7 +217,7 @@ internal class AndroidPdfManager @Inject constructor(
.data(uri)
.size(Size.ORIGINAL)
.build()
).drawable?.toBitmap()?.let {
).image?.toBitmap()?.let {
imageScaler.scaleImage(
image = it,
width = (it.width * percent / 100f).roundToInt(),

View File

@ -90,8 +90,10 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.LocalLifecycleOwner
import coil.memory.MemoryCache
import coil.request.ImageRequest
import coil3.Image
import coil3.asImage
import coil3.memory.MemoryCache
import coil3.request.ImageRequest
import com.t8rin.dynamic.theme.observeAsState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -477,9 +479,9 @@ private fun PdfPage(
val imageLoader = LocalImageLoader.current
val imageLoadingScope = rememberCoroutineScope()
val cacheValue: Bitmap? = imageLoader.memoryCache?.get(cacheKey)?.bitmap
val cacheValue: Image? = imageLoader.memoryCache?.get(cacheKey)?.image
var bitmap: Bitmap? by remember { mutableStateOf(cacheValue) }
var bitmap: Image? by remember { mutableStateOf(cacheValue) }
if (bitmap == null) {
DisposableEffect(cacheKey, index) {
val job = imageLoadingScope.launch(Dispatchers.IO) {
@ -503,7 +505,7 @@ private fun PdfPage(
null,
PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY
)
bitmap = destinationBitmap
bitmap = destinationBitmap.asImage()
}
}
} catch (e: Exception) {
@ -518,11 +520,13 @@ private fun PdfPage(
}
}
val request = ImageRequest.Builder(context)
.size(renderWidth, renderHeight)
.memoryCacheKey(cacheKey)
.data(bitmap)
.build()
val request = remember(context, renderWidth, renderHeight, bitmap) {
ImageRequest.Builder(context)
.size(renderWidth, renderHeight)
.memoryCacheKey(cacheKey)
.data(bitmap)
.build()
}
val transition = updateTransition(selected)
val padding by transition.animateDp { s ->

View File

@ -17,7 +17,7 @@
package ru.tech.imageresizershrinker.feature.recognize.text.domain
import okhttp3.internal.toImmutableList
import kotlinx.collections.immutable.toImmutableList
import ru.tech.imageresizershrinker.feature.recognize.text.domain.Constants.KEY_CHOP_ENABLE
import ru.tech.imageresizershrinker.feature.recognize.text.domain.Constants.KEY_EDGES_MAX_CHILDREN_PER_OUTLINE
import ru.tech.imageresizershrinker.feature.recognize.text.domain.Constants.KEY_ENABLE_NEW_SEGSEARCH

View File

@ -49,7 +49,8 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.request.ImageRequest
import coil3.request.ImageRequest
import coil3.toBitmap
import ru.tech.imageresizershrinker.core.domain.utils.notNullAnd
import ru.tech.imageresizershrinker.core.domain.utils.readableByteCount
import ru.tech.imageresizershrinker.core.resources.R
@ -60,7 +61,6 @@ import ru.tech.imageresizershrinker.core.ui.utils.helper.ContextUtils.copyToClip
import ru.tech.imageresizershrinker.core.ui.utils.helper.FileType
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImagePickerMode
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.safeAspectRatio
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.Picker
import ru.tech.imageresizershrinker.core.ui.utils.helper.isPortraitOrientationAsState
import ru.tech.imageresizershrinker.core.ui.utils.helper.localImagePickerMode
@ -148,7 +148,7 @@ fun RecognizeTextContent(
selector = {
imageLoader.execute(
ImageRequest.Builder(context).data(it).build()
).drawable?.toBitmap()
).image?.toBitmap()
}
)

View File

@ -70,7 +70,7 @@ import ru.tech.imageresizershrinker.feature.recognize.text.domain.TextRecognitio
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import coil.transform.Transformation as CoilTransformation
import coil3.transform.Transformation as CoilTransformation
class RecognizeTextComponent @AssistedInject internal constructor(
@Assisted componentContext: ComponentContext,

View File

@ -23,7 +23,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.exifinterface.media.ExifInterface
import coil.ImageLoader
import coil3.ImageLoader
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.DelicateDecomposeApi
import com.arkivanov.decompose.router.stack.ChildStack

View File

@ -67,6 +67,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil3.toBitmap
import kotlinx.coroutines.launch
import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable
@ -80,7 +81,6 @@ import ru.tech.imageresizershrinker.core.filters.presentation.widget.FilterReord
import ru.tech.imageresizershrinker.core.filters.presentation.widget.FilterTemplateCreationSheetComponent
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.ui.theme.mixedContainer
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedFloatingActionButton
import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton
@ -292,7 +292,7 @@ fun FilterEditOption(
}
}.value,
onSuccess = {
stateBitmap = it.result.drawable.toBitmap()
stateBitmap = it.result.image.toBitmap()
},
showTransparencyChecker = false,
modifier = Modifier

View File

@ -32,10 +32,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.request.ImageRequest
import coil3.request.ImageRequest
import coil3.toBitmap
import ru.tech.imageresizershrinker.core.resources.R
import ru.tech.imageresizershrinker.core.resources.icons.ImageReset
import ru.tech.imageresizershrinker.core.ui.utils.helper.ImageUtils.toBitmap
import ru.tech.imageresizershrinker.core.ui.utils.helper.Picker
import ru.tech.imageresizershrinker.core.ui.utils.helper.asClip
import ru.tech.imageresizershrinker.core.ui.utils.helper.isPortraitOrientationAsState
@ -94,7 +94,7 @@ fun WatermarkingContent(
selector = {
imageLoader.execute(
ImageRequest.Builder(context).data(it).build()
).drawable?.toBitmap()
).image?.toBitmap()
}
)

View File

@ -25,7 +25,7 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.core.net.toUri
import androidx.exifinterface.media.ExifInterface
import coil.transform.Transformation
import coil3.transform.Transformation
import com.arkivanov.decompose.ComponentContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory

View File

@ -7,16 +7,15 @@ versionName = "3.1.0-rc01"
versionCode = "156"
jvmTarget = "17"
compose-compiler = "1.5.15"
imageToolboxLibs = "3.0.1"
imageToolboxLibs = "3.1.1"
trickle = "1.2.2"
avifCoder = "2.0.8"
avifCoderCoil = "2.0.8"
aire = "0.15.4"
jxlCoder = "2.4.0"
jxlCoderCoil = "2.4.0"
jxlCoder = "2.4.0.1"
jxlCoderCoil = "2.4.0.1"
jpegliCoder = "1.0.1"
tesseract = "4.7.0"
@ -40,12 +39,13 @@ detekt = "1.23.7"
detektCompose = "0.4.18"
decompose = "3.2.2"
kotlin = "1.9.25"
kotlin = "2.0.21"
agp = "8.7.2"
hilt = "2.52"
gms = "4.4.2"
coil = "2.7.0"
ktor = "3.0.1"
coil = "3.0.2"
appCompat = "1.7.0"
androidxCore = "1.15.0"
androidxLifecycle = "2.9.0-alpha07"
@ -58,13 +58,13 @@ reviewKtx = "2.0.2"
splashScreen = "1.2.0-alpha02"
espresso = "3.6.1"
ksp = "1.9.25-1.0.20"
ksp = "2.0.21-1.0.27"
androidx-test-ext-junit = "1.2.1"
documentfile = "1.0.1"
uiautomator = "2.3.0"
androidxMacroBenchmark = "1.4.0-alpha05"
quickie = "1.12.4"
quickie = "1.13.0"
material = "1.13.0-alpha07"
jsoup = "1.18.1"
@ -128,13 +128,14 @@ androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", vers
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
androidx-material3-window-sizeclass = { module = "androidx.compose.material3:material3-window-size-class", version.ref = "material3" }
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
androidx-compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics", version.ref = "composeVersion" }
androidx-material = { module = "androidx.compose.material:material", version.ref = "composeVersion" }
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
app-update-ktx = { module = "com.google.android.play:app-update-ktx", version.ref = "appUpdateKtx" }
app-update = { module = "com.google.android.play:app-update", version.ref = "appUpdate" }
avif-coder = { module = "com.github.awxkee:avif-coder", version.ref = "avifCoder" }
avif-coder-coil = { module = "com.github.awxkee:avif-coder-coil", version.ref = "avifCoderCoil" }
compose = { module = "com.github.zed-alpha.shadow-gadgets:compose", version.ref = "shadowGadgets" }
shadowGadgets = { module = "com.github.zed-alpha.shadow-gadgets:compose", version.ref = "shadowGadgets" }
datastore-preferences-android = { module = "androidx.datastore:datastore-preferences-android", version.ref = "androidx-datastorePreferencesAndroid" }
fadingEdges = { module = "com.github.t8rin:ComposeFadingEdges", version.ref = "fadingEdges" }
firebase-crashlytics-ktx = { module = "com.google.firebase:firebase-crashlytics-ktx", version.ref = "firebaseCrashlyticsKtx" }
@ -144,10 +145,14 @@ decomposeExtensions = { module = "com.arkivanov.decompose:extensions-compose", v
shadowsPlus = { module = "com.github.GIGAMOLE:ComposeShadowsPlus", version.ref = "shadowsPlus" }
dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
desugaring = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugaring" }
coilCompose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
coilGif = { module = "io.coil-kt:coil-gif", version.ref = "coil" }
coilSvg = { module = "io.coil-kt:coil-svg", version.ref = "coil" }
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
ktor = { module = "io.ktor:ktor-client-android", version.ref = "ktor" }
coilNetwork = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
coilCompose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coilGif = { module = "io.coil-kt.coil3:coil-gif", version.ref = "coil" }
coilSvg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx", version.ref = "firebaseAnalyticsKtx" }
jxl-coder-coil = { module = "io.github.awxkee:jxl-coder-coil", version.ref = "jxlCoderCoil" }
jxl-coder = { module = "io.github.awxkee:jxl-coder", version.ref = "jxlCoder" }
@ -183,6 +188,7 @@ detekt-gradle = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", v
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
detekt-compose = { module = "io.nlopez.compose.rules:detekt", version.ref = "detektCompose" }
aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin", version.ref = "aboutlibraries" }
compose-compiler-gradle = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
[plugins]
image-toolbox-library = { id = "image.toolbox.library", version = "unspecified" }