Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Meta/Lagom/Contrib/MacPDF/MacPDFView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ @interface MacPDFView ()

auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, page_size));

auto errors = PDF::Renderer::render(document, page, bitmap, PDF::RenderingPreferences {});
auto errors = PDF::Renderer::render(document, page, bitmap, Color::White, PDF::RenderingPreferences {});
if (errors.is_error()) {
for (auto const& error : errors.error().errors())
NSLog(@"warning: %@", @(error.message().characters()));
Expand Down
1 change: 1 addition & 0 deletions Tests/LibPDF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(TEST_FILES
non-linearized.pdf
oss-fuzz-testcase-62065.pdf
password-is-sup.pdf
pattern.pdf
text.pdf
type1.pdf
type3.pdf
Expand Down
Binary file added Tests/LibPDF/pattern.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion Userland/Applications/PDFViewer/PDFViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> PDFViewer::render_page(u32 page_inde
auto& page_size = m_page_dimension_cache.render_info[page_index].size;
auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, page_size.to_type<int>()));

auto maybe_errors = PDF::Renderer::render(*m_document, page, bitmap, m_rendering_preferences);
auto maybe_errors = PDF::Renderer::render(*m_document, page, bitmap, Color::White, m_rendering_preferences);
if (maybe_errors.is_error()) {
auto errors = maybe_errors.release_error();
on_render_errors(page_index, errors);
Expand Down
57 changes: 57 additions & 0 deletions Userland/Libraries/LibGfx/PaintStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,63 @@ class BitmapPaintStyle : public PaintStyle {
IntPoint m_offset;
};

class RepeatingBitmapPaintStyle : public Gfx::PaintStyle {
public:
static ErrorOr<NonnullRefPtr<RepeatingBitmapPaintStyle>> create(Gfx::Bitmap const& bitmap, Gfx::IntPoint steps, Color fallback)
{
return adopt_nonnull_ref_or_enomem(new (nothrow) RepeatingBitmapPaintStyle(bitmap, steps, fallback));
}

virtual Color sample_color(Gfx::IntPoint point) const override
{
point.set_x(point.x() % m_steps.x());
point.set_y(point.y() % m_steps.y());
if (point.x() < 0 || point.y() < 0 || point.x() >= m_bitmap->width() || point.y() >= m_bitmap->height())
return m_fallback;
auto px = m_bitmap->get_pixel(point);
return px;
}

private:
RepeatingBitmapPaintStyle(Gfx::Bitmap const& bitmap, Gfx::IntPoint steps, Color fallback)
: m_bitmap(bitmap)
, m_steps(steps)
, m_fallback(fallback)
{
}

NonnullRefPtr<Gfx::Bitmap const> m_bitmap;
Gfx::IntPoint m_steps;
Color m_fallback;
};

class OffsetPaintStyle : public Gfx::PaintStyle {
public:
static ErrorOr<NonnullRefPtr<OffsetPaintStyle>> create(RefPtr<PaintStyle> other, Gfx::AffineTransform transform)
{
return adopt_nonnull_ref_or_enomem(new (nothrow) OffsetPaintStyle(move(other), transform));
}

virtual void paint(Gfx::IntRect physical_bounding_box, PaintFunction paint) const override
{
m_other->paint(m_transform.map(physical_bounding_box), [=, this, paint = move(paint)](SamplerFunction sampler) {
paint([=, this, sampler = move(sampler)](Gfx::IntPoint point) {
return sampler(m_transform.map(point));
});
});
}

private:
OffsetPaintStyle(RefPtr<PaintStyle> other, Gfx::AffineTransform transform)
: m_other(move(other))
, m_transform(transform)
{
}

RefPtr<PaintStyle> m_other;
Gfx::AffineTransform m_transform;
};

class GradientPaintStyle : public PaintStyle {
public:
ErrorOr<void> add_color_stop(float position, Color color, Optional<float> transition_hint = {})
Expand Down
165 changes: 131 additions & 34 deletions Userland/Libraries/LibPDF/ColorSpace.cpp

Large diffs are not rendered by default.

59 changes: 41 additions & 18 deletions Userland/Libraries/LibPDF/ColorSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <AK/Forward.h>
#include <LibGfx/Color.h>
#include <LibGfx/ICC/Profile.h>
#include <LibGfx/PaintStyle.h>
#include <LibPDF/Function.h>
#include <LibPDF/Value.h>

Expand All @@ -28,6 +29,9 @@

namespace PDF {

typedef Variant<Gfx::Color, NonnullRefPtr<Gfx::PaintStyle>> ColorOrStyle;
class Renderer;

class ColorSpaceFamily {
public:
ColorSpaceFamily(DeprecatedFlyString name, bool may_be_specified_directly)
Expand Down Expand Up @@ -56,13 +60,13 @@ class ColorSpaceFamily {

class ColorSpace : public RefCounted<ColorSpace> {
public:
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, NonnullRefPtr<Object>);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(DeprecatedFlyString const&);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, NonnullRefPtr<ArrayObject>);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, NonnullRefPtr<Object>, Renderer&);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(DeprecatedFlyString const&, Renderer&);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, NonnullRefPtr<ArrayObject>, Renderer&);

virtual ~ColorSpace() = default;

virtual PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const = 0;
virtual PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const = 0;
virtual int number_of_components() const = 0;
virtual Vector<float> default_decode() const = 0; // "TABLE 4.40 Default Decode arrays"
virtual ColorSpaceFamily const& family() const = 0;
Expand All @@ -74,7 +78,7 @@ class DeviceGrayColorSpace final : public ColorSpace {

~DeviceGrayColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 1; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceGray; }
Expand All @@ -89,7 +93,7 @@ class DeviceRGBColorSpace final : public ColorSpace {

~DeviceRGBColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 3; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceRGB; }
Expand All @@ -104,7 +108,7 @@ class DeviceCMYKColorSpace final : public ColorSpace {

~DeviceCMYKColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 4; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceCMYK; }
Expand All @@ -115,11 +119,11 @@ class DeviceCMYKColorSpace final : public ColorSpace {

class DeviceNColorSpace final : public ColorSpace {
public:
static PDFErrorOr<NonnullRefPtr<DeviceNColorSpace>> create(Document*, Vector<Value>&& parameters);
static PDFErrorOr<NonnullRefPtr<DeviceNColorSpace>> create(Document*, Vector<Value>&& parameters, Renderer&);

~DeviceNColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override;
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceN; }
Expand All @@ -140,7 +144,7 @@ class CalGrayColorSpace final : public ColorSpace {

~CalGrayColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 1; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalGray; }
Expand All @@ -159,7 +163,7 @@ class CalRGBColorSpace final : public ColorSpace {

~CalRGBColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 3; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalRGB; }
Expand All @@ -175,11 +179,11 @@ class CalRGBColorSpace final : public ColorSpace {

class ICCBasedColorSpace final : public ColorSpace {
public:
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, Vector<Value>&& parameters);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, Vector<Value>&& parameters, Renderer&);

~ICCBasedColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override;
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::ICCBased; }
Expand All @@ -197,7 +201,7 @@ class LabColorSpace final : public ColorSpace {

~LabColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 3; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Lab; }
Expand All @@ -212,11 +216,11 @@ class LabColorSpace final : public ColorSpace {

class IndexedColorSpace final : public ColorSpace {
public:
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, Vector<Value>&& parameters);
static PDFErrorOr<NonnullRefPtr<ColorSpace>> create(Document*, Vector<Value>&& parameters, Renderer&);

~IndexedColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 1; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Indexed; }
Expand All @@ -231,11 +235,11 @@ class IndexedColorSpace final : public ColorSpace {

class SeparationColorSpace final : public ColorSpace {
public:
static PDFErrorOr<NonnullRefPtr<SeparationColorSpace>> create(Document*, Vector<Value>&& parameters);
static PDFErrorOr<NonnullRefPtr<SeparationColorSpace>> create(Document*, Vector<Value>&& parameters, Renderer&);

~SeparationColorSpace() override = default;

PDFErrorOr<Color> color(ReadonlySpan<Value> arguments) const override;
PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override { return 1; }
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Separation; }
Expand All @@ -249,4 +253,23 @@ class SeparationColorSpace final : public ColorSpace {
Vector<Value> mutable m_tint_output_values;
};

class PatternColorSpace final : public ColorSpace {
public:
static NonnullRefPtr<PatternColorSpace> create(Renderer& renderer);
~PatternColorSpace() override = default;

PDFErrorOr<ColorOrStyle> style(ReadonlySpan<Value> arguments) const override;
int number_of_components() const override;
Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Pattern; }

private:
PatternColorSpace(Renderer& renderer)
: m_renderer(renderer)
{
}

Renderer& m_renderer;
};

}
2 changes: 2 additions & 0 deletions Userland/Libraries/LibPDF/CommonNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@
X(Outlines) \
X(P) \
X(Pages) \
X(PaintType) \
X(Parent) \
X(Pattern) \
X(PatternType) \
X(Perms) \
X(Predictor) \
X(Prev) \
Expand Down
13 changes: 10 additions & 3 deletions Userland/Libraries/LibPDF/Fonts/TrueTypeFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,20 @@ void TrueTypeFont::set_font_size(float font_size)
m_font = m_font->with_size((font_size * POINTS_PER_INCH) / DEFAULT_DPI);
}

PDFErrorOr<void> TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float, u8 char_code, Renderer const& renderer)
PDFErrorOr<void> TrueTypeFont::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
{
auto color = renderer.state().paint_color;
auto style = renderer.state().paint_style;

// Account for the reversed font baseline
auto position = point.translated(0, -m_font->baseline());
painter.draw_glyph(position, char_code, *m_font, color);
if (style.has<Color>()) {
painter.draw_glyph(position, char_code, *m_font, style.get<Color>());
} else {
// FIXME: Bounding box and sample point look to be pretty wrong
style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
painter.draw_glyph(position, char_code, *m_font, sample(Gfx::IntPoint(position.x(), position.y())));
});
}
return {};
}

Expand Down
26 changes: 21 additions & 5 deletions Userland/Libraries/LibPDF/Fonts/Type1Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,19 @@ void Type1Font::set_font_size(float font_size)

PDFErrorOr<void> Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float width, u8 char_code, Renderer const& renderer)
{
auto color = renderer.state().paint_color;
auto style = renderer.state().paint_style;

if (!m_font_program) {
// Account for the reversed font baseline
auto position = point.translated(0, -m_font->baseline());
painter.draw_glyph(position, char_code, *m_font, color);
// FIXME: Bounding box and sample point look to be pretty wrong
if (style.has<Color>()) {
painter.draw_glyph(position, char_code, *m_font, style.get<Color>());
} else {
style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(Gfx::IntRect(position.x(), position.y(), width, 0), [&](auto sample) {
painter.draw_glyph(position, char_code, *m_font, sample(Gfx::IntPoint(position.x(), position.y())));
});
}
return {};
}

Expand All @@ -97,9 +104,18 @@ PDFErrorOr<void> Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint po
m_glyph_cache.set(index, bitmap);
}

painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [color](Color pixel) -> Color {
return pixel.multiply(color);
});
if (style.has<Color>()) {
painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [style](Color pixel) -> Color {
return pixel.multiply(style.get<Color>());
});
} else {
style.get<NonnullRefPtr<Gfx::PaintStyle>>()->paint(bitmap->physical_rect(), [&](auto sample) {
painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [&](Color pixel) -> Color {
// FIXME: Presumably we need to sample at every point in the glyph, not just the top left?
return pixel.multiply(sample(glyph_position.blit_position));
});
});
}
return {};
}
}
2 changes: 2 additions & 0 deletions Userland/Libraries/LibPDF/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ PDFErrorOr<Vector<Operator>> Parser::parse_operators()

while (!m_reader.done()) {
parse_comment();
if (m_reader.done())
break;
auto ch = m_reader.peek();
if (is_operator_char_start(ch)) {
auto operator_start = m_reader.offset();
Expand Down
Loading