summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibPDF
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2021-05-23 12:53:38 -0700
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-05-25 00:24:09 +0430
commit534a2e95d2a0d8cb9d3a4ba1644089b9ea8221ca (patch)
tree649370ca3e820738ba7f35e6db536eeea8c89d3a /Userland/Libraries/LibPDF
parentf4941f5940823f3bafa78deb732c37611ab62db0 (diff)
downloadserenity-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.h24
-rw-r--r--Userland/Libraries/LibPDF/Renderer.cpp145
-rw-r--r--Userland/Libraries/LibPDF/Renderer.h32
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;