You've already forked libart-paperback
Hello libart-paperback
This commit is contained in:
462
art/paperback/graphics/canvas.cxx
Normal file
462
art/paperback/graphics/canvas.cxx
Normal file
@@ -0,0 +1,462 @@
|
||||
#include <art/paperback/graphics/canvas.hxx>
|
||||
#include <art/paperback/graphics/font.hxx>
|
||||
|
||||
#include <art/paperback/except.hxx>
|
||||
#include <art/paperback/page.hxx>
|
||||
|
||||
#include <art/paperback/carousel/name.hxx>
|
||||
#include <art/paperback/carousel/object.hxx>
|
||||
#include <art/paperback/carousel/stream.hxx>
|
||||
|
||||
#include <art/paperback/internals/cp1252.hxx>
|
||||
#include <art/paperback/internals/graphics-state.hxx>
|
||||
#include <art/paperback/internals/resource-collection.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
/// Holds internal canvas data.
|
||||
///
|
||||
struct Canvas::Internal
|
||||
{
|
||||
Internal(Page& page)
|
||||
: page{page},
|
||||
contents{page.contents()}
|
||||
{
|
||||
gstates.push(Internals::Graphics_state{});
|
||||
}
|
||||
|
||||
/// Write single byte to content stream.
|
||||
///
|
||||
void
|
||||
write(char c)
|
||||
{
|
||||
contents->write(&c, 1);
|
||||
}
|
||||
|
||||
/// Write string to content stream.
|
||||
///
|
||||
void
|
||||
write(string const& str)
|
||||
{
|
||||
contents->write(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
/// Write real value to stream.
|
||||
///
|
||||
void
|
||||
write(double v)
|
||||
{
|
||||
stringstream str;
|
||||
str.imbue(std::locale::classic());
|
||||
str << std::fixed << v;
|
||||
write(str.str());
|
||||
}
|
||||
|
||||
/// Write integer value to stream.
|
||||
///
|
||||
void
|
||||
write(long long int v)
|
||||
{
|
||||
stringstream str;
|
||||
str.imbue(std::locale::classic());
|
||||
str << v;
|
||||
write(str.str());
|
||||
}
|
||||
|
||||
/// Write name to content stream.
|
||||
///
|
||||
void
|
||||
write_name(string const& n)
|
||||
{
|
||||
write('/');
|
||||
write(n);
|
||||
}
|
||||
|
||||
/// Write encoded text string to content stream.
|
||||
///
|
||||
/// The text is hexadecimally coded.
|
||||
///
|
||||
void
|
||||
write_encode_text(string const& text)
|
||||
{
|
||||
auto to_hex = [](char c) -> char
|
||||
{
|
||||
return (c < 10) ? ('0' + c) : ('a' + (c - 10));
|
||||
};
|
||||
|
||||
auto encoded = Internals::cp1252::from_utf8(text);
|
||||
|
||||
write('<');
|
||||
for (auto const& j : encoded) {
|
||||
char high = (j & 0xF0) >> 4;
|
||||
char low = (j & 0x0F);
|
||||
|
||||
write(to_hex(high));
|
||||
write(to_hex(low));
|
||||
}
|
||||
write('>');
|
||||
}
|
||||
|
||||
/// Reference to parent page.
|
||||
///
|
||||
Page& page;
|
||||
|
||||
/// Canvas content stream.
|
||||
///
|
||||
Carousel::Stream& contents;
|
||||
|
||||
/// Holds the graphics states.
|
||||
///
|
||||
stack<Internals::Graphics_state> gstates;
|
||||
|
||||
};
|
||||
|
||||
/// \param page The parent page of this canvas.
|
||||
///
|
||||
Canvas::
|
||||
Canvas(Clear const&, Page& page)
|
||||
: internal{new Internal{page}}
|
||||
{
|
||||
content().clear();
|
||||
}
|
||||
|
||||
Canvas::
|
||||
~Canvas()
|
||||
{}
|
||||
|
||||
Page&
|
||||
Canvas::
|
||||
page()
|
||||
{
|
||||
return internal->page;
|
||||
}
|
||||
|
||||
Page const&
|
||||
Canvas::
|
||||
page() const
|
||||
{
|
||||
return internal->page;
|
||||
}
|
||||
|
||||
Carousel::Stream&
|
||||
Canvas::
|
||||
content()
|
||||
{
|
||||
return internal->contents;
|
||||
}
|
||||
|
||||
Carousel::Stream const&
|
||||
Canvas::
|
||||
content() const
|
||||
{
|
||||
return internal->contents;
|
||||
}
|
||||
|
||||
/// \param grey_level The new grey level.
|
||||
///
|
||||
void
|
||||
Canvas::
|
||||
set_stroke(double grey_level)
|
||||
{
|
||||
if (grey_level < 0 || 1 < grey_level) {
|
||||
throw std::out_of_range{"grey level out of range (0-1)"};
|
||||
}
|
||||
|
||||
internal->write(grey_level);
|
||||
internal->write("G\r\n");
|
||||
|
||||
internal->gstates.top().cs_stroke = Color_space::device_grey;
|
||||
internal->gstates.top().grey_stroke = grey_level;
|
||||
}
|
||||
|
||||
/// \param grey_level The new grey level.
|
||||
///
|
||||
void
|
||||
Canvas::
|
||||
set_fill(double grey_level)
|
||||
{
|
||||
if (grey_level < 0 || 1 < grey_level) {
|
||||
throw std::out_of_range{"grey level out of range (0-1)"};
|
||||
}
|
||||
|
||||
internal->write(grey_level);
|
||||
internal->write(' ');
|
||||
internal->write("g\r\n");
|
||||
|
||||
internal->gstates.top().cs_fill = Color_space::device_grey;
|
||||
internal->gstates.top().grey_fill = grey_level;
|
||||
}
|
||||
|
||||
/// \param color The new RGB color.
|
||||
///
|
||||
void
|
||||
Canvas::
|
||||
set_stroke(RGB const& color)
|
||||
{
|
||||
internal->write(color.red());
|
||||
internal->write(' ');
|
||||
internal->write(color.green());
|
||||
internal->write(' ');
|
||||
internal->write(color.blue());
|
||||
internal->write(' ');
|
||||
internal->write("RG\r\n");
|
||||
|
||||
internal->gstates.top().cs_stroke = Color_space::device_rgb;
|
||||
internal->gstates.top().rgb_stroke = color;
|
||||
}
|
||||
|
||||
/// \param color The new RGB color.
|
||||
///
|
||||
void
|
||||
Canvas::
|
||||
set_fill(RGB const& color)
|
||||
{
|
||||
internal->write(color.red());
|
||||
internal->write(' ');
|
||||
internal->write(color.green());
|
||||
internal->write(' ');
|
||||
internal->write(color.blue());
|
||||
internal->write(' ');
|
||||
internal->write("rg\r\n");
|
||||
|
||||
internal->gstates.top().cs_fill = Color_space::device_rgb;
|
||||
internal->gstates.top().rgb_fill = color;
|
||||
}
|
||||
|
||||
/// \param text The text for which to compute the width.
|
||||
///
|
||||
double
|
||||
Canvas::
|
||||
get_text_width(string const& text) const
|
||||
{
|
||||
auto& gstate = internal->gstates.top();
|
||||
auto& font = *gstate.current_font;
|
||||
auto font_size = gstate.font_size;
|
||||
|
||||
auto tw = font.get_text_width(text);
|
||||
|
||||
auto width = static_cast<double>(tw.width) * font_size / 1000;
|
||||
|
||||
// FIXME: the missing functions mentioned below.
|
||||
//
|
||||
width += tw.character_count * 0; // gstate.get_text_character_spacing();
|
||||
width += tw.space_count * 0; // gstate.get_text_word_spacing();
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/// \param canvas The parent canvas.
|
||||
///
|
||||
Canvas::Save::
|
||||
Save(Canvas& canvas)
|
||||
: _canvas{canvas}
|
||||
{
|
||||
canvas.internal->gstates.push(canvas.internal->gstates.top());
|
||||
}
|
||||
|
||||
Canvas::Save::
|
||||
~Save() noexcept
|
||||
{
|
||||
canvas().internal->gstates.pop();
|
||||
}
|
||||
|
||||
Canvas&
|
||||
Canvas::Save::
|
||||
canvas()
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
Canvas const&
|
||||
Canvas::Save::
|
||||
canvas() const
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
/// \param canvas The parent canvas.
|
||||
/// \param mode The paint mode.
|
||||
///
|
||||
Canvas::Path::
|
||||
Path(Canvas& canvas, Paint_mode mode)
|
||||
: _canvas{canvas},
|
||||
_mode{mode}
|
||||
{}
|
||||
|
||||
Canvas::Path::
|
||||
~Path() noexcept
|
||||
{
|
||||
canvas().internal->write("h\r\n");
|
||||
|
||||
switch (_mode) {
|
||||
case stroke:
|
||||
canvas().internal->write("S\r\n");
|
||||
break;
|
||||
|
||||
case fill:
|
||||
canvas().internal->write("R\r\n");
|
||||
break;
|
||||
|
||||
case fill_then_stroke:
|
||||
canvas().internal->write("B\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// \return Returns a reference to the parent canvas.
|
||||
///
|
||||
Canvas&
|
||||
Canvas::Path::
|
||||
canvas()
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
/// \return Returns a reference to the parent canvas.
|
||||
///
|
||||
Canvas const&
|
||||
Canvas::Path::
|
||||
canvas() const
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::Path::
|
||||
move_to(double x, double y)
|
||||
{
|
||||
canvas().internal->write(x);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y);
|
||||
canvas().internal->write(" m\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::Path::
|
||||
line_to(double x, double y)
|
||||
{
|
||||
canvas().internal->write(x);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y);
|
||||
canvas().internal->write(" l\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::Path::
|
||||
bezier_curve_to(double x1,
|
||||
double y1,
|
||||
double x2,
|
||||
double y2,
|
||||
double x3,
|
||||
double y3)
|
||||
{
|
||||
canvas().internal->write(x1);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y1);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(x2);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y2);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(x3);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y3);
|
||||
canvas().internal->write(" c\r\n");
|
||||
}
|
||||
|
||||
/// \param canvas The parent canvas.
|
||||
///
|
||||
Canvas::Begin_text::
|
||||
Begin_text(Canvas& canvas)
|
||||
: _canvas{canvas}
|
||||
{
|
||||
canvas.internal->write("BT\r\n");
|
||||
}
|
||||
|
||||
Canvas::Begin_text::
|
||||
~Begin_text() noexcept
|
||||
{
|
||||
canvas().internal->write("ET\r\n");
|
||||
}
|
||||
|
||||
Canvas&
|
||||
Canvas::Begin_text::
|
||||
canvas()
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
Canvas const&
|
||||
Canvas::Begin_text::
|
||||
canvas() const
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::Begin_text::
|
||||
move_text_pos(double x, double y)
|
||||
{
|
||||
canvas().internal->write(x);
|
||||
canvas().internal->write(' ');
|
||||
canvas().internal->write(y);
|
||||
canvas().internal->write(" Td\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
Canvas::Begin_text::
|
||||
show_text(string const& text)
|
||||
{
|
||||
canvas().internal->write_encode_text(text);
|
||||
canvas().internal->write(" Tj\r\n");
|
||||
}
|
||||
|
||||
/// \param canvas The parent canvas.
|
||||
/// \param f The new font.
|
||||
/// \param size The font size.
|
||||
/// \throw Invalid_operation Thrown if a font is already set.
|
||||
///
|
||||
Canvas::Set_font::
|
||||
Set_font(Canvas& canvas, Font& f, double size)
|
||||
: _canvas{canvas}
|
||||
{
|
||||
if (canvas.internal->gstates.top().current_font) {
|
||||
|
||||
raise<Invalid_operation>{} << "font already set";
|
||||
}
|
||||
|
||||
auto local_name = canvas.page().resources().fonts().embed(f);
|
||||
|
||||
canvas.internal->write_name(*local_name);
|
||||
canvas.internal->write(' ');
|
||||
canvas.internal->write(size);
|
||||
canvas.internal->write(" Tf ");
|
||||
|
||||
canvas.internal->gstates.top().current_font = &f;
|
||||
canvas.internal->gstates.top().font_size = size;
|
||||
}
|
||||
|
||||
/// The current font will be resent during deconstruction.
|
||||
///
|
||||
Canvas::Set_font::
|
||||
~Set_font() noexcept
|
||||
{
|
||||
canvas().internal->gstates.top().current_font = nullptr;
|
||||
}
|
||||
|
||||
Canvas&
|
||||
Canvas::Set_font::
|
||||
canvas()
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
Canvas const&
|
||||
Canvas::Set_font::
|
||||
canvas() const
|
||||
{
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
274
art/paperback/graphics/canvas.hxx
Normal file
274
art/paperback/graphics/canvas.hxx
Normal file
@@ -0,0 +1,274 @@
|
||||
#ifndef art__paperback__graphics__canvas_hxx_
|
||||
#define art__paperback__graphics__canvas_hxx_
|
||||
|
||||
#include <art/paperback/types.hxx>
|
||||
#include <art/paperback/forward.hxx>
|
||||
|
||||
#include <art/paperback/graphics/color.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
/// Represents the drawable canvas of a page.
|
||||
///
|
||||
class Canvas
|
||||
{
|
||||
public:
|
||||
struct Clear {};
|
||||
|
||||
/// Dispatch-tag used to clear a canvas.
|
||||
///
|
||||
static constexpr Clear const clear{};
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
Canvas(Clear const&, Page&);
|
||||
|
||||
/// Destructor.
|
||||
///
|
||||
~Canvas();
|
||||
|
||||
/// Access the parent page.
|
||||
///
|
||||
Page&
|
||||
page();
|
||||
|
||||
/// Access the parent page.
|
||||
///
|
||||
Page const&
|
||||
page() const;
|
||||
|
||||
/// Access the content stream.
|
||||
///
|
||||
Carousel::Stream&
|
||||
content();
|
||||
|
||||
/// Access the content stream.
|
||||
///
|
||||
Carousel::Stream const&
|
||||
content() const;
|
||||
|
||||
class Save;
|
||||
friend Save;
|
||||
|
||||
/// Set stroke greyscale value.
|
||||
///
|
||||
void
|
||||
set_stroke(double);
|
||||
|
||||
/// Set fill greyscale value.
|
||||
///
|
||||
void
|
||||
set_fill(double);
|
||||
|
||||
/// Set stroke RGB color.
|
||||
///
|
||||
void
|
||||
set_stroke(RGB const&);
|
||||
|
||||
/// Set fill RGB color.
|
||||
///
|
||||
void
|
||||
set_fill(RGB const&);
|
||||
|
||||
class Path;
|
||||
friend Path;
|
||||
|
||||
class Begin_text;
|
||||
friend Begin_text;
|
||||
|
||||
class Set_font;
|
||||
friend Set_font;
|
||||
|
||||
/// Compute text width.
|
||||
///
|
||||
double
|
||||
get_text_width(string const&) const;
|
||||
|
||||
private:
|
||||
Canvas(Canvas const&) = delete;
|
||||
Canvas(Canvas&&) = delete;
|
||||
Canvas& operator=(Canvas const&) = delete;
|
||||
Canvas& operator=(Canvas&&) = delete;
|
||||
|
||||
private:
|
||||
struct Internal;
|
||||
unique_ptr<Internal> internal;
|
||||
|
||||
};
|
||||
|
||||
/// Saves graphics state.
|
||||
///
|
||||
class Canvas::Save
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
///
|
||||
explicit
|
||||
Save(Canvas&);
|
||||
|
||||
/// Destructor.
|
||||
///
|
||||
~Save() noexcept;
|
||||
|
||||
/// Access parent canvas.
|
||||
///
|
||||
Canvas&
|
||||
canvas();
|
||||
|
||||
/// Access parent canvas.
|
||||
Canvas const&
|
||||
canvas() const;
|
||||
|
||||
private:
|
||||
Save(Save const&) = delete;
|
||||
Save(Save&&) = delete;
|
||||
Save& operator=(Save const&) = delete;
|
||||
Save& operator=(Save&&) = delete;
|
||||
|
||||
private:
|
||||
Canvas& _canvas;
|
||||
|
||||
};
|
||||
|
||||
/// Path construction class.
|
||||
///
|
||||
/// \todo Add example.
|
||||
///
|
||||
class Canvas::Path
|
||||
{
|
||||
public:
|
||||
/// Paint mode enumeration.
|
||||
///
|
||||
enum Paint_mode
|
||||
{
|
||||
/// Stroke.
|
||||
///
|
||||
stroke,
|
||||
|
||||
/// Fill.
|
||||
///
|
||||
fill,
|
||||
|
||||
/// Fill then stroke.
|
||||
///
|
||||
fill_then_stroke
|
||||
|
||||
};
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
Path(Canvas&, Paint_mode);
|
||||
|
||||
/// Destructor.
|
||||
///
|
||||
~Path() noexcept;
|
||||
|
||||
/// Access parent canvas.
|
||||
///
|
||||
Canvas&
|
||||
canvas();
|
||||
|
||||
/// Access parent canvas.
|
||||
Canvas const&
|
||||
canvas() const;
|
||||
|
||||
/// Move starting point.
|
||||
///
|
||||
void
|
||||
move_to(double, double);
|
||||
|
||||
/// Draw line.
|
||||
///
|
||||
void
|
||||
line_to(double, double);
|
||||
|
||||
/// Draw bezier curve.
|
||||
///
|
||||
void
|
||||
bezier_curve_to(double,
|
||||
double,
|
||||
double,
|
||||
double,
|
||||
double,
|
||||
double);
|
||||
|
||||
|
||||
private:
|
||||
Path(Path const&) = delete;
|
||||
Path(Path&&) = delete;
|
||||
Path& operator=(Path const&) = delete;
|
||||
Path& operator=(Path&&) = delete;
|
||||
|
||||
private:
|
||||
Canvas& _canvas;
|
||||
Paint_mode _mode;
|
||||
|
||||
};
|
||||
|
||||
class Canvas::Begin_text
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Begin_text(Canvas&);
|
||||
|
||||
Begin_text(Begin_text const&) = delete;
|
||||
|
||||
Begin_text(Begin_text&&) = delete;
|
||||
|
||||
~Begin_text() noexcept;
|
||||
|
||||
Canvas&
|
||||
canvas();
|
||||
|
||||
Canvas const&
|
||||
canvas() const;
|
||||
|
||||
void
|
||||
move_text_pos(double, double);
|
||||
|
||||
void
|
||||
show_text(string const&);
|
||||
|
||||
Begin_text&
|
||||
operator=(Begin_text const&) = delete;
|
||||
|
||||
Begin_text&
|
||||
operator=(Begin_text&&) = delete;
|
||||
|
||||
private:
|
||||
Canvas& _canvas;
|
||||
|
||||
};
|
||||
|
||||
class Canvas::Set_font
|
||||
{
|
||||
public:
|
||||
Set_font(Canvas&, Font&, double);
|
||||
|
||||
Set_font(Set_font const&) = delete;
|
||||
|
||||
Set_font(Set_font&&) = delete;
|
||||
|
||||
~Set_font() noexcept;
|
||||
|
||||
Canvas&
|
||||
canvas();
|
||||
|
||||
Canvas const&
|
||||
canvas() const;
|
||||
|
||||
Set_font&
|
||||
operator=(Set_font const&) = delete;
|
||||
|
||||
Set_font&
|
||||
operator=(Set_font&&) = delete;
|
||||
|
||||
private:
|
||||
Canvas& _canvas;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
|
||||
#endif
|
||||
91
art/paperback/graphics/color.cxx
Normal file
91
art/paperback/graphics/color.cxx
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <art/paperback/graphics/color.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
RGB::
|
||||
RGB()
|
||||
{}
|
||||
|
||||
/// \param red The red component.
|
||||
/// \param green The green component.
|
||||
/// \param blue The blue component.
|
||||
RGB::
|
||||
RGB(double red, double green, double blue)
|
||||
: _red{red},
|
||||
_green{green},
|
||||
_blue{blue}
|
||||
{}
|
||||
|
||||
/// \param other The RGB to copy from.
|
||||
///
|
||||
RGB::
|
||||
RGB(RGB const& other)
|
||||
: _red{other._red},
|
||||
_green{other._green},
|
||||
_blue{other._blue}
|
||||
{}
|
||||
|
||||
/// \param other The RGB to move from.
|
||||
///
|
||||
RGB::
|
||||
RGB(RGB&& other)
|
||||
: _red{other._red},
|
||||
_green{other._green},
|
||||
_blue{other._blue}
|
||||
{}
|
||||
|
||||
/// \return Returns the red component.
|
||||
///
|
||||
double
|
||||
RGB::
|
||||
red() const
|
||||
{
|
||||
return _red;
|
||||
}
|
||||
|
||||
/// \return Returns the green component.
|
||||
///
|
||||
double
|
||||
RGB::
|
||||
green() const
|
||||
{
|
||||
return _green;
|
||||
}
|
||||
|
||||
/// \return Returns the blue component.
|
||||
///
|
||||
double
|
||||
RGB::
|
||||
blue() const
|
||||
{
|
||||
return _blue;
|
||||
}
|
||||
|
||||
/// \param other The RGB to copy from.
|
||||
///
|
||||
RGB&
|
||||
RGB::
|
||||
operator=(RGB const& other)
|
||||
{
|
||||
_red = other._red;
|
||||
_green = other._green;
|
||||
_blue = other._blue;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \param other The RGB to move from.
|
||||
///
|
||||
RGB&
|
||||
RGB::
|
||||
operator=(RGB&& other)
|
||||
{
|
||||
_red = other._red;
|
||||
_green = other._green;
|
||||
_blue = other._blue;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
78
art/paperback/graphics/color.hxx
Normal file
78
art/paperback/graphics/color.hxx
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef art__paperback__graphics__color_hxx_
|
||||
#define art__paperback__graphics__color_hxx_
|
||||
|
||||
#include <art/paperback/types.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
/// PDF color space enumeration.
|
||||
///
|
||||
enum class Color_space
|
||||
{
|
||||
/// Device grey.
|
||||
///
|
||||
device_grey,
|
||||
|
||||
/// Device RGB.
|
||||
///
|
||||
device_rgb
|
||||
|
||||
};
|
||||
|
||||
/// Represents an RGB color value.
|
||||
///
|
||||
class RGB
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
///
|
||||
RGB();
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
RGB(RGB const&);
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
RGB(RGB&&);
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
RGB(double, double, double);
|
||||
|
||||
/// Access red component.
|
||||
///
|
||||
double
|
||||
red() const;
|
||||
|
||||
/// Access green component.
|
||||
///
|
||||
double
|
||||
green() const;
|
||||
|
||||
/// Access blue component.
|
||||
///
|
||||
double
|
||||
blue() const;
|
||||
|
||||
/// Assignment.
|
||||
///
|
||||
RGB&
|
||||
operator=(RGB const&);
|
||||
|
||||
/// Assignment.
|
||||
///
|
||||
RGB&
|
||||
operator=(RGB&&);
|
||||
|
||||
private:
|
||||
double _red{};
|
||||
double _green{};
|
||||
double _blue{};
|
||||
|
||||
};
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
|
||||
#endif
|
||||
107
art/paperback/graphics/font.hxx
Normal file
107
art/paperback/graphics/font.hxx
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef art__paperback__graphics__font_hxx_
|
||||
#define art__paperback__graphics__font_hxx_
|
||||
|
||||
#include <art/paperback/types.hxx>
|
||||
#include <art/paperback/forward.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
/// Represents text width computations.
|
||||
///
|
||||
struct Text_width
|
||||
{
|
||||
/// Character count.
|
||||
///
|
||||
uint32_t character_count{};
|
||||
|
||||
/// Space count.
|
||||
///
|
||||
uint32_t space_count{};
|
||||
|
||||
/// Text width.
|
||||
///
|
||||
double width{};
|
||||
|
||||
};
|
||||
|
||||
/// Base class for fonts.
|
||||
///
|
||||
class Font
|
||||
{
|
||||
public:
|
||||
/// Destructor.
|
||||
///
|
||||
virtual
|
||||
~Font() noexcept
|
||||
{}
|
||||
|
||||
/// Access the parent document of this font.
|
||||
///
|
||||
virtual
|
||||
Document&
|
||||
document() = 0;
|
||||
|
||||
/// Get the COS object for this font.
|
||||
///
|
||||
virtual
|
||||
Carousel::Object
|
||||
object() = 0;
|
||||
|
||||
/// Get the name of the font.
|
||||
///
|
||||
/// \return Returns the name of the font.
|
||||
///
|
||||
virtual
|
||||
string
|
||||
name() const = 0;
|
||||
|
||||
/// Get the font ascent.
|
||||
///
|
||||
/// \return Returns the font ascent.
|
||||
///
|
||||
virtual
|
||||
int16_t
|
||||
get_ascent() const = 0;
|
||||
|
||||
/// Get the font descent.
|
||||
///
|
||||
virtual
|
||||
int16_t
|
||||
get_descent() const = 0;
|
||||
|
||||
/// Get the font X-height.
|
||||
///
|
||||
virtual
|
||||
uint16_t
|
||||
get_xheight() const = 0;
|
||||
|
||||
/// Get the font cap-height.
|
||||
///
|
||||
virtual
|
||||
uint16_t
|
||||
get_capheight() const = 0;
|
||||
|
||||
/// Compute text width.
|
||||
///
|
||||
virtual
|
||||
Text_width
|
||||
get_text_width(string const&) = 0;
|
||||
|
||||
protected:
|
||||
/// Constructor.
|
||||
///
|
||||
Font()
|
||||
{}
|
||||
|
||||
private:
|
||||
Font(Font const&) = delete;
|
||||
Font(Font&&) = delete;
|
||||
Font& operator=(Font const&) = delete;
|
||||
Font& operator=(Font&&) = delete;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
|
||||
#endif
|
||||
158
art/paperback/graphics/standard-font.cxx
Normal file
158
art/paperback/graphics/standard-font.cxx
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <art/paperback/graphics/standard-font.hxx>
|
||||
|
||||
#include <art/paperback/document.hxx>
|
||||
|
||||
#include <art/paperback/carousel/dictionary.hxx>
|
||||
#include <art/paperback/carousel/file.hxx>
|
||||
#include <art/paperback/carousel/object.hxx>
|
||||
|
||||
#include <art/paperback/internals/base14-fontdata.hxx>
|
||||
|
||||
#include <art/unicode/reader.hxx>
|
||||
#include <art/unicode/utf8-decoder.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
struct Standard_font::Internal
|
||||
{
|
||||
Internal(Document& document)
|
||||
: document{document},
|
||||
object{document.file().create_object<Carousel::Dictionary>()},
|
||||
data{object_cast<Carousel::Dictionary>(object)}
|
||||
{}
|
||||
|
||||
Document& document;
|
||||
Carousel::Object object;
|
||||
Carousel::Dictionary& data;
|
||||
|
||||
string name;
|
||||
|
||||
Internals::Base14_font_data const* font_data;
|
||||
|
||||
};
|
||||
|
||||
/// \class Standard_font
|
||||
///
|
||||
/// This class represents one of the 14 standard fonts supported by
|
||||
/// the PDF-specification.
|
||||
///
|
||||
|
||||
/// \param document A reference to the parent document.
|
||||
/// \param base_font The name of the base font.
|
||||
///
|
||||
Standard_font::
|
||||
Standard_font(Document& document, string const& base_font)
|
||||
: internal{new Internal{document}}
|
||||
{
|
||||
internal->data.insert("Type", Carousel::Name{"Font"});
|
||||
internal->data.insert("Subtype", Carousel::Name{"Type1"});
|
||||
internal->data.insert("BaseFont", Carousel::Name{base_font});
|
||||
internal->data.insert("Encoding", Carousel::Name{"WinAnsiEncoding"});
|
||||
|
||||
internal->name = base_font;
|
||||
|
||||
auto font_data = Internals::base14_fonts.find(base_font);
|
||||
|
||||
if (font_data == Internals::base14_fonts.end()) {
|
||||
throw std::invalid_argument{"invalid base font"};
|
||||
}
|
||||
|
||||
internal->font_data = &font_data->second;
|
||||
}
|
||||
|
||||
Standard_font::
|
||||
~Standard_font() noexcept
|
||||
{}
|
||||
|
||||
Document&
|
||||
Standard_font::
|
||||
document()
|
||||
{
|
||||
return internal->document;
|
||||
}
|
||||
|
||||
Carousel::Object
|
||||
Standard_font::
|
||||
object()
|
||||
{
|
||||
return internal->object;
|
||||
}
|
||||
|
||||
string
|
||||
Standard_font::
|
||||
name() const
|
||||
{
|
||||
return internal->name;
|
||||
}
|
||||
|
||||
/// \return Returns the font ascent.
|
||||
///
|
||||
int16_t
|
||||
Standard_font::
|
||||
get_ascent() const
|
||||
{
|
||||
return internal->font_data->ascent;
|
||||
}
|
||||
|
||||
/// \return Returns the font descent.
|
||||
///
|
||||
int16_t
|
||||
Standard_font::
|
||||
get_descent() const
|
||||
{
|
||||
return internal->font_data->descent;
|
||||
}
|
||||
|
||||
/// \return Returns the font X-height.
|
||||
///
|
||||
uint16_t
|
||||
Standard_font::
|
||||
get_xheight() const
|
||||
{
|
||||
return internal->font_data->x_height;
|
||||
}
|
||||
|
||||
/// \return Returns the font Cap-height.
|
||||
///
|
||||
uint16_t
|
||||
Standard_font::
|
||||
get_capheight() const
|
||||
{
|
||||
return internal->font_data->cap_height;
|
||||
}
|
||||
|
||||
/// \a text is assumed to be encoded in UTF-8 and will be
|
||||
/// decoded as such during text width computation.
|
||||
///
|
||||
/// \param text The text for which to compute metrics.
|
||||
///
|
||||
Text_width
|
||||
Standard_font::
|
||||
get_text_width(string const& text)
|
||||
{
|
||||
Text_width tw{};
|
||||
|
||||
art::unicode::iterator_reader_t reader{text.begin(), text.end()};
|
||||
art::unicode::utf8_decoder_t decoder{reader};
|
||||
|
||||
for (auto it = decoder.begin(); it != decoder.end(); ++it) {
|
||||
auto const c = *it;
|
||||
|
||||
if (c == ' ')
|
||||
++tw.space_count;
|
||||
|
||||
++tw.character_count;
|
||||
|
||||
for (auto const& j : internal->font_data->cdata) {
|
||||
if (c == j.unicode) {
|
||||
tw.width += j.width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tw;
|
||||
}
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
64
art/paperback/graphics/standard-font.hxx
Normal file
64
art/paperback/graphics/standard-font.hxx
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef art__paperback__graphics__standard_font_hxx_
|
||||
#define art__paperback__graphics__standard_font_hxx_
|
||||
|
||||
#include <art/paperback/types.hxx>
|
||||
#include <art/paperback/forward.hxx>
|
||||
|
||||
#include <art/paperback/graphics/font.hxx>
|
||||
|
||||
namespace Art::Paperback::Graphics
|
||||
{
|
||||
|
||||
/// Represents a standard PDF font.
|
||||
///
|
||||
class Standard_font
|
||||
: public Font
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
///
|
||||
Standard_font(Document&, string const&);
|
||||
|
||||
/// Destructor.
|
||||
///
|
||||
~Standard_font() noexcept override;
|
||||
|
||||
Document&
|
||||
document() override;
|
||||
|
||||
Carousel::Object
|
||||
object() override;
|
||||
|
||||
string
|
||||
name() const override;
|
||||
|
||||
int16_t
|
||||
get_ascent() const override;
|
||||
|
||||
int16_t
|
||||
get_descent() const override;
|
||||
|
||||
uint16_t
|
||||
get_xheight() const override;
|
||||
|
||||
uint16_t
|
||||
get_capheight() const override;
|
||||
|
||||
Text_width
|
||||
get_text_width(string const&) override;
|
||||
|
||||
private:
|
||||
Standard_font(Standard_font const&) = delete;
|
||||
Standard_font(Standard_font&&) = delete;
|
||||
Standard_font& operator=(Standard_font const&) = delete;
|
||||
Standard_font& operator=(Standard_font&&) = delete;
|
||||
|
||||
private:
|
||||
struct Internal;
|
||||
unique_ptr<Internal> internal;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Art::Paperback::Graphics
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user