Increasing the speed of the Robohash SVG to buffer function

This commit is contained in:
Vitor Pamplona 2024-02-21 13:51:27 -05:00
parent 0429c4dc3a
commit 4b9a55e178
4 changed files with 64 additions and 43 deletions

View File

@ -30,9 +30,10 @@ import coil.fetch.Fetcher
import coil.fetch.SourceResult
import coil.request.ImageRequest
import coil.request.Options
import com.vitorpamplona.amethyst.commons.Robohash
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.quartz.utils.Robohash
import okio.Buffer
import okio.buffer
import okio.source
import java.nio.charset.Charset
@Stable
@ -43,14 +44,10 @@ class HashImageFetcher(
) : Fetcher {
override suspend fun fetch(): SourceResult {
checkNotInMainThread()
val source =
try {
val buffer = Buffer()
buffer.writeString(
Robohash.assemble(data.toString(), isLightTheme),
Charset.defaultCharset(),
)
buffer
Robohash.assemble(data.toString(), isLightTheme).byteInputStream(Charset.defaultCharset()).source().buffer()
} finally {
}

View File

@ -18,16 +18,20 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.benchmark
package com.vitorpamplona.amethyst.benchmark
import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.vitorpamplona.quartz.utils.Robohash
import com.vitorpamplona.amethyst.commons.Robohash
import junit.framework.TestCase.assertEquals
import okio.Buffer
import okio.buffer
import okio.source
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.nio.charset.Charset
/**
* Benchmark, which will execute on an Android device.
@ -41,7 +45,7 @@ class RobohashBenchmark {
val warmHex = "f4f016c739b8ec0d6313540a8b12cf48a72b485d38338627ec9d427583551f9a"
val testHex = "48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf"
val resultingSVG =
val expectedTestSVG =
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 300 300\">" +
"<defs>" +
"<style>" +
@ -196,7 +200,26 @@ class RobohashBenchmark {
Robohash.assemble(warmHex, true)
benchmarkRule.measureRepeated {
val result = Robohash.assemble(testHex, true)
assertEquals(resultingSVG, result)
assertEquals(expectedTestSVG, result)
}
}
@Test
fun createSVGInBufferCopy() {
// warm up
Robohash.assemble(warmHex, true)
benchmarkRule.measureRepeated {
val buffer = Buffer()
buffer.writeString(Robohash.assemble(testHex, true), Charset.defaultCharset())
}
}
@Test
fun createSVGInBufferViaInputStream() {
// warm up
Robohash.assemble(warmHex, true)
benchmarkRule.measureRepeated {
Robohash.assemble(testHex, true).byteInputStream(Charset.defaultCharset()).source().buffer()
}
}
}

View File

@ -35,6 +35,8 @@ android {
}
dependencies {
implementation project(path: ':quartz')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

View File

@ -18,10 +18,9 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.utils
package com.vitorpamplona.amethyst.commons
import android.util.Log
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.crypto.CryptoUtils
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.HexValidator
@ -55,9 +54,7 @@ object Robohash {
private fun reduce(
start: Int,
channel: Byte,
): Int {
return (start + (channel.toUByte().toInt() * 0.3906f)).toInt()
}
) = (start + (channel.toUByte().toInt() * 0.3906f)).toInt()
private fun bytesToRGB(
r: Byte,
@ -85,6 +82,7 @@ object Robohash {
Log.w("Robohash", "$msg is not a hex")
CryptoUtils.sha256(msg.toByteArray())
}
val bgColor = bytesToRGB(hash[0], hash[1], hash[2], isLightTheme)
val fgColor = bytesToRGB(hash[3], hash[4], hash[5], !isLightTheme)
val body = bodies[byteMod10(hash[6])]
@ -110,41 +108,42 @@ object Robohash {
BACKGROUND.length +
END.length
val result = StringBuilder(capacity)
val result =
buildString(capacity) {
append(HEADER)
result.append(HEADER)
append(".cls-bg{fill:")
append(bgColor)
append(";}.cls-fill-1{fill:")
append(fgColor)
append(";}.cls-fill-2{fill:")
append(fgColor)
append(";}")
result.append(".cls-bg{fill:")
result.append(bgColor)
result.append(";}.cls-fill-1{fill:")
result.append(fgColor)
result.append(";}.cls-fill-2{fill:")
result.append(fgColor)
result.append(";}")
append(body.style)
append(face.style)
append(eye.style)
append(mouth.style)
append(accessory.style)
result.append(body.style)
result.append(face.style)
result.append(eye.style)
result.append(mouth.style)
result.append(accessory.style)
append(MID)
result.append(MID)
append(BACKGROUND)
append(body.paths)
append(face.paths)
append(eye.paths)
append(mouth.paths)
append(accessory.paths)
result.append(BACKGROUND)
result.append(body.paths)
result.append(face.paths)
result.append(eye.paths)
result.append(mouth.paths)
result.append(accessory.paths)
append(END)
}
result.append(END)
check(result.length == capacity) { "${result.length} was different from $capacity" }
val resultStr = result.toString()
check(resultStr.length == capacity) { "${resultStr.length} was different from $capacity" }
return resultStr
return result
}
@Immutable private data class Part(val style: String, val paths: String)
private data class Part(val style: String, val paths: String)
const val HEADER =
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 300 300\"><defs><style>"