25

I'm working on a migration project in which a database actually stores display sizes in twips. Since I can't use twips to assign sizes to WPF or Winforms controls, I was wondering if .NET has a conversion method usable at runtime?

Chris Pfohl
  • 15,337
  • 8
  • 60
  • 104

4 Answers4

29

It turns out that the migration tool has something, but it wouldn't do any good at runtime. Here's what I did (if the hard-coded value in the extension method were changed to the value for points per inch it would work as a point converter too):

1 Twip = 1/1440th of an inch. The .NET Graphics object has a method DpiX and DpiY which can be used to determine how many pixels are in an inch. Using those measurements I created the following extension methods for Graphics:

using System.Drawing;

static class Extensions
{
    /// <summary>
    /// Converts an integer value in twips to the corresponding integer value
    /// in pixels on the x-axis.
    /// </summary>
    /// <param name="source">The Graphics context to use</param>
    /// <param name="inTwips">The number of twips to be converted</param>
    /// <returns>The number of pixels in that many twips</returns>
    public static int ConvertTwipsToXPixels(this Graphics source, int twips)
    {
        return (int)(((double)twips) * (1.0 / 1440.0) * source.DpiX);
    }

    /// <summary>
    /// Converts an integer value in twips to the corresponding integer value
    /// in pixels on the y-axis.
    /// </summary>
    /// <param name="source">The Graphics context to use</param>
    /// <param name="inTwips">The number of twips to be converted</param>
    /// <returns>The number of pixels in that many twips</returns>
    public static int ConvertTwipsToYPixels(this Graphics source, int twips)
    {
        return (int)(((double)twips) * (1.0 / 1440.0) * source.DpiY);
    }
}

To use these methods one simply has to do the following (assuming you're in a context where CreateGraphics returns a Drawing.Graphics object (here this is a Form, so CreateGraphics is inherited from Form's super-class Control):

using( Graphics g = CreateGraphics() )
{
    Width = g.ConvertTwipsToXPixels(sizeInTwips);
    Height = g.ConvertTwipsToYPixels(sizeInTwips);
}

See the "Remarks" section in the Graphics Class documentation for a list of ways to obtain a graphics object. More complete documentation is available in the tutorial How to: Create Graphics Objects.

Brief summary of easiest ways:

  • Control.CreateGraphics
  • a Paint event's PaintEventArgs has a Graphics available in its Graphics property.
  • Hand Graphics.FromImage an image and it will return a Graphics object that can draw on that image. (NOTE: It is unlikely that you'll want to use twips for an actual image)
Chris Pfohl
  • 15,337
  • 8
  • 60
  • 104
  • 2
    got a small error in your code. In the ConvertTwipsToYPixles, you have it using the DipX instead of the DpiY – Wesley Oct 28 '10 at 20:12
  • thanks, I have another question. You said that CreateGraphics returns a Drawing.Graphics object. What kind of Graphics it returns? Could you give an example of CreateGraphics method please? – Serhii Kyslyi Jun 05 '13 at 10:27
  • 1
    `CreateGraphics` is a member of `Control`. See the [documentation](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.creategraphics.aspx). `Graphics` is an abstract sealed class that encapsulates drawing to the screen. You don't need to know anything about it if you're using this. Just use any control (Form, Button, etc.) and call it on that. If your class inherits from Control you can use it like I did (with the implied `this`). – Chris Pfohl Jun 05 '13 at 16:59
5

For migration projects we can use built in converstion support functions

microsoft.visualbasic.compatibility.vb6.twipsperpixelx
microsoft.visualbasic.compatibility.vb6.twipsperpixely
Chris Pfohl
  • 15,337
  • 8
  • 60
  • 104
Jayesh
  • 51
  • 1
  • 1
4

For reference, another C# version, using the Win32 API instead of requiring a Graphics objects:

using System.Runtime.InteropServices;

static class SomeUtils {

  public static int ConvertTwipsToPixels(int twips, MeasureDirection direction) {
    return (int)(((double)twips)*((double)GetPixperinch(direction))/1440.0);
  }

  public static int ConvertPixelsToTwips(int pixels, MeasureDirection direction) {
    return (int)((((double)pixels)*1440.0)/((double)GetPixperinch(direction)));
  }

  public static int GetPPI(MeasureDirection direction) {
    int ppi;
    IntPtr dc = GetDC(IntPtr.Zero);

    if (direction == MeasureDirection.Horizontal)
      ppi = GetDeviceCaps(dc, 88); //DEVICECAP LOGPIXELSX
    else
      ppi = GetDeviceCaps(dc, 90); //DEVICECAP LOGPIXELSY

    ReleaseDC(IntPtr.Zero, dc);
    return ppi;
  }

  [DllImport("user32.dll")]
  static extern IntPtr GetDC(IntPtr hWnd);

  [DllImport("user32.dll")]
  static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

  [DllImport("gdi32.dll")]
  static extern int GetDeviceCaps(IntPtr hdc, int devCap);
}

public enum MeasureDirection {
  Horizontal,
  Vertical
}

The MeasureDirection is supposed to be specified as there is no guarantee that pixels are always square (according to the kb).

Reference: kb210590: ACC2000: How to Convert Twips to Pixels

Renaud Bompuis
  • 15,947
  • 4
  • 51
  • 81
2

Old post I know but here is an FYI and some math for the 1440 answers above...

A twip is not simply 1/1440th of an inch. A twip is 1/20 of a point.

The point you are working with in a printable document, typically, is a postscript 72dpi:

72dpi * 20Twips/Point = 1440twips.

So in dealing with say a Crystal report, with a twips width of 15840 (and margins of 0 twips), the width would be 11 inches (15840 / (72 * 20)).

Based on a screen density of 96 dpi, the report will post to the screen at:

1056px wide (96dpi * 11in = 1056px).

ShaneLS
  • 356
  • 5
  • 14
  • 1
    just for all your information who are using Infragistics One inch is equal to 1,440 twips (twentieths of a desktop point). One inch is equal to 72 desktop points. Source : http://help.infragistics.com/Help/Doc/WinForms/2016.1/CLR4.0/html/Infragistics4.Documents.IO.v16.1~Infragistics.Documents.Word.WordDocumentWriter~ConvertUnits.html – Syed Mohamed Dec 29 '17 at 06:50