diff --git a/watermarker/src/commonMain/kotlin/fileWatermarker/TextWatermarker.kt b/watermarker/src/commonMain/kotlin/fileWatermarker/TextWatermarker.kt
index dd76986..e30ad45 100644
--- a/watermarker/src/commonMain/kotlin/fileWatermarker/TextWatermarker.kt
+++ b/watermarker/src/commonMain/kotlin/fileWatermarker/TextWatermarker.kt
@@ -400,9 +400,10 @@ class TextWatermarker(
"'${char.toUnicodeRepresentation()}'"
}
- return "The file contains characters of the watermark " +
- "transcoding alphabet. Adding a Watermarking would potentially make the " +
- "file unusable! Maybe the file already contains a watermark?\n\n" +
+ return "The input contains characters of the watermark " +
+ "transcoding alphabet. It is only possible to add a watermark to and input " +
+ "that doesn't contain any watermark. Adding another watermark would potentially " +
+ "make the input unusable! Maybe the input already contains a watermark?\n\n" +
"Contained Chars:\n" +
"$containedChars."
}
diff --git a/watermarker/src/commonTest/kotlin/unitTest/fileWatermarker/TextWatermarkerTest.kt b/watermarker/src/commonTest/kotlin/unitTest/fileWatermarker/TextWatermarkerTest.kt
index 2c6658a..56a540b 100644
--- a/watermarker/src/commonTest/kotlin/unitTest/fileWatermarker/TextWatermarkerTest.kt
+++ b/watermarker/src/commonTest/kotlin/unitTest/fileWatermarker/TextWatermarkerTest.kt
@@ -141,9 +141,10 @@ class TextWatermarkerTest {
// Arrange
val error = TextWatermarker.ContainsAlphabetCharsError(sequenceOf('a', 'b'))
val expected =
- "Error (TextWatermarker.addWatermark): The file contains characters of the watermark " +
- "transcoding alphabet. Adding a Watermarking would potentially make the file " +
- "unusable! Maybe the file already contains a watermark?\n" +
+ "Error (TextWatermarker.addWatermark): The input contains characters of the watermark" +
+ " transcoding alphabet. It is only possible to add a watermark to and input that" +
+ " doesn't contain any watermark. Adding another watermark would potentially make " +
+ "the input unusable! Maybe the input already contains a watermark?\n" +
"\n" +
"Contained Chars:\n" +
"['\\u0061','\\u0062']."
diff --git a/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt b/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt
index b48699f..c5f3ffe 100644
--- a/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt
+++ b/webinterface/src/jsMain/kotlin/WatermarkTextEmbedTab.kt
@@ -7,6 +7,8 @@
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.Placement
import io.kvision.core.TooltipOptions
@@ -170,23 +172,45 @@ class WatermarkTextEmbedTab : SimplePanel() {
submitButton.onClick {
if (textFormPanel.validate()) {
// Modal
- val watermarkedText =
+ val modal = Modal("Result")
+
+ val watermarkedResult =
addWatermarkToText(
textFormPanel.getData().watermark,
textFormPanel.getData().text,
)
- val modal = Modal("Successful")
- modal.add(span("The following text includes your watermark:"))
- modal.add(div(watermarkedText, className = "selectable card-text"))
- modal.addButton(
- Button("Copy to Clipboard") {
- onClick {
- window.navigator.clipboard.writeText(watermarkedText)
- Toast.success("Successful copied to clipboard!")
- }
- },
- )
+ if (watermarkedResult.isSuccess) {
+ val watermarkedText = watermarkedResult.value ?: ""
+
+ modal.add(
+ div(
+ "Successfully embedded your watermark in the " +
+ "cover text",
+ className = "alert alert-success",
+ ),
+ )
+ modal.add(span("The following text includes your watermark:"))
+ modal.add(div(watermarkedText, className = "selectable card-text"))
+ modal.addButton(
+ Button("Copy to Clipboard") {
+ onClick {
+ window.navigator.clipboard.writeText(watermarkedText)
+ Toast.success("Successful copied to clipboard!")
+ }
+ },
+ )
+ } else {
+ modal.add(
+ div(
+ "An error occurs during the watermarking " +
+ "process:
" + watermarkedResult.getMessage(),
+ rich = true,
+ className = "alert alert-danger",
+ ),
+ )
+ }
+
modal.addButton(
Button("Close") {
onClick {
@@ -249,20 +273,14 @@ class WatermarkTextEmbedTab : SimplePanel() {
(if (watermarkerInput.value == null) min else capacityObservable.value)
}
- /** Adds a [watermark] string to [text] and returns the watermarked text */
+ /** Adds a [watermarkString] string to [text] and returns the watermarked text result */
private fun addWatermarkToText(
- watermark: String,
+ watermarkString: String,
text: String,
- ): String {
+ ): Result {
val watermarker = Watermarker()
- val result = watermarker.textAddWatermark(text, watermark.encodeToByteArray().asList())
-
- return if (result.isSuccess) {
- result.value ?: ""
- } else {
- // TODO: Proper error handling
- result.toString()
- }
+ val watermark = TextWatermark.new(watermarkString)
+ return watermarker.textAddWatermark(text, watermark)
}
/**
diff --git a/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt b/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt
index 3b99f70..f6a551f 100644
--- a/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt
+++ b/webinterface/src/jsMain/kotlin/WatermarkTextExtractTab.kt
@@ -6,6 +6,14 @@
*/
import de.fraunhofer.isst.trend.watermarker.Watermarker
+import de.fraunhofer.isst.trend.watermarker.fileWatermarker.DefaultTranscoding
+import de.fraunhofer.isst.trend.watermarker.helper.toUnicodeRepresentation
+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 de.fraunhofer.isst.trend.watermarker.watermarks.toTextWatermarks
+import io.kvision.collapse.collapse
+import io.kvision.collapse.forCollapse
import io.kvision.core.Placement
import io.kvision.core.TooltipOptions
import io.kvision.core.Trigger
@@ -13,13 +21,21 @@ import io.kvision.core.enableTooltip
import io.kvision.form.FormMethod
import io.kvision.form.formPanel
import io.kvision.form.text.TextArea
+import io.kvision.html.Button
import io.kvision.html.ButtonStyle
+import io.kvision.html.br
import io.kvision.html.button
+import io.kvision.html.div
+import io.kvision.html.li
+import io.kvision.html.p
import io.kvision.html.span
-import io.kvision.modal.Alert
+import io.kvision.html.strong
+import io.kvision.html.ul
import io.kvision.modal.Confirm
+import io.kvision.modal.Modal
import io.kvision.panel.HPanel
import io.kvision.panel.SimplePanel
+import io.kvision.panel.simplePanel
import io.kvision.utils.em
import kotlinx.serialization.Serializable
@@ -66,11 +82,120 @@ class WatermarkTextExtractTab : SimplePanel() {
onClick {
if (extractTextFormPanel.validate()) {
println("Starting watermark extraction process ...")
- val watermarkedText =
+ val watermarkedResult =
extractWatermark(
extractTextFormPanel.getData().text,
+ ).toTextWatermarks()
+
+ val modal = Modal("Result")
+
+ // Success
+ if (watermarkedResult.status.isSuccess) {
+ if (watermarkedResult.value.isNullOrEmpty()) {
+ modal.add(
+ div(
+ "Could not find any valid watermark in the" +
+ "text.",
+ className = "alert alert-secondary",
+ ),
+ )
+ } else {
+ modal.add(
+ div(
+ "Successfully extracted the watermark(s)!",
+ className = "alert alert-success",
+ ),
+ )
+
+ val countedWatermarkList =
+ getWatermarkStringList(watermarkedResult)
+ .groupingBy { it }
+ .eachCount()
+
+ // Most frequent watermark
+ modal.add(
+ span(
+ "Most frequent " +
+ "watermark: " +
+ countedWatermarkList.maxByOrNull {
+ it.value
+ }?.key + "
",
+ rich = true,
+ ),
+ )
+
+ // Details section
+ val watermarkDetailsPanel =
+ simplePanel {
+ button(
+ "More details",
+ style = ButtonStyle.SECONDARY,
+ ).forCollapse("watermark-details")
+
+ collapse("watermark-details") {
+ // Print all watermarks
+ strong("Detailed watermark list:")
+ ul {
+ for ((key, value) in countedWatermarkList) {
+ li("$key ($value times)")
+ }
+ }
+ br()
+
+ // Show watermarking type
+ strong("Watermarking type(s): ")
+ p(
+ watermarkedResult.value!!.map { watermark ->
+ watermark.finish().getSource()
+ }.toSet().toString(),
+ )
+
+ // Show input text with hidden chars
+ strong(
+ "Raw data with hidden alphabet chars:",
+ )
+ br()
+ span(
+ showWatermarkChars(
+ extractTextFormPanel.getData().text,
+ ),
+ rich = true,
+ className = "break-all",
+ )
+ }
+ }
+ modal.add(watermarkDetailsPanel)
+ }
+ // Warning
+ } else if (watermarkedResult.status.isWarning) {
+ modal.add(
+ div(
+ "Some problems occur during the extraction: " +
+ watermarkedResult.status.getMessage(),
+ className = "alert alert-warning",
+ ),
+ )
+ modal.add(strong("Extracted Data: "))
+ modal.add(p(getWatermarkStringList(watermarkedResult).toString()))
+ // Error
+ } else if (watermarkedResult.status.isError) {
+ modal.add(
+ div(
+ "An error occurs during the extraction: " +
+ watermarkedResult.status.getMessage(),
+ className = "alert alert-danger",
+ ),
)
- Alert.show("Successful", watermarkedText)
+ }
+
+ modal.addButton(
+ Button("Close") {
+ onClick {
+ modal.hide()
+ }
+ },
+ )
+ modal.show()
}
}
}
@@ -91,17 +216,49 @@ class WatermarkTextExtractTab : SimplePanel() {
}
/** Extracts a watermark from a [text] and returns it */
- private fun extractWatermark(text: String): String {
+ private fun extractWatermark(text: String): Result> {
val watermarker = Watermarker()
- val result = watermarker.textGetWatermarks(text)
-
- return if (result.isSuccess) {
- result.value!!.map { watermark ->
- watermark.watermarkContent.toByteArray().decodeToString()
- }.toString()
- } else {
- // TODO: Proper error handling
- result.toString()
+ return watermarker.textGetWatermarks(text, squash = false)
+ }
+
+ /**
+ * Replaces all whitespaces of the transcoding alphabet of the watermarking library in
+ * [watermarkedText] with its Unicode representation. [html] defines if the result is a
+ * styled HTML string (true) or a plain text without formatting (false).
+ */
+ private fun showWatermarkChars(
+ watermarkedText: String,
+ html: Boolean = true,
+ ): String {
+ val alphabet = DefaultTranscoding.alphabet + DefaultTranscoding.SEPARATOR_CHAR
+ var resultText = watermarkedText
+ var className: String
+
+ for (char in alphabet) {
+ if (html) {
+ className =
+ if (char == DefaultTranscoding.SEPARATOR_CHAR) {
+ "separator-highlight"
+ } else {
+ "whitespace-highlight"
+ }
+
+ resultText =
+ resultText.replace(
+ char.toString(),
+ "" +
+ "${char.toUnicodeRepresentation()}",
+ )
+ } else {
+ resultText = resultText.replace(char.toString(), char.toUnicodeRepresentation())
+ }
}
+ return resultText
}
+
+ /** Creates a list of Strings based on a [watermarkedResult] */
+ private fun getWatermarkStringList(watermarkedResult: Result>) =
+ watermarkedResult.value!!.map { watermark ->
+ watermark.text
+ }
}
diff --git a/webinterface/src/jsMain/resources/css/custom.css b/webinterface/src/jsMain/resources/css/custom.css
index 8987204..38a5c91 100644
--- a/webinterface/src/jsMain/resources/css/custom.css
+++ b/webinterface/src/jsMain/resources/css/custom.css
@@ -12,3 +12,18 @@
padding: 1em;
margin-top: 0.5em;
}
+
+.break-all {
+ word-break: break-all;
+}
+
+.whitespace-highlight {
+ background-color: lightblue;
+ padding: 1px;
+}
+
+.separator-highlight {
+ background-color: black;
+ color: white;
+ padding: 1px;
+}