Skip to content

Commit

Permalink
Merge pull request #529 from takahirom/takahirom/support-lossless-web…
Browse files Browse the repository at this point in the history
…p/2024-11-01

Add the ability to change File writers and readers and add support for lossless WebP
  • Loading branch information
takahirom authored Nov 6, 2024
2 parents d4ff5c6 + 0857614 commit ccb4154
Show file tree
Hide file tree
Showing 17 changed files with 383 additions and 245 deletions.
128 changes: 38 additions & 90 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ fun captureRoboGifSample() {
<img width="350" src="https://user-images.githubusercontent.com/1386930/226362212-35d34c9e-6df1-4671-8949-10fad7ad98c9.gif" />
### Automatically generate gif with test rule
### Generate gif with test rule
> **Note**
> You **don't need to use RoborazziRule** if you're using captureRoboImage().
Expand Down Expand Up @@ -732,7 +732,7 @@ class RuleTestWithOnlyFail {
}
```
### Automatically generate Jetpack Compose gif with test rule
### Generate Jetpack Compose gif with test rule
Test target
Expand Down Expand Up @@ -869,94 +869,6 @@ class RoborazziRule private constructor(
}
```
### Roborazzi options
```kotlin
data class RoborazziOptions(
val captureType: CaptureType = if (isNativeGraphicsEnabled()) CaptureType.Screenshot() else CaptureType.Dump(),
val compareOptions: CompareOptions = CompareOptions(),
val recordOptions: RecordOptions = RecordOptions(),
) {
sealed interface CaptureType {
class Screenshot : CaptureType
data class Dump(
val takeScreenShot: Boolean = isNativeGraphicsEnabled(),
val basicSize: Int = 600,
val depthSlideSize: Int = 30,
val query: ((RoboComponent) -> Boolean)? = null,
val explanation: ((RoboComponent) -> String?) = DefaultExplanation,
) : CaptureType {
companion object {
val DefaultExplanation: ((RoboComponent) -> String) = {
it.text
}
val AccessibilityExplanation: ((RoboComponent) -> String) = {
it.accessibilityText
}
}
}
}
data class CompareOptions(
val roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
val resultValidator: (result: ImageComparator.ComparisonResult) -> Boolean,
) {
constructor(
roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
/**
* This value determines the threshold of pixel change at which the diff image is output or not.
* The value should be between 0 and 1
*/
changeThreshold: Float = 0.01F,
) : this(roborazziCompareReporter, ThresholdValidator(changeThreshold))
}
interface RoborazziCompareReporter {
fun report(compareReportCaptureResult: CompareReportCaptureResult)
companion object {
operator fun invoke(): RoborazziCompareReporter {
...
}
}
class JsonOutputRoborazziCompareReporter : RoborazziCompareReporter {
...
override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
...
}
}
class VerifyRoborazziCompareReporter : RoborazziCompareReporter {
override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
...
}
}
}
data class RecordOptions(
val resizeScale: Double = roborazziDefaultResizeScale(),
val applyDeviceCrop: Boolean = false,
val pixelBitConfig: PixelBitConfig = PixelBitConfig.Argb8888,
)
enum class PixelBitConfig {
Argb8888,
Rgb565;
fun toBitmapConfig(): Bitmap.Config {
...
}
fun toBufferedImageType(): Int {
...
}
}
}
```
#### Image comparator custom settings
When comparing images, you may encounter differences due to minor changes related to antialiasing. You can use the options below to avoid this.
```kotlin
Expand All @@ -977,12 +889,48 @@ val roborazziRule = RoborazziRule(
)
```
### Experimental WebP support and other image formats
You can set `roborazzi.record.image.extension` to `webp` in your `gradle.properties` file to generate WebP images.
```kotlin
roborazzi.record.image.extension=webp
```
WebP is a lossy image format by default, which can make managing image differences challenging. To address this, we provide a lossless WebP image comparison feature.
To enable WebP support, add `testImplementation("io.github.darkxanter:webp-imageio:0.3.3")` to your `build.gradle.kts` file.
```kotlin
onView(ViewMatchers.withId(R.id.textview_first))
.captureRoboImage(
roborazziOptions = RoborazziOptions(
recordOptions = RoborazziOptions.RecordOptions(
imageIoFormat = LosslessWebPImageIoFormat(),
),
)
)
```
You can also use other image formats by implementing your own `AwtImageWriter` and `AwtImageLoader`.
```kotlin
data class JvmImageIoFormat(
val awtImageWriter: AwtImageWriter,
val awtImageLoader: AwtImageLoader
) : ImageIoFormat
```
### Dump mode
If you are having trouble debugging your test, try Dump mode as follows.
![image](https://user-images.githubusercontent.com/1386930/226364158-a07a0fb0-d8e7-46b7-a495-8dd217faaadb.png)
### Roborazzi options
Please check out [RoborazziOptions](https://github.com/takahirom/roborazzi/blob/main/include-build/roborazzi-core/src/commonJvmMain/kotlin/com/github/takahirom/roborazzi/RoborazziOptions.kt) for available Roborazzi options.
</div>
<div name="topic_preview_support">
Expand Down
128 changes: 38 additions & 90 deletions docs/topics/how_to_use.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ fun captureRoboGifSample() {
<img width="350" src="https://user-images.githubusercontent.com/1386930/226362212-35d34c9e-6df1-4671-8949-10fad7ad98c9.gif" />
### Automatically generate gif with test rule
### Generate gif with test rule
> **Note**
> You **don't need to use RoborazziRule** if you're using captureRoboImage().
Expand Down Expand Up @@ -409,7 +409,7 @@ class RuleTestWithOnlyFail {
}
```
### Automatically generate Jetpack Compose gif with test rule
### Generate Jetpack Compose gif with test rule
Test target
Expand Down Expand Up @@ -546,94 +546,6 @@ class RoborazziRule private constructor(
}
```
### Roborazzi options
```kotlin
data class RoborazziOptions(
val captureType: CaptureType = if (isNativeGraphicsEnabled()) CaptureType.Screenshot() else CaptureType.Dump(),
val compareOptions: CompareOptions = CompareOptions(),
val recordOptions: RecordOptions = RecordOptions(),
) {
sealed interface CaptureType {
class Screenshot : CaptureType
data class Dump(
val takeScreenShot: Boolean = isNativeGraphicsEnabled(),
val basicSize: Int = 600,
val depthSlideSize: Int = 30,
val query: ((RoboComponent) -> Boolean)? = null,
val explanation: ((RoboComponent) -> String?) = DefaultExplanation,
) : CaptureType {
companion object {
val DefaultExplanation: ((RoboComponent) -> String) = {
it.text
}
val AccessibilityExplanation: ((RoboComponent) -> String) = {
it.accessibilityText
}
}
}
}
data class CompareOptions(
val roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
val resultValidator: (result: ImageComparator.ComparisonResult) -> Boolean,
) {
constructor(
roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
/**
* This value determines the threshold of pixel change at which the diff image is output or not.
* The value should be between 0 and 1
*/
changeThreshold: Float = 0.01F,
) : this(roborazziCompareReporter, ThresholdValidator(changeThreshold))
}
interface RoborazziCompareReporter {
fun report(compareReportCaptureResult: CompareReportCaptureResult)
companion object {
operator fun invoke(): RoborazziCompareReporter {
...
}
}
class JsonOutputRoborazziCompareReporter : RoborazziCompareReporter {
...
override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
...
}
}
class VerifyRoborazziCompareReporter : RoborazziCompareReporter {
override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
...
}
}
}
data class RecordOptions(
val resizeScale: Double = roborazziDefaultResizeScale(),
val applyDeviceCrop: Boolean = false,
val pixelBitConfig: PixelBitConfig = PixelBitConfig.Argb8888,
)
enum class PixelBitConfig {
Argb8888,
Rgb565;
fun toBitmapConfig(): Bitmap.Config {
...
}
fun toBufferedImageType(): Int {
...
}
}
}
```
#### Image comparator custom settings
When comparing images, you may encounter differences due to minor changes related to antialiasing. You can use the options below to avoid this.
```kotlin
Expand All @@ -654,8 +566,44 @@ val roborazziRule = RoborazziRule(
)
```
### Experimental WebP support and other image formats
You can set `roborazzi.record.image.extension` to `webp` in your `gradle.properties` file to generate WebP images.
```kotlin
roborazzi.record.image.extension=webp
```
WebP is a lossy image format by default, which can make managing image differences challenging. To address this, we provide a lossless WebP image comparison feature.
To enable WebP support, add `testImplementation("io.github.darkxanter:webp-imageio:0.3.3")` to your `build.gradle.kts` file.
```kotlin
onView(ViewMatchers.withId(R.id.textview_first))
.captureRoboImage(
roborazziOptions = RoborazziOptions(
recordOptions = RoborazziOptions.RecordOptions(
imageIoFormat = LosslessWebPImageIoFormat(),
),
)
)
```
You can also use other image formats by implementing your own `AwtImageWriter` and `AwtImageLoader`.
```kotlin
data class JvmImageIoFormat(
val awtImageWriter: AwtImageWriter,
val awtImageLoader: AwtImageLoader
) : ImageIoFormat
```
### Dump mode
If you are having trouble debugging your test, try Dump mode as follows.
![image](https://user-images.githubusercontent.com/1386930/226364158-a07a0fb0-d8e7-46b7-a495-8dd217faaadb.png)
### Roborazzi options
Please check out [RoborazziOptions](https://github.com/takahirom/roborazzi/blob/main/include-build/roborazzi-core/src/commonJvmMain/kotlin/com/github/takahirom/roborazzi/RoborazziOptions.kt) for available Roborazzi options.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ kotlinx-io = "0.3.3"
webjar-material-design-icons = "4.0.0"
webjar-materialize = "1.0.0"
webjars-locator-lite = "0.0.6"
webpImageio = "0.3.3"

composable-preview-scanner = "0.3.2"

Expand Down Expand Up @@ -99,3 +100,4 @@ kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.re
webjars-material-design-icons = { module = "org.webjars:material-design-icons", version.ref = "webjar-material-design-icons" }
webjars-materialize = { module = "org.webjars:materializecss", version.ref = "webjar-materialize" }
webjars-locator-lite = { module = "org.webjars:webjars-locator-lite", version.ref = "webjars-locator-lite" }
webp-imageio = { module = "io.github.darkxanter:webp-imageio", version.ref = "webpImageio" }
3 changes: 3 additions & 0 deletions include-build/roborazzi-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ kotlin {
commonJvmMain {
dependencies {
implementation libs.junit
// The library is a little bit heavy, so we use compileOnly here.
// Users need to add this library to their dependencies.
compileOnly(libs.webp.imageio)
}
}
commonJvmTest {
Expand Down
Loading

0 comments on commit ccb4154

Please sign in to comment.