用Direct2D绘制SVG (1)

矢量图形绘制, 首先想到使用SVG作为图像格式,起步需要的就是SVG文件格式。

GitHub找了一圈,nanosvg是一个很好的C库。
nanosvg是一个很符合KISS的库,分为parser 和 Rasterizer,
Parser部分,都在 #include "nanosvg.h" 头文件中,记得要#define NANOSVG_IMPLEMENTATION
Rasterizer部分,都在 #include "nanosvgrast.h" 头文件中,同样要定义 #define NANOSVGRAST_IMPLEMENTATION

如果需求是 SVG to PNG,这2者用上,加个PNG的write库(这里面是stb_image_write.h)即可。
然而,如果每次绘制都需要把矢量搞成点阵图,非常消耗资源。

另外: nanosvg只支持SVG v1.1,各种Filter就别想了。因此最大的用处在于参考价值。
对照着http://www.w3school.com.cn/svg/
Parser部分, SVG既然是矢量绘制,按图形学的常识,基本图形就是line和 cubic bezier。
再预定义的形状元素,可被开发者使用和操作:
矩形 <rect>
圆形 <circle>
椭圆 <ellipse>
线 <line>
折线 <polyline>
多边形 <polygon>
路径 <path>

Path特别强大,直接以命令方式几乎可以组成任何图形。
M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Belzier curve
T = smooth quadratic Belzier curveto
A = elliptical Arc
Z = closepath
看Parser代码,nanosvg非常简单粗暴,所有图形一律规整为cubic bezier。

Trace出Path代码,尝试使用D2d绘制这些CubicBezier。
按MSDN说明,先从ID2D1Factory, CreatePathGeometry出一个ID2D1PathGeometry
再通过这个ID2D1PathGeometry, Open一个ID2D1GeometrySink
注意这个ID2D1GeometrySink,包含实际功能,可以直接使用。
而对应的ID2D1SimplifiedGeometrySink,则不包含实际功能,必须继承实现接口作为sink回调。

  CComPtr<ID2D1PathGeometry> path;
  _factory->CreatePathGeometry(&path);

  {
    CComPtr<ID2D1GeometrySink> sink;
    path->Open(&sink);

    float af[] = {4.00,52,
      4.00,38, 4.00,31, 6.36,26, 9.29,19, 14.72,13, 21.54,10, 27.03, 8, 
      34.02, 8, 48.00, 8, 61.98, 8, 68.97, 8, 74.46,10, 81.28,13, 86.71,19, 89.64,26, 92.00,31, 
      92.00,38, 92.00,52, 92.00,66, 92.00,73, 89.64,78, 86.71,85, 81.28,91, 74.46,94, 68.97,96, 
      61.98,96, 48.00,96, 34.02,96, 27.03,96, 21.54,94, 14.72,91, 9.29,85, 6.36,78, 4.00,73, 
      4.00,66, 4.00,52, 4.00,52, 4.00,52, 4.00,52};

    sink->BeginFigure(
      D2D1::Point2F(af[0],af[1]),
      D2D1_FIGURE_BEGIN_FILLED
      );

    for( int i = 0; i < 12; i++ ) {
      sink->AddBezier( BezierSegment( Point2F(af[i*6+2],af[i*6+3]),
                                      Point2F(af[i*6+4],af[i*6+5]), 
                                      Point2F(af[i*6+6],af[i*6+7])));
    }

    sink->EndFigure(D2D1_FIGURE_END_OPEN);
    sink->Close();

须注意, BezierSegment是一个 (controlpoint1, controlpoint2, endpoint) 的序列。
其中上一个endpoint(或者moveTo Point) 作为startpoint,也算是cubic bezier在各种图形库的一个使用常态。

猜你喜欢

转载自blog.csdn.net/hellowithsmile/article/details/82589919