Skip to content

WebP Max Size restrictions and compare images #805

Description

@af-jra

Info
WebP has a maximum size of 16383 x 16383 pixel

see: https://developers.google.com/speed/webp/faq?hl=en#what_is_the_maximum_size_a_webp_image_can_be

Problem
While this is most likely more then enough for all screenshots, for the three way comparision this would mean, that any 8k image would "already" hit the limit. And this is also what we are currently facing. We have a few screenshots recorded with 8k pixel in width and the comparision in case of having deltas now fails.
Obviously one could switch to other images formats, but besides this, we are highly satisfied with WebP behavior overall. We would also like to keep the actual image width size at 8k.
The only way we see of working around this issue is, by creating a custom ImageIoFormat for WebP and checking there the size of the bufferedImage and scaling the image if required. Unfortunately this would mean additional "render" steps when creating the comparision image.

Is there any option to only change the scaling of the comparision image (without touching the size of the actual screenshot) or do you have any other idea how this can be achieved.

Current workaround

Our currently dirty workaround (only works for width > max size)

private const val MAX_WEBP_SIZE = 16383

@OptIn(ExperimentalRoborazziApi::class)
public object RescalableWebPFormat {

    /**
     * This is an extension of
     * io.github.takahirom.roborazzi/roborazzi-core-android/1.43.1/roborazzi-core-android-sources.jar!/commonJvmMain/com/github/takahirom/roborazzi/ImageIoFormat.commonJvm.kt:103
     * It creates an [ImageIoFormat] that saves images as WebP.
     * If the image width is greater than [MAX_WEBP_SIZE], it will be resized.
     *
     * @return [ImageIoFormat] for WebP.
     * @throws IllegalStateException if `io.github.darkxanter:webp-imageio` is not on the test classpath.
     */
    public fun imageIOFormat(): ImageIoFormat {
        return JvmImageIoFormat(
            awtImageWriter = { file, context, bufferedImage ->

                val imageToProcess = if (bufferedImage.width > MAX_WEBP_SIZE) {
                    val newWidth = MAX_WEBP_SIZE
                    val scale = newWidth.toDouble() / bufferedImage.width
                    val newHeight = (bufferedImage.height * scale).toInt()
                    val safeNewHeight = if (newHeight > 0) newHeight else 1
                    val resized = BufferedImage(newWidth, safeNewHeight, bufferedImage.type)
                    val g = resized.createGraphics()
                    g.drawImage(bufferedImage, 0, 0, newWidth, safeNewHeight, null)
                    g.dispose()
                    resized
                } else {
                    bufferedImage
                }

                val writer: javax.imageio.ImageWriter =
                    ImageIO.getImageWritersByMIMEType("image/webp").next()
                try {
                    val writeParam = WebPWriteParam(writer.getLocale())
                    writeParam.compressionMode = ImageWriteParam.MODE_EXPLICIT
                    writeParam.compressionType =
                        writeParam.getCompressionTypes()[WebPWriteParam.LOSSLESS_COMPRESSION]

                    writer.setOutput(FileImageOutputStream(file))

                    writer.write(null, IIOImage(imageToProcess, null, null), writeParam)
                } catch (_: NoClassDefFoundError) {
                    throw IllegalStateException("Add testImplementation(\"io.github.darkxanter:webp-imageio:0.3.0\") to use this")
                } finally {
                    writer.dispose()
                }
            }
        )
    }
}

Thank you for this wonderful project

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions