title: C# Determining actual print area
body: <p>In C#, .NET 3.5 with winforms I am working on a print preview control. It seems to work fine, but when I print an A4 page I scanned in at real size on an A3 page, teh scale is out by about  3%...</p>
  
  <p>I am using the following code to compute the actual printable area of the page based on the setting selected by the user and I am wondering if I maybe got those calculations wrong?</p>
  
  <pre><code>public static RectangleF GetPrintArea(PageSettings PageSettings)
      {
          float[] margins;
          RectangleF printArea;
  
          // Get the actual page bounds
          printArea = PageSettings.Bounds;
  
          // Calculate the hard margins taking into account page orientation
          margins = new float[4];
          // Left
          margins[0] = !PageSettings.Landscape ? PageSettings.HardMarginX : PageSettings.HardMarginY;
          // Top
          margins[1] = !PageSettings.Landscape ? PageSettings.HardMarginY : PageSettings.HardMarginX;
          // Right
          margins[2] = margins[0];
          // Bottom
          margins[3] = margins[1];
  
          // Calculate the real print margins taking into account teh hard and soft margins
          // left
          margins[0] = Math.Max(margins[0], PageSettings.Margins.Left);
          // Top
          margins[1] = Math.Max(margins[1], PageSettings.Margins.Top);
          // Right
          margins[2] = Math.Max(margins[2], PageSettings.Margins.Right);
          // Bottom
          margins[3] = Math.Max(margins[3], PageSettings.Margins.Bottom);
  
          return new RectangleF(
              new PointF(margins[0], margins[1]),
              new SizeF(printArea.Width - (margins[0] + margins[2]), printArea.Height - (margins[1] + margins[3]))
           );
      }
  </code></pre>
  
  <p>This should return a rectangle which gives the actual area of the page on printing will happen. I use this rectangle for generating both the preview and the printout.</p>
  
  <p>The code for printing out is as follows:</p>
  
  <pre><code>    /// &lt;summary&gt;
      /// Draws the image on the printing surface
      /// &lt;/summary&gt;
      /// &lt;param name="Graphics"&gt;The graohics object with which to draw&lt;/param&gt;
      protected virtual void PrintImage(Graphics Graphics)
      {
          RectangleF imageBoundingBox;
          RectangleF visibleImageBoundingBox;
          RectangleF visibleImage;
  
          // Offset the visible bounding box location by the position of the print area so as to print right within the margins
          Graphics.TranslateTransform(-this.Page.PrintableArea.Left, -this.Page.PrintableArea.Top);
  
          // Calculate the bounding box of the scaled image
          imageBoundingBox = new RectangleF(this.Page.PrintAreaOrigin.Add(this.ImagePrintLocation), this.Image.Size.Multiply(this.ImagePrintScale));
  
          // Calculate the position and size of the portion of the image bounding box visible in the viewport
          visibleImageBoundingBox = RectangleF.Intersect(imageBoundingBox, this.Page.PrintArea);
  
          // Calculate the portion of the image which corresponds to the visible bounding box
          visibleImage = new RectangleF(
              new PointF(
                  imageBoundingBox.X &lt; this.Page.PrintArea.Left ? Math.Min(this.Page.PrintArea.Left - imageBoundingBox.X, imageBoundingBox.Width) : 0,
                  imageBoundingBox.Y &lt; this.Page.PrintArea.Top ? Math.Min(this.Page.PrintArea.Top - imageBoundingBox.Y, imageBoundingBox.Height) : 0
              ).Divide(this.ImagePrintScale),
              visibleImageBoundingBox.Size.Divide(this.ImagePrintScale)
          );
  
          // Draw the image
          Graphics.DrawImage(this.Image, visibleImageBoundingBox, visibleImage, GraphicsUnit.Pixel);
      }
  </code></pre>
  
  <p>Where <code>Page</code> is a class which contains the page bounds (<code>PageArea</code>), the printable area <code>PrintableArea</code> and the actual print area (<code>PrintArea</code>). The actual print area is the area which is given by the previous rectangle.</p>
  
  <p>Something must be wrong with this approach, but I can't for the life of me figure out what it is. If anybody can identify what's wrong I would be very grateful...</p>