Skip to content

Commit

Permalink
LibPDF+PDFViewer+MacPDF: Don't draw hidden text by default
Browse files Browse the repository at this point in the history
Text can be rendered in various ways in PDFs: Filled, stroked,
both filled and stroked, set as clipping path, hidden, or
some combinations thereof.

We don't implement any of this at the moment except "filled".

Hidden text is used in scanned documents: The image of the scan is
drawn in the background, and then OCRd text is "drawn" as hidden
on top of the scanned bitmap. That way, the (hidden) text can be
selected and copied, and it looks like you're selecting text from
the scanned bitmap. Find-in-page also works similarly. (We currently
have neither text selection nor find-in-page, but one day we will.)

Now that we have pretty good support for CCITT and are growing some
support for JBIG2, we now draw both the scanned background image
as well as the foreground text. They're not always perfectly aligned.

This change makes it so that we don't render text that's marked as
hidden. (We still do most of the coordinate math, which will probably
come in handy at some point when we implement text selection.)

This makes these scanned documents appear as they're supposed to
appear (at least in documents where we manage to decode the background
bitmap).

This also adds a debug option to force rendering of hidden text.
  • Loading branch information
nico committed Mar 16, 2024
1 parent ead7428 commit 7fd79e2
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 4 deletions.
1 change: 1 addition & 0 deletions Meta/Lagom/Contrib/MacPDF/MacPDFView.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@
- (IBAction)toggleClipPaths:(id)sender;
- (IBAction)toggleClipText:(id)sender;
- (IBAction)toggleShowImages:(id)sender;
- (IBAction)toggleShowHiddenText:(id)sender;

@end
12 changes: 12 additions & 0 deletions Meta/Lagom/Contrib/MacPDF/MacPDFView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ - (BOOL)validateMenuItem:(NSMenuItem*)item
[item setState:_preferences.show_images ? NSControlStateValueOn : NSControlStateValueOff];
return _doc ? YES : NO;
}
if ([item action] == @selector(toggleShowHiddenText:)) {
[item setState:_preferences.show_hidden_text ? NSControlStateValueOn : NSControlStateValueOff];
return _doc ? YES : NO;
}
return NO;
}

Expand Down Expand Up @@ -228,6 +232,14 @@ - (IBAction)toggleShowImages:(id)sender
}
}

- (IBAction)toggleShowHiddenText:(id)sender
{
if (_doc) {
_preferences.show_hidden_text = !_preferences.show_hidden_text;
[self invalidateCachedBitmap];
}
}

- (void)keyDown:(NSEvent*)event
{
// Calls moveLeft: or moveRight: below.
Expand Down
1 change: 1 addition & 0 deletions Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
- (IBAction)toggleClipPaths:(id)sender;
- (IBAction)toggleClipText:(id)sender;
- (IBAction)toggleShowImages:(id)sender;
- (IBAction)toggleShowHiddenText:(id)sender;
- (IBAction)showGoToPageDialog:(id)sender;

- (void)pdfDidInitialize;
Expand Down
5 changes: 5 additions & 0 deletions Meta/Lagom/Contrib/MacPDF/MacPDFWindowController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ - (IBAction)toggleShowImages:(id)sender
[_pdfView toggleShowImages:sender];
}

- (IBAction)toggleShowHiddenText:(id)sender
{
[_pdfView toggleShowHiddenText:sender];
}

- (IBAction)showGoToPageDialog:(id)sender
{
auto alert = [[NSAlert alloc] init];
Expand Down
6 changes: 6 additions & 0 deletions Meta/Lagom/Contrib/MacPDF/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,12 @@
<action selector="toggleShowImages:" target="-1" id="mNE-9J-Nle"/>
</connections>
</menuItem>
<menuItem title="Show Hidden Text" id="PhM-XC-ExK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleShowHiddenText:" target="-1" id="7iT-L2-Jd1"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
Expand Down
8 changes: 8 additions & 0 deletions Userland/Applications/PDFViewer/PDFViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ PDFViewer::PDFViewer()
m_page_view_mode = static_cast<PageViewMode>(Config::read_i32("PDFViewer"sv, "Display"sv, "PageMode"sv, 0));
m_rendering_preferences.show_clipping_paths = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ShowClippingPaths"sv, false);
m_rendering_preferences.show_images = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ShowImages"sv, true);
m_rendering_preferences.show_hidden_text = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ShowHiddenText"sv, false);
m_rendering_preferences.show_diagnostics = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ShowDiagnostics"sv, false);
m_rendering_preferences.clip_images = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ClipImages"sv, true);
m_rendering_preferences.clip_paths = Config::read_bool("PDFViewer"sv, "Rendering"sv, "ClipPaths"sv, true);
Expand Down Expand Up @@ -192,6 +193,13 @@ void PDFViewer::set_show_images(bool show_images)
update();
}

void PDFViewer::set_show_hidden_text(bool show_hidden_text)
{
m_rendering_preferences.show_hidden_text = show_hidden_text;
Config::write_bool("PDFViewer"sv, "Rendering"sv, "ShowHiddenText"sv, show_hidden_text);
update();
}

void PDFViewer::set_clip_images(bool clip_images)
{
m_rendering_preferences.clip_images = clip_images;
Expand Down
2 changes: 2 additions & 0 deletions Userland/Applications/PDFViewer/PDFViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class PDFViewer : public GUI::AbstractScrollableWidget {
void set_show_clipping_paths(bool);
bool show_images() const { return m_rendering_preferences.show_images; }
void set_show_images(bool);
bool show_hidden_text() const { return m_rendering_preferences.show_hidden_text; }
void set_show_hidden_text(bool);
bool clip_images() const { return m_rendering_preferences.clip_images; }
void set_clip_images(bool);
bool clip_paths() const { return m_rendering_preferences.clip_paths; }
Expand Down
5 changes: 5 additions & 0 deletions Userland/Applications/PDFViewer/PDFViewerWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ ErrorOr<void> PDFViewerWidget::initialize_menubar(GUI::Window& window)
});
toggle_show_images->set_checked(m_viewer->show_images());
debug_menu->add_action(toggle_show_images);
auto toggle_show_hidden_text = GUI::Action::create_checkable("Show &Hidden Text", [&](auto& action) {
m_viewer->set_show_hidden_text(action.is_checked());
});
toggle_show_hidden_text->set_checked(m_viewer->show_hidden_text());
debug_menu->add_action(toggle_show_hidden_text);
auto toggle_clip_images = GUI::Action::create_checkable("Clip I&mages", [&](auto& action) {
m_viewer->set_clip_images(action.is_checked());
});
Expand Down
6 changes: 4 additions & 2 deletions Userland/Libraries/LibPDF/Fonts/SimpleFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ PDFErrorOr<Gfx::FloatPoint> SimpleFont::draw_string(Gfx::Painter& painter, Gfx::
else
glyph_width = font_size * m_missing_width * m_font_matrix.x_scale();

Gfx::FloatPoint glyph_render_position = text_rendering_matrix.map(glyph_position);
TRY(draw_glyph(painter, glyph_render_position, glyph_width, char_code, renderer));
if (renderer.text_state().rendering_mode != TextRenderingMode::Invisible || renderer.show_hidden_text()) {
Gfx::FloatPoint glyph_render_position = text_rendering_matrix.map(glyph_position);
TRY(draw_glyph(painter, glyph_render_position, glyph_width, char_code, renderer));
}

// glyph_width is scaled by `text_rendering_matrix.x_scale() * renderer.text_state().font_size / horizontal_scaling`,
// but it should only be scaled by `renderer.text_state().font_size`.
Expand Down
6 changes: 4 additions & 2 deletions Userland/Libraries/LibPDF/Fonts/Type0Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,10 @@ PDFErrorOr<Gfx::FloatPoint> Type0Font::draw_string(Gfx::Painter& painter, Gfx::F
}
}

Gfx::FloatPoint glyph_render_position = text_rendering_matrix.map(glyph_position - Gfx::FloatPoint { position_vector_x, position_vector_y });
TRY(m_cid_font_type->draw_glyph(painter, glyph_render_position, glyph_width, cid, renderer));
if (renderer.text_state().rendering_mode != TextRenderingMode::Invisible || renderer.show_hidden_text()) {
Gfx::FloatPoint glyph_render_position = text_rendering_matrix.map(glyph_position - Gfx::FloatPoint { position_vector_x, position_vector_y });
TRY(m_cid_font_type->draw_glyph(painter, glyph_render_position, glyph_width, cid, renderer));
}

// glyph_width is scaled by `text_rendering_matrix.x_scale() * renderer.text_state().font_size / horizontal_scaling`,
// but it should only be scaled by `renderer.text_state().font_size`.
Expand Down
3 changes: 3 additions & 0 deletions Userland/Libraries/LibPDF/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct GraphicsState {
struct RenderingPreferences {
bool show_clipping_paths { false };
bool show_images { true };
bool show_hidden_text { false };
bool show_diagnostics { false };

bool clip_images { true };
Expand Down Expand Up @@ -121,6 +122,8 @@ class Renderer {

PDFErrorOr<void> render_type3_glyph(Gfx::FloatPoint, StreamObject const&, Gfx::AffineTransform const&, Optional<NonnullRefPtr<DictObject>>);

bool show_hidden_text() const { return m_rendering_preferences.show_hidden_text; }

private:
Renderer(RefPtr<Document>, Page const&, RefPtr<Gfx::Bitmap>, Color background_color, RenderingPreferences);

Expand Down

0 comments on commit 7fd79e2

Please sign in to comment.