You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
takeshobo/src/jsMain/kotlin/image.kt

308 lines
9.9 KiB

import kotlinext.js.getOwnPropertyNames
import kotlinx.browser.document
import kotlinx.css.head
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.set
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.Image
import org.w3c.dom.events.Event
import org.w3c.dom.url.URL
import org.w3c.files.Blob
import org.w3c.files.BlobPropertyBag
import kotlin.js.Promise
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
import kotlin.math.round
data class un(val width: Int, val height: Int)
data class coord(
val resid: String,
val xsrc: Int,
val ysrc: Int,
val width: Int,
val height: Int,
val xdest: Int,
val ydest: Int
)
data class formatview(val width: Int, val height: Int, val coords: List<coord>, val areas: List<area>? = null)
data class transfer(val index:Int,val coords: List<coord>)
data class n(val width: Int,val height: Int,val transfers:List<transfer>)
data class N(
val left: Int, val top: Int, val width: Int, val height: Int,
val bottom: Int = top + height, val right: Int = left + width
)
object p {
//speedbinb.js?dmy=016301:formatted:3998
fun Rectangle(t: Int, i: Int, n: Int, r: Int): N {
return N(left = t, top = i, width = n, height = r)
}
//speedbinb.js?dmy=016301:formatted:3966
fun intersect(t:N,i:N):N?{
val n = t.left
val r = t.left + t.width
val e = t.top
val s = t.top + t.height
val h = i.left
val u = i.left + i.width
val o = i.top
val a = i.top + i.height
if (n < u && h < r && e < a && o < s) {
val f = max(n, h)
val c = max(e, o)
return N(f,c,min(r, u) - f,min(s, a) - c)
}
return null
}
}
class e(val Xs: Int = 3, private val Ws: Int = 8, private val Ys: Int = 4, val un: un) {
//speedbinb.js?dmy=016301:formatted:8848
fun Us(t: Int): N {
val i = this.un.height
val n = ceil( (i + this.Ys * (this.Xs - 1)) / this.Ws.toDouble()).toInt()
val r = ceil(t * n / this.Xs.toDouble()).toInt() * this.Ws
val e = ceil((t + 1) * n / this.Xs.toDouble()).toInt() * this.Ws
val s = n * this.Ws
val h = r * i / s
val u = e * i / s
val o = e - r
val a = if (1 == this.Xs) 0 else round(h + (u - h - o) * t / (this.Xs - 1).toDouble()).toInt()
return p.Rectangle(t = 0, i = a, n = this.un.width, r = o)
}
}
object d {
data class e(val resources: resources,val views: List<formatview>)
lateinit var urlResult: UrlResult
//speedbinb.js?dmy=016301:formatted:8699
private fun RS(t: resources, i: String): coord {
val n = (Regex("^([^:]+):(\\d+),(\\d+)\\+(\\d+),(\\d+)>(\\d+),(\\d+)\$").matchEntire(i)
?: throw IllegalArgumentException("Invalid format for Image Transfer : $i")).groupValues
val r = n[1]
if (r !in t.getOwnPropertyNames())
throw IllegalArgumentException("resid $r not found.")
return coord(
resid = r, xsrc = n[2].toInt(10), ysrc = n[3].toInt(10), width = n[4].toInt(10),
height = n[5].toInt(10), xdest = n[6].toInt(10), ydest = n[7].toInt(10)
)
}
//speedbinb.js?dmy=016301:formatted:8632
private fun FS():e {
val t=urlResult.t
val n =
t.resources.copy(i = t.resources.i.copy(src =urlResult.originImagePath))
return e(resources = n,views = t.views.map { it ->
formatview(width = it.width, height = it.height, coords = it.coords.map {
RS(t = n, i = it)
}, areas = it.areas)
})
}
//speedbinb.js?dmy=016301:formatted:8604
fun Gs():n{
val e= FS()
val u=e.views[0]
return n(width = u.width,height = u.height,transfers = listOf(transfer(index = 0,coords = u.coords)))
}
}
class ImageLoader(val urlResult: UrlResult){
private val canvasHtml=createCanvas()
private var imageHeight=0.0
//speedbinb.js?dmy=016301:formatted:8766
private fun callback(t:un): List<n> {
d.urlResult=urlResult
val n=d.Gs()
// console.info("Gs:")
// console.info(n)
val u=e(un=un(width = n.width,height = n.height))
val s=n.transfers[0].coords
val h= mutableListOf<n>()
repeat(u.Xs){
val r=u.Us(t=it)
// console.info("r:")
// console.info(r)
val e= mutableListOf<coord>()
s.forEach {
t->
// console.info("-------------------")
// console.info("t:")
// console.info(t)
val _i=p.Rectangle(t=t.xdest,i=t.ydest,n=t.width,r=t.height)
// console.info("p.Rectangle(i):")
// console.info(_i)
p.intersect(t=r,i=_i)?.let {
n->
// console.info("p.Rectangle.intersect(n):")
// console.info(n)
// console.info("-------------------")
e.add(coord(resid = t.resid,
xsrc = t.xsrc+(n.left-t.xdest),
ysrc= t.ysrc + (n.top - t.ydest),
width= n.width,
height= n.height,
xdest= n.left - r.left,
ydest = n.top - r.top))
}
}
// console.info("e.size=${e.size}")
h.add(n(width = r.width,height = r.height,transfers = listOf(transfer(index = 0,coords = e))))
}
// console.info(h)
return h.toList()
}
private fun createCanvas(): HTMLCanvasElement {
return document.createElement("canvas") as HTMLCanvasElement
}
//speedbinb.js?dmy=016301:formatted:7976
private fun us(t:n,image:Image){
console.info("开始绘制漫画页")
val canvas:HTMLCanvasElement= createCanvas()
canvas.apply {
width=t.width
height=t.height
val ctx:CanvasRenderingContext2D= getContext("2d") as CanvasRenderingContext2D
ctx.clearRect(0.0, 0.0, width.toDouble(), height.toDouble())
t.transfers.forEach {
i->
i.coords.forEach {
t->
ctx.drawImage(image = image,sx=t.xsrc.toDouble(),sy=t.ysrc.toDouble(),sw=t.width.toDouble(),sh=t.height.toDouble(),
dx=t.xdest.toDouble(),dy=t.ydest.toDouble(),dw=t.width.toDouble(),dh=t.height.toDouble())
}
}
}
canvasToBlob(t=canvas,{blob: Blob ->
console.info("blob.size:${blob.size}")
val i=URL.createObjectURL(blob=blob)
console.info("漫画URL:${i}")
Image().apply {
onload={event: Event ->
canvasHtml.let {
canvas->
val ctx:CanvasRenderingContext2D= canvas.getContext("2d") as CanvasRenderingContext2D
ctx.drawImage(this,0.0,imageHeight,naturalWidth.toDouble(),naturalHeight.toDouble().apply {
imageHeight+=this
console.info("拼接图片imageHeight:${imageHeight}")
})
}
}
src=i
}
})
}
fun create(){
Image().apply {
onload={event: Event ->
console.info("拼接图片大小naturalWidth:${naturalWidth},naturalHeight:${naturalHeight}")
}
src=canvasHtml.toDataURL()
}
}
//speedbinb.js?dmy=016301:formatted:3798
fun canvasToBlob(
t:HTMLCanvasElement, callback:(t:Blob)->Unit, n:String="image/jpeg", r: Double =.9){
val i=t.toDataURL(type=n,quality = r).split(",")[1]
console.info("url length:${i.length}")
val blobTransfer=w(t=i)
// console.info("w[i]:")
// console.info(blobTransfer)
val blob= Blob(blobParts=arrayOf(blobTransfer),options = BlobPropertyBag(type = n))
console.info("blob size:${blob.size}")
callback(blob)
}
//speedbinb.js?dmy=016301:formatted:3602
fun _m(t: String): Array<Int> {
val i= arrayOf<Int>()
repeat(t.length){
i[t[it].code]=it
}
return i
}
val m=_m("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
//speedbinb.js?dmy=016301:formatted:3608
fun w(t:String): Uint8Array {
val e=t.length
val s = t.slice(IntRange(e-2,e-1)).split("=").count() - 1
val h = 3 * ((e + 3) / 4) - s
val u = Uint8Array(h)
var i=0
var n=i
while (n<e){
val r=m[t[n].code] shl 18 or (m[t[n + 1].code] shl 12) or (m[t[n + 2].code] shl 6) or m[t[n + 3].code]
u[i]=(r shr 16 and 255).toByte()
u[i+1]=(r shr 8 and 255).toByte()
u[i+2]=(255 and r).toByte()
i+=3
n+=4
}
return u
}
//speedbinb.js?dmy=016301:formatted:8020
fun rebuild(){
hs().then {
console.info("image(naturalWidth:${it.naturalWidth},naturalHeight=${it.naturalHeight})")
val f=un(width = it.naturalWidth,height = it.naturalHeight)
callback(t=f).map {
t->
// val n=t(width = t.width,height = t.height)
us(t=t,image=it)
}
}
}
//speedbinb.js?dmy=016301:formatted:7949
private fun hs(): Promise<Image> {
return Promise(executor = { resolve, reject ->
val e=Image()
// e.crossOrigin="anonymous"
val t=urlResult.serverImagePath
e.onload={
resolve(e)
}
e.onerror = { _: dynamic, _: String, _: Int, _: Int, _: Any? ->
reject(Error("Failed to load image. : $t"))
}
e.onabort = {
reject(Error("Failed to load image. : $t"))
}
e.src=t.apply { console.info("img path:${this}") }
})
}
}