6

My Program: Contains a form with few textboxes and one button. 'Default Printer' is set as Adobe PDF on my computer.

My Goal: Want to take a screenshot of a form/usercontrol when the user clicks 'Print' button. The screenshot is then saved on the desktop in .pdf format.

My Problem: I have following two problems with the code:

  1. Size of Screenshot: The size of the screenshot is too big and it does not fit the size of the page (default page size) when printed/converted to .pdf. Please refer the two images below. I want the entire screenshot to fit inside the page.
  2. Asks twice where to convert and save: When I click on 'Print Form' button, programs asks me TWICE where to print/convert and save the file. I want the program to ask me only Once, where to print and save the file.

Problem 1: The screenshot captured by the program does not fit the page when printed. Problem 1: The screenshot captured by the program does not fit the page when printed.

I want the screenshot image to fit like this on one page of .pdf: enter image description here

Code:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Text = "Print Form";
        button1.Click += new EventHandler(button1_Click);
        printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
        this.Controls.Add(button1);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        CaptureScreen();
        printDocument1.Print();
    }

    Bitmap memoryImage;

    private void CaptureScreen()
    {
        Graphics myGraphics = this.CreateGraphics();
        Size s = this.Size;
        memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
        Graphics memoryGraphics = Graphics.FromImage(memoryImage);
        memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
    }

    private void printDocument1_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
    {
        e.Graphics.DrawImage(memoryImage, 0, 0);
    }
}

Thanks for your help in advance. I am a newbie, learning c# language and your help will be much appreciated. :)

LPL
  • 16,827
  • 6
  • 51
  • 95
Smith
  • 387
  • 3
  • 6
  • 14
  • 1
    Take a look at this Q/A for a sample of C# image scaling: http://stackoverflow.com/questions/249587 – Paul Sasik Oct 03 '13 at 17:23
  • For the 2nd issue (double dialog), this is just a guess but try removing this line `printDocument1.PrintPage += ...` from your constructor. I'm guessing that this already happens inside of `InitializeComponent()` which means that you are explicitly handling the event twice. Open your Form1.Designer.cs file to see if there are other things you're duplicating. (Except for your Init call everything else in the constructor may be redundant.) – Paul Sasik Oct 03 '13 at 17:28
  • @PaulSasik: Nope. For problem 2, removing that line gives me a white PDF and cannot save it. ._. – Smith Oct 03 '13 at 17:32
  • Check out my answer below. For starters just copy/paste the `printDocument1_PrintPage` method from the class. To deal with your doubled up Save Dialog check out the entirety of the code. (Events are usually managed in the associated Designer class file to forms.) – Paul Sasik Oct 03 '13 at 18:14

1 Answers1

3

Ok, check this out, and the modified printDocument1_PrintPage in particular:

        private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
        {
            // calculate width and height scalings taking page margins into account
            var wScale = e.MarginBounds.Width / (float)_memoryImage.Width;
            var hScale = e.MarginBounds.Height / (float)_memoryImage.Height;

            // choose the smaller of the two scales
            var scale = wScale < hScale ? wScale : hScale;

            // apply scaling to the image
            e.Graphics.ScaleTransform(scale, scale);

            // print to default printer's page
            e.Graphics.DrawImage(_memoryImage, 0, 0);
        }

I moved all the event wireup into InitializeComponent where it's usually supposed to go but it's more involved code:

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;

namespace testScreenCapScale
{
    public partial class Form1 : Form
    {
        public Form1() { InitializeComponent(); }

        private void button1_Click(object sender, EventArgs e)
        {
            CaptureScreen();
            printDocument1.Print();
        }

        private Bitmap _memoryImage;

        private void CaptureScreen()
        {
            // put into using construct because Graphics objects do not 
            //  get automatically disposed when leaving method scope
            using (var myGraphics = CreateGraphics())
            {
                var s = Size;
                _memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
                using (var memoryGraphics = Graphics.FromImage(_memoryImage))
                {
                    memoryGraphics.CopyFromScreen(Location.X, Location.Y, 0, 0, s);
                }
            }
        }

        private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
        {
            // calculate width and height scalings taking page margins into account
            var wScale = e.MarginBounds.Width / (float)_memoryImage.Width;
            var hScale = e.MarginBounds.Height / (float)_memoryImage.Height;

            // choose the smaller of the two scales
            var scale = wScale < hScale ? wScale : hScale;

            // apply scaling to the image
            e.Graphics.ScaleTransform(scale, scale);

            // print to default printer's page
            e.Graphics.DrawImage(_memoryImage, 0, 0);
        }
    }
}

Form1.Designer.cs

namespace testScreenCapScale
{
    partial class Form1
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
                components.Dispose();
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.printDocument1 = new System.Drawing.Printing.PrintDocument();
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // printDocument1
            // 
            this.printDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.printDocument1_PrintPage);
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(64, 220);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(384, 377);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }

        private System.Drawing.Printing.PrintDocument printDocument1;
        private System.Windows.Forms.Button button1;
    }
}
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
  • @Smith: Like I said, for starters (a quick test) just copy and paste the contents of the `printDocument1_PrintPage` method. The scaling is self-contained and nothing else needs to change. It's the event handling that's more involved which you can work on separately. – Paul Sasik Oct 03 '13 at 18:43