I am trying to save InkCanvas , InkStorkes as a SVG. I found a previous question that works for Wpf,but I have been unable to get it to work with uwp. Wpf InkCanvas save stokes as svg
. I made some changes to it, but I am running into issues with GetGrometry and XamlWriter.
var svg = new SvgDocument();
var colorServer = new SvgColourServer(System.Drawing.Color.Black);
var group = new SvgGroup { Fill = colorServer, Stroke = colorServer };
svg.Children.Add(group);
foreach (var stroke in inkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
var geometry = stroke.GetGeometry(stroke.DrawingAttributes).GetOutlinedPathGeometry();
var s = XamlWriter.Save(geometry);
if (s.IsNotNullOrEmpty())
{
var element = XElement.Parse(s);
var data = element.Attribute("Figures")?.Value;
if (data.IsNotNullOrEmpty())
{
group.Children.Add(new SvgPath
{
PathData = SvgPathBuilder.Parse(data),
Fill = colorServer,
Stroke = colorServer
});
}
}
}
I implemented an approach from the comments Xavier Xie - MSFT.
The main idea was to use own implementation of ICanvasPathReceiver interface - here is CanvasGeometryToSvgPathReader class:
var svgDocument = new CanvasSvgDocument(canvasDevice);
foreach (var stroke in InkCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
var canvasGeometry = CanvasGeometry.CreateInk(drawingSession, new[] {stroke});
var pathReceiver = new CanvasGeometryToSvgPathReader();
canvasGeometry.SendPathTo(pathReceiver);
var element = svgDocument.Root.CreateAndAppendNamedChildElement("path");
element.SetStringAttribute("d", pathReceiver.Path);
element.SetColorAttribute("fill", stroke.DrawingAttributes.Color);
}
As result ballpoint pen renders fine, highlighter worse and pencil doesn't render.
Full source code: https://github.com/ycherkes/InkToSvg
Related
I am trying to calculate the average(mean) color of a superpixel without luck, I am using the astronaut image as an example and want to display the last image as result, I would really appreciate it if someone can help.
using OpenCvSharp;
using OpenCvSharp.XImgProc;
var imgPath = "C:\\img";
var imgName = "astronaut.png";
var imgFullPath = Path.Combine(imgPath, imgName);
var bgrImage = Cv2.ImRead(imgFullPath, ImreadModes.Color);
var hsvImage = new Mat();
Cv2.CvtColor(bgrImage, hsvImage, ColorConversionCodes.BGR2HSV);
var superpixelSLIC = SuperpixelSLIC.Create(bgrImage, SLICType.SLIC, 75);
superpixelSLIC.Iterate();
superpixelSLIC.EnforceLabelConnectivity();
var numberOfSuperpixels = superpixelSLIC.GetNumberOfSuperpixels();
var labels = new Mat(bgrImage.Size(), MatType.CV_32SC1);
superpixelSLIC.GetLabels(labels);
using var labelContourMask = new Mat();
superpixelSLIC.GetLabelContourMask(labelContourMask);
Cv2.ImShow("labelContourMask", labelContourMask);
Cv2.ImShow("bgrImage", bgrImage);
Cv2.WaitKey();
Cv2.DestroyAllWindows();
Input image
Expected result
I tried to display the labels but getting an error, I am not sure if displaying the labels is needed but I tried it anyway
Cv2.ImShow("labels", labels);
Cv2.WaitKey();
Cv2.DestroyAllWindows();
I'm using the DexExpress.Xpf.Map.v15.1 MapControl and trying to create code that will be able to run in a Windows Service (i.e. no front end) to generate maps as images.
I have the following code which creates a map, adds GeoPoints to a PolyLine and then adds that PolyLine to a map. This works fine in my WPF test harness application:
public MapWindow1()
{
InitializeComponent();
var mapControl = new MapControl
{
Name = "TheMap",
ZoomLevel = 4,
CenterPoint = new GeoPoint(47, 5)
};
var imageLayer = new ImageTilesLayer
{
DataProvider = new OpenStreetMapDataProvider()
};
mapControl.Layers.Add(imageLayer);
var vectorLayer = new VectorLayer();
mapControl.Layers.Add(vectorLayer);
var mapItemStorage = new MapItemStorage();
vectorLayer.Data = mapItemStorage;
var polyLineCollection = DbfGenerator.GeneratePolyLineCollection();
polyLineCollection.ForEach(line =>
{
var mapItem = new MapPolyline();
mapItemStorage.Items.Add(mapItem);
mapItem.Points.AddRange(line);
});
mapControl.MouseDoubleClick += mapControl_MouseDoubleClick;
MainGrid.Children.Add(mapControl);
}
This runs and adds the map control to the WPF page without a problem. I've then added double click handler to export the map as an image:
void mapControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var m = GenerateMapPng((MapControl) sender);
m.Save(#"C:\0Temp\test.bmp");
}
public Bitmap GenerateMapPng(MapControl map)
{
Bitmap bmp;
// export image from map
using (MemoryStream ms = new MemoryStream())
{
var exportOptions = new ImageExportOptions(ImageFormat.Png);
map.ExportToImage(ms, exportOptions);
ms.Position = 0;
bmp = new Bitmap(System.Drawing.Image.FromStream(ms));
}
return bmp;
}
Again - this works without a problem.
However, If I remove the UI element and run the following code:
public MapWindow1()
{
InitializeComponent();
var mapControl = new MapControl
{
Name = "TheMap",
ZoomLevel = 4,
CenterPoint = new GeoPoint(47, 5)
};
var imageLayer = new ImageTilesLayer
{
DataProvider = new OpenStreetMapDataProvider()
};
mapControl.Layers.Add(imageLayer);
var vectorLayer = new VectorLayer();
mapControl.Layers.Add(vectorLayer);
var mapItemStorage = new MapItemStorage();
vectorLayer.Data = mapItemStorage;
var polyLineCollection = DbfGenerator.GeneratePolyLineCollection();
polyLineCollection.ForEach(line =>
{
var mapItem = new MapPolyline();
mapItemStorage.Items.Add(mapItem);
mapItem.Points.AddRange(line);
});
var m = GenerateMapPng(mapControl);
m.Save(#"C:\0Temp\test.bmp");
}
I get a NullReferenceException on the "map.ExportToImage(ms, exportOptions);" line.
I'm assuming that when the WPF application loads it calls a method to initialise the map, but I can't find anything that I can manually do to the control (Load/Init method) to mimic this.
Is there a way to trick the MapControl in to thinking it is in a WPF page when it isn't?
DevExpress said that this was not possible due to the maps reliance on the UI Thread in WPF
I'm trying to generate Word documents using OpenXML SDK and Word Document Generator. I need to apply my custom style on ContentControls (Repeating Section).
For Recursive Placeholders, I use
foreach (var item in list)
{
var datacontext = new OpenXmlElementDataContext()
{
Element = openXmlElementDataContext.Element,
DataContext = item.Value
};
var clonedElement = CloneElementAndSetContentInPlaceholders(datacontext);
SetContentOfContentControl(clonedElement, item.Value);
}
openXmlElementDataContext.Element.Remove();
I need to apply my style on this element. How to I can do ?
I try to see generated code with "Open XML SDK 2.5 Productivity Tool for Microsoft Office" to inspire me:
var moduleDatacontext = new OpenXmlElementDataContext()
{
Element = openXmlElementDataContext.Element,
DataContext = module.Valeur
};
var moduleClonedElement = CloneElementAndSetContentInPlaceholders(moduleDatacontext);
var sdtProperties1 = new SdtProperties();
var styleId1 = new StyleId() { Val = "FormationTitre2" };
ParagraphMarkRunProperties paragraphMarkRunProperties1 = new ParagraphMarkRunProperties();
RunFonts runFonts1 = new RunFonts() { ComplexScriptTheme = ThemeFontValues.MinorHighAnsi };
paragraphMarkRunProperties1.Append(runFonts1);
sdtProperties1.Append(styleId1);
sdtProperties1.Append(paragraphMarkRunProperties1);
Run run1 = new Run() { RsidRunProperties = "00C463E5" };
RunProperties runProperties1 = new RunProperties();
RunFonts runFonts2 = new RunFonts() { ComplexScriptTheme = ThemeFontValues.MinorHighAnsi };
runProperties1.Append(runFonts2);
run1.Append(runProperties1);
moduleClonedElement.Append(sdtProperties1);
moduleClonedElement.Append(run1);
When I open the generated document, I have this error :
We're sorry. We can't open "...docx" because we found a problem with its contents.
I validate the document and I can see 15 errors:
Full Size
I've found the solution. I search first paragraph and apply my custom style on it.
// clone element
var clonedElement = CloneElementAndSetContentInPlaceholders(datacontext);
// search the first created paragraph on my clonedElement
Paragraph p = clonedElement.Descendants<Paragraph>().FirstOrDefault();
if (p != null)
p.PrependChild<ParagraphProperties>(new ParagraphProperties());
// get the paragraph properties
ParagraphProperties pPr = p.Elements<ParagraphProperties>().First();
// apply style
pPr.ParagraphStyleId = new ParagraphStyleId { Val = "FormationTitre2" };
// set content of content control
SetContentOfContentControl(clonedElement, item.Value);
Hello i am using windows map control described in this link and i have a MapLayer with multiple MapOverlays with differents pois on map. And i want to do the clustering thing. I try to do this but no ClusteringLayer exist and no Pushpin. How can i do the clustering?
var cluster = new ClusteringLayer();
layer = new ClusteringLayer(Mymap)
{
ClusterRadius = 10,
ClusterType = ClusteringType.Grid
};
//Add event handlers to create the pushpins
layer.CreateClusteredItemPushpin += CreateClusteredItemPushpin1;
layer.CreateItemPushpin+=layer_CreateItemPushpin;
private MapOverlay layer_CreateItemPushpin(object item, ClusteredPoint clusterInfo)
{
var x = clusterInfo.Location;
var poi = new BuildingPoi { Coordinate = x, Buid = _selectedBuild };
var imagePoiLocation = new Image
{
Source = new BitmapImage(new Uri("/Assets/MapPin.png", UriKind.Relative)),
DataContext = poi
};
var over = new MapOverlay();
imagePoiLocation.Tap += loadClickedBuilding;
over.Content = imagePoiLocation;
over.PositionOrigin = new Point(0.5, 0.5);
over.GeoCoordinate = new GeoCoordinate(x.Latitude, x.Longitude);
return over;
}
private MapOverlay CreateClusteredItemPushpin1(ClusteredPoint clusterInfo)
{
var x = clusterInfo.Location;
var poi = new BuildingPoi { Coordinate = x, Buid = _selectedBuild };
var imagePoiLocation = new Image
{
Source = new BitmapImage(new Uri("/Assets/MapPin.png", UriKind.Relative)),
DataContext = poi
};
var over = new MapOverlay();
imagePoiLocation.Tap += loadClickedBuilding;
over.Content = imagePoiLocation;
over.PositionOrigin = new Point(0.5, 0.5);
over.GeoCoordinate = new GeoCoordinate(x.Latitude, x.Longitude);
return over;
}
As they don't have any nuget package or dll to reference directly, you need to download the source code of specific classes like ClusteringLayer & PushPin with related .cs files or the project itself to your machine and add reference of this project in your windows phone project to get ClusteringLayer and PushPin classes.
See following screenshot for ClusteringLayer class. For other classes, just import the solution to visual studio and you will see source code of all the classes. BTW, ClusteringLayer constructor need at-least one argument in cluster.
I advice you to download source code and get familiar with it's usage from samples in source code.
I have a WPF Form ,I need to print it ,i use DocumentViewer to print. but when I want to Print it or Preview , I only See the first page while i have more than one page
private void Print(object sender, RoutedEventArgs e)
{
PrintSettings printSettings = PrintSettings.Default;
UIElement container = this.Content as UIElement;
ScrollViewer containerPanel = Helper.FindVisualChildren<ScrollViewer>(container).FirstOrDefault();
var origParentDirection = containerPanel.FlowDirection;
var origDirection = (containerPanel.Content as FrameworkElement).FlowDirection;
if (containerPanel != null && containerPanel.FlowDirection == FlowDirection.RightToLeft)
{
containerPanel.FlowDirection = FlowDirection.LeftToRight;
(containerPanel.Content as FrameworkElement).FlowDirection = FlowDirection.RightToLeft;
}
var window = new Window();
string tempFileName = System.IO.Path.GetTempFileName();
System.IO.File.Delete(tempFileName);
using (XpsDocument xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite, System.IO.Packaging.CompressionOption.Fast))
{
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
(containerPanel.Content as FrameworkElement).Margin = new Thickness(20);
writer.Write((containerPanel.Content as FrameworkElement), printSettings.PrintTicket);
var doc = xpsDocument.GetFixedDocumentSequence();
doc.PrintTicket = printSettings.PrintTicket;
window.FlowDirection = System.Windows.FlowDirection.RightToLeft;
window.Content = new DocumentViewer { Document = doc };
window.Margin = new Thickness(10);
window.ShowDialog();
}
(containerPanel.Content as FrameworkElement).FlowDirection = origDirection;
containerPanel.FlowDirection = origParentDirection;
}
user1780436, I am currently looking for a similar answer. You are trying to print a panel, correct?
I am finding that scaling the element is the biggest problem. Which brings another issue with scaling what you want to print and not the actual visible element. You will have to copy the element to a new element.
public class Copy<T>
{
public static T DeepCopy<T>(T element)
{
string xaml = XamlWriter.Save(element);
StringReader xamlString = new StringReader(xaml);
XmlTextReader xmlTextReader = new XmlTextReader(xamlString);
var DeepCopyobject = (T)XamlReader.Load(xmlTextReader);
return DeepCopyobject;
}
}
or
myNewElement = XamlReader.Parse(XamlWriter.Save(myOldElement.DataContext)) as ElementType
I have found this answer repeatedly on multiple sites to copy/clone an element, but I have had issues with string xaml = XamlWriter.Save(element); causing stackoverflows.
I am currently using.
myNewElement = new ElementType() { DataContext = myOldElement.DataContext }
Either one you use there becomes the issue of changing the size of the Element. This is what I am looking for.
I tried a rendering pass, but that just pointed out that in my situation to use a copied/cloned element. Although while writing this I did get some of it to work, but gives me a black image, note I am trying to scale a Chart.
myNewElement.Width = newWidth;
myNewElement.Height = newHeight;
myNewElement.Measure(new System.Windows.Size(newWidth, newHeight));
myNewElement.Arrange(new Rect(0, 0, newWidth, newHeight));
I tried a layout pass, and didn't get it.
I am going to keep working on mine and I will post anything new I find. Please do the same if you find the answer.
Edit - Here is what I did. My problem and solution