Commit de69aae0 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

graphics: port basic SVG layer

parent 577a9e8e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ foreach(spec_test_path ${spec_test_files})
  get_filename_component(spec_test_name ${spec_test_path} NAME_WE)
  get_filename_component(spec_test_srcdir ${spec_test_path} DIRECTORY)
  add_test(
      NAME ${spec_test_name}
      NAME ${spec_test_name}_svg
      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
      COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_runner.sh ${CMAKE_CURRENT_BINARY_DIR}/plotfx ${spec_test_path} ${CMAKE_CURRENT_BINARY_DIR}/${spec_test_name}.png ${spec_test_srcdir}/${spec_test_name}.png)
      COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_runner.sh ${CMAKE_CURRENT_BINARY_DIR}/plotfx ${spec_test_path} ${CMAKE_CURRENT_BINARY_DIR}/${spec_test_name}.svg ${spec_test_srcdir}/${spec_test_name}.svg)
endforeach()
+16 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <string.h>
#include <iostream>
#include <iomanip>
#include <utils/stringutil.h>
#include "colour.h"

@@ -134,6 +136,20 @@ bool Colour::parseHexShort(const std::string& str) {
  return true;
}

std::string Colour::to_hex_str() const {
  std::stringstream ss;
  ss
    << "#"
    << std::setfill('0')
    << std::setw(2)
    << std::hex
    << int(components_[0] * 255)
    << int(components_[1] * 255)
    << int(components_[2] * 255);

  return ss.str();
}

std::ostream& operator <<(std::ostream& os, const Colour& c) {
  os << "Colour(";
  os << c[0];
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@ public:
  bool parseHexAlpha(const std::string& str);
  bool parseHexShort(const std::string& str);

  std::string to_hex_str() const;

protected:
  double components_[kMaxComponents];
};
+79 −1
Original line number Diff line number Diff line
@@ -28,10 +28,88 @@
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "layer_svg.h"
#include "utils/fileutil.h"
#include "utils/exception.h"

namespace plotfx {

ReturnCode layer_new_svg(Layer* layer) {
SVGData::SVGData() {}

Status svg_text_span(const TextSpanOp& op, SVGData* svg) {
  const auto& style = op.style;

  std::string anchor = "middle";
  std::string baseline = "middle";

  svg->buffer
    << "  "
    << "<text "
    << "x='" << op.x << "' "
    << "y='" << op.y << "' "
    << "fill='" << style.colour.to_hex_str() << "' "
    << "font-size='" << style.font_size << "' "
    << "text-anchor='" << anchor << "' "
    << "dominant-baseline='" << baseline << "' "
    << ">"
    << op.text // FIXME escape
    << "</text>";

  return OK;
}

Status svg_stroke_path(const BrushStrokeOp& op, SVGData* svg) {
  const auto& clip = op.clip;
  const auto& path = op.path;
  const auto& style = op.style;

  if (path.size() < 2) {
    return ERROR_INVALID_ARGUMENT;
  }

  svg->buffer << StringUtil::format(
      "  <path stroke-width='$0' stroke='$1' fill='none' d=\"",
      style.line_width.value, // FIXME
      style.colour.to_hex_str());

  for (const auto& cmd : path) {
    switch (cmd.command) {
      case PathCommand::MOVE_TO:
        svg->buffer << StringUtil::format("M$0 $1 ", cmd[0], cmd[1]);
        break;
      case PathCommand::LINE_TO:
        svg->buffer << StringUtil::format("L$0 $1 ", cmd[0], cmd[1]);
        break;
      case PathCommand::ARC_TO:
        break;
    }
  }

  svg->buffer << "\" />\n";

  return OK;
}

std::string SVGData::to_svg() const {
  return StringUtil::format(
      "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox='0 0 $0 $1' viewport-fill='white'>\n$2\n</svg>",
      width,
      height,
      buffer.str());
}

Status SVGData::writeToFile(const std::string& path) {
  auto svg = to_svg();
  FileUtil::write(path, Buffer(svg.data(), svg.size()));
  return OK;
}

ReturnCode layer_new_svg(Layer* layer, SVGData* svg) {
  svg->width = layer->width;
  svg->height = layer->height;

  layer->op_brush_stroke = std::bind(&svg_stroke_path, std::placeholders::_1, svg);
  layer->op_brush_fill = [] (auto op) { return OK; };
  layer->op_text_span = std::bind(&svg_text_span, std::placeholders::_1, svg);

  return OK;
}
+16 −1
Original line number Diff line number Diff line
@@ -28,11 +28,26 @@
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once
#include <iostream>
#include <sstream>
#include "layer.h"
#include "utils/outputstream.h"

namespace plotfx {

ReturnCode layer_new_svg(Layer* layer);
class SVGData {
public:
  SVGData();
  std::stringstream buffer;

  uint32_t width;
  uint32_t height;

  std::string to_svg() const;
  Status writeToFile(const std::string& path);
};

ReturnCode layer_new_svg(Layer* layer, SVGData* svg);

} // namespace plotfx
Loading