Image manipulation in .NET is far simpler than it has been in the past - even VB users get
to play with GDI+! This sample shows how to draw semi-transparent text onto an image so that
it fills (at least most of) the image area.
New in v.1.2: the core overlay function has been ported to C#. When you run the code in the demo,
it will alternate between using the original VB and the C# implementation (for lack of anything better to do).
This sample is built around actual production code that I use to draw the program environment
(e.g. Development, QA, etc.) onto the application's splash screen. It could also be used to
"rubber stamp" an image, or whatever else you can dream up.
Using the code
The main code is in the function (VB):
Public Function Overlay(ByVal img As Image, ByVal OverlayText As String, _
ByVal OverlayFont As Font, ByVal OverlayColor As Color, ByVal AddAlpha As Boolean, _
ByVal AddShadow As Boolean, ByVal Position As Drawing.ContentAlignment, _
ByVal PercentFill As Single) As Bitmap
public static Bitmap TextOverlay( Image img,
string OverlayText, Font OverlayFont,
Color OverlayColor, bool AddAlpha, bool AddShadow,
System.Drawing.ContentAlignment Position, float PercentFill)
img is any loaded image reference,
OverlayText is the text to draw onto the image,
OverlayFont is the font to use (size will be calculated),
OverlayColor is the color to use,
AddAlpha enables transparency (amount is calculated),
AddShadow adds a drop shadow
Position sets the text position on the image
PercentFill sets the relative fill factor (0-100%)
The function returns a bitmap. The text will wrap (if necessary) and will fill
PercentFill of the image's area. When using transparency (alpha), the
shorter the text, the greater the transparency.
Points of Interest
Pretty much all the work in the function is simply to determine the correct font
size to use. This is done in several steps:
- Determine the area required to draw the text as a single line, using initial font size:
| ||The Code Project: Your Visual Studio .NET Homepage|
- Estimate a scaling factor by comparing the text area to the image area * PercentFill (default = 80%):
Scaling Factor = Square Root(80% Image Area / Text Area)
= Square Root(51725 px2/ 3998 px2) = 3.6
- Scale the font by that factor, then measure the text to fit 90% (SQRT(80%)) of the image width, but allow
the height to run over. This is necessary because
MeasureString will leave off lines
if there isn't enough room, and will return only the size used and not the size needed.
| ||The Code Project:|
| <-- Layout too tall for image|
- Reduce the font size (if necessary) and remeasure until the width and height are within limits.
- Once the appropriate size is found, position the layout rectangle on the image and draw:
| || |
| ||The Code Project: Your Visual|
Studio .NET Homepage
| || <-- Final layout|
| || |
At first I was concerned about (in)efficiency, since the function must make an initial
guess at the font size, then test to see how well it fits, and adjust until the text
will actually fit on the given image. This is because you must measure the string
with a specific font size, but the actual area required depends on how well (or not)
the text can "flow" into the region -- wrapping to multiple lines when necessary.
However, changing the font size often changes how the text wraps, thereby changing the
overall area required to print it. In testing, however, I found that the "reduction
loop" only rarely took two passes to fit the text, and often the initial estimate
did not require adjusting -- especially for long, frequently breaking text (like a
sentence). For those who like numbers, various stats are written to the
when run from the IDE.
Areas of Improvement
- It would be more interesting to draw the text at an angle (diagonally). Still looking for someone
to tackle those calculations!
Changes in 1.1
- Added Positioning and %Fill as suggested by Mike.
- Added Text Rendering Hint as suggested by Thomas.
Changes in 1.2
- Added Save As for cliven
- Added Load from for Bariah
for more accurate measurements
- Moved core function to separate assembly (for easy inclusion in your own solution), AAANNNDDDD
- Ported core function to C# for all you "purists" out there.