Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement image diff plugin #96

Merged
merged 32 commits into from
Jan 7, 2023
Merged

Implement image diff plugin #96

merged 32 commits into from
Jan 7, 2023

Conversation

tuliren
Copy link
Member

@tuliren tuliren commented Dec 26, 2022

Summary

The image diff plugin can compare an image against a baseline one. The image can be static or generated during the build. This plugin will be most useful for machine learning CI.

The logo image is modified for testing purpose only. The change should be reverted before merging.

Limitation

  • pixelmatch can only compare images with exact same size.

TODOs

  • Include task name and image filename in the table.
  • Support local or remote URL for both path and baseline files.
  • Figure out other image formats.

@stoat-app
Copy link

stoat-app bot commented Dec 26, 2022

Easy and customizable dashboards for your build system. Learn more about Stoat ↗︎

Static Hosting

Name Link Commit Status
Documentation Visit 8971456
CLI Test Coverage Visit 8971456
Action Test Coverage Visit 8971456
Action Test Coverage (single file) Visit 8971456

Image Diff

Name Baseline Current Diff
Logo baseline current diff

Job Runtime

debug

@vercel
Copy link

vercel bot commented Dec 26, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
docs 🔄 Building (Inspect) Dec 26, 2022 at 9:23AM (UTC)

@tuliren tuliren changed the title Add image diff plugin Implement image diff plugin Dec 26, 2022
@tuliren tuliren requested a review from jrhizor December 26, 2022 07:04
Copy link
Contributor

@jrhizor jrhizor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome!

A few concerns:

  • For now, if the user wants to pull an image from an external location, they should do so in a separate step in their GH workflow (we shouldn't do it as part of the plugin). I think this is actually a crucial pattern for us in order to limit complexity for private repos.
  • The baseline should default to default-branch output for this plugin
  • We need to be able to express that the image didn't originally exist (especially for default branch)
  • For the first release of this, it'd be great to have some error handling around non-matching inputs so we just drop the diff instead of fail

I'm also curious what diffs are most important for users. Is it default/baseline to the latest commit? Is it default/baseline to each commit (which implies the need for a separate UI for the plugin). Is pixel diffing enough or do we need swipes/onion skins/resemblejs. I don't think any of these should block the PR but it's worth discussing on our upcoming customer calls. I'm not sure how they think about which data they want to compare. I'm also curious about their tolerance for checking in images into the repo or how many images they actually want to compare on a regular basis. If it's 100s or 1000s for PR, or only ones with changes we may need to make significant changes.

action/src/schemas/stoatConfigSchema.json Show resolved Hide resolved
.stoat/config.yaml Outdated Show resolved Hide resolved
action/src/plugins/imageDiff/plugin.ts Outdated Show resolved Hide resolved
action/src/plugins/imageDiff/plugin.ts Outdated Show resolved Hide resolved
const diffPath = `${currentDirectory}/${uuid}-diff.png`;
core.info(`[${taskId}] Creating image diff to ${diffPath}...`);
const baselineImage = PNG.sync.read(fs.readFileSync(baselinePath));
const currentImage = PNG.sync.read(fs.readFileSync(taskConfig.path));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use https://www.npmjs.com/package/jimp or similar to convert to PNG first so we can support jpeg/png/bmp/tiff/gif out of the box?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is super nice. Also this library can resize the image so that we can compare images with different sizes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. A downside of introducing jimp though is that this library is huge, 3MB, adding 88K lines of code to dist/index.js.

const currentImage = PNG.sync.read(fs.readFileSync(taskConfig.path));
const { width, height } = baselineImage;
const diffImage = new PNG({ width, height });
pixelmatch(baselineImage.data, currentImage.data, diffImage.data, width, height, { threshold: 0.1 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking this PR at all, but ideally we should have a link to a static site that takes the user to a page that lets them do similar things to the GitHub image comparison functionality except for non-checked-in images.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

@tuliren
Copy link
Member Author

tuliren commented Dec 27, 2022

For now, if the user wants to pull an image from an external location, they should do so in a separate step in their GH workflow (we shouldn't do it as part of the plugin). I think this is actually a crucial pattern for us in order to limit complexity for private repos.

Agree. The current implementation downloads a static image mainly for demo and testing purposes.

The baseline should default to default-branch output for this plugin

Yes. This will be implemented in a follow-up PR. It's easier this way because we will have some partial config from the default branch for testing.

We need to be able to express that the image didn't originally exist (especially for default branch)

I think it's also fine if the image already exists. For example, it can be a file checked into the codebase. It's not the main use case, but it does not hurt to have this extra feature, and some users may like it.

For the first release of this, it'd be great to have some error handling around non-matching inputs so we just drop the diff instead of fail.

Will do.

I'm also curious what diffs are most important for users. Is it default/baseline to the latest commit? Is it default/baseline to each commit (which implies the need for a separate UI for the plugin). Is pixel diffing enough or do we need swipes/onion skins/resemblejs. I don't think any of these should block the PR but it's worth discussing on our upcoming customer calls. I'm not sure how they think about which data they want to compare. I'm also curious about their tolerance for checking in images into the repo or how many images they actually want to compare on a regular basis. If it's 100s or 1000s for PR, or only ones with changes we may need to make significant changes.

Yes. All these depend on customer needs.

@jrhizor
Copy link
Contributor

jrhizor commented Dec 27, 2022

We need to be able to express that the image didn't originally exist (especially for default branch)

I think it's also fine if the image already exists. For example, it can be a file checked into the codebase. It's not the main use case, but it does not hurt to have this extra feature, and some users may like it.

For this we could probably use a gray placeholder image or something or even just text saying it doesn't exist. I just want to make sure it doesn't fail on this (probably common) case.

@tuliren tuliren marked this pull request as ready for review January 7, 2023 06:23
@tuliren tuliren merged commit 0ffd0e2 into main Jan 7, 2023
@tuliren tuliren deleted the liren/image-diff-plugin branch January 7, 2023 06:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants