1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:17:34 +00:00

LibPDF: Use Variant<Color, PaintStyle> instead of Color for ColorSpaces

This is in anticipation of Pattern color space support which does not
yield a simple color.
This commit is contained in:
Kyle Pereira 2023-12-05 12:51:42 +00:00 committed by Andreas Kling
parent e4b8d68039
commit 082a4197b6
6 changed files with 116 additions and 55 deletions

View file

@ -101,7 +101,7 @@ NonnullRefPtr<DeviceGrayColorSpace> DeviceGrayColorSpace::the()
return instance; return instance;
} }
PDFErrorOr<Color> DeviceGrayColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> DeviceGrayColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 1); VERIFY(arguments.size() == 1);
auto gray = static_cast<u8>(arguments[0].to_float() * 255.0f); auto gray = static_cast<u8>(arguments[0].to_float() * 255.0f);
@ -119,7 +119,7 @@ NonnullRefPtr<DeviceRGBColorSpace> DeviceRGBColorSpace::the()
return instance; return instance;
} }
PDFErrorOr<Color> DeviceRGBColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> DeviceRGBColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 3); VERIFY(arguments.size() == 3);
auto r = static_cast<u8>(arguments[0].to_float() * 255.0f); auto r = static_cast<u8>(arguments[0].to_float() * 255.0f);
@ -139,7 +139,7 @@ NonnullRefPtr<DeviceCMYKColorSpace> DeviceCMYKColorSpace::the()
return instance; return instance;
} }
PDFErrorOr<Color> DeviceCMYKColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> DeviceCMYKColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 4); VERIFY(arguments.size() == 4);
auto c = arguments[0].to_float(); auto c = arguments[0].to_float();
@ -197,7 +197,7 @@ DeviceNColorSpace::DeviceNColorSpace(NonnullRefPtr<ColorSpace> alternate_space,
{ {
} }
PDFErrorOr<Color> DeviceNColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> DeviceNColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
// FIXME: Does this need handling for the special colorant name "None"? // FIXME: Does this need handling for the special colorant name "None"?
// FIXME: When drawing to a printer, do something else. // FIXME: When drawing to a printer, do something else.
@ -211,7 +211,7 @@ PDFErrorOr<Color> DeviceNColorSpace::color(ReadonlySpan<Value> arguments) const
for (size_t i = 0; i < tint_output.size(); ++i) for (size_t i = 0; i < tint_output.size(); ++i)
m_tint_output_values[i] = tint_output[i]; m_tint_output_values[i] = tint_output[i];
return m_alternate_space->color(m_tint_output_values); return m_alternate_space->style(m_tint_output_values);
} }
int DeviceNColorSpace::number_of_components() const int DeviceNColorSpace::number_of_components() const
@ -347,7 +347,7 @@ PDFErrorOr<NonnullRefPtr<CalGrayColorSpace>> CalGrayColorSpace::create(Document*
return color_space; return color_space;
} }
PDFErrorOr<Color> CalGrayColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> CalGrayColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 1); VERIFY(arguments.size() == 1);
auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f); auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f);
@ -433,7 +433,7 @@ PDFErrorOr<NonnullRefPtr<CalRGBColorSpace>> CalRGBColorSpace::create(Document* d
return color_space; return color_space;
} }
PDFErrorOr<Color> CalRGBColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> CalRGBColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 3); VERIFY(arguments.size() == 3);
auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f); auto a = clamp(arguments[0].to_float(), 0.0f, 1.0f);
@ -493,7 +493,7 @@ ICCBasedColorSpace::ICCBasedColorSpace(NonnullRefPtr<Gfx::ICC::Profile> profile)
{ {
} }
PDFErrorOr<Color> ICCBasedColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> ICCBasedColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
if (!s_srgb_profile) if (!s_srgb_profile)
s_srgb_profile = TRY(Gfx::ICC::sRGB()); s_srgb_profile = TRY(Gfx::ICC::sRGB());
@ -593,7 +593,7 @@ PDFErrorOr<NonnullRefPtr<LabColorSpace>> LabColorSpace::create(Document* documen
return color_space; return color_space;
} }
PDFErrorOr<Color> LabColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> LabColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 3); VERIFY(arguments.size() == 3);
auto L_star = clamp(arguments[0].to_float(), 0.0f, 100.0f); auto L_star = clamp(arguments[0].to_float(), 0.0f, 100.0f);
@ -692,7 +692,7 @@ IndexedColorSpace::IndexedColorSpace(NonnullRefPtr<ColorSpace> base)
{ {
} }
PDFErrorOr<Color> IndexedColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> IndexedColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
VERIFY(arguments.size() == 1); VERIFY(arguments.size() == 1);
@ -705,7 +705,7 @@ PDFErrorOr<Color> IndexedColorSpace::color(ReadonlySpan<Value> arguments) const
for (size_t i = 0; i < n; ++i) for (size_t i = 0; i < n; ++i)
TRY(components.try_append(Value(m_lookup[index * n + i] / 255.0f))); TRY(components.try_append(Value(m_lookup[index * n + i] / 255.0f)));
return m_base->color(components); return m_base->style(components);
} }
Vector<float> IndexedColorSpace::default_decode() const Vector<float> IndexedColorSpace::default_decode() const
@ -748,7 +748,7 @@ SeparationColorSpace::SeparationColorSpace(NonnullRefPtr<ColorSpace> alternate_s
{ {
} }
PDFErrorOr<Color> SeparationColorSpace::color(ReadonlySpan<Value> arguments) const PDFErrorOr<ColorOrStyle> SeparationColorSpace::style(ReadonlySpan<Value> arguments) const
{ {
// "For an additive device such as a computer display, a Separation color space never applies a process colorant directly; // "For an additive device such as a computer display, a Separation color space never applies a process colorant directly;
// it always reverts to the alternate color space as described below." // it always reverts to the alternate color space as described below."
@ -765,12 +765,11 @@ PDFErrorOr<Color> SeparationColorSpace::color(ReadonlySpan<Value> arguments) con
for (size_t i = 0; i < tint_output.size(); ++i) for (size_t i = 0; i < tint_output.size(); ++i)
m_tint_output_values[i] = tint_output[i]; m_tint_output_values[i] = tint_output[i];
return m_alternate_space->color(m_tint_output_values); return m_alternate_space->style(m_tint_output_values);
} }
Vector<float> SeparationColorSpace::default_decode() const Vector<float> SeparationColorSpace::default_decode() const
{ {
return { 0.0f, 1.0f }; return { 0.0f, 1.0f };
} }
} }

View file

@ -10,6 +10,7 @@
#include <AK/Forward.h> #include <AK/Forward.h>
#include <LibGfx/Color.h> #include <LibGfx/Color.h>
#include <LibGfx/ICC/Profile.h> #include <LibGfx/ICC/Profile.h>
#include <LibGfx/PaintStyle.h>
#include <LibPDF/Function.h> #include <LibPDF/Function.h>
#include <LibPDF/Value.h> #include <LibPDF/Value.h>
@ -28,6 +29,9 @@
namespace PDF { namespace PDF {
typedef Variant<Gfx::Color, NonnullRefPtr<Gfx::PaintStyle>> ColorOrStyle;
class Renderer;
class ColorSpaceFamily { class ColorSpaceFamily {
public: public:
ColorSpaceFamily(DeprecatedFlyString name, bool may_be_specified_directly) ColorSpaceFamily(DeprecatedFlyString name, bool may_be_specified_directly)
@ -62,7 +66,7 @@ public:
virtual ~ColorSpace() = default; 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 int number_of_components() const = 0;
virtual Vector<float> default_decode() const = 0; // "TABLE 4.40 Default Decode arrays" virtual Vector<float> default_decode() const = 0; // "TABLE 4.40 Default Decode arrays"
virtual ColorSpaceFamily const& family() const = 0; virtual ColorSpaceFamily const& family() const = 0;
@ -74,7 +78,7 @@ public:
~DeviceGrayColorSpace() override = default; ~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; } int number_of_components() const override { return 1; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceGray; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceGray; }
@ -89,7 +93,7 @@ public:
~DeviceRGBColorSpace() override = default; ~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; } int number_of_components() const override { return 3; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceRGB; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceRGB; }
@ -104,7 +108,7 @@ public:
~DeviceCMYKColorSpace() override = default; ~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; } int number_of_components() const override { return 4; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceCMYK; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceCMYK; }
@ -119,7 +123,7 @@ public:
~DeviceNColorSpace() override = default; ~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; int number_of_components() const override;
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceN; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::DeviceN; }
@ -140,7 +144,7 @@ public:
~CalGrayColorSpace() override = default; ~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; } int number_of_components() const override { return 1; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalGray; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalGray; }
@ -159,7 +163,7 @@ public:
~CalRGBColorSpace() override = default; ~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; } int number_of_components() const override { return 3; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalRGB; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::CalRGB; }
@ -179,7 +183,7 @@ public:
~ICCBasedColorSpace() override = default; ~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; int number_of_components() const override;
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::ICCBased; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::ICCBased; }
@ -197,7 +201,7 @@ public:
~LabColorSpace() override = default; ~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; } int number_of_components() const override { return 3; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Lab; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Lab; }
@ -216,7 +220,7 @@ public:
~IndexedColorSpace() override = default; ~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; } int number_of_components() const override { return 1; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Indexed; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Indexed; }
@ -235,7 +239,7 @@ public:
~SeparationColorSpace() override = default; ~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; } int number_of_components() const override { return 1; }
Vector<float> default_decode() const override; Vector<float> default_decode() const override;
ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Separation; } ColorSpaceFamily const& family() const override { return ColorSpaceFamily::Separation; }
@ -248,5 +252,4 @@ private:
NonnullRefPtr<Function> m_tint_transform; NonnullRefPtr<Function> m_tint_transform;
Vector<Value> mutable m_tint_output_values; Vector<Value> mutable m_tint_output_values;
}; };
} }

View file

@ -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); 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 // Account for the reversed font baseline
auto position = point.translated(0, -m_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 {}; return {};
} }

View file

@ -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) 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) { if (!m_font_program) {
// Account for the reversed font baseline // Account for the reversed font baseline
auto position = point.translated(0, -m_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 {}; return {};
} }
@ -97,9 +104,18 @@ PDFErrorOr<void> Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint po
m_glyph_cache.set(index, bitmap); m_glyph_cache.set(index, bitmap);
} }
painter.blit_filtered(glyph_position.blit_position, *bitmap, bitmap->rect(), [color](Color pixel) -> Color { if (style.has<Color>()) {
return pixel.multiply(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 {}; return {};
} }
} }

View file

@ -311,7 +311,11 @@ void Renderer::end_path_paint()
RENDERER_HANDLER(path_stroke) RENDERER_HANDLER(path_stroke)
{ {
begin_path_paint(); begin_path_paint();
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width); if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
} else {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
}
end_path_paint(); end_path_paint();
return {}; return {};
} }
@ -327,7 +331,11 @@ RENDERER_HANDLER(path_fill_nonzero)
{ {
begin_path_paint(); begin_path_paint();
m_current_path.close_all_subpaths(); m_current_path.close_all_subpaths();
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::Nonzero); if (state().paint_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), 1.0, Gfx::Painter::WindingRule::Nonzero);
} else {
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<Color>(), Gfx::Painter::WindingRule::Nonzero);
}
end_path_paint(); end_path_paint();
return {}; return {};
} }
@ -341,20 +349,32 @@ RENDERER_HANDLER(path_fill_evenodd)
{ {
begin_path_paint(); begin_path_paint();
m_current_path.close_all_subpaths(); m_current_path.close_all_subpaths();
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_color, Gfx::Painter::WindingRule::EvenOdd); if (state().paint_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), 1.0, Gfx::Painter::WindingRule::EvenOdd);
} else {
m_anti_aliasing_painter.fill_path(m_current_path, state().paint_style.get<Color>(), Gfx::Painter::WindingRule::EvenOdd);
}
end_path_paint(); end_path_paint();
return {}; return {};
} }
RENDERER_HANDLER(path_fill_stroke_nonzero) RENDERER_HANDLER(path_fill_stroke_nonzero)
{ {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width); if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
} else {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
}
return handle_path_fill_nonzero(args); return handle_path_fill_nonzero(args);
} }
RENDERER_HANDLER(path_fill_stroke_evenodd) RENDERER_HANDLER(path_fill_stroke_evenodd)
{ {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_color, state().ctm.x_scale() * state().line_width); if (state().stroke_style.has<NonnullRefPtr<Gfx::PaintStyle>>()) {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>(), state().ctm.x_scale() * state().line_width);
} else {
m_anti_aliasing_painter.stroke_path(m_current_path, state().stroke_style.get<Color>(), state().ctm.x_scale() * state().line_width);
}
return handle_path_fill_evenodd(args); return handle_path_fill_evenodd(args);
} }
@ -590,7 +610,7 @@ RENDERER_HANDLER(set_painting_space)
RENDERER_HANDLER(set_stroking_color) RENDERER_HANDLER(set_stroking_color)
{ {
state().stroke_color = TRY(state().stroke_color_space->color(args)); state().stroke_style = TRY(state().stroke_color_space->style(args));
return {}; return {};
} }
@ -603,13 +623,13 @@ RENDERER_HANDLER(set_stroking_color_extended)
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented"); return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
} }
state().stroke_color = TRY(state().stroke_color_space->color(args)); state().stroke_style = TRY(state().stroke_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_painting_color) RENDERER_HANDLER(set_painting_color)
{ {
state().paint_color = TRY(state().paint_color_space->color(args)); state().paint_style = TRY(state().paint_color_space->style(args));
return {}; return {};
} }
@ -622,49 +642,49 @@ RENDERER_HANDLER(set_painting_color_extended)
return Error::rendering_unsupported_error("Pattern color spaces not yet implemented"); return Error::rendering_unsupported_error("Pattern color spaces not yet implemented");
} }
state().paint_color = TRY(state().paint_color_space->color(args)); state().paint_style = TRY(state().paint_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_stroking_color_and_space_to_gray) RENDERER_HANDLER(set_stroking_color_and_space_to_gray)
{ {
state().stroke_color_space = DeviceGrayColorSpace::the(); state().stroke_color_space = DeviceGrayColorSpace::the();
state().stroke_color = TRY(state().stroke_color_space->color(args)); state().stroke_style = TRY(state().stroke_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_gray) RENDERER_HANDLER(set_painting_color_and_space_to_gray)
{ {
state().paint_color_space = DeviceGrayColorSpace::the(); state().paint_color_space = DeviceGrayColorSpace::the();
state().paint_color = TRY(state().paint_color_space->color(args)); state().paint_style = TRY(state().paint_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_stroking_color_and_space_to_rgb) RENDERER_HANDLER(set_stroking_color_and_space_to_rgb)
{ {
state().stroke_color_space = DeviceRGBColorSpace::the(); state().stroke_color_space = DeviceRGBColorSpace::the();
state().stroke_color = TRY(state().stroke_color_space->color(args)); state().stroke_style = TRY(state().stroke_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_rgb) RENDERER_HANDLER(set_painting_color_and_space_to_rgb)
{ {
state().paint_color_space = DeviceRGBColorSpace::the(); state().paint_color_space = DeviceRGBColorSpace::the();
state().paint_color = TRY(state().paint_color_space->color(args)); state().paint_style = TRY(state().paint_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk) RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk)
{ {
state().stroke_color_space = DeviceCMYKColorSpace::the(); state().stroke_color_space = DeviceCMYKColorSpace::the();
state().stroke_color = TRY(state().stroke_color_space->color(args)); state().stroke_style = TRY(state().stroke_color_space->style(args));
return {}; return {};
} }
RENDERER_HANDLER(set_painting_color_and_space_to_cmyk) RENDERER_HANDLER(set_painting_color_and_space_to_cmyk)
{ {
state().paint_color_space = DeviceCMYKColorSpace::the(); state().paint_color_space = DeviceCMYKColorSpace::the();
state().paint_color = TRY(state().paint_color_space->color(args)); state().paint_style = TRY(state().paint_color_space->style(args));
return {}; return {};
} }
@ -956,8 +976,16 @@ PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<Stream
sample = sample.slice(bytes_per_component); sample = sample.slice(bytes_per_component);
component_values[i] = Value { component_value_decoders[i].interpolate(component[0]) }; component_values[i] = Value { component_value_decoders[i].interpolate(component[0]) };
} }
auto color = TRY(color_space->color(component_values)); auto color = TRY(color_space->style(component_values));
bitmap->set_pixel(x, y, color); if (color.has<Color>()) {
auto c = color.get<Color>();
bitmap->set_pixel(x, y, c);
} else {
auto paint_style = color.get<NonnullRefPtr<Gfx::PaintStyle>>();
paint_style->paint(bitmap->rect(), [&](auto sample) {
bitmap->set_pixel(x, y, sample(Gfx::IntPoint(x, y)));
});
}
++x; ++x;
if (x == width) { if (x == width) {
x = 0; x = 0;

View file

@ -74,8 +74,8 @@ struct GraphicsState {
ClippingPaths clipping_paths; ClippingPaths clipping_paths;
RefPtr<ColorSpace> stroke_color_space { DeviceGrayColorSpace::the() }; RefPtr<ColorSpace> stroke_color_space { DeviceGrayColorSpace::the() };
RefPtr<ColorSpace> paint_color_space { DeviceGrayColorSpace::the() }; RefPtr<ColorSpace> paint_color_space { DeviceGrayColorSpace::the() };
Gfx::Color stroke_color { Gfx::Color::NamedColor::Black }; ColorOrStyle stroke_style { Color::Black };
Gfx::Color paint_color { Gfx::Color::NamedColor::Black }; ColorOrStyle paint_style { Color::Black };
DeprecatedString color_rendering_intent { "RelativeColorimetric"sv }; DeprecatedString color_rendering_intent { "RelativeColorimetric"sv };
float flatness_tolerance { 0.0f }; float flatness_tolerance { 0.0f };
float line_width { 1.0f }; float line_width { 1.0f };
@ -286,8 +286,16 @@ struct Formatter<PDF::GraphicsState> : Formatter<StringView> {
StringBuilder builder; StringBuilder builder;
builder.append("GraphicsState {\n"sv); builder.append("GraphicsState {\n"sv);
builder.appendff(" ctm={}\n", state.ctm); builder.appendff(" ctm={}\n", state.ctm);
builder.appendff(" stroke_color={}\n", state.stroke_color); if (state.stroke_style.has<Color>()) {
builder.appendff(" paint_color={}\n", state.paint_color); builder.appendff(" stroke_style={}\n", state.stroke_style.get<Color>());
} else {
builder.appendff(" stroke_style={}\n", state.stroke_style.get<NonnullRefPtr<Gfx::PaintStyle>>());
}
if (state.paint_style.has<Color>()) {
builder.appendff(" paint_style={}\n", state.paint_style.get<Color>());
} else {
builder.appendff(" paint_style={}\n", state.paint_style.get<NonnullRefPtr<Gfx::PaintStyle>>());
}
builder.appendff(" color_rendering_intent={}\n", state.color_rendering_intent); builder.appendff(" color_rendering_intent={}\n", state.color_rendering_intent);
builder.appendff(" flatness_tolerance={}\n", state.flatness_tolerance); builder.appendff(" flatness_tolerance={}\n", state.flatness_tolerance);
builder.appendff(" line_width={}\n", state.line_width); builder.appendff(" line_width={}\n", state.line_width);