Skip to content

Commit b48663a

Browse files
committed
Migrate GUI from JavaFX to Kotlin Compose, adjust CLI
1 parent 3c6e96a commit b48663a

22 files changed

Lines changed: 1682 additions & 817 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
output/
33
.gradle/
44
build/
5-
out/
5+
out/
6+
.kotlin

CONTRIBUTING.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue]
2828
People *love* thorough bug reports. I'm not even kidding.
2929

3030
### Used technologies
31-
* Kotlin
32-
* Gradle
33-
* JavaFX
34-
* RxJava 3
35-
* For testing: Jupiter JUnit
36-
* IDE: IntelliJ IDEA
31+
* **Kotlin** - Primary programming language
32+
* **Gradle** - Build system and dependency management
33+
* **Compose Multiplatform** - Modern declarative UI framework (replaced JavaFX)
34+
* **Material Design 3** - UI design system and components
35+
* **Coroutines** - Asynchronous programming and threading
36+
* **JCommander** - Command-line argument parsing
37+
* **Jupiter JUnit** - Unit testing framework
38+
* **IDE**: IntelliJ IDEA
3739

3840
### How to develop ImageCipher?
3941
1. Choose issue that is opened and not associated to anyone **or** propose something to develop.

README.md

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,72 @@
66
Steganography software for encrypting text into image that uses modified version of LSB (Least Significant Bit) algorithm. Project is part of this [Medium article](https://medium.com/@szymonkocur/how-i-redesigned-lsb-steganography-algorithm-ee45503dd47).
77

88
## Usage:
9-
### Window option
10-
#### To encrypt text into image:
11-
1. Find a photo to use for encryption.
12-
2. Enter the name of that photo in place of "image_name".
13-
3. Enter text to encrypt.
14-
4. Click "Encrypt".
15-
5. Enjoy!
16-
17-
#### To decrypt text from image:
18-
1. Enter name of image with encrypted message.
19-
2. Click "Decrypt".
20-
3. Enjoy!
21-
22-
### Command line arguments:
23-
`-EM arg` or `--encryption-mode arg` - sets encryption mode to one of the following:
24-
* if `arg` is equal to 1, then SingleColorEncryption will be used
25-
* if `arg` is equal to 2, then MultiColorEncryptio will be used
26-
* if `arg` is equal to 3, then LowLevelBitEncryption will be used
27-
* if `arg` is equal to 4, then RSAEncryption will be used. WARNING: EXPERIMENTAL IMPLEMENTATION
28-
29-
`-DM arg` or `--decryption-mode arg` - sets decryption mode with `arg` option analogically used as above (of course it will decrypt specific algorithm)
30-
31-
`-f fileName` or `--file-name fileName` - sets image name (or path to it) which will store encrypted data
32-
33-
#### Example:
34-
`java -jar Image-Cipher.jar -DM 3 -f my_awesome_image_with_embedded_data.file`
9+
10+
### GUI Application
11+
Launch desktop application:
12+
```bash
13+
./gradlew :app:run
14+
```
15+
Or run the compiled JAR:
16+
```bash
17+
java -jar app.jar
18+
```
19+
20+
### Command Line Interface
21+
22+
The CLI has been redesigned with intuitive parameters and comprehensive help:
23+
24+
```bash
25+
# Show help
26+
java -jar app.jar --help
27+
28+
# Show version
29+
java -jar app.jar --version
30+
```
31+
32+
#### Encryption Examples:
33+
```bash
34+
# Encrypt text into image (interactive input)
35+
java -jar app.jar --encrypt single-color --input photo.jpg
36+
37+
# Encrypt specific text
38+
java -jar app.jar -e multi-color -i image.png -t "Secret message"
39+
40+
# Encrypt with output file
41+
java -jar app.jar -e low-level-bit -i input.jpg -t "Hidden data" -o encrypted.png
42+
43+
# Encrypt from stdin
44+
java -jar app.jar -e single-color -i photo.jpg -t :stdin
45+
```
46+
47+
#### Decryption Examples:
48+
```bash
49+
# Decrypt text from image
50+
java -jar app.jar --decrypt single-color --input encrypted.jpg
51+
52+
# Decrypt with verbose output
53+
java -jar app.jar -d multi-color -i hidden.png --verbose
54+
55+
# Decrypt low-level bit data
56+
java -jar app.jar -d low-level-bit -i steganographic.png
57+
```
58+
59+
#### Available Algorithms:
60+
- **single-color**: Basic LSB steganography in single color channel
61+
- **multi-color**: Enhanced LSB using multiple color channels
62+
- **low-level-bit**: Advanced bit-level manipulation
63+
- **rsa**: RSA encryption with steganography (experimental, encryption only)
64+
65+
#### CLI Parameters:
66+
- `-h, --help` - Show help message with examples
67+
- `-e, --encrypt <algorithm>` - Encrypt text using specified algorithm
68+
- `-d, --decrypt <algorithm>` - Decrypt text using specified algorithm
69+
- `-i, --input, --image <file>` - Input image file path
70+
- `-o, --output <file>` - Output image file (encryption only)
71+
- `-t, --text <text>` - Text to encrypt (use `:stdin` for interactive input)
72+
- `-c, --certificate <file>` - Certificate file for RSA encryption
73+
- `-v, --verbose` - Enable detailed output
74+
- `--version` - Show version information
3575

3676
### Before encryption
3777
![Demo](images/github-logo.jpeg)

app/build.gradle.kts

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

33
plugins {
4-
kotlin("jvm") version "2.2.0"
5-
id("org.openjfx.javafxplugin") version "0.1.0"
4+
kotlin("jvm") version "2.1.0"
5+
kotlin("plugin.compose") version "2.1.0"
6+
id("org.jetbrains.compose") version "1.7.1"
67
application
78
java
89
}
910

1011
java {
11-
sourceCompatibility = JavaVersion.VERSION_21
12-
targetCompatibility = JavaVersion.VERSION_21
12+
sourceCompatibility = JavaVersion.VERSION_17
13+
targetCompatibility = JavaVersion.VERSION_17
1314
}
1415

1516
group = "com.imagecipher"
1617
version = "1.0.0"
1718

1819
repositories {
1920
mavenCentral()
21+
google()
22+
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
2023
}
2124

2225
application {
23-
mainClass.set("com.skocur.imagecipher.MainKt")
24-
applicationDefaultJvmArgs = listOf(
25-
"--add-modules", "javafx.controls,javafx.fxml",
26-
"--add-exports", "javafx.graphics/com.sun.javafx.application=ALL-UNNAMED"
27-
)
26+
mainClass.set("com.imagecipher.app.MainKt")
2827
}
2928

3029
tasks {
3130
jar {
3231
manifest {
33-
attributes["Start-Class"] = "com.skocur.imagecipher.MainKt"
32+
attributes["Main-Class"] = "com.imagecipher.app.MainKt"
3433
}
3534
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
35+
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
3636
}
3737
}
3838
dependencies {
39-
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.2.0")
39+
implementation(compose.desktop.currentOs)
40+
implementation(compose.material3)
41+
implementation(compose.materialIconsExtended)
42+
43+
implementation("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
4044
implementation("org.jetbrains:annotations:24.0.0")
45+
46+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
47+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.6.4")
4148

4249
implementation("org.jcommander:jcommander:2.0")
4350

44-
implementation("org.openjfx:javafx-controls:21")
45-
implementation("org.openjfx:javafx-fxml:21")
46-
implementation("org.openjfx:javafx-swing:21")
47-
4851
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
4952
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2")
5053

51-
implementation("org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0")
52-
implementation("com.jfoenix:jfoenix:9.0.10")
53-
5454
implementation("io.reactivex.rxjava3:rxjava:3.1.6")
5555

5656
implementation("com.squareup.retrofit2:retrofit:2.9.0")
@@ -75,5 +75,5 @@ tasks.test {
7575
useJUnitPlatform()
7676
}
7777
kotlin {
78-
jvmToolchain(21)
78+
jvmToolchain(17)
7979
}

app/src/main/kotlin/com/imagecipher/app/CommandArgs.kt

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,76 @@ class CommandArgs {
88
var parameters: MutableList<String> = mutableListOf()
99

1010
@Parameter(
11-
names = ["-EM", "--enryption-mode"],
12-
description = "Encryption mode: 1 - SingleColorEncryption, 2 - MultiColorEncryption, 3 - LowLevelBitEncryption, 4 - RSAEncryption"
11+
names = ["-h", "--help"],
12+
description = "Show this help message",
13+
help = true
1314
)
14-
var encryptionMode: Int = 0 // If 0, then message will not be encrypted
15+
var help: Boolean = false
1516

1617
@Parameter(
17-
names = ["-DM", "--decryption-mode"],
18-
description = "Decryption mode: options as in encryption mode"
18+
names = ["-e", "--encrypt"],
19+
description = "Encryption algorithm: single-color, multi-color, low-level-bit, rsa"
1920
)
20-
var decryptionMode: Int = 0 // If 0, then message will not be decrypted
21+
var encryptAlgorithm: String? = null
2122

2223
@Parameter(
23-
names = ["-f", "--file-name"],
24-
description = "Path to file which will store encrypted data"
24+
names = ["-d", "--decrypt"],
25+
description = "Decryption algorithm: single-color, multi-color, low-level-bit"
2526
)
26-
var originalFileName: String? = null
27+
var decryptAlgorithm: String? = null
2728

2829
@Parameter(
29-
names = ["-cf", "--certificate-file"],
30-
description = "Path to file that contains certificate"
30+
names = ["-i", "--input", "--image"],
31+
description = "Path to input image file",
32+
required = false
3133
)
32-
var certificateFileName: String? = null
34+
var imageFile: String? = null
35+
36+
@Parameter(
37+
names = ["-o", "--output"],
38+
description = "Path to output image file (for encryption only)"
39+
)
40+
var outputFile: String? = null
41+
42+
@Parameter(
43+
names = ["-t", "--text"],
44+
description = "Text to encrypt (use :stdin to read from standard input)"
45+
)
46+
var textToEncrypt: String? = null
47+
48+
@Parameter(
49+
names = ["-c", "--certificate"],
50+
description = "Path to certificate file (for RSA encryption only)"
51+
)
52+
var certificateFile: String? = null
53+
54+
@Parameter(
55+
names = ["-v", "--verbose"],
56+
description = "Enable verbose output"
57+
)
58+
var verbose: Boolean = false
59+
60+
@Parameter(
61+
names = ["--version"],
62+
description = "Show version information"
63+
)
64+
var version: Boolean = false
65+
66+
// Legacy support - keep old parameters but mark as deprecated
67+
val encryptionMode: Int
68+
get() = when (encryptAlgorithm?.lowercase()) {
69+
"single-color" -> 1
70+
"multi-color" -> 2
71+
"low-level-bit" -> 3
72+
"rsa" -> 4
73+
else -> 0
74+
}
75+
76+
val decryptionMode: Int
77+
get() = when (decryptAlgorithm?.lowercase()) {
78+
"single-color" -> 1
79+
"multi-color" -> 2
80+
"low-level-bit" -> 3
81+
else -> 0
82+
}
3383
}

0 commit comments

Comments
 (0)