diff --git a/docs/docs/03-usage/11-cli/01-installation.md b/docs/docs/03-usage/11-cli/01-installation.md index c247170..8f7a2d7 100644 --- a/docs/docs/03-usage/11-cli/01-installation.md +++ b/docs/docs/03-usage/11-cli/01-installation.md @@ -31,7 +31,7 @@ Use Gradle to build the CLI tool: *Note:* You must replace `` in the following commands (e.g. `0.1.0-SNAPSHOT`) 1. `cd cli` (if not already there) -2. `./gradlew shadowJar"` +2. `./gradlew shadowJar` - This will create a standalone jar file: `./build/libs/cli--all.jar` 3. `java -jar build/libs/cli--all.jar --help` - This will print all possible commands of the CLI tool. diff --git a/docs/docs/03-usage/12-webinterface/01-installation.md b/docs/docs/03-usage/12-webinterface/01-installation.md index f3275d7..1c7e07e 100644 --- a/docs/docs/03-usage/12-webinterface/01-installation.md +++ b/docs/docs/03-usage/12-webinterface/01-installation.md @@ -27,6 +27,12 @@ the following commands from the root directory of the project: 1. `cd watermarker` 2. `./gradlew publishToMavenLocal` +:::info +The source code comes with enabled source maps to allow frontend debugging. They should be disabled +in production to prevent the exposure of source code. To disable it, add `sourceMaps = false` inside +the `build.gradle.kts`. +::: + ## Building from Source (Manual Build) Use Gradle to manually build and run the webinterface: diff --git a/watermarker/src/commonTest/kotlin/unitTest/WatermarkerTest.kt b/watermarker/src/commonTest/kotlin/unitTest/WatermarkerTest.kt index ba6e0a8..86b2735 100644 --- a/watermarker/src/commonTest/kotlin/unitTest/WatermarkerTest.kt +++ b/watermarker/src/commonTest/kotlin/unitTest/WatermarkerTest.kt @@ -6,6 +6,7 @@ */ package unitTest +import Platform import de.fraunhofer.isst.trend.watermarker.SupportedFileType import de.fraunhofer.isst.trend.watermarker.Watermarker import de.fraunhofer.isst.trend.watermarker.fileWatermarker.DefaultTranscoding @@ -167,6 +168,22 @@ class WatermarkerTest { assertEquals(expected, result.value) } + @Test + fun textGetWatermarks_exactlyOneWatermark_successAndWatermark() { + // Arrange + val expected = + listOf( + Watermark.fromString("a"), + ) + + // Act + val result = watermarker.textGetWatermarks("a a a a a a a a a a") + + // Assert + assertTrue(result.isSuccess) + assertEquals(expected, result.value) + } + @Test fun textGetWatermarks_differentWatermarks_successAndNotSquashedWatermarks() { // Arrange diff --git a/webinterface/build.gradle.kts b/webinterface/build.gradle.kts index ef010f9..a749f9e 100644 --- a/webinterface/build.gradle.kts +++ b/webinterface/build.gradle.kts @@ -52,7 +52,6 @@ kotlin { runTask( Action { mainOutputFileName = "main.bundle.js" - sourceMaps = false devServerProperty = KotlinWebpackConfig.DevServer( open = false, diff --git a/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt b/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt index 3cdb92b..6a1846c 100644 --- a/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt +++ b/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt @@ -9,13 +9,14 @@ import de.fraunhofer.isst.trend.watermarker.Watermarker import de.fraunhofer.isst.trend.watermarker.fileWatermarker.TextWatermarker import de.fraunhofer.isst.trend.watermarker.returnTypes.Result import de.fraunhofer.isst.trend.watermarker.watermarks.TextWatermark -import de.fraunhofer.isst.trend.watermarker.watermarks.Watermark +import io.kvision.core.FontWeight import io.kvision.core.Placement import io.kvision.core.TooltipOptions import io.kvision.core.Trigger import io.kvision.core.enableTooltip import io.kvision.core.onInput import io.kvision.form.FormMethod +import io.kvision.form.check.CheckBox import io.kvision.form.formPanel import io.kvision.form.text.Text import io.kvision.form.text.TextArea @@ -24,10 +25,13 @@ import io.kvision.html.ButtonStyle import io.kvision.html.button import io.kvision.html.div import io.kvision.html.span +import io.kvision.i18n.tr import io.kvision.modal.Confirm import io.kvision.modal.Modal import io.kvision.panel.HPanel import io.kvision.panel.SimplePanel +import io.kvision.panel.fieldsetPanel +import io.kvision.panel.hPanel import io.kvision.progress.Progress import io.kvision.progress.progressNumeric import io.kvision.state.ObservableValue @@ -43,6 +47,10 @@ import kotlin.math.round data class WatermarkerTextForm( val watermark: String, val text: String, + val trendmarkCompressed: Boolean, + val trendmarkSized: Boolean, + val trendmarkCRC32: Boolean, + val trendmarkSHA3256: Boolean, ) class WatermarkTextEmbedTab : SimplePanel() { @@ -72,6 +80,62 @@ class WatermarkTextEmbedTab : SimplePanel() { ) } + private val compressedCheckBox = + CheckBox(label = "Compressed ⓘ", rich = true) { + paddingRight = 20.px + enableTooltip( + TooltipOptions( + title = + "Compress the watermark content before embedding into" + + " the text. Good for longer watermarks.", + triggers = listOf(Trigger.HOVER), + ), + ) + } + + private val sizedCheckBox = + CheckBox(label = "Sized ⓘ", rich = true) { + paddingRight = 20.px + enableTooltip( + TooltipOptions( + title = + "Include the size of the watermark for additional " + + "verification. Needs a longer cover text content.", + triggers = listOf(Trigger.HOVER), + ), + ) + } + + @Suppress("ktlint:standard:property-naming") + private val CRC32CheckBox = + CheckBox(label = "CRC32 ⓘ", rich = true) { + paddingRight = 20.px + enableTooltip( + TooltipOptions( + title = + "Uses the Cyclic Redundancy Check (CRC) " + + "error-detecting code for additional robustness. " + + "Needs a longer cover text content.", + triggers = listOf(Trigger.HOVER), + ), + ) + } + + @Suppress("ktlint:standard:property-naming") + private val SHA3256CheckBox = + CheckBox(label = "SHA3-256 ⓘ", rich = true) { + paddingRight = 20.px + enableTooltip( + TooltipOptions( + title = + "Include a SHA3-256 hash of the watermark for " + + "additional verification. Needs a longer cover text " + + "content.", + triggers = listOf(Trigger.HOVER), + ), + ) + } + // Progress bar private var min: Int = -1 private val capacityObservable = ObservableValue(-1) @@ -151,7 +215,30 @@ class WatermarkTextEmbedTab : SimplePanel() { coverTextInput, required = true, ) + fieldsetPanel(tr("Advanced Settings")) { + hPanel { + div("Trendmark: ⓘ", rich = true) { + paddingRight = 10.px + fontWeight = FontWeight.BOLD + enableTooltip( + TooltipOptions( + title = + "A special type of watermarks using additional " + + "features.", + triggers = listOf(Trigger.HOVER), + ), + ) + } + + add(compressedCheckBox.bind(WatermarkerTextForm::trendmarkCompressed)) + + add(sizedCheckBox.bind(WatermarkerTextForm::trendmarkSized)) + + add(CRC32CheckBox.bind(WatermarkerTextForm::trendmarkCRC32)) + add(SHA3256CheckBox.bind(WatermarkerTextForm::trendmarkSHA3256)) + } + } add(progressBar) span().bind(capacityObservable) { val percentage = @@ -164,6 +251,10 @@ class WatermarkTextEmbedTab : SimplePanel() { // Check if watermark fits into the cover text watermarkerInput.onInput { updateCapacity() } coverTextInput.onInput { updateCapacity() } + compressedCheckBox.onInput { updateCapacity() } + sizedCheckBox.onInput { updateCapacity() } + CRC32CheckBox.onInput { updateCapacity() } + SHA3256CheckBox.onInput { updateCapacity() } textFormPanel.add( HPanel { @@ -178,6 +269,10 @@ class WatermarkTextEmbedTab : SimplePanel() { addWatermarkToText( textFormPanel.getData().watermark, textFormPanel.getData().text, + textFormPanel.getData().trendmarkCompressed, + textFormPanel.getData().trendmarkSized, + textFormPanel.getData().trendmarkCRC32, + textFormPanel.getData().trendmarkSHA3256, ) if (watermarkedResult.isSuccess) { @@ -253,6 +348,10 @@ class WatermarkTextEmbedTab : SimplePanel() { watermarkFitsInText( watermarkerInput.value.toString(), coverTextInput.value.toString(), + compressedCheckBox.value, + sizedCheckBox.value, + CRC32CheckBox.value, + SHA3256CheckBox.value, ) // Enable or disable the submit form button and user hint @@ -277,9 +376,19 @@ class WatermarkTextEmbedTab : SimplePanel() { private fun addWatermarkToText( watermarkString: String, text: String, + trendmarkCompressed: Boolean = false, + trendmarkSized: Boolean = false, + trendmarkCRC32: Boolean = false, + trendmarkSHA3256: Boolean = false, ): Result { val watermarker = Watermarker() - val watermark = TextWatermark.new(watermarkString) + val watermark = + TextWatermark.raw(watermarkString).apply { + if (trendmarkCompressed) compressed() + if (trendmarkSized) sized() + if (trendmarkCRC32) CRC32() + if (trendmarkSHA3256) SHA3256() + } return watermarker.textAddWatermark(text, watermark) } @@ -294,8 +403,18 @@ class WatermarkTextEmbedTab : SimplePanel() { private fun watermarkFitsInText( watermark: String, text: String, + trendmarkCompressed: Boolean, + trendmarkSized: Boolean, + trendmarkCRC32: Boolean, + trendmarkSHA3256: Boolean, ): Int { - val parsedWatermark = Watermark.fromString(watermark) + val parsedWatermark = + TextWatermark.raw(watermark).apply { + if (trendmarkCompressed) compressed() + if (trendmarkSized) sized() + if (trendmarkCRC32) CRC32() + if (trendmarkSHA3256) SHA3256() + } val numberOfInsertPositions = textWatermarker.placement(text).count() val numberOfNeededPositions = textWatermarker.getMinimumInsertPositions(parsedWatermark) diff --git a/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt b/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt index f6a551f..745f38e 100644 --- a/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt +++ b/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt @@ -94,7 +94,7 @@ class WatermarkTextExtractTab : SimplePanel() { if (watermarkedResult.value.isNullOrEmpty()) { modal.add( div( - "Could not find any valid watermark in the" + + "Could not find any valid watermark in the " + "text.", className = "alert alert-secondary", ), @@ -167,22 +167,22 @@ class WatermarkTextExtractTab : SimplePanel() { modal.add(watermarkDetailsPanel) } // Warning - } else if (watermarkedResult.status.isWarning) { + } else if (watermarkedResult.isWarning) { modal.add( div( "Some problems occur during the extraction: " + - watermarkedResult.status.getMessage(), + watermarkedResult.getMessage(), className = "alert alert-warning", ), ) modal.add(strong("Extracted Data: ")) modal.add(p(getWatermarkStringList(watermarkedResult).toString())) // Error - } else if (watermarkedResult.status.isError) { + } else if (watermarkedResult.isError) { modal.add( div( "An error occurs during the extraction: " + - watermarkedResult.status.getMessage(), + watermarkedResult.getMessage(), className = "alert alert-danger", ), ) diff --git a/webinterface/webpack.config.d/webpack.js b/webinterface/webpack.config.d/webpack.js index 239d440..eb24944 100644 --- a/webinterface/webpack.config.d/webpack.js +++ b/webinterface/webpack.config.d/webpack.js @@ -3,7 +3,6 @@ config.resolve.conditionNames = ['import', 'require', 'default']; if (config.devServer) { config.devServer.hot = true; - config.devtool = 'eval-cheap-source-map'; } else { config.devtool = undefined; }