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(¤t); 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 }