Skip to content

Fix dotted brushstrokes when drawing with semitransparent colors#942

Merged
cameronwhite merged 7 commits into
PintaProject:masterfrom
khoidauminh:fix-dotted-semitranscolor
Aug 22, 2024
Merged

Fix dotted brushstrokes when drawing with semitransparent colors#942
cameronwhite merged 7 commits into
PintaProject:masterfrom
khoidauminh:fix-dotted-semitranscolor

Conversation

@khoidauminh

@khoidauminh khoidauminh commented Aug 12, 2024

Copy link
Copy Markdown
Contributor

This PR deals with issue #941.

Why the issue happens:

Each line segment of the stroke in the PlainBrush is drawn independently, one after another. With semitransparent colors, the line segments overlap each other on their ends, causing the dark dots in the stroke.

How this PR solves it:

Upon OnMouseDown(), we create a Cairo Path variable called path as a class member, set it to null, and show the ToolLayer.

During OnMouseMove() events, we operate on the ToolLayer surface and clear it before drawing (we only clear for the PlainBrush), append path to the cairo context and after stroking, copy the new path back to the class member. Cairo will draw the entire path in one go, which gets rid of the dark dots. Performance hit is negligible.

In OnMouseUp() we draw the contents of the ToolLayer onto the destination Layer, clear and hide it.

The Pencil Tool isn't affected by this PR.

Paint strokes before and after applying the PR:
pinta

@cameronwhite

Copy link
Copy Markdown
Member

Thanks for looking at this!
Rather than managing the surface yourself (and in particular, making a copy of it on each mouse move), I'd suggest making use of the ToolLayer, which is a scratch layer that's always available for tools to make use of, and is displayed right above the current layer when it's not hidden.
A good example of this is the freeform shape tool which draws to the tool layer while moving the mouse, and then just does a final draw to the actual layer on mouse up: https://github.com/PintaProject/Pinta/blob/master/Pinta.Tools/Tools/FreeformShapeTool.cs#L85

@khoidauminh

Copy link
Copy Markdown
Contributor Author

@cameronwhite Thanks! I'll be looking into that soon

@cameronwhite

Copy link
Copy Markdown
Member

Thanks, the ToolLayer approach looks better 👍

Some notes from doing a bit more testing:

  • Doing a single click (not a click + drag) doesn't cause anything to be drawn now
  • Using a brush width of 1 seems to sometimes produce some odd results, like drawing a filled polygon from the whole sequence of mouse movements. Might be some odd interaction with the DrawSinglePixelLine() code path?
  • If possible, it would be great to move more of the logic into the PlainBrush to avoid special casing things too much. If necessary there can be more virtual functions added to BasePaintBrush to facilitate this, e.g. requesting that the brush should use the tool layer

@khoidauminh

khoidauminh commented Aug 15, 2024

Copy link
Copy Markdown
Contributor Author

Hi @cameronwhite, I just pushed a few commits that deals with the issues above:

  1. Not clearing the ToolLayer in OnMouseDown() seems to have fixed the single click interaction (which, to be frank, I don't know how both the issue and the solution works).

  2. For the brush width of 1, I was able to bypass checking and calling DrawSinglePixelLine() completely because the code will always force out a line, which looks like this:

ảnh

3. path seemed to be the only variable that could be brought to the inner PlainBrush class so I move it over. Currently the only code that depends on the type of active_brush is this one.

  1. I was able to bring the path and surf variable into PlainBrush and clear them inside PlainBrush, which should clean up code and eliminate some conditionals.

@cameronwhite

Copy link
Copy Markdown
Member
  1. Not clearing the ToolLayer in OnMouseDown() seems to have fixed the single click interaction (which, to be frank, I don't know how both the issue and the solution works).

I think this was because the base class OnMouseDown() calls the OnMouseMove handler to avoid dealing with single-click as a special case (

OnMouseMove (document, e);
)
So a better fix would be to move the ToolLayer.Clear() / ToolLayer.Hidden = false before calling base.OnMouseDown() in the paintbrush tool

  1. For the brush width of 1, I was able to bypass checking and calling DrawSinglePixelLine() completely because the code will always force out a line, which looks like this:

I think the behaviour looks okay when dragging to draw a line, but doing just a single click produces some odd asymmetric antialiasing which you can see in the screenshot. The old behaviour produced a "plus" shape which I think would be more expected for that scenario

Otherwise, the changes are looking good!

@khoidauminh

Copy link
Copy Markdown
Contributor Author

Thanks for telling me, @cameronwhite
I'll try to tackle the remaining problems in a few days

@cameronwhite cameronwhite linked an issue Aug 22, 2024 that may be closed by this pull request
@cameronwhite

Copy link
Copy Markdown
Member

Looks good, thanks for contributing!

@cameronwhite cameronwhite merged commit cd5ed6a into PintaProject:master Aug 22, 2024
@khoidauminh khoidauminh deleted the fix-dotted-semitranscolor branch August 22, 2024 14:06
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.

Artifact when drawing with semitransparent colors

2 participants