Introduction
I've seen many questions on the internet concerning saving an active screen to PDF-file. While I was searching for a solution to save a Winform
as a PDF
-file, I found a solution. After a lot of research and combining multiple answers, I've come across a solution.
Background
In this project, I use PDFSharp. You can download the needed files from here.
Add a reference to your project by right-clicking the references folder in your Solution Explorer. Choose, Add Reference... Go to the Browse tab. Browse to the location where you stored the PDFSharp assemblies. In your GDI+ folder, pick the PdfSharp.dll and add it as a reference.
Using the Code
This is how the process generally works:
You will create a class which will take care of the screen capturing part. In this class, you will have some flexibility on save format, as well as the ability to save by hWnd, .NET Control/Form. You can save the file with different extensions. You have multiple options by using ImageFormat
.
This is the code for a screen capturing class:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ScreenToPDF
{
public enum CaptureMode
{
Screen, Window
}
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
public void CaptureAndSave(string filename, CaptureMode mode, ImageFormat format)
{
mode = CaptureMode.Window;
format = null;
ImageSave(filename, format, Capture(mode));
}
public void CaptureAndSave(string filename, IntPtr handle, ImageFormat format)
{
format = null;
ImageSave(filename, format, Capture(handle));
}
public void CaptureAndSave(string filename, Control c, ImageFormat format)
{
format = null;
ImageSave(filename, format, Capture(c));
}
public Bitmap Capture(CaptureMode mode)
{
mode = CaptureMode.Window;
return Capture(mode == CaptureMode.Screen ?
GetDesktopWindow() : GetForegroundWindow());
}
public Bitmap Capture(Control c)
{
return Capture(c.Handle);
}
public Bitmap Capture(IntPtr handle)
{
Rectangle bounds;
Rect rect = new Rect();
GetWindowRect(handle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top,
rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left,
Cursor.Position.Y - rect.Top);
Bitmap result = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(result))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return result;
}
public Point CursorPosition;
void ImageSave(string filename, ImageFormat format, Image image)
{
format = format ?? ImageFormat.Png;
if (!filename.Contains("."))
filename = filename.Trim() + "." + format.ToString().ToLower();
if (!filename.Contains(@"\"))
filename = Path.Combine(Environment.GetEnvironmentVariable
("TEMP") ?? @"C:\Temp", filename);
filename = filename.Replace("%NOW%",
DateTime.Now.ToString("yyyy-MM-dd@hh.mm.ss"));
image.Save(filename, format);
}
}
}
In the class of the form you want to capture, you have to create an instance of the ScreenCapture
class. Where you want to make the screencapture, just call the function of the ScreenCapture
class you want. The exporting to PDF can be handled when a button is clicked. On the form
in my example project, I've added a MenuStrip
, some labels,
textboxes
and a SaveFileDialog
. See the code below for an example of how to catch your active form in a PDF.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using PdfSharp.Pdf;
using PdfSharp.Drawing;
namespace ScreenToPDF
{
public partial class Form1 : Form
{
ScreenCapture capScreen = new ScreenCapture();
public Form1()
{
InitializeComponent();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void captureScreen()
{
try
{
capScreen.CaptureAndSave
(@"C:\Temp\test.png", CaptureMode.Window, ImageFormat.Png);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
}
private void btnExport_Click(object sender, EventArgs e)
{
captureScreen();
PdfDocument doc = new PdfDocument();
PdfPage oPage = new PdfPage();
doc.Pages.Add(oPage);
XGraphics xgr = XGraphics.FromPdfPage(oPage);
XImage img = XImage.FromFile(@"C:\Temp\test.png");
xgr.DrawImage(img, 0, 0);
saveFileDialog.Filter = ("PDF File|*.pdf");
DialogResult btnSave = saveFileDialog.ShowDialog();
if (btnSave.Equals(DialogResult.OK))
{
doc.Save(saveFileDialog.FileName);
doc.Close();
}
img.Dispose();
}
}
}
At this moment, the PDF-page that is created is much bigger than the form I catch. If someone knows how to improve this, please let me know.
I hope I have helped a lot of people with this tip!