private void InsertSquare(SvgGroupElement group, int xIndex, int yIndex) { bool isBlack = ((xIndex + yIndex) % 2 == 0); if (!isBlack) { // nothing to draw in case of a white square return; } float x = m_UpperLeft.X + xIndex * m_SquareLength; float y = m_UpperLeft.Y + yIndex * m_SquareLength; SvgRectElement rectangle = new SvgRectElement( x, y, m_SquareLength, m_SquareLength ); rectangle.Style = s_FilledBlack; group.AddChild(rectangle); }
public SvgGraphics() { _root = new SvgSvgElement(); _root.Id = "SvgGdi_output"; _bg = new SvgRectElement(0, 0, "100%", "100%"); _bg.Style.Set("fill", new SvgColor(Color.FromName("Control"))); _bg.Id = "background"; _root.AddChild(_bg); _topgroup = new SvgGroupElement("root_group"); _topgroup.Style.Set("shape-rendering", "crispEdges"); _cur = _topgroup; _root.AddChild(_topgroup); _defs = new SvgDefsElement("clips_hatches_and_gradients"); _root.AddChild(_defs); _transforms = new MatrixStack(); }
public void AddSquares(float yOffset, float xOffset, float sideLength, int xCount, int yCount) { SvgGroupElement squaresGroup = new SvgGroupElement("Squares"); squaresGroup.Style = s_NormalLineStyle; float xStart = this.Origin.X + xOffset - xCount / 2.0F * sideLength; float yStart = this.Origin.Y + yOffset; for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { SvgRectElement rectElement = new SvgRectElement( GetSvgLength(xStart + i * sideLength), GetSvgLength(yStart + j * sideLength), GetSvgLength(sideLength), GetSvgLength(sideLength)); squaresGroup.AddChild(rectElement); } } this.Root.AddChild(squaresGroup); }
/// <summary> /// Implemented /// </summary> public void DrawRectangle(Pen pen, Single x, Single y, Single width, Single height) { SvgRectElement rc= new SvgRectElement(x,y,width,height); rc.Style = new SvgStyle(pen); if (!_transforms.Result.IsIdentity) rc.Transform = new SvgTransformList(_transforms.Result.Clone()); _cur.AddChild(rc); }
/// <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)); }
private void DrawText(String s, Font font, Brush brush, RectangleF rect, StringFormat fmt, bool ignoreRect) { SvgTextElement txt = new SvgTextElement(s, rect.X, rect.Y); //GDI takes x and y as the upper left corner; svg takes them as the lower left. //We must therefore move the text one line down, but SVG does not understand about lines, //so we do as best we can, applying a downward translation before the current GDI translation. txt.Transform = new SvgTransformList(_transforms.Result.Clone()); txt.Style = HandleBrush(brush); txt.Style += new SvgStyle(font); if (fmt.Alignment == StringAlignment.Center) { txt.Style.Set("text-anchor", "middle"); txt.X = rect.X + rect.Width/2; } if (fmt.Alignment == StringAlignment.Far) { txt.Style.Set("text-anchor", "end"); txt.X = rect.Right; } txt.Style.Set("baseline-shift", "-86%");//a guess. if(!ignoreRect && (fmt.FormatFlags != StringFormatFlags.NoClip)) { SvgClipPathElement clipper = new SvgClipPathElement(); clipper.Id += "_text_clipper"; SvgRectElement rc = new SvgRectElement(rect.X, rect.Y, rect.Width, rect.Height); clipper.AddChild(rc); _defs.AddChild(clipper); txt.Style.Set("clip-path", new SvgUriReference(clipper)); } _cur.AddChild(txt); }
private void DrawEndAnchor(LineCap lc, CustomLineCap clc, Color col, float w, PointF pt, float angle) { SvgStyledTransformedElement anchor=null; PointF[] points = null; switch(lc) { case LineCap.ArrowAnchor: points = new PointF[3]; points[0] = new PointF(0, -w/2f); points[1] = new PointF(-w, w); points[2] = new PointF(w, w); anchor = new SvgPolygonElement(points); break; case LineCap.DiamondAnchor: points = new PointF[4]; points[0] = new PointF(0, -w); points[1] = new PointF(w, 0); points[2] = new PointF(0, w); points[3] = new PointF(-w, 0); anchor = new SvgPolygonElement(points); break; case LineCap.RoundAnchor: anchor = new SvgEllipseElement(0, 0, w, w); break; case LineCap.SquareAnchor: float ww = (w/3)*2; anchor = new SvgRectElement(0 - ww, 0 - ww, ww*2, ww*2); break; case LineCap.Custom: //not implemented! return; default: return; } anchor.Id += "_line_anchor"; anchor.Style.Set("fill", new SvgColor(col)); anchor.Style.Set("stroke", "none"); Matrix rotation = new Matrix(); rotation.Rotate((angle/(float)Math.PI)*180); Matrix translation = new Matrix(); translation.Translate(pt.X, pt.Y); anchor.Transform = new SvgTransformList(_transforms.Result.Clone()); anchor.Transform.Add(translation); anchor.Transform.Add(rotation); _cur.AddChild(anchor); }
private void AddHatchBrushDetails(SvgPatternElement patty, SvgColor col, HatchStyle hs) { SvgStyledTransformedElement l1=null; SvgStyledTransformedElement l2 = null; SvgStyledTransformedElement l3 = null; SvgStyledTransformedElement l4 = null; switch(hs) { case HatchStyle.Cross: l1 = new SvgLineElement(4,0,4,8); l2 = new SvgLineElement(0,4,8,4); break; case HatchStyle.BackwardDiagonal: l1 = new SvgLineElement(8,0,0,8); break; case HatchStyle.LightDownwardDiagonal: case HatchStyle.DarkDownwardDiagonal: l1 = new SvgLineElement(4,0,8,4); l2 = new SvgLineElement(0,4,4,8); l3 = new SvgLineElement(0,0,8,8); break; case HatchStyle.LightHorizontal: case HatchStyle.DarkHorizontal: l1 = new SvgLineElement(0,2,8,2); l2 = new SvgLineElement(0,6,8,6); break; case HatchStyle.LightUpwardDiagonal: case HatchStyle.DarkUpwardDiagonal: l1 = new SvgLineElement(0,4,4,0); l2 = new SvgLineElement(4,8,8,4); l3 = new SvgLineElement(0,8,8,0); break; case HatchStyle.LightVertical: case HatchStyle.DarkVertical: l1 = new SvgLineElement(2,0,2,8); l2 = new SvgLineElement(6,0,6,8); break; case HatchStyle.DashedDownwardDiagonal: l1 = new SvgLineElement(0,0,4,4); l2 = new SvgLineElement(4,0,8,4); break; case HatchStyle.DashedHorizontal: l1 = new SvgLineElement(0,2,4,2); l2 = new SvgLineElement(4,6,8,6); break; case HatchStyle.DashedUpwardDiagonal: l1 = new SvgLineElement(4,0,0,4); l2 = new SvgLineElement(8,0,4,4); break; case HatchStyle.DashedVertical: l1 = new SvgLineElement(2,0,2,4); l2 = new SvgLineElement(6,4,6,8); break; case HatchStyle.DiagonalBrick: l1 = new SvgLineElement(0,8,8,0); l2 = new SvgLineElement(0,0,4,4); break; case HatchStyle.DiagonalCross: l1 = new SvgLineElement(0,0,8,8); l2 = new SvgLineElement(8,0,0,8); break; case HatchStyle.Divot: l1 = new SvgLineElement(2,2,4,4); l2 = new SvgLineElement(4,4,2,6); break; case HatchStyle.DottedDiamond: l1 = new SvgLineElement(0,0,8,8); l2 = new SvgLineElement(0,8,8,0); break; case HatchStyle.DottedGrid: l1 = new SvgLineElement(4,0,4,8); l2 = new SvgLineElement(0,4,8,4); break; case HatchStyle.ForwardDiagonal: l1 = new SvgLineElement(0,0,8,8); break; case HatchStyle.Horizontal: l1 = new SvgLineElement(0,4,8,4); break; case HatchStyle.HorizontalBrick: l1 = new SvgLineElement(0,3,8,3); l2 = new SvgLineElement(3,0,3,3); l3 = new SvgLineElement(0,3,0,7); l4 = new SvgLineElement(0,7,7,7); break; case HatchStyle.LargeCheckerBoard: l1 = new SvgRectElement(0,0,3f,3f); l2 = new SvgRectElement(4,4,4,4f); break; case HatchStyle.LargeConfetti: l1 = new SvgRectElement(0,0,1,1); l2 = new SvgRectElement(2,3,1,1); l3 = new SvgRectElement(5,2,1,1); l4 = new SvgRectElement(6,6,1,1); break; case HatchStyle.NarrowHorizontal: l1 = new SvgLineElement(0,1,8,1); l2 = new SvgLineElement(0,3,8,3); l3 = new SvgLineElement(0,5,8,5); l4 = new SvgLineElement(0,7,8,7); break; case HatchStyle.NarrowVertical: l1 = new SvgLineElement(1,0,1,8); l2 = new SvgLineElement(3,0,3,8); l3 = new SvgLineElement(5,0,5,8); l4 = new SvgLineElement(7,0,7,8); break; case HatchStyle.OutlinedDiamond: l1 = new SvgLineElement(0,0,8,8); l2 = new SvgLineElement(8,0,0,8); break; case HatchStyle.Plaid: l1 = new SvgLineElement(0,0,8,0); l2 = new SvgLineElement(0,3,8,3); l3 = new SvgRectElement(0,4,3,3); break; case HatchStyle.Shingle: l1 = new SvgLineElement(0,2,2,0); l2 = new SvgLineElement(2,0,7,5); l3 = new SvgLineElement(0,3,3,7); break; case HatchStyle.SmallCheckerBoard: l1 = new SvgRectElement(0,0,1,1); l2 = new SvgRectElement(4,4,1,1); l3 = new SvgRectElement(4,0,1,1); l4 = new SvgRectElement(0,4,1,1); break; case HatchStyle.SmallConfetti: l1 = new SvgLineElement(0,0,2,2); l2 = new SvgLineElement(7,3,5,5); l3 = new SvgLineElement(2,6,4,4); break; case HatchStyle.SmallGrid: l1 = new SvgLineElement(0,2,8,2); l2 = new SvgLineElement(0,6,8,6); l3 = new SvgLineElement(2,0,2,8); l4 = new SvgLineElement(6,0,6,8); break; case HatchStyle.SolidDiamond: l1 = new SvgPolygonElement("3 0 6 3 3 6 0 3"); break; case HatchStyle.Sphere: l1 = new SvgEllipseElement(3,3,2,2); break; case HatchStyle.Trellis: l1 = new SvgLineElement(0,1,8,1); l2 = new SvgLineElement(0,3,8,3); l3 = new SvgLineElement(0,5,8,5); l4 = new SvgLineElement(0,7,8,7); break; case HatchStyle.Vertical: l4 = new SvgLineElement(0,0,0,8); break; case HatchStyle.Wave: l3 = new SvgLineElement(0,4,3,2); l4 = new SvgLineElement(3,2,8,4); break; case HatchStyle.Weave: l1 = new SvgLineElement(0,4,4,0); l2 = new SvgLineElement(8,4,4,8); l3 = new SvgLineElement(0,0,0,4); l4 = new SvgLineElement(0,4,4,8); break; case HatchStyle.WideDownwardDiagonal: l1 = new SvgLineElement(0,0,8,8); l2 = new SvgLineElement(0,1,8,9); l3 = new SvgLineElement(7,0,8,1); break; case HatchStyle.WideUpwardDiagonal: l1 = new SvgLineElement(8,0,0,8); l2 = new SvgLineElement(8,1,0,9); l3 = new SvgLineElement(0,1,-1,0); break; case HatchStyle.ZigZag: l1 = new SvgLineElement(0,4,4,0); l2 = new SvgLineElement(4,0,8,4); break; case HatchStyle.Percent05: l1 = new SvgLineElement(0,0,1,0); l2 = new SvgLineElement(4,4,5,4); break; case HatchStyle.Percent10: l1 = new SvgLineElement(0,0,1,0); l2 = new SvgLineElement(4,2,5,2); l3 = new SvgLineElement(2,4,3,4); l4 = new SvgLineElement(6,6,7,6); break; case HatchStyle.Percent20: l1 = new SvgLineElement(0,0,2,0); l2 = new SvgLineElement(4,2,6,2); l3 = new SvgLineElement(2,4,4,4); l4 = new SvgLineElement(5,6,7,6); break; case HatchStyle.Percent25: l1 = new SvgLineElement(0,0,3,0); l2 = new SvgLineElement(4,2,6,2); l3 = new SvgLineElement(2,4,5,4); l4 = new SvgLineElement(5,6,7,6); break; case HatchStyle.Percent30: l1 = new SvgRectElement(0,0,3,1); l2 = new SvgLineElement(4,2,6,2); l3 = new SvgRectElement(2,4,3,1); l4 = new SvgLineElement(5,6,7,6); break; case HatchStyle.Percent40: l1 = new SvgRectElement(0,0,3,1); l2 = new SvgRectElement(4,2,3,1); l3 = new SvgRectElement(2,4,3,1); l4 = new SvgRectElement(5,6,3,1); break; case HatchStyle.Percent50: l1 = new SvgRectElement(0,0,3,3); l2 = new SvgRectElement(4,4,4,4f); break; case HatchStyle.Percent60: l1 = new SvgRectElement(0,0,4,3); l2 = new SvgRectElement(4,4,4,4f); break; case HatchStyle.Percent70: l1 = new SvgRectElement(0,0,4,5); l2 = new SvgRectElement(4,4,4,4f); break; case HatchStyle.Percent75: l1 = new SvgRectElement(0,0,7,3); l2 = new SvgRectElement(0,2,3,7); break; case HatchStyle.Percent80: l1 = new SvgRectElement(0,0,7,4); l2 = new SvgRectElement(0,2,4,7); break; case HatchStyle.Percent90: l1 = new SvgRectElement(0,0,7,5); l2 = new SvgRectElement(0,2,5,7); break; default: break; } if (l1 != null) { l1.Style.Set("stroke", col); l1.Style.Set("fill", col); patty.AddChild(l1); } if (l2 != null) { l2.Style.Set("stroke", col); l2.Style.Set("fill", col); patty.AddChild(l2); } if (l3 != null) { l3.Style.Set("stroke", col); l3.Style.Set("fill", col); patty.AddChild(l3); } if (l4 != null) { l4.Style.Set("stroke", col); l4.Style.Set("fill", col); patty.AddChild(l4); } }
/// <summary> /// Implemented. /// </summary> public void SetClip(RectangleF rect) { SvgClipPathElement clipper = new SvgClipPathElement(); clipper.Id += "_SetClip"; SvgRectElement rc = new SvgRectElement(rect.X, rect.Y, rect.Width, rect.Height); clipper.AddChild(rc); _defs.AddChild(clipper); _cur.Style.Set("clip-path", new SvgUriReference(clipper)); }
/// <summary> /// Implemented /// </summary> public void FillRectangle(Brush brush, Single x, Single y, Single width, Single height) { SvgRectElement rc = new SvgRectElement(x, y, width, height); rc.Style = HandleBrush(brush); if (!_transforms.Result.IsIdentity) rc.Transform = _transforms.Result.Clone(); _cur.AddChild(rc); }
private void DrawImagePixel(SvgElement container, Color c, float x, float y, float w, float h) { if (c.A == 0) return; SvgRectElement rc = new SvgRectElement(x, y, w, h); rc.Id=""; rc.Style.Set("fill", "rgb("+c.R+","+c.G+","+c.B+")"); if (c.A < 255) rc.Style.Set("opacity", c.A/255f); container.AddChild(rc); }
private void DrawText(String s, Font font, Brush brush, RectangleF rect, StringFormat fmt, bool ignoreRect) { if (s != null && s.Contains("\n")) throw new SvgGdiNotImpl("DrawText multiline text"); SvgTextElement txt = new SvgTextElement(s, rect.X, rect.Y); //GDI takes x and y as the upper left corner; svg takes them as the lower left. //We must therefore move the text one line down, but SVG does not understand about lines, //so we do as best we can, applying a downward translation before the current GDI translation. txt.Transform = new SvgTransformList(_transforms.Result.Clone()); txt.Style = HandleBrush(brush); txt.Style += new SvgStyle(font); switch (fmt.Alignment) { case StringAlignment.Near: break; case StringAlignment.Center: { if (ignoreRect) throw new SvgGdiNotImpl("DrawText automatic rect"); txt.Style.Set("text-anchor", "middle"); txt.X = rect.X + rect.Width / 2; } break; case StringAlignment.Far: { if (ignoreRect) throw new SvgGdiNotImpl("DrawText automatic rect"); txt.Style.Set("text-anchor", "end"); txt.X = rect.Right; } break; default: throw new SvgGdiNotImpl("DrawText horizontal alignment"); } if (!ignoreRect && ((fmt.FormatFlags & StringFormatFlags.NoClip) != StringFormatFlags.NoClip)) { SvgClipPathElement clipper = new SvgClipPathElement(); clipper.Id += "_text_clipper"; SvgRectElement rc = new SvgRectElement(rect.X, rect.Y, rect.Width, rect.Height); clipper.AddChild(rc); _defs.AddChild(clipper); txt.Style.Set("clip-path", new SvgUriReference(clipper)); } switch (fmt.LineAlignment) { case StringAlignment.Near: { // TODO: ?? // txt.Style.Set("baseline-shift", "-86%");//a guess. var span = new SvgTspanElement(s); span.DY = new SvgLength(txt.Style.Get("font-size").ToString()); txt.Text = null; txt.AddChild(span); } break; case StringAlignment.Center: { if (ignoreRect) throw new SvgGdiNotImpl("DrawText automatic rect"); txt.Y.Value = txt.Y.Value + (rect.Height / 2); var span = new SvgTspanElement(s); span.DY = new SvgLength(txt.Style.Get("font-size").ToString()); span.DY.Value = span.DY.Value * ((1 - GetFontDescentPercentage(font)) - 0.5f); txt.Text = null; txt.AddChild(span); } break; case StringAlignment.Far: { if (ignoreRect) throw new SvgGdiNotImpl("DrawText automatic rect"); txt.Y.Value = txt.Y.Value + rect.Height; // This would solve the alignment as well, but it's not supported by Internet Explorer // // txt.Attributes["dominant-baseline"] = "text-after-edge"; var span = new SvgTspanElement(s); span.DY = new SvgLength(txt.Style.Get("font-size").ToString()); span.DY.Value = span.DY.Value * ((1 - GetFontDescentPercentage(font)) - 1); txt.Text = null; txt.AddChild(span); } break; default: throw new SvgGdiNotImpl("DrawText vertical alignment"); } _cur.AddChild(txt); }
private void DrawEndAnchor(LineCap lc, CustomLineCap clc, Color col, float w, PointF pt, float angle, bool ignoreUnsupportedLineCaps) { SvgStyledTransformedElement anchor = null; PointF[] points = null; switch (lc) { case LineCap.NoAnchor: break; case LineCap.Flat: // TODO: what is the correct look? break; case LineCap.ArrowAnchor: points = new PointF[3]; points[0] = new PointF(0, -w / 2f); points[1] = new PointF(-w, w); points[2] = new PointF(w, w); anchor = new SvgPolygonElement(points); break; case LineCap.DiamondAnchor: points = new PointF[4]; points[0] = new PointF(0, -w); points[1] = new PointF(w, 0); points[2] = new PointF(0, w); points[3] = new PointF(-w, 0); anchor = new SvgPolygonElement(points); break; case LineCap.RoundAnchor: anchor = new SvgEllipseElement(0, 0, w, w); break; case LineCap.SquareAnchor: float ww = (w / 3) * 2; anchor = new SvgRectElement(0 - ww, 0 - ww, ww * 2, ww * 2); break; case LineCap.Custom: if (clc != null) { if (!ignoreUnsupportedLineCaps) throw new SvgGdiNotImpl("DrawEndAnchor custom"); } break; default: if (!ignoreUnsupportedLineCaps) throw new SvgGdiNotImpl("DrawEndAnchor " + lc.ToString()); break; } if (anchor == null) return; anchor.Id += "_line_anchor"; anchor.Style.Set("fill", new SvgColor(col)); anchor.Style.Set("stroke", "none"); Matrix rotation = new Matrix(); rotation.Rotate((angle / (float)Math.PI) * 180); Matrix translation = new Matrix(); translation.Translate(pt.X, pt.Y); anchor.Transform = new SvgTransformList(_transforms.Result.Clone()); anchor.Transform.Add(translation); anchor.Transform.Add(rotation); _cur.AddChild(anchor); }