Saving a scrollable panel in PDF format using .NET

I have a dashboard filled with many user controls. These include text fields, check boxes, radio buttons, etc. This is a long form to fill in, so the controls are located in a scrollable panel. I need to save the entire panel in pdf format. I think that PDFsharp is a good library that allows you to save any text or image in pdf format, but I do not want to write code for each control inside the panel. I once wrote a class to create a PDF file from a Control object. He iterated over all the internal controls (and their internal controls until there was no internal control) of that control and wrote their Text property (yes / no for chekable controls) in pdf using their Location and Size properties. I could not find it now, but I remember that it had problems with some DevExpress controls that I used, so I did not write it again. (Edit: I had to, you can find it below.) I think I’m taking a picture and saving this image in pdf format, but I couldn’t figure out how to achieve it. This question seems to him, but there is no satisfactory answer to it.

So, a screenshot or not. I am open to any advice. There should be many cases where users must fill out long forms and be able to store them in pdf format. Again, any advice or workaround would be appreciated. (I am thinking of creating a form using html, displaying it in a WebBrowser control and using the html library in pdf, but I really prefer to use an existing form)

Thank you very much.


Edit: I had to write something to iterate the internal container controls (like a panel) and write each internal control in pdf using their Location, Size and Font properties, although I do not recommend using it (at least that's the way it is and there is) because of this:

  • It sets the page size for a given control size and uses only one (usually huge) pdf page. You can add logic to divide it into pages if you need to. (I did not do this, but probably you will probably need your PDF file to print).
  • The Cheeso method (using FlowDocument) is a much more legitimate way to do this. I prefer to use this, but in this case I had no choice.

In this code, I used PDFsharp. You can find it in this hompage or this is a CodePlex page .

PdfReport Class:

private PdfDocument Document; public Control Control { get; private set; } public PdfReport(Control control) { Control = control; } public PdfDocument CreatePdf(PdfDocument document = null) { Document = document != null ? document : new PdfDocument(); PdfPage page = Document.AddPage(); page.Height = Control.Height; page.Width = Control.Width; XGraphics gfx = XGraphics.FromPdfPage(page); foreach (PdfItem item in CreatePdf(new Point(0, 0), Control.Controls)) { XStringFormat format = item.IsContainer ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.BottomCenter ? XStringFormats.BottomCenter : item.TextAlign == ContentAlignment.TopLeft ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.TopCenter ? XStringFormats.TopCenter : XStringFormats.Center; gfx.DrawString(item.Text, item.Font, item.Brush, new XRect(item.Location, item.Size), format); } return Document; } private IEnumerable<PdfItem> CreatePdf(Point location, Control.ControlCollection controls) { List<PdfItem> items = new List<PdfItem>(); foreach (Control control in controls) { if (control.Controls.Count > 0) items.AddRange(CreatePdf(control.Location, control.Controls)); items.Add(new PdfItem(control, location)); } return items; } public void SaveAsPdf(string path, bool open = false) { CreatePdf().Save(path); if (open) Process.Start(path); } 

PdfItem Class:

  public string Text { get; set; } public Point Location { get; set; } public Size Size { get; set; } public Font Font { get; set; } public bool IsContainer { get; set; } public ContentAlignment TextAlign { get; set; } public Color ForeColor { get; set; } public XBrush Brush { get { return new SolidBrush(ForeColor); } } public PdfItem() { } public PdfItem(string text, Point location, Font font, Color foreColor, Size size, bool isContainer = false, ContentAlignment alignment = ContentAlignment.MiddleCenter) { Text = text; Location = location; Size = size; Font = new Font(font.FontFamily, font.Size, font.Style, GraphicsUnit.World); TextAlign = alignment; ForeColor = foreColor; IsContainer = isContainer; } public PdfItem(string text, Point location, Size size) : this(text, location, new Font("Calibri", 12), Color.Black, size) { } public PdfItem(Control control, Point parentLocation) : this(control.Text, control.Location, control.Font, control.ForeColor, control.Size, control.Controls.Count > 0) { Location = new Point(Location.X + parentLocation.X, Location.Y + parentLocation.Y); IEnumerable<PropertyInfo> properties = control.GetType().GetProperties(); if (properties.FirstOrDefault(p => p.Name == "TextAlign" && p.PropertyType == typeof(ContentAlignment)) != null) TextAlign = (control as dynamic).TextAlign; if (properties.FirstOrDefault(p => p.Name == "Checked" && p.PropertyType == typeof(bool)) != null) { string title = control.Text != null && control.Text.Length > 0 ? string.Format("{0}: ", control.Text) : string.Empty; Text = string.Format("{0}{1}", title, (control as dynamic).Checked ? "Yes" : "No"); } } 
+4
source share
3 answers

Relatively

. I think I’m taking a screenshot and saving this image in pdf format, but I couldn’t figure out how to achieve it.

There is a tool called cropper available on codeplex.com. It is intended to be used as a user tool that can take screenshots. It is open source managed code.

I can imagine how to put some cropping magic into your application so that you can take this screenshot. I can also imagine that it would be useful to collect a diagnostic screen image during a problem.

On the other hand ... if you are interested in creating a print form that reproduces content on the screen, then I think you should use WPF, and in this case, doing what you want is pretty easy. For example, this question describes how to do a print preview for a FlowDocument. From now on, your user can print to PDF (if they have a PDF printer installed) or print to XPS or print to a physical output device, etc.

+2
source

I don’t know if this would help you or not, but DocRaptor.com pdf api could be built so that it does it for you, no matter what the user enters. It uses basic html.

+1
source

How can you use below :)

 YourPanel.AutoSize = true; int width = YourPanel.Size.Width; int height = YourPanel.Size.Height; Bitmap bm = new Bitmap(width, height); YourPanel.DrawToBitmap(bm, new Rectangle(0, 0, width, height)); string outputFileName = @"C:\YourDirectory/myimage.bmp"; using (MemoryStream memory = new MemoryStream()) { using (FileStream fs = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite)) { bm.Save(memory, ImageFormat.Bmp); Clipboard.SetImage(bm); byte[] bytes = memory.ToArray(); fs.Write(bytes, 0, bytes.Length); } } YourPanel.AutoSize = false; 

Clipboard.SetImage will send you bm to the clipboard so you can paste them into your pdf form or any document

It also has an example inline that saves it as an image for you if you want.

The trick here is auto-creation for your dashboard. It must be set to true so that the panel changes by itself, as a visible area, and then right after completing your work, you can resize it to false to use the scrollbars again for the user screen (you can see that it is blinking in for half a second, but this code really works.

Saving it to PDF, I personally simply prefer to write it there as my clipboard, or you can write a byte. But ITextSharp is a great extension library to work with!

I really hope this helps.

0
source

All Articles