starting with canvas
parent
b4ab91e1db
commit
a2483c85d7
|
|
@ -17,6 +17,9 @@ Asset can be found under <path>memento:/mnt/wd/export/data</path>
|
||||||
<def title="Aurora">
|
<def title="Aurora">
|
||||||
<a href="https://github.com/kirill-grouchnikov/aurora">Building modern, elegant and fast desktop Compose applications</a>
|
<a href="https://github.com/kirill-grouchnikov/aurora">Building modern, elegant and fast desktop Compose applications</a>
|
||||||
</def>
|
</def>
|
||||||
|
<def title="Zoomimage">
|
||||||
|
<a href="https://github.com/panpf/zoomimage">Zooming an Image</a>
|
||||||
|
</def>
|
||||||
</deflist>
|
</deflist>
|
||||||
|
|
||||||
## Modules - Libraries
|
## Modules - Libraries
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,5 @@ dependencies {
|
||||||
implementation("org.pushing-pixels:aurora-window:1.3.0")
|
implementation("org.pushing-pixels:aurora-window:1.3.0")
|
||||||
implementation(compose.desktop.currentOs)
|
implementation(compose.desktop.currentOs)
|
||||||
implementation("io.github.panpf.zoomimage:zoomimage-compose:1.0.0-beta11")
|
implementation("io.github.panpf.zoomimage:zoomimage-compose:1.0.0-beta11")
|
||||||
|
implementation("io.github.panpf.zoomimage:zoomimage-compose-desktop:1.0.0-beta11")
|
||||||
}
|
}
|
||||||
|
|
@ -1,20 +1,34 @@
|
||||||
package de.itkl.documentViewer
|
package de.itkl.documentViewer
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.text.ExperimentalTextApi
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
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.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.BitmapPainter
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
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.layout.ContentScale
|
||||||
import androidx.compose.ui.res.loadImageBitmap
|
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.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.WindowPlacement
|
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.ZoomImage
|
||||||
import com.github.panpf.zoomimage.compose.ZoomState
|
import com.github.panpf.zoomimage.compose.ZoomState
|
||||||
import com.github.panpf.zoomimage.compose.rememberZoomState
|
import com.github.panpf.zoomimage.compose.rememberZoomState
|
||||||
import com.github.panpf.zoomimage.compose.subsampling.fromResource
|
import com.github.panpf.zoomimage.compose.zoom.ScrollBarSpec
|
||||||
import com.github.panpf.zoomimage.subsampling.ImageSource
|
import com.github.panpf.zoomimage.compose.zoom.ZoomableState
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
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.auroraBackground
|
||||||
import org.pushingpixels.aurora.theming.marinerSkin
|
import org.pushingpixels.aurora.theming.marinerSkin
|
||||||
import org.pushingpixels.aurora.window.AuroraWindow
|
import org.pushingpixels.aurora.window.AuroraWindow
|
||||||
|
|
@ -36,17 +48,17 @@ import org.pushingpixels.aurora.window.AuroraWindowTitlePaneConfigurations
|
||||||
import org.pushingpixels.aurora.window.auroraApplication
|
import org.pushingpixels.aurora.window.auroraApplication
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
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 {
|
fun main() = auroraApplication {
|
||||||
val state = rememberWindowState(
|
val state = rememberWindowState(
|
||||||
placement = WindowPlacement.Floating,
|
placement = WindowPlacement.Floating,
|
||||||
position = WindowPosition.Aligned(Alignment.Center),
|
position = WindowPosition.Aligned(Alignment.Center),
|
||||||
size = DpSize(220.dp, 150.dp)
|
size = DpSize(1000. dp, 800.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
AuroraWindow(
|
AuroraWindow(
|
||||||
|
|
@ -56,31 +68,37 @@ fun main() = auroraApplication {
|
||||||
windowTitlePaneConfiguration = AuroraWindowTitlePaneConfigurations.AuroraPlain(),
|
windowTitlePaneConfiguration = AuroraWindowTitlePaneConfigurations.AuroraPlain(),
|
||||||
onCloseRequest = ::exitApplication
|
onCloseRequest = ::exitApplication
|
||||||
) {
|
) {
|
||||||
var text by remember { mutableStateOf("Hello, World!") }
|
viewImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
@Composable
|
||||||
horizontalArrangement = Arrangement.Center,
|
@Preview
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
fun viewImage() {
|
||||||
modifier = Modifier.fillMaxSize().auroraBackground()
|
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")) },
|
load = { loadImageBitmap(File("assets/xs-reg/00001.jpg")) },
|
||||||
painterFor = { remember { BitmapPainter(it) } },
|
painterFor = { remember { BitmapPainter(it) } },
|
||||||
contentDescription = "Sample",
|
contentDescription = "Sample",
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
|
|
||||||
)
|
)
|
||||||
// CommandButtonProjection(
|
canvas(state.zoomable)
|
||||||
// contentModel = Command(
|
// shapes(state.zoomable)
|
||||||
// text = text,
|
|
||||||
// action = { text = "Hello, Desktop!" }
|
|
||||||
// )
|
|
||||||
// ).project()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T> AsyncImage(
|
fun <T> ZoomedImage(
|
||||||
|
state: ZoomState,
|
||||||
load: suspend () -> T,
|
load: suspend () -> T,
|
||||||
painterFor: @Composable (T) -> Painter,
|
painterFor: @Composable (T) -> Painter,
|
||||||
contentDescription: String,
|
contentDescription: String,
|
||||||
|
|
@ -101,13 +119,101 @@ fun <T> AsyncImage(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
|
val scrollBar = remember {
|
||||||
|
ScrollBarSpec(
|
||||||
|
color = Color.Red,
|
||||||
|
size = 6.dp,
|
||||||
|
margin = 12.dp,
|
||||||
|
)
|
||||||
|
}
|
||||||
ZoomImage(
|
ZoomImage(
|
||||||
painter = painterFor(image!!),
|
painter = painterFor(image!!),
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
contentScale = contentScale,
|
contentScale = contentScale,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
scrollBar = scrollBar,
|
||||||
|
state = state
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun loadImageBitmap(file: File): ImageBitmap =
|
fun loadImageBitmap(file: File): ImageBitmap =
|
||||||
file.inputStream().buffered().use(::loadImageBitmap)
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import gradle.kotlin.dsl.accessors._d9dcfd1a467b0b6fe90c5571a57aa558.api
|
||||||
import org.gradle.api.plugins.jvm.JvmTestSuite
|
import org.gradle.api.plugins.jvm.JvmTestSuite
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
|
@ -17,6 +18,7 @@ dependencies {
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
|
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")
|
testImplementation("io.insert-koin:koin-test:$koin_version")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class MsOcr: KoinComponent {
|
||||||
contentType(resource.contentType)
|
contentType(resource.contentType)
|
||||||
setBody(resource.read())
|
setBody(resource.read())
|
||||||
}
|
}
|
||||||
println("got response: ${response.status} in ${response.responseTime}")
|
println(response.bodyAsText())
|
||||||
return response.body()
|
return response.body()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue