Implement simple pages copping

remotes/weblate/feature/pagecrop
Koitharu 6 years ago
parent e0d45961f8
commit 963d93ca7b

@ -1,7 +1,11 @@
package org.koitharu.kotatsu.domain package org.koitharu.kotatsu.domain
import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.Rect
import android.util.Size import android.util.Size
import androidx.core.graphics.get
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
@ -11,6 +15,8 @@ import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.await
import org.koitharu.kotatsu.utils.ext.medianOrNull import org.koitharu.kotatsu.utils.ext.medianOrNull
import org.koitharu.kotatsu.utils.ext.use
import java.io.File
import java.io.InputStream import java.io.InputStream
object MangaUtils : KoinComponent { object MangaUtils : KoinComponent {
@ -54,4 +60,81 @@ object MangaUtils : KoinComponent {
check(imageHeight > 0 && imageWidth > 0) check(imageHeight > 0 && imageWidth > 0)
return Size(imageWidth, imageHeight) return Size(imageWidth, imageHeight)
} }
@JvmStatic
fun cropBitmap(input: Bitmap): Bitmap? {
return try {
val bounds = Rect(0, 0, input.width, input.height)
var isBoundsChanged = false
for (x in 1 until input.width / 2) {
var leftColor = 0
var rightColor = 0
for (y in 0 until input.height) {
leftColor += input[x, y]
rightColor += input[input.width - x - 1, y]
}
leftColor /= input.height
rightColor /= input.height
var consumed = false
if (leftColor == Color.WHITE) {
bounds.left++
consumed = true
}
if (rightColor == Color.WHITE) {
bounds.right--
consumed = true
}
if (consumed) {
isBoundsChanged = true
} else {
break
}
}
for (y in 1 until input.height / 2) {
var topColor = 0
var bottomColor = 0
for (x in 0 until input.width) {
topColor += input[x, y]
bottomColor += input[x, input.height - y - 1]
}
topColor /= input.width
bottomColor /= input.width
var consumed = false
if (topColor == Color.WHITE) {
bounds.top++
consumed = true
}
if (bottomColor == Color.WHITE) {
bounds.bottom--
consumed = true
}
if (consumed) {
isBoundsChanged = true
} else {
break
}
}
if (isBoundsChanged) {
Bitmap.createBitmap(input, bounds.left, bounds.top, bounds.width(), bounds.height())
} else {
null
}
} catch (e: Throwable) {
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
null
}
}
@JvmStatic
fun cropBitmap(file: File) {
BitmapFactory.decodeFile(file.path).use { bmp ->
cropBitmap(bmp)?.use { cropped ->
file.outputStream().use { out ->
cropped.compress(Bitmap.CompressFormat.WEBP, 100, out)
}
}
}
}
} }

@ -1,7 +1,9 @@
package org.koitharu.kotatsu.ui.reader package org.koitharu.kotatsu.ui.reader
import android.net.Uri import android.net.Uri
import androidx.annotation.WorkerThread
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
@ -16,13 +18,14 @@ import kotlin.coroutines.CoroutineContext
class PageLoader : KoinComponent, CoroutineScope, DisposableHandle { class PageLoader : KoinComponent, CoroutineScope, DisposableHandle {
private val job = SupervisorJob() private val job = SupervisorJob()
private val tasks = HashMap<String, Job>() private val mutex = Mutex()
private val okHttp by inject<OkHttpClient>() private val okHttp by inject<OkHttpClient>()
private val cache by inject<PagesCache>() private val cache by inject<PagesCache>()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job get() = Dispatchers.Main + job
@WorkerThread
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
suspend fun loadFile(url: String, force: Boolean): File { suspend fun loadFile(url: String, force: Boolean): File {
if (!force) { if (!force) {
@ -55,6 +58,10 @@ class PageLoader : KoinComponent, CoroutineScope, DisposableHandle {
response.body!!.byteStream().copyTo(out) response.body!!.byteStream().copyTo(out)
} }
} }
}.also {
mutex.withLock(this) {
MangaUtils.cropBitmap(it)
}
} }
} }

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.utils.ext package org.koitharu.kotatsu.utils.ext
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Bitmap
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@ -43,4 +44,10 @@ fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
} else { } else {
resources.getString(R.string.error_occurred) resources.getString(R.string.error_occurred)
} }
}
inline fun <R> Bitmap.use(block: (Bitmap) -> R): R = try {
block(this)
} finally {
recycle()
} }
Loading…
Cancel
Save