diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2021-05-23 12:53:38 -0700 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-05-25 00:24:09 +0430 |
commit | 534a2e95d2a0d8cb9d3a4ba1644089b9ea8221ca (patch) | |
tree | 649370ca3e820738ba7f35e6db536eeea8c89d3a /Userland/Libraries/LibPDF | |
parent | f4941f5940823f3bafa78deb732c37611ab62db0 (diff) | |
download | serenity-534a2e95d2a0d8cb9d3a4ba1644089b9ea8221ca.zip |
LibPDF: Add basic color space support to the renderer
This commit only supports the three most basic color spaces:
DeviceGray, DeviceRGB, and DeviceCMYK
Diffstat (limited to 'Userland/Libraries/LibPDF')
-rw-r--r-- | Userland/Libraries/LibPDF/Command.h | 24 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Renderer.cpp | 145 | ||||
-rw-r--r-- | Userland/Libraries/LibPDF/Renderer.h | 32 |
3 files changed, 177 insertions, 24 deletions
diff --git a/Userland/Libraries/LibPDF/Command.h b/Userland/Libraries/LibPDF/Command.h index c1ba23c8fa..539cba6d8b 100644 --- a/Userland/Libraries/LibPDF/Command.h +++ b/Userland/Libraries/LibPDF/Command.h @@ -59,18 +59,18 @@ V(TextShowStringArray, text_show_string_array, TJ) \ V(Type3FontSetGlyphWidth, type3_font_set_glyph_width, d0) \ V(Type3FontSetGlyphWidthAndBBox, type3_font_set_glyph_width_and_bbox, d1) \ - V(ColorSetStrokingSpace, color_set_stroking_space, CS) \ - V(ColorSetPaintingSpace, color_set_painting_space, cs) \ - V(ColorSetStroking, color_set_stroking, SC) \ - V(ColorSetStrokingExtended, color_set_stroking_extended, SCN) \ - V(ColorSetPainting, color_set_painting, sc) \ - V(ColorSetPaintingExtended, color_set_painting_extended, scn) \ - V(ColorSetStrokingSpaceToGray, color_set_stroking_space_to_gray, G) \ - V(ColorSetPaintingSpaceToGray, color_set_painting_space_to_gray, g) \ - V(ColorSetStrokingSpaceToRGB, color_set_stroking_space_to_rgb, RG) \ - V(ColorSetPaintingSpaceToRGB, color_set_painting_space_to_rgb, rg) \ - V(ColorSetStrokingSpaceToCMYK, color_set_stroking_space_to_cmyk, K) \ - V(ColorSetPaintingSpaceToCMYK, color_set_painting_space_to_cmyk, k) \ + V(SetStrokingSpace, set_stroking_space, CS) \ + V(SetPaintingSpace, set_painting_space, cs) \ + V(SetStrokingColor, set_stroking_color, SC) \ + V(SetStrokingColorExtended, set_stroking_color_extended, SCN) \ + V(SetPaintingColor, set_painting_color, sc) \ + V(SetPaintingColorExtended, set_painting_color_extended, scn) \ + V(SetStrokingColorAndSpaceToGray, set_stroking_color_and_space_to_gray, G) \ + V(SetPaintingColorAndSpaceToGray, set_painting_color_and_space_to_gray, g) \ + V(SetStrokingColorAndSpaceToRGB, set_stroking_color_and_space_to_rgb, RG) \ + V(SetPaintingColorAndSpaceToRGB, set_painting_color_and_space_to_rgb, rg) \ + V(SetStrokingColorAndSpaceToCMYK, set_stroking_color_and_space_to_cmyk, K) \ + V(SetPaintingColorAndSpaceToCMYK, set_painting_color_and_space_to_cmyk, k) \ V(Shade, shade, sh) \ V(InlineImageBegin, inline_image_begin, BI) \ V(InlineImageBeginData, inline_image_begin_data, ID) \ diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index 443a44c630..8b46f9dfa2 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -21,6 +21,58 @@ namespace PDF { +Optional<ColorSpace::Type> ColorSpace::color_space_from_string(const StringView& str) +{ +#define ENUM(name) \ + if (str == #name) \ + return ColorSpace::Type::name; + ENUMERATE_COLOR_SPACES(ENUM) +#undef ENUM + + return {}; +} + +Color ColorSpace::default_color_for_color_space(ColorSpace::Type color_space) +{ + switch (color_space) { + case Type::DeviceGray: + case Type::DeviceRGB: + return Color::NamedColor::Black; + case Type::DeviceCMYK: + return Color::from_cmyk(1.0f, 1.0f, 1.0f, 0.0f); + default: + TODO(); + } +} + +Color ColorSpace::color_from_parameters(ColorSpace::Type color_space, const Vector<Value>& args) +{ + switch (color_space) { + case Type::DeviceGray: { + VERIFY(args.size() == 1); + auto gray = static_cast<u8>(args[0].to_float() * 255.0f); + return Color(gray, gray, gray); + } + case Type::DeviceRGB: { + VERIFY(args.size() == 3); + auto r = static_cast<u8>(args[0].to_float() * 255.0f); + auto g = static_cast<u8>(args[1].to_float() * 255.0f); + auto b = static_cast<u8>(args[2].to_float() * 255.0f); + return Color(r, g, b); + } + case Type::DeviceCMYK: { + VERIFY(args.size() == 4); + auto c = args[0].to_float(); + auto m = args[1].to_float(); + auto y = args[2].to_float(); + auto k = args[3].to_float(); + return Color::from_cmyk(c, m, y, k); + } + default: + TODO(); + } +} + void Renderer::render(Document& document, const Page& page, RefPtr<Gfx::Bitmap> bitmap) { Renderer(document, page, bitmap).render(); @@ -381,18 +433,69 @@ RENDERER_TODO(text_next_line_show_string_set_spacing); RENDERER_TODO(text_show_string_array); RENDERER_TODO(type3_font_set_glyph_width); RENDERER_TODO(type3_font_set_glyph_width_and_bbox); -RENDERER_TODO(color_set_stroking_space); -RENDERER_TODO(color_set_painting_space); -RENDERER_TODO(color_set_stroking); -RENDERER_TODO(color_set_stroking_extended); -RENDERER_TODO(color_set_painting); -RENDERER_TODO(color_set_painting_extended); -RENDERER_TODO(color_set_stroking_space_to_gray); -RENDERER_TODO(color_set_painting_space_to_gray); -RENDERER_TODO(color_set_stroking_space_to_rgb); -RENDERER_TODO(color_set_painting_space_to_rgb); -RENDERER_TODO(color_set_stroking_space_to_cmyk); -RENDERER_TODO(color_set_painting_space_to_cmyk); + +RENDERER_HANDLER(set_stroking_space) +{ + state().stroke_color_space = get_color_space(args[0]); + state().stroke_color = ColorSpace::default_color_for_color_space(state().stroke_color_space); +} + +RENDERER_HANDLER(set_painting_space) +{ + state().paint_color_space = get_color_space(args[0]); + state().paint_color = ColorSpace::default_color_for_color_space(state().paint_color_space); +} + +RENDERER_HANDLER(set_stroking_color) +{ + state().stroke_color = ColorSpace::color_from_parameters(state().stroke_color_space, args); +} + +RENDERER_TODO(set_stroking_color_extended); + +RENDERER_HANDLER(set_painting_color) +{ + state().paint_color = ColorSpace::color_from_parameters(state().paint_color_space, args); +} + +RENDERER_TODO(set_painting_color_extended); + +RENDERER_HANDLER(set_stroking_color_and_space_to_gray) +{ + state().stroke_color_space = ColorSpace::Type::DeviceGray; + state().stroke_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceGray, args); +} + +RENDERER_HANDLER(set_painting_color_and_space_to_gray) +{ + state().paint_color_space = ColorSpace::Type::DeviceGray; + state().paint_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceGray, args); +} + +RENDERER_HANDLER(set_stroking_color_and_space_to_rgb) +{ + state().stroke_color_space = ColorSpace::Type::DeviceRGB; + state().stroke_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceRGB, args); +} + +RENDERER_HANDLER(set_painting_color_and_space_to_rgb) +{ + state().paint_color_space = ColorSpace::Type::DeviceRGB; + state().paint_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceRGB, args); +} + +RENDERER_HANDLER(set_stroking_color_and_space_to_cmyk) +{ + state().stroke_color_space = ColorSpace::Type::DeviceCMYK; + state().stroke_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceCMYK, args); +} + +RENDERER_HANDLER(set_painting_color_and_space_to_cmyk) +{ + state().paint_color_space = ColorSpace::Type::DeviceCMYK; + state().paint_color = ColorSpace::color_from_parameters(ColorSpace::Type::DeviceCMYK, args); +} + RENDERER_TODO(shade); RENDERER_TODO(inline_image_begin); RENDERER_TODO(inline_image_begin_data); @@ -419,6 +522,12 @@ Gfx::Size<T> Renderer::map(Gfx::Size<T> size) const return state().ctm.map(size); } +template<typename T> +Gfx::Rect<T> Renderer::map(Gfx::Rect<T> rect) const +{ + return state().ctm.map(rect); +} + void Renderer::show_text(const String& string, int shift) { auto utf = Utf8View(string); @@ -449,6 +558,18 @@ void Renderer::show_text(const String& string, int shift) } } +ColorSpace::Type Renderer::get_color_space(const Value& value) +{ + auto name = object_cast<NameObject>(value.as_object())->name(); + auto color_space_opt = ColorSpace::color_space_from_string(name); + if (!color_space_opt.has_value()) { + // The name is probably a key into the resource dictionary + TODO(); + } + + return color_space_opt.value(); +} + const Gfx::AffineTransform& Renderer::calculate_text_rendering_matrix() { if (m_text_rendering_matrix_is_dirty) { diff --git a/Userland/Libraries/LibPDF/Renderer.h b/Userland/Libraries/LibPDF/Renderer.h index a71f708032..46427753c4 100644 --- a/Userland/Libraries/LibPDF/Renderer.h +++ b/Userland/Libraries/LibPDF/Renderer.h @@ -19,6 +19,19 @@ #include <LibPDF/Document.h> #include <LibPDF/Object.h> +#define ENUMERATE_COLOR_SPACES(V) \ + V(DeviceGray) \ + V(DeviceRGB) \ + V(DeviceCMYK) \ + V(CalGray) \ + V(CalRGB) \ + V(Lab) \ + V(ICCBased) \ + V(Indexed) \ + V(Pattern) \ + V(Separation) \ + V(DeviceN) + namespace PDF { enum class LineCapStyle : u8 { @@ -60,8 +73,23 @@ struct TextState { bool knockout { true }; }; +class ColorSpace { +public: + enum class Type { +#define ENUM(name) name, + ENUMERATE_COLOR_SPACES(ENUM) +#undef ENUM + }; + + static Optional<ColorSpace::Type> color_space_from_string(const StringView&); + static Color default_color_for_color_space(ColorSpace::Type); + static Color color_from_parameters(ColorSpace::Type color_space, const Vector<Value>& args); +}; + struct GraphicsState { Gfx::AffineTransform ctm; + ColorSpace::Type stroke_color_space { ColorSpace::Type::DeviceGray }; + ColorSpace::Type paint_color_space { ColorSpace::Type::DeviceGray }; Gfx::Color stroke_color { Gfx::Color::NamedColor::Black }; Gfx::Color paint_color { Gfx::Color::NamedColor::Black }; float line_width { 1.0f }; @@ -91,6 +119,7 @@ private: // shift is the manual advance given in the TJ command array void show_text(const String&, int shift = 0); + ColorSpace::Type get_color_space(const Value&); ALWAYS_INLINE const GraphicsState& state() const { return m_graphics_state_stack.last(); } ALWAYS_INLINE GraphicsState& state() { return m_graphics_state_stack.last(); } @@ -103,6 +132,9 @@ private: template<typename T> ALWAYS_INLINE Gfx::Size<T> map(Gfx::Size<T>) const; + template<typename T> + ALWAYS_INLINE Gfx::Rect<T> map(Gfx::Rect<T>) const; + const Gfx::AffineTransform& calculate_text_rendering_matrix(); RefPtr<Document> m_document; |