From 90c0bf46f41e30a57fef8e221bb3ed6a13425c6e Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Thu, 23 May 2024 11:36:09 +0500 Subject: [PATCH] image redrawing api --- build.gradle | 1 + .../kotatsu/parsers/MangaLoaderContext.kt | 13 +++++ .../koitharu/kotatsu/parsers/bitmap/Bitmap.kt | 53 +++++++++++++++++++ .../koitharu/kotatsu/parsers/bitmap/Rect.kt | 13 +++++ .../parsers/site/all/MangaReaderToParser.kt | 23 +++----- 5 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Bitmap.kt create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt diff --git a/build.gradle b/build.gradle index b51f4bb0..c97b769b 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ dependencies { api 'org.jsoup:jsoup:1.17.2' implementation 'org.json:json:20240303' implementation 'androidx.collection:collection:1.4.0' + implementation 'org.jetbrains.kotlinx:kotlinx-io-core:0.3.4' ksp project(':kotatsu-parsers-ksp') diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt index fe282967..eca1324e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt @@ -2,6 +2,8 @@ package org.koitharu.kotatsu.parsers import okhttp3.CookieJar import okhttp3.OkHttpClient +import okhttp3.Response +import org.koitharu.kotatsu.parsers.bitmap.Bitmap import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.model.MangaSource import java.util.* @@ -31,4 +33,15 @@ abstract class MangaLoaderContext { abstract fun getConfig(source: MangaSource): MangaSourceConfig abstract fun getDefaultUserAgent(): String + + /** + * Helper function to be used in an interceptor + * to descramble images + * @param response Image response + * @param redraw lambda function to implement descrambling logic + */ + abstract fun redrawImageResponse( + response: Response, + redraw: (image: Bitmap) -> Bitmap + ): Response } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Bitmap.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Bitmap.kt new file mode 100644 index 00000000..ebbfdcea --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Bitmap.kt @@ -0,0 +1,53 @@ +package org.koitharu.kotatsu.parsers.bitmap + +import kotlinx.io.Sink + +abstract class Bitmap { + abstract val width: Int + abstract val height: Int + + enum class CompressFormat { + JPEG, + PNG, + WEBP_LOSSY, + WEBP_LOSSLESS, + } + + enum class Config { + ALPHA_8, + RGB_565, + ARGB_8888, + RGBA_F16, + HARDWARE, + RGBA_1010102, + } + + abstract fun compress( + format: CompressFormat, + quality: Int, + sink: Sink + ): Boolean + + abstract fun getPixels( + /*@ColorInt*/ + pixels: IntArray, + offset: Int, + stride: Int, + x: Int, + y: Int, + width: Int, + height: Int, + ) + + abstract fun drawBitmap(sourceBitmap: Bitmap, src: Rect, dst: Rect) + + companion object { + fun createBitmap(width: Int, height: Int, config: Config): Bitmap { + throw NotImplementedError("createBitmap(width, height, config) is not implemented") + } + + fun createBitmap(source: Bitmap, x: Int, y: Int, width: Int, height: Int): Bitmap { + throw NotImplementedError("createBitmap(source, x, y, width, height) is not implemented") + } + } +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt new file mode 100644 index 00000000..dbb321a7 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.parsers.bitmap + +data class Rect( + val left: Int = 0, + val top: Int = 0, + val right: Int = 0, + val bottom: Int = 0, +) { + val width: Int + get() = right - left + val height: Int + get() = bottom - top +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt index 4b4819dd..7f0d69df 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt @@ -1,18 +1,16 @@ package org.koitharu.kotatsu.parsers.site.all -import android.graphics.* import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Interceptor -import okhttp3.MediaType.Companion.toMediaType import okhttp3.Response -import okhttp3.ResponseBody.Companion.toResponseBody import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.* +import org.koitharu.kotatsu.parsers.bitmap.Bitmap +import org.koitharu.kotatsu.parsers.bitmap.Rect import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* -import java.io.* import java.util.* import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec @@ -258,22 +256,17 @@ class MangaReaderToParser(context: MangaLoaderContext) : PagedMangaParser(contex val response = chain.proceed(request) if (request.url.fragment != "scrambled") return response - val image = response.body!!.byteStream().use(::descramble) - val body = image.toResponseBody("image/jpeg".toMediaType()) - return response.newBuilder() - .body(body) - .build() + + return context.redrawImageResponse(response, ::descramble) } private val memo = hashMapOf() - private fun descramble(image: InputStream): ByteArray { - val bitmap = BitmapFactory.decodeStream(image) + private fun descramble(bitmap: Bitmap): Bitmap { val width = bitmap.width val height = bitmap.height val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) - val canvas = Canvas(result) val pieces = ArrayList() for (y in 0 until height step PIECE_SIZE) { @@ -304,13 +297,11 @@ class MangaReaderToParser(context: MangaLoaderContext) : PagedMangaParser(contex val srcRect = Rect(src.x, src.y, src.x + src.w, src.y + src.h) val dstRect = Rect(dst.x, dst.y, dst.x + dst.w, dst.y + dst.h) - canvas.drawBitmap(bitmap, srcRect, dstRect, null) + result.drawBitmap(bitmap, srcRect, dstRect) } } - val output = ByteArrayOutputStream() - result.compress(Bitmap.CompressFormat.JPEG, 90, output) - return output.toByteArray() + return result } private class Piece(val x: Int, val y: Int, val w: Int, val h: Int)