November 27, 2020
Hot Topics:

Managed C++: Use GDI+ to Render Reflected Text

  • By Tom Archer
  • Send Email »
  • More Articles »
  • Calculate the true height of the text being rendered.
    You need the reflected text to be drawn starting below the original text. Although you got the text's height from the Measurestring method, that value includes spacing for descenders and whitespace. In this case, you want only the height from the baseline. This involves getting the cell ascent of the font family being used. (You can retrieve the font family from the Font object via it's FontFamily property.) However, the cell ascent value is in design units, which must be converted to pixels and then scaled for the font size. After much testing and research, this is the best formula I've found for doing this, where the final value (represented by cy) is the height of the text to be drawn).
    This formula is optimized for characters that are drawn above the baseline. If you use characters that are drawn below the baseline (i.e., characters with descents), you'll see overlap in the descending parts of the characters between the original and reflected text. To remedy this, tweak the calculation by incorporating the cell descent (retrieved via the FontFamily::GetCellDescent method):
    int lineAscent = font->FontFamily->GetCellAscent(font->Style);
    int lineSpacing = font->FontFamily->GetLineSpacing(font->Style);
    Single lineHeight = font->GetHeight(g);
    Single cy = lineHeight * lineAscent / lineSpacing;
  • Draw the original text.
    Note that the x and y positions are at 0 and 0. This is due to your having called TranslateTransform as described earlier:
    g->DrawString(textToDisplay, font, Brushes::Black, 0, 0);
  • Apply the necessary scaling factor to the graphic object's transformation matrix.
    To reflect text, you use the ScaleTransform method with a value of -1 in order to invert the text without distorting it:
    g->ScaleTransform(1, -1.0F);
  • Draw the reflected text.
    Once the scaling factor has been established, you simply draw the reflected text. Note the y value is set to the negative of the text height multiplied by two so that it displays below the original text:
    g->DrawString(textToDisplay, font, Brushes::Gray, 0, -(cy*2));
  • Saving and Restoring the GraphicsState

    The previous section showed how to use the ScaleTransform method to produce reflected text. In terms of the order in which the text was drawn, the code first drew the original string, scaled the text in the exact opposite direction (in the y direction), and then drew the text's "reflection". However, what if you needed to perform these steps in reverse? In other words, draw the reflection first. You could scale the text twice—once to draw the reflection and then back to the normal scaling. Or you could save the current state of the Graphics object, set the scaling factor, and then when finished drawing on that scale, restore the original graphics state to draw the normal text. Here's how that would look:
    // Save the graphics state
    GraphicsState* prevGraphicsState = g->Save();
    // Scale to draw reflected text
    g->ScaleTransform(1.0F, -1.0F);
    // Draw the reflected text
    // Restore the saved graphics state
    // Draw the normal text

    Download the Code

    To download the accompanying source code for the demo, click here.

    About the Author

    The founder of the Archer Consulting Group (ACG), Tom Archer has been the project lead on three award-winning applications and is a best-selling author of 10 programming books as well as countless magazine and online articles.

    Page 2 of 2

    This article was originally published on November 22, 2004

    Enterprise Development Update

    Don't miss an article. Subscribe to our newsletter below.

    Thanks for your registration, follow us on our social networks to keep up-to-date