Skip to content

Conversation

@nicolo-ribaudo
Copy link
Contributor

@nicolo-ribaudo nicolo-ribaudo commented Feb 4, 2026

Add support for right-clicking on images

This patch adds right-click support for images in the PDF, allowing
users to download them. To minimize memory consumption, we:

  • Do not store the images separately, and instead crop them out of the
    PDF page canvas
  • Only extract the images when needed (i.e. when the user right-clicks
    on them), rather than eagerly having all of them available.

To do so, we layer one empty 0x0 canvas per image, stretched to cover
the whole image, and only populate its contents on right click.
These images need to be inside the text layer: they cannot be behind
it, otherwise they would be covered by the text layer's container and
not be clickable, and they cannot be in front of it, otherwise they
would make the text spans unselectable.

This feature is managed by a new preference, imagesRightClickMinSize:

  • when it's set to -1, right-click support is disabled
  • when set to 0, all images are available for right click
  • when set to a positive integer, only images whose width and height are
    greater than or equal to that value (in the PDF page frame of
    reference) are available for right click.

Fixes https://bugzilla.mozilla.org/show_bug.cgi?id=1012805

TODO:

  • Fix handling of images that are rotated (see TODO in the code)
  • Add tests

@marco-c marco-c changed the title Add support for right-clicking on images Add support for right-clicking on images (bug 1012805) Feb 4, 2026
@nicolo-ribaudo nicolo-ribaudo marked this pull request as ready for review February 5, 2026 12:00
This patch adds right-click support for images in the PDF, allowing
users to download them. To minimize memory consumption, we:
- Do not store the images separately, and instead crop them out of the
  PDF page canvas
- Only extract the images when needed (i.e. when the user right-clicks
  on them), rather than eagery having all of them available.

To do so, we layer one empty 0x0 canvas per image, stretched to cover
the whole image, and only populate its contents on right click.
These images need to be inside the text layer: they cannot be _behind_
it, otherwise they would be covered by the text layer's container and
not be clickable, and they cannot be in front of it, otherwise they
would make the text spans unselectable.

This feature is managed by a new preference, `imagesRightClickMinSize`:
- when it's set to `-1`, right-click support is disabled
- when set to `0`, all images are available for right click
- when set to a positive integer, only images whose width and height are
  greater than or equal to that value (in the PDF page frame of
  reference) are available for right click.
Copy link
Contributor

@timvandermeij timvandermeij left a comment

Choose a reason for hiding this comment

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

I did a first pass over this PR, which resulted in the following comments. Overall this looks really good, and we can run the tests after this has been addressed.

@@ -0,0 +1,159 @@
/* Copyright 2024 Mozilla Foundation
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: s/2024/2026

const cwdURL = pathToFileURL(process.cwd()) + "/";
this.rootURL = new URL(`${root || "."}/`, cwdURL);
this.host = host || "localhost";
this.host = host; // || "localhost";
Copy link
Contributor

Choose a reason for hiding this comment

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

This change should probably be reverted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I opened #20646 so that I can stop having to comment this line out when testing on mobile.

return `${(value * 100).toFixed(2)}%`;
}

class TextLayerImages {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be good to add a small docstring to this class to explain its purpose.

};

export { CanvasDependencyTracker, CanvasNestedDependencyTracker, Dependencies };
class CanvasImagesTracker {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be good to add a small docstring to this class to explain its purpose.

* @returns {Promise<void>}
*/
async render({ viewport, textContentParams = null }) {
async render({ viewport, images, textContentParams = null }) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The TextLayerBuilderRenderOptions type should be updated accordingly.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants