Convert between twips and pixels in Visual FoxPro

A pair of VFP functions to convert from twips to pixels and back again.

By Dan Macleod

When it comes to measuring objects on the screen, Visual FoxPro folk are accustomed to thinking in pixels. By default, an object's height, width, top and left properties are all expressed in pixels, as are the size of a viewport, the screen co-ordinates used in drag-and-drop, and many similar items.

But, occasionally, we come across measurements expressed in twips. Some ActiveX controls use twips, as do a few Windows API functions. Twips also crop up in older versions of Visual Basic and Microsoft Access, in Microsoft's Rich Text Format, Adobe Flash files, Crystal Reports, and a few other places.

What exactly is a twip?

A twip is defined as one twentieth of a printer's point, or 1/1,440 of an inch. Strictly speaking, there are 72.27 points to the inch, but in computing, this is always rounded to 72, hence the value of 1,440 twips to the inch.

The important point about twips is that it is an absolute unit - it doesn't depend on the characteristics of any particular device. If you placed a ruler up against your monitor, an object on the screen whose width was 1,440 twips would always be one inch wide, regardless of the screen settings.

A pixel, by contrast, varies in size according to the current screen resolution. An object that fills a 1280 x 768 screen would be 1,280 pixels wide. But if you changed the screen resolution to, say, 1024 x 768, the width of the object would go down to 1,024 pixels. Similarly, if you printed the object, its size in pixels would depend on the resolution of the device on which it was printed.

Converting

Clearly, we can't use a simple arithmetic formula to convert between the two units. We need to factor in the resolution of the output device. And to determine the resolution, we need to make a couple of Windows API calls.

Just to confuse the issue slightly, pixels don't necessarily have a 1:1 aspect ratio. In other words, the height of a pixel might not be the same as its width. So we need to do separate conversions for horizontal and vertical measurements.

Here then is a Visual FoxPro function that converts twips to pixels. It receives two parameters: the number of twips, and a flag that says whether the conversion is for a horizontal (.T.) or vertical (.F.) distance.

FUNCTION TwipsToPixels
LPARAMETERS tnTwips, tlHorizontal

LOCAL lnDeviceHandle, lnPixelsPerInch

* Declare the required API functions
DECLARE INTEGER GetDC IN USER32 AS GetDC INTEGER hwnd
DECLARE INTEGER ReleaseDC IN USER32 AS ReleaseDC ;
  INTEGER hwnd, INTEGER hdc  
DECLARE INTEGER GetDeviceCaps IN GDI32 AS GetDeviceCaps ;
  INTEGER hdc, INTEGER nIndex

* Get a handle to the current device
lnDeviceHandle = GetDC(0)

* Get pixels per inch for the device in the 
* specified direction
lnPixelsPerInch = ;
  GetDeviceCaps(lnDeviceHandle, IIF(tlHorizontal, 88, 90))

* Release the handle
lnDeviceHandle = ReleaseDC(0, lnDeviceHandle)

CLEAR DLLS "GetCD", "ReleaseDC", "GetDeviceCaps"

* Do the conversion
RETURN tnTwips / 1440 * lnPixelsPerInch

ENDFUNC

And here is a function that goes the other way, that is, it converts pixels to twips. As you can see, it's very similar to the previous function; only the actual conversion formula is different.

FUNCTION PixelsToTwips
LPARAMETERS tnPixels, tlHorizontal

LOCAL lnDeviceHandle, lnPixelsPerInch

* Declare the required API functions
DECLARE INTEGER GetDC IN USER32 AS GetDC INTEGER hwnd
DECLARE INTEGER ReleaseDC IN USER32 AS ReleaseDC ;
  INTEGER hwnd, INTEGER hdc  
DECLARE INTEGER GetDeviceCaps IN GDI32 AS GetDeviceCaps ;
  INTEGER hdc, INTEGER nIndex

* Get a handle to the current device
lnDeviceHandle = GetDC(0)

* Get pixels per inch for the device in the 
* specified direction
lnPixelsPerInch = ;
  GetDeviceCaps(lnDeviceHandle, IIF(tlHorizontal, 88, 90))

* Release the handle
lnDeviceHandle = ReleaseDC(0, lnDeviceHandle)

CLEAR DLLS "GetCD", "ReleaseDC", "GetDeviceCaps"

* Do the conversion
RETURN tnPixels * 1440 / lnPixelsPerInch

ENDFUNC

Because of the way they use the CLEAR DLLS command, the functions require VFP 7.0 or above. If you are using an earlier FoxPro version, you should omit these commands (which means that the functions won't clear the DLLS, which in turn could lead to a a very small drop in efficiency if the functions are called many times in a session; this is rarely an issue).

Most of the time, VFP developers never need to worry about twips. But for those occasions when they are unavoidable, I hope these two little functions will make life easier for you.

December 2011

Please note: The information given on this site has been carefully checked and is believed to be correct, but no legal liability can be accepted for its use. Do not use code, components or techniques unless you are satisfied that they will work correctly with your sites or applications.

If you found this article useful, please tell your friends: