使用 JUnit 测试图形生成

发布于 2024-09-12 12:44:39 字数 191 浏览 7 评论 0原文

我正在使用 Java 的 Graphics2D 生成图形的图形表示。我还使用 ImageIO 来编写 PNG 文件。 (ImageIO.write(image, "png", out);)

我想知道应该如何编写 JUnit 测试来测试生成的图形是否是预期的。我可以预先生成 PNG 文件,但如果不同机器上的字体有点不同怎么办?

I'm using Java's Graphics2D to generate a graphical representation of a graph. I'm also using ImageIO to write a PNG file. (ImageIO.write(image, "png", out);)

I'm wondering how should I write JUnit tests to test whether the generated graphics is what is expected. I could pre-generate the PNG files but what if the font is a bit different on a different machine?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

幼儿园老大 2024-09-19 12:44:39

对我来说,这个具体的实现似乎有效:

private void compareRasterImages(BufferedImage expectedPngIo, BufferedImage actualPngIo) throws AssertionError {
    int minX = expectedPngIo.getMinX();
    int minY = expectedPngIo.getMinY();
    int maxX = expectedPngIo.getMinX() + expectedPngIo.getWidth();
    int maxY = expectedPngIo.getMinY()+ expectedPngIo.getHeight();

    assertEquals(minX, actualPngIo.getMinX()); 
    assertEquals(minY, actualPngIo.getMinY()); 
    assertEquals(expectedPngIo.getHeight(), actualPngIo.getHeight()); 
    assertEquals(expectedPngIo.getWidth(), actualPngIo.getWidth()); 
    for (int x_i = minX; x_i < maxX; x_i++){
        for (int y_i = minY; y_i < maxY; y_i++) {
            assertEquals(expectedPngIo.getRGB(x_i, y_i), actualPngIo.getRGB(x_i, y_i));
        }
    }
}

我使用 ImageIO 从我的 PNG 中检索 BufferedImage(作为 byte[]):

BufferedImage expectedPngIo = ImageIO.read(new ByteArrayInputStream(expectedPng));
enter code here

For me, this concrete implementation seems to work:

private void compareRasterImages(BufferedImage expectedPngIo, BufferedImage actualPngIo) throws AssertionError {
    int minX = expectedPngIo.getMinX();
    int minY = expectedPngIo.getMinY();
    int maxX = expectedPngIo.getMinX() + expectedPngIo.getWidth();
    int maxY = expectedPngIo.getMinY()+ expectedPngIo.getHeight();

    assertEquals(minX, actualPngIo.getMinX()); 
    assertEquals(minY, actualPngIo.getMinY()); 
    assertEquals(expectedPngIo.getHeight(), actualPngIo.getHeight()); 
    assertEquals(expectedPngIo.getWidth(), actualPngIo.getWidth()); 
    for (int x_i = minX; x_i < maxX; x_i++){
        for (int y_i = minY; y_i < maxY; y_i++) {
            assertEquals(expectedPngIo.getRGB(x_i, y_i), actualPngIo.getRGB(x_i, y_i));
        }
    }
}

I retrieve the BufferedImage from my PNG (as byte[]) using ImageIO:

BufferedImage expectedPngIo = ImageIO.read(new ByteArrayInputStream(expectedPng));
enter code here
℡Ms空城旧梦 2024-09-19 12:44:39

您可以尝试测试输出的特定已知特征,例如:

  • (100,100)处是否有白色像素?
  • 边框全黑吗?
  • 图像的尺寸是预期的吗?

和/或您可以为某些“聚合属性”编写测试,以允许结果中存在一些模糊性:

  • 图像是否至少 90% 与参考图像匹配? (允许不同的字体、抗锯齿差异等)
  • 图像中最常见的颜色是否等于背景颜色?

You could try testing for specific, known features of the output e.g.:

  • It there a white pixel at (100,100)?
  • It the border completely black?
  • Is the image the expected size?

And/or you could write tests for some "aggregate properties" that allow for some fuzziness in the results:

  • Does the image at least 90% match the reference image? (to allow for different fonts, antialiasing differences etc.)
  • Is the most common colour in the image equal to the background colour?
Bonjour°[大白 2024-09-19 12:44:39

如果您确实对完整图像很具体,您可以将生成的图像的所有 RGB 值读入一个数组,并将该 2D 数组与表示预生成图像的数组进行比较。

如果您希望忽略字体,则可以根据生成图像的环境,对不包含任何可变数据的图像区域执行相同的操作。为单元测试构建校正和标准化例程将是浪费时间,除非应用程序预计会生成保证的高精度图像。

You could read all the RGB values of the generated images into an array and compare that 2D-array against one representing a pre-generated image, if you are really specific about the complete image.

If you wish to ignore the fonts, you could do the same for the same for regions of the image that do not contain any variable data depending on the environment where the images are generated. Building in correction and normalization routines for unit tests would be a waste of time, unless the application is expected to generate images of such high accuracy as warranted.

不寐倦长更 2024-09-19 12:44:39

我发现这可以有效地使渲染的字体在跨平台上相同,以进行简单事物(例如覆盖在静态图像上的文本)的像素完美图形单元测试。

  1. FontFontRenderContext 注入到渲染字体的类中,以便可以在测试下控制它们。
  2. 向单元测试提供 .ttf 文件,并使用 Font.createFont() 从该文件生成字体。
  3. 在单元测试中,在使用的 FontRenderContext 中禁用抗锯齿功能。如果您跳过此步骤,结果似乎确实会因平台而异。

我很好奇其他人是否认为这是脆弱的或容易失败的,但到目前为止我已经取得了很好的结果。

I've found this to be effective at making rendered fonts identical cross-platform for pixel perfect graphics unit tests of simple things like text overlaid on a static image.

  1. Inject the Font and FontRenderContext into the class rendering the fonts, so they can be controlled under test.
  2. Supply a .ttf file to the unit test and use Font.createFont() to generate a font from the file.
  3. In the unit test, disable anti-aliasing in the FontRenderContext used. If you skip this step, the results do vary cross platform it seems.

I'm curious if others think this is brittle or failure-prone for any reason, but I've had good results with it so far.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文