Skip to content

Commit 8208a9a

Browse files
authored
Merge pull request #1 from rokuosan/develop
First release
2 parents 286b7fa + 543af46 commit 8208a9a

File tree

10 files changed

+637
-3
lines changed

10 files changed

+637
-3
lines changed

build.gradle.kts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
22

33
plugins {
4-
kotlin("jvm") version "1.7.10"
4+
application
5+
java
6+
7+
kotlin("jvm") version "1.6.10"
8+
id("org.jetbrains.compose") version "1.1.0"
9+
id("com.github.johnrengelman.shadow") version "7.1.2"
510
}
611

712
group = "me.konso"
8-
version = "1.0-SNAPSHOT"
13+
version = "1.0.0"
14+
java.sourceCompatibility = JavaVersion.VERSION_17
15+
java.targetCompatibility = JavaVersion.VERSION_1_8
16+
17+
application {
18+
mainClass.set("${group}.qrcodeTools.MainKt")
19+
}
920

1021
repositories {
1122
mavenCentral()
23+
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
1224
}
1325

1426
dependencies {
27+
// QR Code
28+
implementation("com.google.zxing:core:3.5.0")
29+
implementation("com.google.zxing:javase:3.5.0")
30+
31+
// Webcam
32+
implementation("com.github.sarxos:webcam-capture:0.3.12")
33+
implementation("org.slf4j:slf4j-log4j12:2.0.3")
34+
35+
// Compose
36+
implementation(compose.desktop.currentOs)
37+
1538
testImplementation(kotlin("test"))
1639
}
1740

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package me.konso.qrcodeTools
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.compositionLocalOf
5+
import androidx.compose.runtime.remember
6+
import com.github.sarxos.webcam.Webcam
7+
import com.github.sarxos.webcam.WebcamPanel
8+
import com.github.sarxos.webcam.WebcamResolution
9+
10+
class AppResources(
11+
val webcamPanel: WebcamPanel,
12+
var isCapturing: Boolean
13+
)
14+
15+
val LocalAppResources = compositionLocalOf<AppResources> {
16+
error("No resources are provided.")
17+
}
18+
19+
@Composable
20+
fun rememberAppResources(): AppResources{
21+
val camera = Webcam.getDefault()
22+
camera.viewSize = WebcamResolution.VGA.size
23+
val panel = WebcamPanel(camera)
24+
panel.isDisplayDebugInfo = true
25+
panel.preferredSize = WebcamResolution.VGA.size
26+
panel.isFPSDisplayed = true
27+
28+
return remember {
29+
AppResources(
30+
webcamPanel = panel,
31+
isCapturing = false
32+
)
33+
}
34+
}
Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,129 @@
11
package me.konso.qrcodeTools
22

3-
fun main(){
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Row
5+
import androidx.compose.foundation.layout.fillMaxSize
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.material.Button
8+
import androidx.compose.material.Text
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.CompositionLocalProvider
11+
import androidx.compose.runtime.mutableStateMapOf
12+
import androidx.compose.runtime.remember
13+
import androidx.compose.ui.Alignment
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.unit.DpSize
16+
import androidx.compose.ui.unit.dp
17+
import androidx.compose.ui.window.ApplicationScope
18+
import androidx.compose.ui.window.Window
19+
import androidx.compose.ui.window.WindowPlacement
20+
import androidx.compose.ui.window.WindowPosition
21+
import androidx.compose.ui.window.WindowState
22+
import androidx.compose.ui.window.application
23+
import me.konso.qrcodeTools.WindowType.CAMERA
24+
import me.konso.qrcodeTools.WindowType.DESKTOP
25+
import me.konso.qrcodeTools.WindowType.GENERATOR
26+
import me.konso.qrcodeTools.WindowType.values
27+
import me.konso.qrcodeTools.window.CaptureWindow
28+
import me.konso.qrcodeTools.window.GeneratorWindow
29+
import me.konso.qrcodeTools.window.ReaderWindow
430

31+
enum class WindowType(
32+
val title: String,
33+
val text: String,
34+
) {
35+
GENERATOR("QR Code Generator", "Open Generator"),
36+
CAMERA("QR Code Reader [Camera]", "Open Camera"),
37+
DESKTOP("QR Code Reader [Desktop]", "Open Desktop Reader")
38+
}
39+
fun main() = application{
40+
CompositionLocalProvider(LocalAppResources provides rememberAppResources()){
41+
AppWindow(this)
42+
}
43+
}
44+
45+
@Composable
46+
fun AppWindow(app: ApplicationScope) {
47+
val windows=values().toList()
48+
val isOpen=remember { mutableStateMapOf<String, Boolean>() }
49+
var isCapturing = LocalAppResources.current.isCapturing
50+
51+
// Initialize state
52+
for(w in windows) {
53+
isOpen+=w.name to false
54+
}
55+
56+
Window(
57+
title="QRCode Tools",
58+
onCloseRequest={ app.exitApplication() },
59+
resizable = false,
60+
state=WindowState(
61+
size = DpSize(600.dp, 200.dp),
62+
placement = WindowPlacement.Floating,
63+
position=WindowPosition(Alignment.Center)
64+
)
65+
) {
66+
Row(
67+
modifier=Modifier.fillMaxSize()
68+
.padding(horizontal = 12.dp),
69+
horizontalArrangement = Arrangement.SpaceEvenly,
70+
verticalAlignment = Alignment.CenterVertically,
71+
) {
72+
for(w in windows) {
73+
if(w==CAMERA) continue
74+
75+
Button(
76+
onClick={
77+
isOpen[w.name]=true
78+
79+
if(w==DESKTOP){
80+
isCapturing = true
81+
}
82+
},
83+
enabled=!isOpen[w.name]!!
84+
) {
85+
Text(w.text)
86+
}
87+
88+
if(isOpen[w.name]!!) {
89+
Window(
90+
onCloseRequest={
91+
isOpen[w.name]=false
92+
93+
if(w == DESKTOP){
94+
isCapturing = false
95+
}
96+
},
97+
title=w.title,
98+
resizable=false
99+
) {
100+
when(w){
101+
GENERATOR -> GeneratorWindow()
102+
DESKTOP -> CaptureWindow(isCapturing)
103+
else -> {}
104+
}
105+
}
106+
}
107+
}
108+
109+
Button(
110+
onClick={ isOpen[CAMERA.name]=true },
111+
enabled=!isOpen[CAMERA.name]!!
112+
) {
113+
Text(CAMERA.text)
114+
}
115+
116+
if(isOpen[CAMERA.name]!!) {
117+
Window(
118+
onCloseRequest={
119+
isOpen[CAMERA.name]=false
120+
},
121+
title=CAMERA.title,
122+
resizable=false,
123+
) {
124+
ReaderWindow()
125+
}
126+
}
127+
}
128+
}
5129
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package me.konso.qrcodeTools.qrcode
2+
3+
import java.awt.Rectangle
4+
import java.awt.Robot
5+
import java.awt.Toolkit
6+
import java.awt.image.BufferedImage
7+
8+
object Capture {
9+
fun getDesktopImage(): BufferedImage?{
10+
return try{
11+
Robot().createScreenCapture(Rectangle(Toolkit.getDefaultToolkit().screenSize))
12+
}catch(e: Exception){
13+
e.printStackTrace()
14+
null
15+
}
16+
}
17+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package me.konso.qrcodeTools.qrcode
2+
3+
import com.google.zxing.BarcodeFormat
4+
import com.google.zxing.EncodeHintType
5+
import com.google.zxing.client.j2se.MatrixToImageWriter
6+
import com.google.zxing.qrcode.QRCodeWriter
7+
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
8+
import java.awt.image.BufferedImage
9+
import java.util.*
10+
11+
object Generator {
12+
private val writer = QRCodeWriter()
13+
14+
fun makeQRCode(text: String, width: Int = 512, height: Int = 512): BufferedImage{
15+
val hints: MutableMap<EncodeHintType, Any> = EnumMap(EncodeHintType::class.java)
16+
hints[EncodeHintType.ERROR_CORRECTION]=ErrorCorrectionLevel.L
17+
hints[EncodeHintType.CHARACTER_SET]=Charsets.UTF_8.displayName()
18+
hints[EncodeHintType.MARGIN]=4
19+
20+
return MatrixToImageWriter.toBufferedImage(writer.encode(text, BarcodeFormat.QR_CODE, width, height, hints))
21+
}
22+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package me.konso.qrcodeTools.qrcode
2+
3+
import com.github.sarxos.webcam.Webcam
4+
import com.google.zxing.BinaryBitmap
5+
import com.google.zxing.DecodeHintType
6+
import com.google.zxing.MultiFormatReader
7+
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
8+
import com.google.zxing.common.HybridBinarizer
9+
import java.awt.image.BufferedImage
10+
import java.util.*
11+
12+
object Reader{
13+
private lateinit var image: BufferedImage
14+
15+
fun read(camera: Webcam): String?{
16+
if(!camera.isOpen) return null
17+
18+
// Get image
19+
image = camera.image?:return null
20+
return this.read(image)
21+
}
22+
23+
fun read(image: BufferedImage?): String?{
24+
image?:return null
25+
26+
// Create bitmap
27+
val src = BufferedImageLuminanceSource(image)
28+
val bitmap = BinaryBitmap(HybridBinarizer(src))
29+
val hints: MutableMap<DecodeHintType, Any> = EnumMap(DecodeHintType::class.java)
30+
hints[DecodeHintType.CHARACTER_SET]=Charsets.UTF_8.displayName()
31+
32+
return try{
33+
MultiFormatReader().decode(bitmap, hints).text
34+
}catch(e: Exception){
35+
null
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)