Skip to content

feat(ui): support FLUX Fill on Canvas #7811

New issue

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

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

Already on GitHub? # to your account

Merged
merged 17 commits into from
Mar 20, 2025

Conversation

psychedelicious
Copy link
Collaborator

Summary

  • Support for FLUX Fill on Canvas.
  • New Canvas compositing nodes. These are required for FLUX Fill and are substantial improvement over the previous nodes we used for this.

Canvas Compositing

I'm using this canvas setup for testing:
image

On the current release, there are subtle banding artifacts on the generated outputs. Here's a video attempting to show them:

Screen.Recording.2025-03-20.at.12.39.13.pm.mov

I took a screenshot and fiddled with the levels to accentuate the artifacts:
image

Depending on the image, these artifacts can range from nearly invisible to hard-to-miss.

Compare to this PR - there is still some minor banding but it's vastly improved:

Screen.Recording.2025-03-20.at.12.44.57.pm.mov

image

Besides the banding artifacts, the new nodes fix the size of the mask and its fade-out. The old logic didn't really make sense and didn't work how we wanted it to. The result was masks were blurred too much, then had to be made larger to compensate. So the mask parameters weren't respected.

See b80b964 for technical details and my best guess as to why the banding occurred in the first place.

TODO

  • Figure out the Guidance parameter. FLUX Fill wants a guidance up around 30, but we currently limit FLUX guidance to 10 on the slider (20 on the number input). Should we just open up the range? Silently override on behalf of the user?
  • FLUX Fill does not work well with t2i or i2i. We do not know the generation mode (t2i, i2i, inpaint, or outpaint) until the user clicks Invoke, so we cannot detect when the user has selected FLUX Fill and want them that t2i/i2i isn't going to work well. The solution in this PR is to bail on enqueuing, showing an error toast, if the user attempts to use FLUX Fill with t2i or i2i.

Related Issues / Discussions

There have been numerous discussions about the banding and mask size issues. Hopefully this resolves them all.

QA Instructions

Besides the new FLUX Fill support on Canvas, I revised the graphs for inpainting and outpainting to use the new nodes. Both scaled bbox and unscaled bbox pathways were changed.

So, testing this PR fully means trying:

  • Generate with an inpaint mask and filled-in bbox (i.e. inpaint). Try with scaled bbox and unscaled.
  • Generate with an inpaint mask and a partially-transparent bbox (i.e. outpaint). Try with scaled bbox and unscaled.
  • Generate with FLUX Fill. Inpaint and outpaint are handled by the same graph, but you should try both. Try with scaled bbox and unscaled.

Merge Plan

n/a

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Tests added / updated (if applicable)
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

@github-actions github-actions bot added python PRs that change python files invocations PRs that change invocations frontend PRs that change frontend files labels Mar 20, 2025
@hipsterusername
Copy link
Member

Likely should override silently for Guidance specifically. Can’t rely on obscure knowledge for things to work, and “non-standard” guidance there is likely a job for workflows

Failing on T2I or I2I with a clear message works.

How did we land on solving the ergonomics of having to switch to fill? Are users manually selecting that as their model?

@psychedelicious
Copy link
Collaborator Author

How did we land on solving the ergonomics of having to switch to fill? Are users manually selecting that as their model?

Yes - FLUX Fill is a separate main model alongside FLUX dev/schnell and works like other main models.

We can differentiate between FLUX Fill and other FLUX models with the variant field. It is "inpaint" for the Fill model and "normal" for the others.

We check this when building the graph.

Due to the partial feature overlap between the FLUX model variants, it doesn't make sense to automatically choose FLUX Fill or dev/schnell on behalf of the user based on the generation mode (t2i/i2i/inpaint/outpaint). For example, Control LoRA isn't compatible with FLUX Fill. There are some other gotchas.

Also, we don't have confidence that all the normal FLUX auxiliary models work the same with Fill.

So we offer too much flexibility & control to choose the base model for the user without causing a lot of headaches and possibly compromising outputs.

@psychedelicious
Copy link
Collaborator Author

Error message when attempting to t2i or i2i with FLUX Fill:
image

Warnings when using Control LoRA with FLUX Fill:
image
image

When a FLUX Fill model is selected, the Guidance widget is hidden and guidance is silently set to 30 - the user-defined value is ignored.

It simply applies the mask to an image.
…iting needs

Previously we used erode/dilate and a Gaussian blur to expand and fade the edges of Canvas masks. The implementation a number of problems:
- Erode/dilate kernel sizes were not calculated correctly, and extra iterations were run to compensate. The result is the blur size, which should have been pixels, was very inaccurate and unreliable.
- What we want is to add a "soft bleed" - like a drop shadow with no offset - starting from the edge of the mask, extending out by however many pixels. But Gaussian blur does not do this. The blurred area starts _inside_ the mask and extends outside it. So it kinda blurs inwards and outwards. We compensated for this by expanding the mask.
- Using a Gaussian blur can cause banding artifacts. Gaussian blur doesn't have a "size" or "radius" parameter in the sense that you think it should. It's a convolution matrix and there are _no non-zero values in the result_. This means that, far away from the mask, once compositing completes, we have some values that are very close to zero but not quite zero. These values are quantized by HTML Canvas, resulting in banding artifacts where you'd expect the blur to have faded to 0% alpha. At least, that is my understanding of why the banding artifacts occur.

The new node uses a better strategy to expand the mask and add the fade out effect:
- Calculate the distance from each white pixel to the nearest black pixel.
- Normalize this distance by dividing by the fade size in px, then clip the values to 0 - 1. The result represents the distance of each white pixel to its nearest black pixel as a percentage of the fade size. At this point, it is a linear distribution.
- Create a polynomial to describe the fade's intensity so that we can have a smooth transition from the masked region (black) to unmasked (white). There are some magic numbers here, deterined experimentally.
- Evaluate the polynomial over the normalized distances, so we now have a matrix representing the fade intensity for every pixel
- Convert this matrix back to uint8 and apply it to the mask

This works soooo much better than the previous method. Not only does it fix the banding issues, but when we enable "output only generated regions", we get a much smaller image. Will add images to the PR to clarify.
@psychedelicious psychedelicious force-pushed the psyche/feat/ui/flux-fill-canvas branch from df69bfd to 0f1519e Compare March 20, 2025 23:09
@psychedelicious psychedelicious enabled auto-merge (rebase) March 20, 2025 23:15
@psychedelicious psychedelicious merged commit c2b20a5 into main Mar 20, 2025
15 checks passed
@psychedelicious psychedelicious deleted the psyche/feat/ui/flux-fill-canvas branch March 20, 2025 23:24
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
frontend PRs that change frontend files invocations PRs that change invocations python PRs that change python files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants