I am using the OutlineTextControl that I found linked here somewhere and its great, however the outline gets drawn on the text instead of outside the text (like an outline). Is there any way to modify the class to do what I need?
Link to control code:
http://blogs.msdn.com/b/wpfsdk/archive/2006/12/24/using-text-as-a-decorative-graphic.aspx
Maybe there is an alternative way to do sharp outlines on text?
**Edit
I modified the class to draw the outline separately as below, and created a private variable in the class to hold my formatted text. This works almost perfect, the N letter has a little sharp point above it, and the W has a sharp point below as shown in my image, what would cause this?
drawingContext.DrawGeometry(null, new Pen(Stroker, StrokeThickness), _textGeometry);
drawingContext.DrawText(_formattedText, new Point(0, 0));
****Edit 2
Added the following code above the drawing code to define my stroke pen:
Pen pop = new Pen(Stroker, StrokeThickness);
pop.LineJoin = PenLineJoin.Round;
pop.MiterLimit = 10;
Now my outline is smooth and exactly what I wanted:
Added the following code above the drawing code to define my stroke pen:
Pen pop = new Pen(Stroker, StrokeThickness);
pop.LineJoin = PenLineJoin.Round;
pop.MiterLimit = 10;
Now my outline is smooth and exactly what I wanted:
Related
I'm using the Svg.Core library (version 3.0.49.2) to render SVGs (defined in strings) to PNG images. No matter what I do, any shape seems to be rendered with a black stroke and a black fill.
Here's the code I'm using for a simple rectangle, as an example:
var svgString = #"<svg width=""300"" height=""300"" xmlns=""http://www.w3.org/2000/svg"" xmlns:xlink=""http://www.w3.org/1999/xlink""><rect x=""5"" y=""5"" height=""90"" width=""50"" fill=""#ef0000"" stroke=""#00ef00"" /></svg>";
var svgDocument = SvgDocument.FromSvg<SvgDocument>(svgString);
var bitmap = svgDocument.Draw();
bitmap.Save(fileName, ImageFormat.Png);
which ends up rendering a rectangle of the correct height and width, but all black:
I've seen a number of posts that mention various versions of inlining styles, but regardless of whether I'm using a style="" approach or a fill="", the problem continues. Also seems to happen without fill color specified or using standard color names instead of RGB values.
Any help or ideas are appreciated!
The best answer I have come up with here is from the comment earlier. If you put the following around it: svgDoc.Color = new SvgColourServer(Color.DarkGreen); svgDoc.StopColor = new SvgColourServer(Color.DarkGreen); svgDoc.Stroke = new SvgColourServer(Color.DarkGreen); svgDoc.Fill = new SvgColourServer(Color.DarkGreen); , you will get colors in the SVG. Posting this as the answer in case anyone runs into this issue down the road.
I am currently working on a module to create charts to display data.
I use System.Windows.Forms.DataVisualization.Charting.Chart.
I have two striplines showing the the average result we got and another one showing what we want.
So far I was really happy with what I had but I want to add explicit arrow to point these lines. And I can't figure out how to do it.
I saw that Line Annotation might be of help but I couldn't find a way to do what I wanted.
Here is an example of what I would like to do :
You have a choice of using
Annotations or
GDI+ drawing
In both cases the challenge is to get the positions right.
The more natural way to go is using Annotations, so let's look at this first:
There are various types but different capabilities; text can be displayed by RectangleAnnotation or a TextAnnotation. Lines and arrowheads can only be displayed by LineAnnotations. So we need a pair of Line- plus TextAnnotation for each of your two lines.
Like many other chart elements annotations are positioned in percentages of their respective containers; this makes things rather tricky at times.
To place a line annotation all to the right of the chart you could set its X property to 100; to let it go to the left you set the width to a negative number. The problems are starting after that..
To find out where the right edge of the ChartArea is you need to code the Pre- or PostPaint event and use the ToRectangleF method.
To find out the y-value you will want to calculate it from a data value; for this you can use the AxisY.ValueToPixelPosition method, which converts to pixels, from which you can calculate the percantage using the chart's ClientArea along with the ChartArea percentage size.
Complicated? Yup. Annotations get a lot simpler to use if you can anchor them to a certain DataPoint; but yours are outside the ChartArea..
Here is a function that should help when doing the calculations:
double PercentFromValue(Chart chart, ChartArea ca, double value)
{
Axis ay = ca.AxisY;
RectangleF car = ca.Position.ToRectangleF();
double py = ay.ValueToPixelPosition(value);
int caHeight = (int)(chart.ClientRectangle.Height * car.Height / 100f);
return 100d * py / caHeight;
}
Note that it will only work reliably when called from of of the Pre/PostPaint events..
So this is an example of a PrePaint event that positions a LineAnnotation lAnn:
private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
{
Rectangle cr = chart1.ClientRectangle;
ChartArea ca = chart1.ChartAreas[0];
RectangleF car = ca.Position.ToRectangleF();
lAnn.Width = car.Width - lAnn.X;
lAnn.Y = PercentFromValue(chart1, ca, someDataValue);
}
When you insert a valid DataPoint YValue the starting y-position will be set. You can play with it until you find a nice combination of setting the four position properties..
When creating and adding the four(!) annotations you may want to keep class level references, so you won't have to refer to them from the Annotations collection..
For the LineAnnotation you will want to set the linewidth, color and the capstyle, either using the EndCap or the StartCap:
lAnn.EndCap = LineAnchorCapStyle.Arrow;
GDI+ drawing is more straight-forward, provided you know where you want to draw the lines and the text.
It is also done in the PrePaint event, again using the ValueToPixelPosition to find the pixelposition of the two data lines.. Other than that is all the usual stuff with Graphics.DrawLine, a Pen with and Start- or EndCap and Graphics.DrawString or maybe TextRenderer.DrawText..
I'm frankly not sure which way I would choose..
create triangle image and set the marker image as:
Chart1.Series.Points.AddXY(0, 10);
Chart1.Series.Points.AddXY(20,10);
Chart1.Series[0].Points[1].MarkerImage = "TriangleImage.bmp";
Chart1.Series[0].Points[1].MarkerImageTransparentColor = Color.White;
or
Chart1.Series[0].Points[1].MarkerStyle = MarkerStyle.Triangle;
Starting from a curve defined as a series of points drawn by the user (left in figure below), I would like to derive the points describing the area around that curve. To this end I'm using the Widen function from GraphisPath as shown here below:
PointF[] ComputeAreaAroundCurve(PointF[] curvePoints)
{
GraphicsPath gp = new GraphicsPath();
gp.AddLines(curvePoints);
using(Pen pen = new Pen(Color.Black, 10))
gp.Widen(pen);
return gp.PathPoints;
}
If I then draw the result, I obtain the figure to the right where of course the intersecting portion (red arrow) is not taken. Any idea of how to compute instead the PointF[] that when drawn would include that portion too?
The trick is to use two GraphicsPaths:
The first one is the one you use to get the outline points with the Widen call. It has to be in the (default) fillmode Alternate.
After you have returned the outline points opp you need to add them to a second GraphicsPath. This one must be set to FillMode.Winding.
The second GraphicsPath will fill the full outline including the crossing(s) and will also report points inside to be 'visible'..
gpWinding = new GraphicsPath();
gpWinding.FillMode = FillMode.Winding;
gpWinding.AddCurve(opp);
Now a MouseClick will work:
Text = gpWinding.IsVisible(e.Location) ? "Yes" : "No";
And filling it will fill all the outlined area:
e.Graphics.FillPath(Brushes.DarkKhaki, gpWinding );
e.Graphics.DrawPath(Pens.White, gpWinding );
I was wondering how PowerPoint slides can be automatically annotated using digital ink in .NET (using c#). Currently, I'm doing the same thing using free-form shapes, which is straightforward but has some issues. When selecting Office.MsoEditingType.msoEditingAuto as an editing type, the free-forms are smooth, but when constructing them and then converting into a shape (when consisting of more than a couple of points) takes a very long time (the following method would take ca 5s!)
PowerPoint.Shape Shape = builder.ConvertToShape();
When using Office.MsoEditingType.msoEditingCorner, the shape is generated much quicker, but the resulting shapes are jagged (surprise!).
I found the following code sample for doing the same using digital ink:
DrawingAttributes drawingAttributes1 = new DrawingAttributes();
drawingAttributes1.Color = Colors.Green;
StylusPoint stylusPoint1 = new StylusPoint(100, 100);
StylusPoint stylusPoint2 = new StylusPoint(100, 200);
StylusPoint stylusPoint3 = new StylusPoint(200, 200);
StylusPoint stylusPoint4 = new StylusPoint(200, 100);
StylusPoint stylusPoint5 = new StylusPoint(100, 100);
StylusPointCollection points = new StylusPointCollection(
new StylusPoint[] { stylusPoint1, stylusPoint2, stylusPoint3,
stylusPoint4, stylusPoint5 });
Stroke newStroke = new Stroke(points, drawingAttributes1);
InkPresenter inkPres = new InkPresenter();
inkPres.Strokes.Add(newStroke);
However, not being a PowerPoint Add-in expert (hardly even a beginner, actually), I don't know how to attach the inkpresenter to the current slide. Ideally, a new inkpresenter would be created & kept per slide (so I don't have to worry about re-drawing on each slide navigation)
I understood it's possible to create an ink canvas using the designer, and then drawing on that, but would that canvas then be attached to the entire presentation or just the current slide? And would it allow users to draw on the canvas (which is not the goal; drawing would be done automatically)?
I spent quite some time looking for relevant code samples, but none of them seemed to do what I am intending. For instance, as mentioned, I'm not planning to allow users to draw on the slide, but automatically annotating the slide.
Thanks,
William
You are my only hope. I have searched everywhere and just can't find anything that could help me with this one.
I've done a simple code marking plugin for Visual Studio (2010). It just finds some parts of code to highlight (by Regex), creates Spans out of the matches found and then creates Rectangle adornments for them (in the background of the text), that scroll with the text. All of this is done in view.LayoutChanged event's implementation. It works fine... but... NOT EVERY TIME! Sometimes the markers get moved by various distances (mostly up or down) and then just keep these incorrect positions while the text is scrolled. I have no idea why and WHEN this happens. I was able to discover only these few things:
you can reproduce this bug (move some markers from their correct positions) by dragging the vertical scrollbar of the code editor window very fast and agresively up and down (but sometimes it also fixes the positions...)
you cannot fix a marker's position by editing the line on which it is placed (or even the marked text)
you can fix the marker's position by deleting and restoring the ending "}" of the code block in which the marked code is placed (which causes the whole block of code to be reformatted)
the view.ViewportTop is negative when the positions are calculated incorrectly (view is a WpfTextView class) and the Geometry "g" (see below) is getting the negative Bounds.Top too. (You can test it by attaching one VS to another and set a breakpoint)
Here is the piece of my code that calculates the positions and creates the markers (LayoutChanged event):
Geometry g = textViewLines.GetMarkerGeometry(span);
if (g != null)
{
GeometryDrawing drawing = new GeometryDrawing(_brush, _pen, g);
drawing.Freeze();
DrawingImage drawingImage = new DrawingImage(drawing);
drawingImage.Freeze();
Image image = new Image();
image.Source = drawingImage;
//Align the image with the top of the bounds of the text geometry
Canvas.SetLeft(image, g.Bounds.Left);
Canvas.SetTop(image, g.Bounds.Top);
//_layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);
Rect rect = new Rect(g.Bounds.Location, g.Bounds.Size);
Rectangle marker = new Rectangle();
marker.Margin = new Thickness(rect.X - 3, rect.Y - 2, 0, 0);
marker.Width = rect.Width + 6; marker.Height = rect.Height + 4;
marker.Fill = new SolidColorBrush(mark);
marker.RadiusX = marker.RadiusY = 5;
marker.Stroke = new SolidColorBrush(color);
_layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, marker, null);
}
This is basically the MSDN example for creating adornments, I'm not doing any magic here.
Please help!
I had the same problem. If you use
_layer.AddAdornment(AdornmentPositioningBehavior.TextRelative,...);
more then once you have to insert
Canvas.SetLeft(image, g.Bounds.Left);
Canvas.SetTop(image, g.Bounds.Top);
every time before.
I've just spent the whole day on similar issue.
There're a lot of undocumented corner cases besides span moving issue. Even worse, seems-to-be-proven solution tend to break in never VS version (especially, starting with roslyn and VS2015). My favorite one was the following: the adornments were removed occasionally if you press enter multiple times inside a multiline comment. Hilarious!
So, the only working approach is the following: don't try to outsmart VS editor, it'll fool you anyway.
Instead, borrow the code from the roslyn's AdornmentManager<T>. It contains a lot of hacks I had to reinvent and even more I didn't ever suspect about, but it works. All you need to do is replace the code below
// add the visual to the adornment layer.
with yours one (the part is a good candidate to refactor into overridable method).
P.S. I know that I'm slightly late :) Hope this will save some time to another poor soul.