Skip to content

Fix several bugs in the background-painting logic#54

Merged
fedelibre merged 5 commits into
masterfrom
fix-background-painting
May 17, 2026
Merged

Fix several bugs in the background-painting logic#54
fedelibre merged 5 commits into
masterfrom
fix-background-painting

Conversation

@bmjcode
Copy link
Copy Markdown
Member

@bmjcode bmjcode commented May 6, 2026

Previously the background was painted or erased several times in separate parts of the code when rendering a PDF page. This was partly my own fault, as I did not fully understand the rendering logic when I first wrote the QtPDF backend (the previous Poppler backend I used as a reference also overrode significant parts of it).

This new code only paints the background once, and only when necessary to do so. For example, it's not necessary or desirable to paint the background when printing.

Another consequence of this fix is that it's possible now to render an image with a transparent background, for example in Frescobaldi's copy-to-image dialog. I believe this was how it worked in older versions of qpageview, and was also the intended behavior here all along.

Previously the background was painted or erased several times in
separate parts of the code when rendering a PDF page. This was partly my
own fault, as I did not fully understand the rendering logic when I
first wrote the QtPDF backend (the previous Poppler backend I used as a
reference also overrode significant parts of it).

This new code only paints the background once, and only when necessary
to do so. For example, it's not necessary or desirable to paint the
background when printing.

Another consequence of this fix is that it's possible now to render an
image with a transparent background, for example in Frescobaldi's
copy-to-image dialog. I believe this was how it worked in older versions
of qpageview, and was also the intended behavior here all along.
@bmjcode bmjcode marked this pull request as draft May 7, 2026 21:04
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 7, 2026

I think there's still too much repainting going on. Using my tried-and-true debugging method of sticking print() calls everywhere, I've found that AbstractRenderer.paint() gets called after virtually any interaction with the view area -- scrolling, zooming, hovering over a point-and-click link, and so on. That can cause quite a bit of flicker, especially on older hardware or at higher zoom levels.

If I'm getting this deep into it anyway, I may as well take the time to fix that too while I'm at it.

See my later comment below.

This is an optimization that eliminates the need to fill the background
separately before calling drawImage(), which can cause flicker.

We do this in job() rather than in render() so that it only affects the
cached images used to paint the widget, not images rendered for other
purposes such as printing or Frescobaldi's copy-to-image feature.
@bmjcode bmjcode force-pushed the fix-background-painting branch from 7fcfce3 to 69ebd8b Compare May 8, 2026 12:02
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 8, 2026

Ignore my previous comment. There was a regression in my first commit causing a small amount of excess flicker, which I've since fixed. Whatever flicker remains was already there before, and is beyond the scope of this PR.

I'm satisfied now that this fixes the problems it originally set out to solve.

@bmjcode bmjcode marked this pull request as ready for review May 8, 2026 12:25
@fedelibre
Copy link
Copy Markdown
Member

Another consequence of this fix is that it's possible now to render an image with a transparent background, for example in Frescobaldi's copy-to-image dialog.

I've tried but the background is always white. How can you do it?

@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 12, 2026

Another consequence of this fix is that it's possible now to render an image with a transparent background, for example in Frescobaldi's copy-to-image dialog.

I've tried but the background is always white. How can you do it?

The preview in the dialog always shows a white background if no color is set, but this PR makes the actual image that's saved or copied have a transparent background:

VirtualBox_Mint Test VM_12_05_2026_17_50_08

@fedelibre
Copy link
Copy Markdown
Member

Here's an image copied with Background unchecked. The background is white:

immagine

I think I'm using this branch in my test, but let me double-check.

@fedelibre
Copy link
Copy Markdown
Member

No, I was not using this branch of qpageview. I tried a pipx installation that didn't work.
Now running $ PYTHONPATH=../qpageview python -m frescobaldi.

and I get a black image if Background is unchecked, as if transparency didn't work.

immagine immagine immagine

@fedelibre
Copy link
Copy Markdown
Member

Ooops, sorry, there was the Gray option checked by mistake.
Now without Gray, but still no transparency:

immagine

@fedelibre
Copy link
Copy Markdown
Member

In case you have any doubts about what I'm running:

fede@fedora:~/src/frescobaldi/qpageview$ git status
On branch fix-background-painting
Your branch is up to date with 'origin/fix-background-painting'.

nothing to commit, working tree clean
fede@fedora:~/src/frescobaldi/qpageview$ pip freeze | grep qpageview
fede@fedora:~/src/frescobaldi/qpageview$

@bmjcode bmjcode marked this pull request as draft May 13, 2026 10:45
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 13, 2026

I get a black image if Background is unchecked, as if transparency didn't work.

OK, so there's definitely a bug with the grayscale mode. My guess is it's converting the image to a format that doesn't support transparency.

Ooops, sorry, there was the Gray option checked by mistake. Now without Gray, but still no transparency:

I don't know why it's doing this. What Qt version are you running?

At any rate, let's come back to this one after the release, since it's not performance-critical like my other recent PRs.

@fedelibre
Copy link
Copy Markdown
Member

I'm running these versions:

Qt: 6.10.3
PyQt: 6.11.0

Converting a transparent image as-is usually results in black-on-black,
which is less than ideal for readability. Instead, we render the image
with a solid background, then use some trickery to manually restore the
transparent areas.
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 15, 2026

I found a quite clever fix for transparency in grayscale images:

image

I still don't know why yours won't do transparency in color, though.

This is my favorite optimization yet because it looks so wrong at first
glance, but then it makes sense once you've thought more about it.
@bmjcode bmjcode marked this pull request as ready for review May 15, 2026 19:09
@fedelibre
Copy link
Copy Markdown
Member

Yes, with the latest commit the Gray option is working correctly also for me:

immagine

Best not to risk confusing future maintainers -- especially if one of
those future maintainers is me, and therefore prone to messing with
anything whose workings are not immediately obvious at first glance.
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 16, 2026

Excellent. (I just tweaked the grayscale code to be slightly clearer, but functionally it is still the same.)

Ready to merge?

@fedelibre fedelibre merged commit d1ef6a5 into master May 17, 2026
3 checks passed
@fedelibre
Copy link
Copy Markdown
Member

Ok, merged.

Should I open a new issue to remember the issue with the background not being transparent on my configuration?

@bmjcode bmjcode deleted the fix-background-painting branch May 17, 2026 23:35
@bmjcode
Copy link
Copy Markdown
Member Author

bmjcode commented May 17, 2026

Yes, let's do that.

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