image redrawing api
This commit is contained in:
@@ -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')
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt
Normal file
13
src/main/kotlin/org/koitharu/kotatsu/parsers/bitmap/Rect.kt
Normal file
@@ -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
|
||||
}
|
||||
@@ -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<Int, IntArray>()
|
||||
|
||||
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<Piece>()
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user