/// <summary> /// When a GDI instruction with a brush parameter is called, there can be a lot we have to do to emulate the brush. The aim is to return a /// style that represents the brush. /// <para> /// Solid brush is very easy. /// </para> /// <para> /// Linear grad brush: we ignore the blend curve and the transformation (and therefore the rotation parameter if any) /// Hatch brush: /// </para> /// <para> /// Other types of brushes are too hard to emulate and are rendered pink. /// </para> /// </summary> /// <param name="br"></param> /// <returns></returns> private SvgStyle HandleBrush(Brush br) { if (br.GetType() == typeof(SolidBrush)) { return new SvgStyle((SolidBrush)br); } if (br.GetType() == typeof(LinearGradientBrush)) { LinearGradientBrush grbr = (LinearGradientBrush)br; RectangleF rc = grbr.Rectangle; SvgLinearGradient grad = new SvgLinearGradient(rc.Left, rc.Top, rc.Right, rc.Bottom); switch(grbr.WrapMode) { //I have not been able to test Clamp because using a clamped gradient appears to crash the process //under XP (?!?!) case WrapMode.Clamp: grad.SpreadMethod = "pad"; grad.GradientUnits = "objectBoundingBox"; break; case WrapMode.Tile: grad.SpreadMethod = "repeat"; grad.GradientUnits = "userSpaceOnUse"; break; default: grad.SpreadMethod = "reflect"; grad.GradientUnits = "userSpaceOnUse"; break; } ColorBlend cb = null; //GDI dll tends to crash when you try and access some members of gradient brushes that haven't been specified. try { cb = grbr.InterpolationColors; } catch(Exception){} if(cb != null) { for(int i = 0; i < grbr.InterpolationColors.Colors.Length; ++i) { grad.AddChild(new SvgStopElement(grbr.InterpolationColors.Positions[i], grbr.InterpolationColors.Colors[i])); } } else { grad.AddChild(new SvgStopElement("0%", grbr.LinearColors[0])); grad.AddChild(new SvgStopElement("100%", grbr.LinearColors[1])); } grad.Id += "_LinearGradientBrush"; _defs.AddChild(grad); SvgStyle s = new SvgStyle(); s.Set("fill", new SvgUriReference(grad)); return s; } if (br.GetType() == typeof(HatchBrush)) { HatchBrush habr = (HatchBrush)br; SvgPatternElement patty = new SvgPatternElement(0,0,8,8, new SvgNumList("4 4 12 12")); patty.Style.Set("shape-rendering", "crispEdges"); patty.Style.Set("stroke-linecap", "butt"); SvgRectElement rc = new SvgRectElement(0,0,8,8); rc.Style.Set("fill", new SvgColor(habr.BackgroundColor)); patty.AddChild(rc); AddHatchBrushDetails(patty, new SvgColor(habr.ForegroundColor), habr.HatchStyle); patty.Id += "_HatchBrush"; patty.PatternUnits = "userSpaceOnUse"; patty.PatternContentUnits = "userSpaceOnUse"; _defs.AddChild(patty); SvgStyle s = new SvgStyle(); s.Set("fill", new SvgUriReference(patty)); return s; } //most types of brush we can't emulate, but luckily they are quite unusual return new SvgStyle(new SolidBrush(Color.Salmon)); }