starting with canvas

3
Timo Bryant 2023-12-30 22:53:11 +01:00
parent b4ab91e1db
commit a2483c85d7
5 changed files with 143 additions and 31 deletions

View File

@ -17,6 +17,9 @@ Asset can be found under <path>memento:/mnt/wd/export/data</path>
<def title="Aurora">
<a href="https://github.com/kirill-grouchnikov/aurora">Building modern, elegant and fast desktop Compose applications</a>
</def>
<def title="Zoomimage">
<a href="https://github.com/panpf/zoomimage">Zooming an Image</a>
</def>
</deflist>
## Modules - Libraries

View File

@ -12,4 +12,5 @@ dependencies {
implementation("org.pushing-pixels:aurora-window:1.3.0")
implementation(compose.desktop.currentOs)
implementation("io.github.panpf.zoomimage:zoomimage-compose:1.0.0-beta11")
implementation("io.github.panpf.zoomimage:zoomimage-compose-desktop:1.0.0-beta11")
}

View File

@ -1,20 +1,34 @@
package de.itkl.documentViewer
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawscope.DrawStyle
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.loadImageBitmap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.drawText
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPlacement
@ -23,12 +37,10 @@ import androidx.compose.ui.window.rememberWindowState
import com.github.panpf.zoomimage.ZoomImage
import com.github.panpf.zoomimage.compose.ZoomState
import com.github.panpf.zoomimage.compose.rememberZoomState
import com.github.panpf.zoomimage.compose.subsampling.fromResource
import com.github.panpf.zoomimage.subsampling.ImageSource
import com.github.panpf.zoomimage.compose.zoom.ScrollBarSpec
import com.github.panpf.zoomimage.compose.zoom.ZoomableState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.pushingpixels.aurora.component.model.Command
import org.pushingpixels.aurora.component.projection.CommandButtonProjection
import org.pushingpixels.aurora.theming.auroraBackground
import org.pushingpixels.aurora.theming.marinerSkin
import org.pushingpixels.aurora.window.AuroraWindow
@ -36,17 +48,17 @@ import org.pushingpixels.aurora.window.AuroraWindowTitlePaneConfigurations
import org.pushingpixels.aurora.window.auroraApplication
import java.io.File
import java.io.IOException
import java.nio.file.Paths
import io.github.oshai.kotlinlogging.KotlinLogging
import com.github.panpf.zoomimage.util.Logger as ZoomLogger
class DocumentViewer {
}
private val Log = KotlinLogging.logger { }
fun main() = auroraApplication {
val state = rememberWindowState(
placement = WindowPlacement.Floating,
position = WindowPosition.Aligned(Alignment.Center),
size = DpSize(220.dp, 150.dp)
size = DpSize(1000. dp, 800.dp)
)
AuroraWindow(
@ -56,31 +68,37 @@ fun main() = auroraApplication {
windowTitlePaneConfiguration = AuroraWindowTitlePaneConfigurations.AuroraPlain(),
onCloseRequest = ::exitApplication
) {
var text by remember { mutableStateOf("Hello, World!") }
viewImage()
}
}
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxSize().auroraBackground()
@Composable
@Preview
fun viewImage() {
Column (
modifier = Modifier.fillMaxSize().auroraBackground()
) {
val state = rememberZoomState(logger = ZoomLogger("zoom", level = ZoomLogger.INFO))
Text("${state.zoomable.transform.scale} ${state.zoomable.transform.offset}")
Box(
modifier = Modifier.fillMaxSize()
) {
AsyncImage(
ZoomedImage(
state = state,
load = { loadImageBitmap(File("assets/xs-reg/00001.jpg")) },
painterFor = { remember { BitmapPainter(it) } },
contentDescription = "Sample",
modifier = Modifier.fillMaxSize()
)
// CommandButtonProjection(
// contentModel = Command(
// text = text,
// action = { text = "Hello, Desktop!" }
// )
// ).project()
canvas(state.zoomable)
// shapes(state.zoomable)
}
}
}
@Composable
fun <T> AsyncImage(
fun <T> ZoomedImage(
state: ZoomState,
load: suspend () -> T,
painterFor: @Composable (T) -> Painter,
contentDescription: String,
@ -101,13 +119,101 @@ fun <T> AsyncImage(
}
if (image != null) {
val scrollBar = remember {
ScrollBarSpec(
color = Color.Red,
size = 6.dp,
margin = 12.dp,
)
}
ZoomImage(
painter = painterFor(image!!),
contentDescription = contentDescription,
contentScale = contentScale,
modifier = modifier
modifier = modifier,
scrollBar = scrollBar,
state = state
)
}
}
fun loadImageBitmap(file: File): ImageBitmap =
file.inputStream().buffered().use(::loadImageBitmap)
data class PointConverter(
val docWidth: Int,
val docHeight: Int,
val canvasWidth: Float,
val canvasHeight: Float
) {
fun convertX(x: Int): Float {
val xf = x.toFloat()
val relXf = docWidth / xf
val scaledXf = canvasWidth * relXf
// println("X: $scaledXf")
return scaledXf
}
fun convertY(y: Int): Float {
val yf = y.toFloat()
val relYf = docHeight / yf
val scaledYf = canvasHeight * relYf
// println("Y: $scaledYf")
return scaledYf
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun shapes(zoomableState: ZoomableState) {
Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.offset(100.dp)
.size(100.dp)
.clip(RectangleShape)
.background(Color.Red)
.onClick(true) { println("clicked") }
)
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun canvas(zoomableState: ZoomableState) {
Canvas(modifier = Modifier
.fillMaxSize()
.onPointerEvent(PointerEventType.Move) {
val position = it.changes.first().position
println(position)
}
)
{
val converter = PointConverter(
docWidth = 2481,
docHeight = 3507,
canvasWidth = this.size.width,
canvasHeight = this.size.height
)
// val width = 2481
// val height = 3507
// val x =
// "width": 2481,
// "height": 3507,
// "boundingBox": [
// 288,
// 697,
// 793,
// 700,
// 793,
// 744,
// 288,
// 741
// ],
drawRect(
Color.Blue,
// topLeft = Offset(converter.convertX(288), converter.convertY(697)),
topLeft = zoomableState.transform.offset + Offset(800f,800f),
size = Size(30f, 30f),
style = Stroke(width = 5f)
)
}
}

View File

@ -1,3 +1,4 @@
import gradle.kotlin.dsl.accessors._d9dcfd1a467b0b6fe90c5571a57aa558.api
import org.gradle.api.plugins.jvm.JvmTestSuite
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
@ -17,6 +18,7 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
api("io.github.oshai:kotlin-logging-jvm:5.1.0")
testImplementation("io.insert-koin:koin-test:$koin_version")
}

View File

@ -24,7 +24,7 @@ class MsOcr: KoinComponent {
contentType(resource.contentType)
setBody(resource.read())
}
println("got response: ${response.status} in ${response.responseTime}")
println(response.bodyAsText())
return response.body()
}
}