d2d_svg.cpp
  1  #include "pch.h"
  2  #include "d2d_svg.h"
  3  
  4  D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc)
  5  {
  6      svg = nullptr;
  7      winrt::com_ptr<IStream> svg_stream;
  8      auto h = SHCreateStreamOnFileEx(filename.c_str(),
  9                                      STGM_READ,
 10                                      FILE_ATTRIBUTE_NORMAL,
 11                                      FALSE,
 12                                      nullptr,
 13                                      svg_stream.put());
 14      winrt::check_hresult(h);
 15  
 16      auto h1 = d2d_dc->CreateSvgDocument(
 17          svg_stream.get(),
 18          D2D1::SizeF(1, 1),
 19          svg.put());
 20  
 21      winrt::check_hresult(h1);
 22  
 23      winrt::com_ptr<ID2D1SvgElement> root;
 24      svg->GetRoot(root.put());
 25      float tmp;
 26      winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
 27      svg_width = static_cast<int>(tmp);
 28      winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
 29      svg_height =  static_cast<int>(tmp);
 30      return *this;
 31  }
 32  
 33  D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale)
 34  {
 35      // Center
 36      transform = D2D1::Matrix3x2F::Identity();
 37      transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
 38      float h_scale = fill * height / svg_height;
 39      float v_scale = fill * width / svg_width;
 40      used_scale = std::min(h_scale, v_scale);
 41      if (max_scale > 0)
 42      {
 43          used_scale = std::min(used_scale, max_scale);
 44      }
 45      transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
 46      transform = transform * D2D1::Matrix3x2F::Translation(static_cast<float>(x), static_cast<float>(y));
 47      return *this;
 48  }
 49  
 50  D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor)
 51  {
 52      auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
 53      auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
 54      std::function<void(ID2D1SvgElement * element)> recurse = [&](ID2D1SvgElement* element) {
 55          if (!element)
 56              return;
 57          if (element->IsAttributeSpecified(L"fill"))
 58          {
 59              D2D1_COLOR_F elem_fill;
 60              winrt::com_ptr<ID2D1SvgPaint> paint;
 61              element->GetAttributeValue(L"fill", paint.put());
 62              paint->GetColor(&elem_fill);
 63              if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b)
 64              {
 65                  winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
 66              }
 67          }
 68          winrt::com_ptr<ID2D1SvgElement> sub;
 69          element->GetFirstChild(sub.put());
 70          while (sub)
 71          {
 72              recurse(sub.get());
 73              winrt::com_ptr<ID2D1SvgElement> next;
 74              element->GetNextChild(sub.get(), next.put());
 75              sub = next;
 76          }
 77      };
 78      winrt::com_ptr<ID2D1SvgElement> root;
 79      svg->GetRoot(root.put());
 80      recurse(root.get());
 81      return *this;
 82  }
 83  
 84  D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc)
 85  {
 86      D2D1_MATRIX_3X2_F current;
 87      d2d_dc->GetTransform(&current);
 88      d2d_dc->SetTransform(transform * current);
 89      d2d_dc->DrawSvgDocument(svg.get());
 90      d2d_dc->SetTransform(current);
 91      return *this;
 92  }
 93  
 94  D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible)
 95  {
 96      winrt::com_ptr<ID2D1SvgElement> element;
 97      if (svg->FindElementById(id, element.put()) != S_OK)
 98          return *this;
 99      if (!element)
100          return *this;
101      element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
102      return *this;
103  }
104  
105  winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id)
106  {
107      winrt::com_ptr<ID2D1SvgElement> element;
108      winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
109      return element;
110  }
111  
112  D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect)
113  {
114      D2D1_RECT_F result;
115      auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
116      auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
117      dst[0] = src[0] * transform;
118      dst[1] = src[1] * transform;
119      return result;
120  }