Index

FAQs: Text Metrics

Q-2-1. When I draw glyphs using dtGlyphDoOutput or dtCharDoOutput, will the top-left corner of my character appear at the screen point (x, y)?

No, most likely it will not. The origin of a character is not its top left corner, but an initial reference point chosen by the font manufacturer. In virtually all Latin characters, this point is located at the base line of the glyph and very close to its left edge. The origin is made to coincide with the screen point (x, y) when the character is drawn using dtGlyphDoOutput or dtCharDoOutput. Therefore, two characters with a different font size but equal Y coordinate will always be drawn on the same base line.

Q-2-2. I understand the font size in D-Type API is specified in pixels. What if I need to use points? What is the relationship between points and pixels?

On a 72dpi device, points and pixels are equal. A typical VGA monitor has a resolution of 96dpi. Therefore, to convert points (pts) to pixels, you must multiply the point value by 96/72 (or 1.3333). On a 300dpi laser printer, the multiplication factor would be 300/72 (or 4.1666).

Similarly, to convert pixels to points, just divide the pixel value by 1.3333.

Q-2-3. How do I handle size_h and size_v within the DT_TRANSFORM_PARAMS structure? When I specify size_h, is that the cell height or the average character height?

Font width and height is really the width and height of the so-called "em-square". In traditional typography, the em-square is an imaginary box that traditionally encloses the capital letter M. However, in digital fonts the em-square does not have to enclose any particular glyph. The actual value for the width and height of the em-square (which we also call base font width and base font height) is chosen by the font manufacturer and is arbitrary.

For example, if the font size is 50x30 pixels, this means that the base font width should be set to 50 pixels and the base font height to 30 pixels. All glyphs in the font are then scaled relative to this size. It is important to understand that 50x30 is not the size of any particular glyph in the font, it is only a way to measure the global font size.

Some font software does not support different font widths and heights — you can only specify one size (typically font height in points). With that software glyph expansion or compression is not possible. With D-Type font engine, this is trivial. In addition, negative font widths and/or heights can be used to output mirrored glyphs.

Q-2-4. What is D-Type's equivalent of the Windows GetTextMetricsfunction?

In Windows, global font information, such as font width, height, descent etc. can be retrieved via the GetTextMetrics function:

Example:

SelectFont(hDC, hfont);
GetTextMetrics(hDC, (LPTEXTMETRIC)&tm);
height = (int)tm.height;
descent = (int)tm.descent;

In D-Type API, the equivalent information can be obtained by calling the dtFontGetMetrics function. All return values are in font units. For more information, see the manual.

Q-2-5. I don't have knowledge of font units. What is the relationship between font units and pixels?

Typically, you create a new font size by setting the size_h and size_v values within the DT_TRANSFORM_PARAMS structure:

/* Transformation specified using raw transformation parameters */ 
typedef struct
{
   size_h, size_v;
   skew_h, skew_v;
   rotation;

} DT_TRANSFORM_PARAMS;

where size_h and size_v are specified in pixels.

If you call the dtFontGetMetrics function, you can obtain the font_xbs and font_ybs values:

DT_SWORD dtFontGetMetrics(DT_DTENGINE engine, DT_ID_SWORD font_index, DT_UWORD* fnt_xbs, DT_UWORD* fnt_ybs, DT_RECT_SWORD* extent)

It is important to know that font_xbs and font_ybs measure the same feature as size_h and size_v. However, font_xbs and font_ybs are measured in font units while size_h and size_v are measured in pixels. Therefore, the scaling factor that can be used to convert font units to pixels is:

fx = size_h / font_xbs (for horizontal scaling)
fy = size_v / font_ybs (for vertical scaling)

Q-2-6. I need something like the TEXTMETRIC structure. I need to be able to calculate:

1) the width and height of a font, in pixels, per point size
2) the X and Y extents, calculated in pixel units, that bounds a single character
3) the width of a character as defined in the font, in pixels
4) the maximum character width, in pixels
5) the maximum character height, in pixels
6) the width of text string in font units
7) the width of text string in pixels

Most of the calculations concerning pixel values are very easy to perform once the horizontal and vertical scaling factor for converting font units to pixels are known. See the above answer for information on how to obtain those factors.

1) the width and height of a font, in pixels, per the point size

This point is trivial. These are exactly the size_h and size_v parameters defined within the DT_TRANSFORM_PARAMS structure. Unlike Windows, D-Type does not use points. If you wish to use points, please see Q-2-2.

2) The X and Y extents, calculated in pixel units, that bounds a single character

Call the dtCharGetMetrics function to obtain the X and Y extents of the character in font units (the extent parameter returned via the DT_RECT_SWORD structure). Then, apply the scaling factors fx and fy to get minimum and maximum X and Y extents for a single character in pixels.

3) the width of a character as defined in the font, in pixels

Again, use the dtCharGetMetrics function to obtain advance_width for a single character and multiply by fx.

advance_width_pixels = fx * advance_width

4) The maximum character width, in pixels

This is simply the distance between the character's maximum and minimum x coordinate expressed in pixels, or

fx * (extent.xmx - extent.xmn)

5) The maximum character height, in pixels

This is the distance between the character's maximum and minimum y coordinate expressed in pixels, or

fy * (extent.ymx - extent.ymn)

6) The width of text string in font units

If you are not using kerning or additional character spacing, simply sum the advance widths of all characters in the string. If you are using additional character spacing, add this value to each advance width. Finally, if you are using kerning, call dtCharGetKern for each kern-pair, adjust the advance width accordingly and then sum.

7) The width of text string in pixels

The process is very similar to the previous procedure, but the result must be converted to pixels by multiplying by fx.

Alternatively, you can use the dtxCharsGetBound or dtxGlyphsGetBound function and just read the returned advance_width value.

Q-2-7. How to calculate the approximate pixel distance of my text row from the previous one?

The simplest method of calculating the y coordinate of the base line corresponding to the current text row is to add the maximum height of the font that appears in the current row to the y coordinate of the base line corresponding the previous row.

Example:

DT_TYPE_ATTRIBS type = {1, 0, 0, 0, 0, {{100, 100, 0, 0, 0}}};
/*
    Same as
    type.font_index = 1;
    type.thickness = 0;
    type.segment = 0;
    type.reserved = 0;
    type.descriptor = 0;
    type.transform.params.size_h = 100;
    type.transform.params.size_v = 100;
    type.transform.params.skew_h = 0;
    type.transform.params.skew_v = 0;
    type.transform.params.rotation = 0;
*/ 
DT_SWORD x = 0, y = 0;
DT_SWORD i;

/* Select type */ 
dtTypesetterSetTypeAttribs(engine, &type);

for (i = 0; i < 3; i++)
{
     y += type.transform.params.size_v;

     dtxCharsDoOutput(engine, x, y, 0, DV_TEXTMODE_DEVICE_2, DV_NULL, "Hello World");
}

An alternative method is to determine the minimum and maximum y extent of the row. For more information see Q-2-8.

Q-2-8. How do I determine the height of my font in pixels, based on the minimum and maximum y coordinate?

The dtFontGetMetrics function returns global font information, including its maximum Y extent (extent.ymx) and minimum Y extent (extent.ymn).

Assuming that more than a single type is used in each text row, the first step is to determine the maximum of all maximum Y extents in the row. We can call this value RowYMax. Similarly, we determine the minimum of all minimum Y extents in the row and call it RowYMin.

Finally, the distance (RowYMaxRowYMin) is the height of a text row. Since this distance is in font units, the last step is to convert that value to pixels by multiplying by fy.

Q-2-9. Why in some cases characters from 2 different fonts appear to have a slightly different size, although their pixel size set up via the DT_TRANSFORM_PARAMS structure is the same.

Sometimes the size of different fonts might slightly differ depending on how font designers define the base font size (or em-square). As mentioned earlier, the em-square is an imaginary box that traditionally encloses the capital letter M and is chosen independently by each font manufacturer. In some cases font designers may choose to make certain fonts appear smaller than others at the same size. However, this effect is normal and in some cases desirable. For example, the Courier font is usually designed to look slightly smaller than Arial or Times at the same pixel size, because this is a monospaced font that requires more horizontal space than non-monospaced fonts such as Arial or Times.

Q-2-10. I understand the advance_width parameter returned by dtxCharsDoOutput and dtxGlyphsDoOutput (or dtxCharsGetBound and dtxGlyphsGetBound) can be used to determine the width of my text string in pixels. But what about a 90° orientation where the width and height will be reversed?

The advance_width is a vector which represents the width of a text string. The orientation of this vector will change if your text is rotated, but its pixel value remains constant. Therefore, the advance_width always represents the width of your text string, regardless of the rotation.

Q-2-11. The advance_width returned by the dtxCharsGetBound (or dtxGlyphsGetBound) function is what I need, but I don't know exactly where text begins in the bitmap.

The x coordinate of the origin of the text string is exactly -bmp.x pixels away from the left edge of the bitmap. Similarly, the y coordinate of the origin is exactly bmp.y pixels away from the top edge. So, the text string is located at the coordinates (-bmp.x, bmp.y) inside the bitmap.

 

Index