diff --git a/Writerside/topics/docthor.md b/Writerside/topics/docthor.md
index a053f24..23957b0 100644
--- a/Writerside/topics/docthor.md
+++ b/Writerside/topics/docthor.md
@@ -17,6 +17,9 @@ Asset can be found under memento:/mnt/wd/export/data
Building modern, elegant and fast desktop Compose applications
+
+Zooming an Image
+
## Modules - Libraries
diff --git a/apps/documentViewer/build.gradle.kts b/apps/documentViewer/build.gradle.kts
index 87c9a51..25e7f04 100644
--- a/apps/documentViewer/build.gradle.kts
+++ b/apps/documentViewer/build.gradle.kts
@@ -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")
}
\ No newline at end of file
diff --git a/apps/documentViewer/src/main/kotlin/de/itkl/documentViewer/DocumentViewer.kt b/apps/documentViewer/src/main/kotlin/de/itkl/documentViewer/DocumentViewer.kt
index b3a6e24..523a64a 100644
--- a/apps/documentViewer/src/main/kotlin/de/itkl/documentViewer/DocumentViewer.kt
+++ b/apps/documentViewer/src/main/kotlin/de/itkl/documentViewer/DocumentViewer.kt
@@ -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 AsyncImage(
+fun ZoomedImage(
+ state: ZoomState,
load: suspend () -> T,
painterFor: @Composable (T) -> Painter,
contentDescription: String,
@@ -101,13 +119,101 @@ fun 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)
+ )
+ }
+}
diff --git a/buildSrc/src/main/kotlin/docthor.kotlin-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/docthor.kotlin-common-conventions.gradle.kts
index ab74060..a997a22 100644
--- a/buildSrc/src/main/kotlin/docthor.kotlin-common-conventions.gradle.kts
+++ b/buildSrc/src/main/kotlin/docthor.kotlin-common-conventions.gradle.kts
@@ -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")
}
diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/MsOcr.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/MsOcr.kt
index ea56045..0ea6c06 100644
--- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/MsOcr.kt
+++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/MsOcr.kt
@@ -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()
}
}
\ No newline at end of file