Skip to content

Commit a9026b2

Browse files
committed
Added auto classification feedback.
1 parent 7d3d3f7 commit a9026b2

File tree

9 files changed

+182
-86
lines changed

9 files changed

+182
-86
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"raw-content": {
3+
"configuration": {
4+
"analyzer": {
5+
"bundle": "raw-content2",
6+
"name": "standard"
7+
},
8+
"math": {
9+
"bundle": "math2",
10+
"name": "standard"
11+
}
12+
},
13+
"classification": {
14+
"types": [ "text", "drawing", "math", "shape" ]
15+
},
16+
"recognition": {
17+
"types": [ "text", "math", "shape" ]
18+
},
19+
"pen": {
20+
"gestures": [ "scratch-out", "strike-through" ]
21+
}
22+
},
23+
"export": {
24+
"jiix": {
25+
"text": {
26+
"chars": true,
27+
"words": true
28+
},
29+
"bounding-box": true,
30+
"strokes": false,
31+
"glyphs": false,
32+
"primitives": false,
33+
"ids": true
34+
}
35+
}
36+
}

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/ink/serialization/jiix/Element.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ data class Element(
1414
@SerializedName("bounding-box")
1515
val boundingBox: BoundingBox,
1616
@SerializedName("words")
17-
val words: List<Word>? = null
17+
val words: List<Word>? = null,
18+
@SerializedName("expressions")
19+
val expressions: List<Expression>? = null
1820
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright @ MyScript. All rights reserved.
2+
3+
package com.myscript.iink.demo.ink.serialization.jiix
4+
5+
import com.google.gson.annotations.SerializedName
6+
7+
data class Expression(
8+
@SerializedName("bounding-box")
9+
val boundingBox: BoundingBox? = null
10+
)

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/ink/serialization/jiix/StrokeExt.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,13 @@ fun Word.toScreenCoordinates(converter: DisplayMetricsConverter?): Word {
8686
} else {
8787
this
8888
}
89+
}
90+
91+
fun BoundingBox.toScreenCoordinates(converter: DisplayMetricsConverter?): BoundingBox {
92+
return BoundingBox(
93+
x = converter?.x_mm2px(this.x) ?: this.x,
94+
y = converter?.y_mm2px(this.y) ?: this.y,
95+
width = converter?.x_mm2px(this.width) ?: this.width,
96+
height = converter?.y_mm2px(this.height) ?: this.height
97+
)
8998
}

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/inksample/ui/InkViewModel.kt

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import com.myscript.iink.ItemIdHelper
2424
import com.myscript.iink.MimeType
2525
import com.myscript.iink.OffscreenEditor
2626
import com.myscript.iink.OffscreenGestureAction
27+
import com.myscript.iink.demo.ink.serialization.jiix.BoundingBox
28+
import com.myscript.iink.demo.ink.serialization.jiix.Element
2729
import com.myscript.iink.demo.ink.serialization.jiix.RecognitionRoot
2830
import com.myscript.iink.demo.ink.serialization.jiix.Word
2931
import com.myscript.iink.demo.ink.serialization.jiix.convertPointerEvent
@@ -37,7 +39,6 @@ import com.myscript.iink.demo.inksample.data.InkRepository
3739
import com.myscript.iink.demo.inksample.data.InkRepositoryImpl
3840
import com.myscript.iink.demo.inksample.util.DisplayMetricsConverter
3941
import com.myscript.iink.demo.inksample.util.autoCloseable
40-
import com.myscript.iink.demo.inksample.util.iinkConfig
4142
import kotlinx.coroutines.CoroutineDispatcher
4243
import kotlinx.coroutines.Dispatchers
4344
import kotlinx.coroutines.asCoroutineDispatcher
@@ -46,9 +47,20 @@ import kotlinx.coroutines.withContext
4647
import java.io.File
4748
import java.util.concurrent.Executors
4849

50+
enum class BlockType {
51+
TEXT,
52+
MATH
53+
}
54+
55+
data class RecognitionItem(
56+
val text: String,
57+
val type: BlockType,
58+
val boundingBox: BoundingBox?
59+
)
60+
4961
data class RecognitionFeedback(
5062
val isVisible: Boolean = false,
51-
val words: List<Word> = emptyList()
63+
val items: List<RecognitionItem> = emptyList()
5264
)
5365

5466
enum class EditorHistoryAction {
@@ -325,12 +337,32 @@ class InkViewModel(
325337
val recognitionRoot = Gson().fromJson(exportedData, RecognitionRoot::class.java)
326338

327339
// Filter out elements that are null or contain any null list of words
328-
recognitionRoot.elements?.flatMap { element ->
329-
element.words?.map { word ->
330-
word.toScreenCoordinates(converter)
331-
} ?: emptyList()
332-
} ?: emptyList()
340+
val recognitionResult = mutableListOf<RecognitionItem>()
341+
342+
recognitionRoot.elements?.forEach { element ->
343+
if (element.expressions != null) {
344+
recognitionResult.add(RecognitionItem(
345+
text = "",
346+
type = BlockType.MATH,
347+
boundingBox = element.boundingBox.toScreenCoordinates(converter)
348+
))
349+
}
350+
if (element.words != null) {
351+
recognitionResult.addAll(
352+
element.words.map { word ->
353+
RecognitionItem(
354+
text = word.label ?: "",
355+
type = BlockType.TEXT,
356+
boundingBox = word.boundingBox?.toScreenCoordinates(converter)
357+
)
358+
}
359+
)
360+
}
361+
}
362+
363+
recognitionResult
333364
}
365+
334366
_iinkJIIX.value = withContext(defaultDispatcher) {
335367
val engine = engine ?: return@withContext ""
336368

@@ -344,7 +376,7 @@ class InkViewModel(
344376

345377
})
346378
} ?: ""
347-
_recognitionFeedback.value = _recognitionFeedback.value?.copy(words = adjustedWords)
379+
_recognitionFeedback.value = _recognitionFeedback.value?.copy(items = adjustedWords)
348380
}
349381
}
350382

@@ -636,7 +668,9 @@ class InkViewModel(
636668
val application = checkNotNull(this[APPLICATION_KEY])
637669
val engine = checkNotNull((application as InkApplication).engine)
638670
val dataDir = File(application.filesDir, "data")
639-
InkViewModel(InkRepositoryImpl(dataDir), engine, dataDir, iinkConfig)
671+
672+
val config = application.assets.open("part_conf.json").bufferedReader().use { it.readText() }
673+
InkViewModel(InkRepositoryImpl(dataDir), engine, dataDir, config)
640674
}
641675
}
642676
}

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/inksample/ui/MainActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ class MainActivity : AppCompatActivity() {
136136
inkView.alpha = if (recognitionFeedback.isVisible) .25f else 1f
137137

138138
if (recognitionFeedback.isVisible) {
139-
recognitionFeedback.words.forEach { word ->
140-
val customView = WordView(this@MainActivity, word)
139+
recognitionFeedback.items.forEach { item ->
140+
val customView = RecognitionItemView(this@MainActivity, item)
141141
recognitionContent.addView(customView)
142142
}
143143
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright @ MyScript. All rights reserved.
2+
3+
package com.myscript.iink.demo.inksample.ui
4+
5+
import android.content.Context
6+
import android.graphics.Canvas
7+
import android.graphics.Color
8+
import android.graphics.Paint
9+
import android.graphics.Typeface
10+
import android.text.TextPaint
11+
import android.view.View
12+
13+
class RecognitionItemView(context: Context, private val item: RecognitionItem) : View(context) {
14+
15+
private val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
16+
color = Color.BLACK
17+
textSize = 48f
18+
}
19+
20+
private val boxPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
21+
color = Color.GRAY
22+
style = Paint.Style.STROKE
23+
strokeWidth = 2f
24+
}
25+
26+
private val typePaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
27+
color = Color.GRAY
28+
textSize = 32f
29+
typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
30+
}
31+
32+
override fun onDraw(canvas: Canvas) {
33+
super.onDraw(canvas)
34+
35+
item.boundingBox?.let { box ->
36+
canvas.drawRect(
37+
box.x,
38+
box.y,
39+
box.x + box.width,
40+
box.y + box.height,
41+
boxPaint.apply {
42+
color = when(item.type) {
43+
BlockType.TEXT -> TEXT_COLOR
44+
BlockType.MATH -> MATH_COLOR
45+
}
46+
}
47+
)
48+
49+
if (item.text.isNotEmpty()) {
50+
canvas.drawText(
51+
item.text,
52+
box.x + 5,
53+
box.y + box.height - textPaint.descent(),
54+
textPaint
55+
)
56+
}
57+
58+
canvas.drawText(
59+
when(item.type) {
60+
BlockType.TEXT -> "abc"
61+
BlockType.MATH -> "Σ"
62+
},
63+
box.x + 5,
64+
box.y + (textPaint.descent() - textPaint.ascent()) / 2,
65+
typePaint.apply {
66+
color = when(item.type) {
67+
BlockType.TEXT -> TEXT_COLOR
68+
BlockType.MATH -> MATH_COLOR
69+
}
70+
}
71+
)
72+
}
73+
}
74+
75+
companion object {
76+
private const val TEXT_COLOR = Color.RED
77+
private const val MATH_COLOR = Color.BLUE
78+
}
79+
}

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/inksample/ui/WordView.kt

Lines changed: 0 additions & 46 deletions
This file was deleted.

samples/offscreen-interactivity/src/main/java/com/myscript/iink/demo/inksample/util/IInkConfiguration.kt

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)