Skip to content

Support exclusion zones #163

Closed
Closed

Description

@iso-ivanv

This is a really great tool for checking images.
However, sometimes there are dynamic areas in the actual image which is subject to verification.
So a static expected image fixture won't do the job.
A simple solution would be : before comparing the images draw a black rectangle on specified position on both expected and actual images so any difference would be eliminated.
Another more elegant solution might be : mark the exclusion zones in the expected image in a certain way and the tool would simply ignore them . They can be marked with either maximum opacity alpha:255 or specific color which can serve as ignore color.
Does this sound like a useful feature and what option seems better?
Regards

Activity

  1. Venefilyn commented on Jun 10, 2026

    @Venefilyn
    Contributor

    @mourner I was looking at this library as a substitute for our pixel tests in the Cockpit project. The only thing really missing was the masked/excluded/ignored regions so I've modified https://github.com/whtsky/pixelmatch-py/ locally to include this but feels like it is best to implement here first before I ask for it to be added to pixelmatch-py

    Looking at the previous attempt

    I did notice a comment about the mask output which looks like this in the PR currently

    Image

    However have you considered embedding the ignored regions inside the expected image?
    For example if you have an expected image with areas which are marked with full opacity or particular color these areas can be excluded from matching.

    I was thinking we just use a different color for found changes but within an ignored zone, similar to how AA rendered. That way the diff can still get rendered for those areas where each pixel differs but is ignored.

    For the case where a pixeldiff is detected and relates to AA but is within an ignored zone we should still render it as ignored and not as AA.

    WDYT? If it sounds good I can add this to my queue to add at some point to take up the PR and refine it

  2. mourner commented on Jun 10, 2026

    @mourner
    Member

    @Venefilyn I'm still not convinced this kind of feature should be built-in — my general philosophy for focused libraries like this is minimalism and simplicity, and exclusion zones can be trivially implemented on the app side (before passing the input to pixelmatch) by nulling the given pixels in both expected and actual image data. See prior discussion in #9

  3. Venefilyn commented on Jun 11, 2026

    @Venefilyn
    Contributor

    @mourner that is a nice workaround but doesn't highlight changed but ignored pixels which would be nice. It also means iterating over the images once before sending it in and then have pixelmatch do it again. With a lot of images that doesn't sit right with me. Not to mention that if we want to display before and after we have to keep those or save it before modifying and sending in the nulled pixel variants

    For us it is a core thing to have excluded areas as we display system CPU usage, memory, networking, and other dynamic properties that mocking out either is a lot of work or doesn't make sense. We do want to see when stuff change but not so much with heavily dynamic charts or network activity

    The absolute easiest to allow for custom usage like this might be to split up the main pixelmatch function to make extending easier without having to iterate over the images twice

  4. mourner commented on Jun 11, 2026

    @mourner
    Member

    It also means iterating over the images once before sending it in and then have pixelmatch do it again.

    @Venefilyn it might sound not right but it's probably significantly faster than the approach in #153 in practice. The reason is that going linearly through a packed block of memory (a typed array) is very fast and highly optimized by the engines & hardware. But downstream, checking every pixel for "does it fall in one of the given regions" breaks that optimization and is way slower.

    Highlighting is nice, but doesn't seem essential for use cases like this, but if performance is your priority, the pre-pass is a way superior approach IMO.

  5. krassowski commented on Jun 15, 2026

    @krassowski

    I'm still not convinced this kind of feature should be built-in — my general philosophy for focused libraries like this is minimalism and simplicity, and exclusion zones can be trivially implemented on the app side (before passing the input to pixelmatch) by nulling the given pixels in both expected and actual image data

    For what's it worth, this would have a big impact for users of downstream Playwright because Playwright teams do not wish to accept such a change implemented on the app side (microsoft/playwright#41236). So right now, users are stuck with neither the testing framework, nor the underlying library willing to support it :(

  6. mourner commented on Jun 15, 2026

    @mourner
    Member

    @krassowski that might not help though even if implemented — Playwright vendored Pixelmatch so they don't get upstream updates microsoft/playwright#13585

  7. Venefilyn commented on Jun 16, 2026

    @Venefilyn
    Contributor

    The approach of blanking out the excluded zones before sending it to pixelmatch would work for playwright as well, if not part of playwright itself then as a plugin that adds a new toHaveScreenshot.

    But yeah, you do have a point in keeping the core lib clean. Would it be possible to publish two packages? One for pixelmatch itself as the core and another package for extra features like excluded zones

  8. added a commit that references this issue on Jun 23, 2026
  9. mourner commented on Jul 8, 2026

    @mourner
    Member

    Question for those interested in this feature: would an API that accepts a precomputed ignore mask (e.g. Uint8Array with one item per pixel where ignored pixels are >0) work for you?

    It's quite a bit more low level than accepting ignoredRegions bboxes, but would sidestep all my performance concerns while also being much more flexible (e.g. you can define not only rectangles but any shapes over the image area).

  10. Venefilyn commented on Jul 9, 2026

    @Venefilyn
    Contributor

    That is a brilliantly simple and flexible approach, I dig it. I assume this would also mean supporting both UInt8Array and Uint8ClampedArray

    Essentially, this means sending in an image mask that has the same dimensions of the images and black (I'm assuming 0 would be black) means we check and anything else becomes a mask

    Would a mask impact anti-aliasing at all?

  11. mourner commented on Jul 9, 2026

    @mourner
    Member

    @Venefilyn it would just mark any pixels that were different but masked with ignoreColor and not count it towards diff count, not evening checking anything else (AA or diff magnitude). I think we can make it any typed array because the format doesn't matter. E.g. draw some shapes on a Canvas, then new Uint32Array(ctx.getImageData(0, 0, w, h).data.buffer) and all drawn pixels would form an ignore mask (a uint32 value would be 0 if RGBA are all 0).

  12. Venefilyn commented on Jul 14, 2026

    @Venefilyn
    Contributor
  13. Venefilyn commented on Sep 7, 2026

    @Venefilyn
    Contributor

    @mourner I spun up a PR in #171. @pavelfeldman @krassowski have you had a chance to look the comments above over or this PR to see if this is something you'd need?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions