From e25b1df961ce499f241518141464a29aaf76689b Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Mon, 11 May 2026 13:00:34 -0500 Subject: [PATCH 1/2] fix(cv): normalize OCR dimension values to correct property scaling Prevents misinterpretation of trailing units as an extra zero (e.g., 1500dp to 150dp). --- .../domain/parser/ValueCleanersImpl.kt | 26 ++++++++++++++++++- .../domain/FuzzyAttributeParserTest.kt | 24 +++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt index 36298fd17c..a6c9400491 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt @@ -45,6 +45,7 @@ internal object DimensionCleaner : ValueCleaner { private val matchKeywords = setOf("match", "parent") private val wrapKeywords = setOf("wrap", "content", "wrapcan") private val DIMENSION_CONSTANTS = listOf("wrap_content", "match_parent") + private val explicitDimensionRegex = Regex("^(-?\\d+)(dp|sp|px|dip)\\s*$") override fun clean(rawValue: String): String { val normalized = rawValue.lowercase().replace(" ", "_") @@ -55,9 +56,32 @@ internal object DimensionCleaner : ValueCleaner { if (fuzzyResult.score >= 60) return fuzzyResult.string val fixedUnit = normalized.replace(Regex("0p$|op$|olp$"), "dp") + explicitDimensionRegex.matchEntire(fixedUnit)?.let { match -> + val normalizedNumber = normalizeOcrDimensionNumber(match.groupValues[1]) + return normalizedNumber + match.groupValues[2] + } + val numericPart = NumberCleaner.clean(fixedUnit.replace("_", "")) + val normalizedNumericPart = normalizeOcrDimensionNumber(numericPart) + + return if (numericPart != fixedUnit) "${normalizedNumericPart}dp" else rawValue + } + + private fun normalizeOcrDimensionNumber(numericPart: String): String { + if (!numericPart.matches(Regex("-?\\d+"))) return numericPart + + val isNegative = numericPart.startsWith("-") + val numericValue = numericPart.toLongOrNull() ?: return numericPart + val canonical = numericValue.toString() + val unsignedCanonical = canonical.removePrefix("-") + + // OCR sometimes reads the trailing "dp" as a single zero, turning 150dp into 1500. + if (unsignedCanonical.endsWith('0') && unsignedCanonical.toLong() >= 1000L) { + val normalizedValue = numericValue / 10L + return normalizedValue.toString() + } - return if (numericPart != fixedUnit) "${numericPart}dp" else rawValue + return if (isNegative && numericValue == 0L) "0" else canonical } } diff --git a/cv-image-to-xml/src/test/java/org/appdevforall/codeonthego/computervision/domain/FuzzyAttributeParserTest.kt b/cv-image-to-xml/src/test/java/org/appdevforall/codeonthego/computervision/domain/FuzzyAttributeParserTest.kt index 47d0fcc97a..0a2f106c94 100644 --- a/cv-image-to-xml/src/test/java/org/appdevforall/codeonthego/computervision/domain/FuzzyAttributeParserTest.kt +++ b/cv-image-to-xml/src/test/java/org/appdevforall/codeonthego/computervision/domain/FuzzyAttributeParserTest.kt @@ -132,6 +132,30 @@ class FuzzyAttributeParserTest { assertEquals("wrap_content", result["android:layout_height"]) } + @Test + fun `OCR dimension with trailing zero before dp is normalized`() { + val annotation = "height: 1500dp | width: 100dp" + val result = FuzzyAttributeParser.parse(annotation, "EditText") + + assertEquals("150dp", result["android:layout_height"]) + } + + @Test + fun `zero padded dimension values are normalized`() { + val annotation = "height: 0010dp | width: 100dp" + val result = FuzzyAttributeParser.parse(annotation, "EditText") + + assertEquals("10dp", result["android:layout_height"]) + } + + @Test + fun `all zero padded dimension values normalize to zero`() { + val annotation = "height: 0000dp | width: 100dp" + val result = FuzzyAttributeParser.parse(annotation, "EditText") + + assertEquals("0dp", result["android:layout_height"]) + } + @Test fun `empty chunks between pipes are skipped`() { val annotation = "width: 100dp | | height: 80dp" From de25331e345a679891b65d157357f629b49684ec Mon Sep 17 00:00:00 2001 From: John Trujillo Date: Tue, 12 May 2026 08:20:34 -0500 Subject: [PATCH 2/2] refactor: cleaned regex --- .../computervision/domain/parser/ValueCleanersImpl.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt index a6c9400491..ab1cc56a3d 100644 --- a/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt +++ b/cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/domain/parser/ValueCleanersImpl.kt @@ -45,10 +45,12 @@ internal object DimensionCleaner : ValueCleaner { private val matchKeywords = setOf("match", "parent") private val wrapKeywords = setOf("wrap", "content", "wrapcan") private val DIMENSION_CONSTANTS = listOf("wrap_content", "match_parent") - private val explicitDimensionRegex = Regex("^(-?\\d+)(dp|sp|px|dip)\\s*$") + private val explicitDimensionRegex = Regex("^(-?\\d+)(dp|sp|px|dip)$") override fun clean(rawValue: String): String { - val normalized = rawValue.lowercase().replace(" ", "_") + val trimmedValue = rawValue.trim() + val normalized = trimmedValue.lowercase().replace(" ", "_") + if (matchKeywords.any { it in normalized }) return "match_parent" if (wrapKeywords.any { it in normalized }) return "wrap_content" @@ -64,7 +66,7 @@ internal object DimensionCleaner : ValueCleaner { val numericPart = NumberCleaner.clean(fixedUnit.replace("_", "")) val normalizedNumericPart = normalizeOcrDimensionNumber(numericPart) - return if (numericPart != fixedUnit) "${normalizedNumericPart}dp" else rawValue + return if (numericPart != fixedUnit) "${normalizedNumericPart}dp" else trimmedValue } private fun normalizeOcrDimensionNumber(numericPart: String): String {