summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibPDF
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2021-05-27 14:01:37 -0700
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-06-12 22:45:01 +0430
commit7b4e36bf88ae1498287c262c910874e9ad9c5cbf (patch)
tree0bab3957e91c387f928a9c7efcef57daca22fbd8 /Userland/Libraries/LibPDF
parentea3abb14fe2eff0ef5d319c2d83358fbb233e4f5 (diff)
downloadserenity-7b4e36bf88ae1498287c262c910874e9ad9c5cbf.zip
LibPDF: Split ColorSpace into a different class for each color space
While unnecessary at the moment, this will allow for more fine-grained control when complex color spaces get added.
Diffstat (limited to 'Userland/Libraries/LibPDF')
-rw-r--r--Userland/Libraries/LibPDF/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibPDF/ColorSpace.cpp56
-rw-r--r--Userland/Libraries/LibPDF/ColorSpace.h72
-rw-r--r--Userland/Libraries/LibPDF/CommonNames.h10
-rw-r--r--Userland/Libraries/LibPDF/Document.cpp5
-rw-r--r--Userland/Libraries/LibPDF/Renderer.cpp103
-rw-r--r--Userland/Libraries/LibPDF/Renderer.h33
7 files changed, 174 insertions, 106 deletions
diff --git a/Userland/Libraries/LibPDF/CMakeLists.txt b/Userland/Libraries/LibPDF/CMakeLists.txt
index ea1cbce233..c3a959e4b2 100644
--- a/Userland/Libraries/LibPDF/CMakeLists.txt
+++ b/Userland/Libraries/LibPDF/CMakeLists.txt
@@ -1,4 +1,5 @@
set(SOURCES
+ ColorSpace.cpp
CommonNames.cpp
Document.cpp
Filter.cpp
diff --git a/Userland/Libraries/LibPDF/ColorSpace.cpp b/Userland/Libraries/LibPDF/ColorSpace.cpp
new file mode 100644
index 0000000000..1651c3fff8
--- /dev/null
+++ b/Userland/Libraries/LibPDF/ColorSpace.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibPDF/ColorSpace.h>
+#include <LibPDF/CommonNames.h>
+
+namespace PDF {
+
+RefPtr<DeviceGrayColorSpace> DeviceGrayColorSpace::the()
+{
+ static auto instance = adopt_ref(*new DeviceGrayColorSpace());
+ return instance;
+}
+
+Color DeviceGrayColorSpace::color(const Vector<Value>& arguments) const
+{
+ VERIFY(arguments.size() == 1);
+ auto gray = static_cast<u8>(arguments[0].to_float() * 255.0f);
+ return Color(gray, gray, gray);
+}
+
+RefPtr<DeviceRGBColorSpace> DeviceRGBColorSpace::the()
+{
+ static auto instance = adopt_ref(*new DeviceRGBColorSpace());
+ return instance;
+}
+
+Color DeviceRGBColorSpace::color(const Vector<Value>& arguments) const
+{
+ VERIFY(arguments.size() == 3);
+ auto r = static_cast<u8>(arguments[0].to_float() * 255.0f);
+ auto g = static_cast<u8>(arguments[1].to_float() * 255.0f);
+ auto b = static_cast<u8>(arguments[2].to_float() * 255.0f);
+ return Color(r, g, b);
+}
+
+RefPtr<DeviceCMYKColorSpace> DeviceCMYKColorSpace::the()
+{
+ static auto instance = adopt_ref(*new DeviceCMYKColorSpace());
+ return instance;
+}
+
+Color DeviceCMYKColorSpace::color(const Vector<Value>& arguments) const
+{
+ VERIFY(arguments.size() == 4);
+ auto c = arguments[0].to_float();
+ auto m = arguments[1].to_float();
+ auto y = arguments[2].to_float();
+ auto k = arguments[3].to_float();
+ return Color::from_cmyk(c, m, y, k);
+}
+
+}
diff --git a/Userland/Libraries/LibPDF/ColorSpace.h b/Userland/Libraries/LibPDF/ColorSpace.h
new file mode 100644
index 0000000000..cea624a6ac
--- /dev/null
+++ b/Userland/Libraries/LibPDF/ColorSpace.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/FlyString.h>
+#include <LibGfx/Color.h>
+#include <LibPDF/Object.h>
+#include <LibPDF/Value.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 {
+
+class ColorSpace : public RefCounted<ColorSpace> {
+public:
+ virtual ~ColorSpace() = default;
+
+ virtual Color color(const Vector<Value>& arguments) const = 0;
+};
+
+class DeviceGrayColorSpace final : public ColorSpace {
+public:
+ static RefPtr<DeviceGrayColorSpace> the();
+
+ virtual ~DeviceGrayColorSpace() override = default;
+
+ virtual Color color(const Vector<Value>& arguments) const override;
+
+private:
+ DeviceGrayColorSpace() = default;
+};
+
+class DeviceRGBColorSpace final : public ColorSpace {
+public:
+ static RefPtr<DeviceRGBColorSpace> the();
+
+ virtual ~DeviceRGBColorSpace() override = default;
+
+ virtual Color color(const Vector<Value>& arguments) const override;
+
+private:
+ DeviceRGBColorSpace() = default;
+};
+
+class DeviceCMYKColorSpace final : public ColorSpace {
+public:
+ static RefPtr<DeviceCMYKColorSpace> the();
+
+ virtual ~DeviceCMYKColorSpace() override = default;
+
+ virtual Color color(const Vector<Value>& arguments) const override;
+
+private:
+ DeviceCMYKColorSpace() = default;
+};
+
+}
diff --git a/Userland/Libraries/LibPDF/CommonNames.h b/Userland/Libraries/LibPDF/CommonNames.h
index fe4010dc7e..b300c81396 100644
--- a/Userland/Libraries/LibPDF/CommonNames.h
+++ b/Userland/Libraries/LibPDF/CommonNames.h
@@ -12,14 +12,20 @@
V(ASCII85Decode) \
V(ASCIIHexDecode) \
V(BaseFont) \
+ V(BlackPoint) \
V(C) \
+ V(CalRGB) \
V(CCITTFaxDecode) \
+ V(ColorSpace) \
V(Contents) \
V(Count) \
V(CropBox) \
V(Crypt) \
V(DCTDecode) \
V(Dest) \
+ V(DeviceCMYK) \
+ V(DeviceGray) \
+ V(DeviceRGB) \
V(E) \
V(F) \
V(Filter) \
@@ -33,6 +39,7 @@
V(FitV) \
V(FlateDecode) \
V(Font) \
+ V(Gamma) \
V(H) \
V(JBIG2Decode) \
V(JPXDecode) \
@@ -42,6 +49,7 @@
V(Last) \
V(Length) \
V(Linearized) \
+ V(Matrix) \
V(MediaBox) \
V(N) \
V(Next) \
@@ -50,6 +58,7 @@
V(P) \
V(Pages) \
V(Parent) \
+ V(Pattern) \
V(Prev) \
V(Resources) \
V(Root) \
@@ -59,6 +68,7 @@
V(Title) \
V(Type) \
V(UserUnit) \
+ V(WhitePoint) \
V(XYZ)
namespace PDF {
diff --git a/Userland/Libraries/LibPDF/Document.cpp b/Userland/Libraries/LibPDF/Document.cpp
index a127a4359f..c545e781dd 100644
--- a/Userland/Libraries/LibPDF/Document.cpp
+++ b/Userland/Libraries/LibPDF/Document.cpp
@@ -89,6 +89,11 @@ Page Document::get_page(u32 index)
auto page_object_index = m_page_object_indices[index];
auto raw_page_object = resolve_to<DictObject>(get_or_load_value(page_object_index));
+ if (!raw_page_object->contains(CommonNames::Resources)) {
+ // This page inherits its resource dictionary
+ TODO();
+ }
+
auto resources = raw_page_object->get_dict(this, CommonNames::Resources);
auto contents = raw_page_object->get_object(this, CommonNames::Contents);
diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp
index a0de5c37f9..009b660d06 100644
--- a/Userland/Libraries/LibPDF/Renderer.cpp
+++ b/Userland/Libraries/LibPDF/Renderer.cpp
@@ -7,8 +7,6 @@
#include <AK/Utf8View.h>
#include <LibPDF/CommonNames.h>
#include <LibPDF/Renderer.h>
-#include <ctype.h>
-#include <math.h>
#define RENDERER_HANDLER(name) \
void Renderer::handle_##name([[maybe_unused]] const Vector<Value>& args)
@@ -22,58 +20,6 @@
namespace PDF {
-Optional<ColorSpace::Type> ColorSpace::color_space_from_string(const FlyString& 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();
@@ -438,63 +384,63 @@ RENDERER_TODO(type3_font_set_glyph_width_and_bbox);
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);
+ VERIFY(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);
+ VERIFY(state().paint_color_space);
}
RENDERER_HANDLER(set_stroking_color)
{
- state().stroke_color = ColorSpace::color_from_parameters(state().stroke_color_space, args);
+ state().stroke_color = state().stroke_color_space->color(args);
}
RENDERER_TODO(set_stroking_color_extended);
RENDERER_HANDLER(set_painting_color)
{
- state().paint_color = ColorSpace::color_from_parameters(state().paint_color_space, args);
+ state().paint_color = state().paint_color_space->color(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);
+ state().stroke_color_space = DeviceGrayColorSpace::the();
+ state().stroke_color = state().stroke_color_space->color(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);
+ state().paint_color_space = DeviceGrayColorSpace::the();
+ state().paint_color = state().paint_color_space->color(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);
+ state().stroke_color_space = DeviceRGBColorSpace::the();
+ state().stroke_color = state().stroke_color_space->color(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);
+ state().paint_color_space = DeviceRGBColorSpace::the();
+ state().paint_color = state().paint_color_space->color(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);
+ state().stroke_color_space = DeviceCMYKColorSpace::the();
+ state().stroke_color = state().stroke_color_space->color(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);
+ state().paint_color_space = DeviceCMYKColorSpace::the();
+ state().paint_color = state().paint_color_space->color(args);
}
RENDERER_TODO(shade);
@@ -560,16 +506,19 @@ void Renderer::show_text(const String& string, int shift)
}
}
-ColorSpace::Type Renderer::get_color_space(const Value& value)
+RefPtr<ColorSpace> 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();
+ // Simple color spaces with no parameters, which can be specified directly
+ if (name == CommonNames::DeviceGray)
+ return DeviceGrayColorSpace::the();
+ if (name == CommonNames::DeviceRGB)
+ return DeviceRGBColorSpace::the();
+ if (name == CommonNames::DeviceCMYK)
+ return DeviceCMYKColorSpace::the();
+
+ TODO();
}
const Gfx::AffineTransform& Renderer::calculate_text_rendering_matrix()
diff --git a/Userland/Libraries/LibPDF/Renderer.h b/Userland/Libraries/LibPDF/Renderer.h
index 5709d1c564..36bd103d7a 100644
--- a/Userland/Libraries/LibPDF/Renderer.h
+++ b/Userland/Libraries/LibPDF/Renderer.h
@@ -16,22 +16,10 @@
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
#include <LibGfx/Size.h>
+#include <LibPDF/ColorSpace.h>
#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 {
@@ -73,23 +61,10 @@ 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 FlyString&);
- 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 };
+ RefPtr<ColorSpace> stroke_color_space { DeviceGrayColorSpace::the() };
+ RefPtr<ColorSpace> paint_color_space { DeviceGrayColorSpace::the() };
Gfx::Color stroke_color { Gfx::Color::NamedColor::Black };
Gfx::Color paint_color { Gfx::Color::NamedColor::Black };
float line_width { 1.0f };
@@ -119,7 +94,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&);
+ RefPtr<ColorSpace> 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(); }