WPF to XPS Very Slow - c#

Hello We are trying to create a custom template system based such as WPF Header and Footer elements, with a canvas for 2D Drawings for export to PDF. The problem is the XpsWriter takes about 7 seconds to write the XPS Document, and another 3 Seconds to convert to pdf with PDFSharp. We need to get this down as the user waits for the PDF. I first suspected its due to the number of FrameworkElements in the, but there are only 5000. The framework elements are mostly PATH data with fills, strokes, and brushes.
Canvas ComplexCanvas = new Canvas();
ComplexCanvas.Children.Add(5000Elements);
System.Windows.Documents.FixedDocument fixedDoc = new System.Windows.Documents.FixedDocument();
System.Windows.Documents.PageContent pageContent = new System.Windows.Documents.PageContent();
System.Windows.Documents.FixedPage fixedPage = new System.Windows.Documents.FixedPage();
//Create first page of document
fixedPage.Children.Add(ComplexCanvas);
fixedPage.Width = PageWidth;
fixedPage.Height = PageHeight;
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
System.Windows.Xps.Packaging.XpsDocument xpsd = new XpsDocument(Path, System.IO.FileAccess.Write);
System.Windows.Xps.XpsDocumentWriter xw = XpsDocument.CreateXpsDocumentWriter(xpsd);
xw.Write(fixedDoc);
xpsd.Close();
Does anyone know a way to speed this up? Perhaps some type Visual Object, or "Flatten" the Canvas somehow or any ideas. When it does work the PDF is over 5MB.
Would like to keep it VECTOR as much as possible

There are several ways to speed up the conversion from WPF to XPS to PDF:-
Freeze any pens or brushes as this will speed up rendering:-
SolidColorBrush brush = new SolidColorBrush(Colors.PaleGreen);
brush.Opacity = .25d;
brush.Freeze();
Pen paleGreenPen = new Pen(brush, 1);
paleGreenPen.Freeze();
Pen linePen = new Pen(Brushes.Red, 1);
linePen.Freeze();
Render in the background (create a background UI thread).
Do not save the interim XPS document to disk but use a MemoryStream.

Related

Rendering WPF to PNG produces blank image

I am trying to render a figure to a PNG using WPF (rather than the old GDI API) and the result is always blank.
I am writing a small program that will produce images routes around a warehouse to various items. I am using WPF API for drawing rather than the old GDI API as the images need to be both saved to disk and displayed within a WPF application. The problem is that all of the png files that it produces are currently entirely black.
To reduce the scope of the problem and prove that it was not a problem with code for drawing the map I made a minimal test method that should simply render a red circle on a black background. However the result is still an entirely black.
[TestMethod]
public void DrawingTest()
{
//define the dimensions of the test image
int width = 100;
int height = 100;
int dpi = 100;
//define where the image should be saved
var path = #"C:\temp\DrawingTest.png";
//create a bitmap to render the image into
RenderTargetBitmap bitmap = new RenderTargetBitmap(
width, height, dpi, dpi, PixelFormats.Default);
//create a drawing context to draw the image onto
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext canvas = drawingVisual.RenderOpen())
{
//draw a circle
canvas.DrawEllipse(Brushes.Red, new Pen(Brushes.Red, 1), new System.Windows.Point(50, 50), 50, 50);
//render the image into a bitmap
bitmap.Render(drawingVisual);
}
//create the file encoder
var encoder = new PngBitmapEncoder();
//encode the bitmap in PNG format
encoder.Frames.Clear();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
//make sure that the file can be saved in this location
var directory = System.IO.Path.GetDirectoryName(path);
if (!System.IO.Directory.Exists(directory))
System.IO.Directory.CreateDirectory(directory);
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
//save the map to file
using (var stream = System.IO.File.Create(path))
encoder.Save(stream);
}
The test method runs without any errors and produces a png file at the location that I expected. However, this file is simply a black square rather than the red circle in a black square that I was expecting. Can anybody tell me why it is just rendering a black image, and what I can do to make it show the red circle.
You have to call bitmap.Render(drawingVisual) after the DrawingContext is closed.
From the Remarks on DrawingContext.Close:
A DrawingContext must be closed before its content can be rendered ...
So just move the Render call outside the using block:
using (DrawingContext dc = drawingVisual.RenderOpen())
{
dc.DrawEllipse(Brushes.Red, new Pen(Brushes.Red, 1),
new System.Windows.Point(50, 50), 50, 50);
}
bitmap.Render(drawingVisual);
Besides that, the red Pen seems redundant, since the circle is already filled red. So this should be ok:
dc.DrawEllipse(Brushes.Red, null, new System.Windows.Point(50, 50), 50, 50);
Also make sure to create the bitmap with a DPI value of 96, which corresponds to WPF device-independent units. Otherwise you would have to scale the drawing appropriately.
One and a half year later I faced the same problem - how to properly render a canvas without displaying it in the screen.
The solution was simpler than I thought and produces exactly the result one expects.
Long story short - to render the canvas without displaying it call Arrange(Rect finalRect) method on your canvas:
canvas.Arrange(new Rect(new Size(width, height)));
According to the documentation it:
Positions child elements and determines a size for a UIElement. Parent elements call this method from their ArrangeCore(Rect) implementation (or a WPF framework-level equivalent) to form a recursive layout update. This method constitutes the second pass of a layout update.

Using Digital Ink in PowerPoint .NET

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

How Can I make my PDF exactly fit within 4x6 inches? currently It is printing in regular A4 document

I am creating Shipping Label using iTextSharp.
What I am doing is Creating a Label in PDF so I can format it in any way I want and then send it to my THERMAL PRINTER.
My problem is, My labels are of size 4x6 (standard shipping label). These are the labels which we see on UPS & Fedex Packages. How Can i make my PDF exactly fit within 4x6 inches? currently It is printing in regular A4 document.
I am using following:
Dim document As New Document()
document.SetPageSize(PageSize.A4_LANDSCAPE)
Set a Custom Page Size:
Dim pgSize As New iTextSharp.text.Rectangle(myWidth, myHeight)
Dim doc As New iTextSharp.text.Document(pgSize, leftMargin, rightMargin, topMargin, bottomMargin)
iTextSharp uses 72 pixels per inch, so if you know the height and width of your desired page size in inches, just multiply those numbers by 72 to get myWidth and myHeight.
https://stackoverflow.com/a/2503476/102937
I would recommend producing raw printer language. Thermal bar code printers all have a native language. Languages such as ZPLII (Zebra Printer Language 2) or DPL (Datamax Printer Language). You can build them as a string and pass them directly to the printer. Searching the printer manufactures website you can quickly find the printer language manual for the printer you are using.
The great advantage to this method is control and speed. As Zebras and Datamax printers do not actually care about a page size you can focus on rendering the data you want in the size and orientation you want.
You may also be able to take advantage of some of the extra logic that the printers have. This is especially useful for serialized tags with sequential numbering. A single string sent to the printer can produce dozens to hundreds of labels. If you are going to do a lot of thermal bar code printing I strongly recommend understanding the power these printers contain in their native languages.
To Set document size use like this:-
Document doc = new Document(new iTextSharp.text.Rectangle(295f, 420f), 0f, 0f, 0f, 0f);
PdfWriter.GetInstance(doc, Response.OutputStream);
doc.Open();
-----------
-----
---------
For font here is code:-
iTextSharp.text.Font myFont1 = new iTextSharp.text.Font() { Size = 4.5f };
PdfPTable header1 = new PdfPTable(2);
header1.AddCell(new PdfPCell(new Phrase("", myFont1 )) { UseAscender = true, PaddingTop = 0, Border = 0, HorizontalAlignment = 0 });
i have just added other property's for you information future use.
happy coding!!

Exporting a transparent TChart PNG distorts text

I'm using Steema TeeChart v4.1.2010.11303. I want to export a chart to a PNG image with a transparent background.
The resulting image has "distorted" or bold text in the left and bottom axis and in the header. It looks like being rendered with a raster font with a too low resolution. The legend on the right on the other hand looks fine:
The following sample code can be used to reproduce the problem:
TChart tChart = new TChart();
tChart.Aspect.View3D = false;
tChart.Panel.Brush.Gradient.Visible = false;
// Make the background of the chart transparent.
tChart.Panel.Transparent = true;
Steema.TeeChart.Styles.Bar series1 = new Steema.TeeChart.Styles.Bar( tChart.Chart );
series1.FillSampleValues();
tChart.Draw();
tChart.Graphics3D.BufferStyle = Steema.TeeChart.Drawing.BufferStyle.None;
using ( System.IO.Stream stream = new System.IO.MemoryStream() )
{
tChart.Export.Image.PNG.Width = m_PictureBox.Width;
tChart.Export.Image.PNG.Height = m_PictureBox.Height;
tChart.Export.Image.PNG.Save( stream );
// Show the bitmap in a Windows Forms PictureBox.
// Alternatively, it can also be saved in a file, which makes no difference.
PictureBox.Image = new Bitmap( stream );
}
When switching off the transparency with tChart.Panel.Transparent = false;, all text looks fine. However, I need a transparent background.
Is this a bug in TeeChart or am I missing something?
It is a know behavior for us and we haven't found a good solution for this problem, for the moment. If we will find a solution that we consider correct or we will arrive an interesting conclusion about problem of png export, we will inform you immediatly.
Thanks.
Best Regard,
Sandra Pazos

.NET set image display size

I am using some custom controls one of which is a tooltip controller that can display images, so I am using th ebelow code to instantiate it:
Image newImage = Image.FromFile(imagePath);
e.ToolTipImage = newImage;
obviously could inline it but just testing at the moment. The trouble is the image is sometimes the wrong size, is there a way to set the display size. The only way I can currently see is editing the image using GDI+ or something like that. Seems like a lot of extra processing when I am only wanting to adjust display size not affect the actual image.
Once you have an image object loaded from its source, the Height and Width (and Size, and all ancillary properties) are read-only. Therefore, you are stuck with GDI+ methods for resizing it in RAM and then displaying it accordingly.
There are a lot of approaches you can take, but if you were to encapsulate that out to a library which you could reuse should this problem occur again, you'll be set to go. This isn't exactly optimized (IE, may have some bugs), but should give you an idea of how to approach it:
Image newImage = Image.FromFile(myFilePath);
Size outputSize = new Size(200, 200);
Bitmap backgroundBitmap = new Bitmap(outputSize.Width, outputSize.Height);
using (Bitmap tempBitmap = new Bitmap(newImage))
{
using (Graphics g = Graphics.FromImage(backgroundBitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Get the set of points that determine our rectangle for resizing.
Point[] corners = {
new Point(0, 0),
new Point(backgroundBitmap.Width, 0),
new Point(0, backgroundBitmap.Height)
};
g.DrawImage(tempBitmap, corners);
}
}
this.BackgroundImage = backgroundBitmap;
I did test this, and it worked. (It created a 200x200 resized version of one of my desktop wallpapers, then set that as the background image of the main form in a scratch WinForms project. You'll need using statements for System.Drawing and System.Drawing.Drawing2D.
In Winforms, if you contain the image inside a PictureBox control, the PictureBox control can be set to zoom to a particular height/width, and the image should conform.
At least that's what happened in my Head First C# book when I did the exercise.

Categories

Resources