LibPDF: Add an initial implementation of type 3 glyph rendering

This is a very inefficient implementation: Every time a type 3 font
glyph is drawn, we parse its operator stream and execute all the
operators therein.

We'll want to instead cache the glyphs in bitmaps (at least in most
cases), like we do for other fonts. But it's a good first step, and
all the coordinate math seems to work in the files I've tested.

Good test files from pdfa dataset 0000.zip:

- 0000559.pdf page 1 (and 2): Has a non-default font matrix;
  text appears mirrored if the font matrix isn't handled correctly

- 0000425.pdf, page 1: Draws several glyphs in a single run;
  glyphs overlap if Renderer::render_type3_glyph() ignores the
  passed-in point

- 0000211.pdf, any page: Uses type 3 glyphs for all text.
  Good perf test (already "reasonably fast")

- 0000521.pdf, page 5 (or 7 or or 16): The little red flag in the
  purple box is a type 3 font glyph, and it's colored (which in part
  means the first operator is `d0`, while all the other documents above
  use `d1`)
This commit is contained in:
Nico Weber 2023-11-15 07:51:56 -05:00 committed by Sam Atkins
parent 14ddab5519
commit 29396415d5
Notes: sideshowbarker 2024-07-17 09:37:30 +09:00
3 changed files with 26 additions and 4 deletions

View file

@ -7,6 +7,7 @@
#include <LibGfx/Painter.h>
#include <LibPDF/CommonNames.h>
#include <LibPDF/Fonts/Type3Font.h>
#include <LibPDF/Renderer.h>
namespace PDF {
@ -53,7 +54,7 @@ void Type3Font::set_font_size(float)
{
}
PDFErrorOr<void> Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u8 char_code, Renderer const&)
PDFErrorOr<void> Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint point, float, u8 char_code, Renderer const& renderer)
{
// PDF 1.7 spec, 5.5.4 Type 3 Fonts:
// "For each character code shown by a text-showing operator that uses a Type 3 font,
@ -71,8 +72,9 @@ PDFErrorOr<void> Type3Font::draw_glyph(Gfx::Painter&, Gfx::FloatPoint, float, u8
return {};
// "3. Invokes the glyph description, as described below."
// FIXME
return Error { Error::Type::RenderingUnsupported, "Type3 fonts not yet implemented" };
// The Gfx::Painter isn't used because `renderer` paints to it already.
// FIXME: Do color things dependent on if the glyph data starts with d0 or d1.
// FIXME: Glyph caching.
return const_cast<Renderer&>(renderer).render_type3_glyph(point, *char_proc.value(), font_matrix(), m_resources);
}
}

View file

@ -1008,4 +1008,21 @@ Gfx::AffineTransform const& Renderer::calculate_text_rendering_matrix() const
return m_text_rendering_matrix;
}
PDFErrorOr<void> Renderer::render_type3_glyph(Gfx::FloatPoint point, StreamObject const& glyph_data, Gfx::AffineTransform const& font_matrix, Optional<NonnullRefPtr<DictObject>> resources)
{
ScopedState scoped_state { *this };
auto text_rendering_matrix = calculate_text_rendering_matrix();
text_rendering_matrix.set_translation(point);
state().ctm = text_rendering_matrix;
state().ctm.scale(text_state().font_size, text_state().font_size);
state().ctm.multiply(font_matrix);
m_text_rendering_matrix_is_dirty = true;
auto operators = TRY(Parser::parse_operators(m_document, glyph_data.bytes()));
for (auto& op : operators)
TRY(handle_operator(op, resources));
return {};
}
}

View file

@ -111,6 +111,9 @@ public:
ALWAYS_INLINE TextState const& text_state() const { return state().text_state; }
Gfx::AffineTransform const& calculate_text_rendering_matrix() const;
PDFErrorOr<void> render_type3_glyph(Gfx::FloatPoint, StreamObject const&, Gfx::AffineTransform const&, Optional<NonnullRefPtr<DictObject>>);
private:
Renderer(RefPtr<Document>, Page const&, RefPtr<Gfx::Bitmap>, RenderingPreferences);