mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +00:00
LibPDF: Add basic color space support to the renderer
This commit only supports the three most basic color spaces: DeviceGray, DeviceRGB, and DeviceCMYK
This commit is contained in:
parent
f4941f5940
commit
534a2e95d2
Notes:
sideshowbarker
2024-07-18 17:26:25 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/534a2e95d2a Pull-request: https://github.com/SerenityOS/serenity/pull/7436 Reviewed-by: https://github.com/alimpfard
3 changed files with 177 additions and 24 deletions
|
@ -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) \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue