Convert points to pixel

• Question

•

Hi,

I'm trying to print a single image using a PrintDocument control and responding to the PrintPage Event.

I'd like to make my picture to be centered by calculating left and top position :

Code Snippet

int Left = (e.MarginBounds.Width - img.Width) / 2;

int Top = (e.MarginBounds.Height - img.Height) / 2;

Unfortunately this line always give me wrong answer because MarginBounds returns 'points' value whereas img.Width and Height return size in 'pixels'.

Do anyone know a way for converting wether pixels to points or points to pixels ?

Wednesday, February 6, 2008 2:17 PM

• Hi Beebop,

As for the pixel based size of the printing area, I think you may need to calculate it in code. In the Print_Page event, you can get the following from the event object:

**e.PageSettings.PrintableArea that will give you the printable area size
** e.PageSettings.PrinterResolution will give you the DPI of printer

and the following thread has mentioned how to perform the calculation between the point based value to pixel:

#Printing Photographs full page

I've extracted the fragment from it

>>>>>>>>>>>>>>>
If you're printing the image already, all you have to do is create a new bitmap and to scale it to your printers margins before you print it.  In theory, this sounds easy but I've not found any "easy" way to access the printer's properties in a remotely pixel-friendly way.

Your PrintDocument object has properties (such as PrinterSettings.DefaultPageSettings.PaperSize.Height) that will return the available size of your output.  However, these values are in 1/100th of an inch so you'll need to convert to pixels by dividing by 100 then multiplying by the printer's DPI x or y before you can use them.  Then you'll need to subtract the printer's hard-margin, again x and y, from your values.

Once you have the paper dimensions in pixels you can figure the aspect ratio of your picture (assuming you wish to scale it and not stretch it) then resize the image and print.

<<<<<<<<<<<<<<<<<<

if you want to know more about the DPI or any other display related info, here is an article maybe helpful:

#Display, Printing, DPI and PPI
http://photo.net/learn/resize/

Sincerely,

Steven Cheng

Friday, February 8, 2008 8:30 AM

All replies

• Hi Beebop,

As for the pixel based size of the printing area, I think you may need to calculate it in code. In the Print_Page event, you can get the following from the event object:

**e.PageSettings.PrintableArea that will give you the printable area size
** e.PageSettings.PrinterResolution will give you the DPI of printer

and the following thread has mentioned how to perform the calculation between the point based value to pixel:

#Printing Photographs full page

I've extracted the fragment from it

>>>>>>>>>>>>>>>
If you're printing the image already, all you have to do is create a new bitmap and to scale it to your printers margins before you print it.  In theory, this sounds easy but I've not found any "easy" way to access the printer's properties in a remotely pixel-friendly way.

Your PrintDocument object has properties (such as PrinterSettings.DefaultPageSettings.PaperSize.Height) that will return the available size of your output.  However, these values are in 1/100th of an inch so you'll need to convert to pixels by dividing by 100 then multiplying by the printer's DPI x or y before you can use them.  Then you'll need to subtract the printer's hard-margin, again x and y, from your values.

Once you have the paper dimensions in pixels you can figure the aspect ratio of your picture (assuming you wish to scale it and not stretch it) then resize the image and print.

<<<<<<<<<<<<<<<<<<

if you want to know more about the DPI or any other display related info, here is an article maybe helpful:

#Display, Printing, DPI and PPI
http://photo.net/learn/resize/

Sincerely,

Steven Cheng

Friday, February 8, 2008 8:30 AM
• To convert pixels to 1/100 in. use 100 * img.Width / img.HorizontalResolution and 100 * img.Height /img.VerticalResolution.  Use the default page unit of display for measurement when printing.  Don't set the MarginBounds in points.  Use 1/100 in. for all measurements

Friday, February 8, 2008 10:18 AM
• Does someone have a code example to do this, i'm new in c# and i'm having a hard timie to print .jpg and bmp. center on paper size letter and 11x17 in landscape mode.

I create jpg with xceed graph and I need to print them after, but my problem it's that I can't print and center my picture in one page from each format.

Thank you

Steve

Friday, February 8, 2008 1:41 PM
• Steve and all, I researched the web extensively and did not find a good answer to this question.  Most answers that I found were wrong.  The first solution (that worked) was to hardcode a ppi of 72 into a class and directly convert pixels to PageUnits(1/00 inch).  Then I came upon the correct solution shown below.  Hope this helps someone.  John

/*Class Manages Print Functions
* 10feb2008 intial draft john king
* 10feb2008 (Rnd 1)
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;

namespace KES.PhotoAlbumn
{
public class PrintManager
{
Image image;
bool isShuttingdown = false;
PrinterFormat printPageFormat;
int offset;
int ppi = 72;
float imageRatio;

public PrintManager()
{
this.offset = ppi / 4;
}
public void PrintImage(Image image, PrinterFormat format)
{
//check parameters
if (image == null)
throw new NullReferenceException();

//set class variable
this.image = image;
this.printPageFormat = format;

//create a print document
PrintDocument printDoc = new PrintDocument();

//create event handler and register event to method Print_Page
printDoc.PrintPage += new PrintPageEventHandler(Print_Page);

//create a dialog that lets user select printer
PrintDialog printDialog = new PrintDialog();

//set the print document to the dialog to allow automatic update
printDialog.Document = printDoc;

//get the result
DialogResult result = printDialog.ShowDialog();

if (result == DialogResult.OK)
{
//set the settings in printdocumet
printDoc.PrinterSettings = printDialog.PrinterSettings;

//relax margins to zero
printDoc.PrinterSettings.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);

//print the page ... note we have not told it what to print yet
printDoc.Print();
}

}

public void Print_Page(object o, PrintPageEventArgs e)
{
//get the image to print
Image i = this.image;

//get rectangle of printable bounds... in pageUnits = 1/100 of an inch
Rectangle marginBoundsPageUnits = e.MarginBounds;

//resize the image based on requested format
//Image formattedImage = FormatImage(i, this.printPageFormat, out listRectangles, marginBoundsPageUnits);
List<Rectangle> listRectangles = FormatImage(i, this.printPageFormat, marginBoundsPageUnits);

// Create the source rectangle from the BackgroundImage Bitmap Dimensions (Pixel Units)
RectangleF srcRect = new Rectangle(0, 0, i.Width, i.Height);

//draw the image to Graphics
if (listRectangles != null)
{
foreach (Rectangle rectangle in listRectangles)
{
//draw image and convert from Pixel Units to PageUnits
e.Graphics.DrawImage(image, rectangle, srcRect, GraphicsUnit.Pixel);
}
}
}//exiting method will send print job to printer

//first try... formats for single picture only... good for full page but other need to be improved
private List<Rectangle> FormatImage(Image image, PrinterFormat format, Rectangle PrintAreaPageUnits)
{
//PageUnits of 1/100 of an inch
Point UpperLeft = PrintAreaPageUnits.Location;
float PageUnitWidth = PrintAreaPageUnits.Width;
float PageUnitHeight = PrintAreaPageUnits.Height;

//look at format of Print the user is asking for... determines the Rectangles that we return
switch (format)
{
case PrinterFormat.onePic8inchesByAspectRatio: //prints to full print area on the paper
{
//Call method that will keep short dimension in the x axis
LandscapeImage(image);

//calculate width and height of rectangle in page Units
float rectWidth = 800; //Page Units
float rectHeight = 800 * this.imageRatio; //Page Units

//make sure an 8X will fit on the page
if(rectWidth < PageUnitWidth && rectHeight < PageUnitHeight)
{
//create a rectangle (Page Units) to print to
Point firstP = UpperLeft;
Size firstS = new Size((int)rectWidth, (int)rectHeight);
Rectangle firstR = new Rectangle(firstP, firstS);

//create a list of Rectangles that will be passed to calling method via "out" method
List<Rectangle> listR = new List<Rectangle>();

//return the list of rectangles (Page Units)
return listR;
}
else
{
MessageBox.Show("8X10 Photo will not fit on the selected Printer Page","Page Size Error");
return null;
}
}

case PrinterFormat.twoPic5inchesByAspectRatio: //case is used to print two pictures full width, one stacked on other
{
//call method that will keep long dimension in the x axis
ReverseLandscapeImage(image);

//calculate width and height of rectangle in page Units
float rectHeight = 500;
float rectWidth = 500 / this.imageRatio;

//make sure that two 5X will fit on the page
if (rectWidth < PageUnitWidth && rectHeight < PageUnitHeight/2 - offset)
{
//create a rectangle (Page Units) to print to
Point firstP = UpperLeft;
Size firstS = new Size((int)rectWidth, (int)rectHeight);
Rectangle firstR = new Rectangle(firstP, firstS);

//create a second rectangle(Page Units) for the second picture
Point secondP = new Point(firstP.X, firstP.Y + (int)rectHeight + (int)offset);
Size secondS = firstS;
Rectangle secondR = new Rectangle(secondP, secondS);

//create a list of Rectangles that will be passed to calling method via "out" method
List<Rectangle> listR = new List<Rectangle>();

//return the list of Rectangles (Page Units)
return listR;
}
else
{
MessageBox.Show("8X10 Photo will not fit on the selected Printer Page", "Page Size Error");
return null;
}
}

default:
{
return null;
}
}
}

//method will rotate image 90 degrees if width > height for landscape
private void LandscapeImage(Image image)
{
int x = image.Width;
int y = image.Height;

if (x > y) //image is wider and better handled in landscape
{
image.RotateFlip(RotateFlipType.Rotate90FlipNone);
}

//set image aspect ratio (Height/width)
//Landscape-- Height = aspectRatio * width
//Normal -- Width = Height/aspectRatio
this.imageRatio = GetImageRatio(image);
}

//method reverses landscape alignment
private void ReverseLandscapeImage(Image image)
{
int x = image.Width;
int y = image.Height;

if (x < y) //image is wider and better handled in landscape
{
image.RotateFlip(RotateFlipType.Rotate90FlipNone);
}

//set image aspect ratio (Height/width)
//Landscape-- Height = aspectRatio * width
//Normal -- Width = Height/aspectRatio
this.imageRatio = GetImageRatio(image);
}

//returns ratio used to calculate image height given a width
//LandscapeHeight = width * ImageRatio
//ReverseLandscapeWidth = Height/ ImageRatio
private float GetImageRatio(Image i)
{
float height = i.Height;
float width = i.Width;
float ratio = height / width;
return ratio;
}

public static void Main()
{
PrintManager pm = new PrintManager();
Image i = Image.FromFile("C:\\IMG_0026.JPG");
pm.PrintImage(i,PrinterFormat.twoPic5inchesByAspectRatio);

while (!pm.isShuttingdown)
{