locked
Convert points to pixel RRS feed

  • 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

Answers

  • 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


    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1716913&SiteID=1

     

    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


    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1716913&SiteID=1

     

    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.Threading;
    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>();

                                //add Rectangle to local list
                                listR.Add(firstR);

                                //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>();

                                //add Rectangle to local list
                                listR.Add(firstR);
                                listR.Add(secondR);

                                //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)
                {
                    Thread.Sleep(1000);
                }
            }

            public enum PrinterFormat
            {
                onePic8inchesByAspectRatio,
                twoPic5inchesByAspectRatio,
                notSet
            }

        }
    }
    Saturday, May 17, 2008 1:56 PM