Alistair Evans
Alistair Evans

Reputation: 36483

Drawing a contrasted string on an image

So, I have a snapshot of a video source, which I get into an Image, grab a Graphics object for it, and then draw a timestamp in the bottom right of the image. No problem thus far. However, I cannot guarantee what colour is going to be behind the text, so no matter what brush I use, it will almost certainly clash with some of the images that it is drawn on, making the text unreadable.

I am wondering if anyone knows of a way (either a method in .net, or a nice algorithm), for determining the best colour for a string based on the image behind it.

Cheers

Upvotes: 3

Views: 2006

Answers (6)

qnaninf
qnaninf

Reputation: 67

The following snippet shows how to invert a color (background) and then applies Dinah's suggestion to create the background using Graphics.DrawString().

private static Color InvertColor(Color c)
{
  return Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B);
}
// In the following, constants and inplace vars can be parameters in your code
const byte ALPHA = 192;
var textColor = Color.Orange;
var textBrush = new SolidBrush(Color.FromArgb(ALPHA, textColor));
var textBrushBkg = new SolidBrush(Color.FromArgb(ALPHA, InvertColor(textColor)));
var font = new Font("Tahoma", 7);
var info = "whatever you wanna write";
var r = new Rectangle(10, 10, 10, 10);

// write the text
using (var g = Graphics.FromImage(yourBitmap))
{
  g.Clear(Color.Transparent);
  // to avoid bleeding of transparent color, must use SingleBitPerPixelGridFit
  g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  // Draw background for text
  g.DrawString(info, font, textBrushBkg, r.Left - 1, r.Top - 1);
  g.DrawString(info, font, textBrushBkg, r.Left + 1, r.Top + 1);
  g.DrawString(info, font, textBrushBkg, r.Left + 1, r.Top - 1);
  g.DrawString(info, font, textBrushBkg, r.Left - 1, r.Top + 1);
  // Draw text
  g.DrawString(info, font, textBrush, r.Left, r.Top);
}

Upvotes: 0

peSHIr
peSHIr

Reputation: 6360

This could be a number of variations on the answer by reinier.

  1. Draw underlying text (the four offset ones mentioned by reinier) not in black, but actually in a contrasting color to the foreground color of the actualy text.
  2. Draw the text twice: once in a contrasting color but in bold and/or a slightly larger size, then in the text foreground color over that. Might have to fiddle a bit with coordinates and even need to do the drawing per word or even character to get both passes to nicely align and not give an ugly end result.
  3. Do what reinier suggested, but perhaps not four times (all four directions), but maybe three or even two times to get a kind of "shaded" look.
  4. Let go of the whole "draw text pixel by pixel using API calls" approach and use advanced multilayer compositing techniques like the ones available in WPF design.

For some examples of the last option, check out slides 18 and 21 in Advanced OSM Cartography on SlideShare.

Upvotes: 0

Bogdan Maxim
Bogdan Maxim

Reputation: 5946

Or, if it is allowed, you could use a background color (your choice) for the text (for example white text on black background).

Otherwise, you would need to capture the rectangle where the text is written (for every frame), create the negative image of it, and then get the median color in the rectangle and use it to write the text.

A more complex solution would get you to use two layers (initial picture - L1 and Text (transparent background, black text) - L2), and before combining them, take all the pixels from L2 that contain text and change the color for the each pixel of the text to the "negative" underlying pixel color value of the L1, but you won't get something that's too usable from a "viewer's" point of view.

Upvotes: 0

Drew Noakes
Drew Noakes

Reputation: 310997

Back in the days of Commodore 64 sprite graphics, if you wanted something to stand out against any background, you used XOR blitting. Some people referred to this as 'reverse video'.

You can draw lines this way using ControlPaint.DrawReversibleLine, but that won't work for text.

This CodeProject article shows how you can create an XOR brush using interop to gdi32.dll.

Upvotes: 1

Henk Holterman
Henk Holterman

Reputation: 273274

The only reliable way is to use a contrasting outline.

Upvotes: 2

Toad
Toad

Reputation: 15925

 just draw the string 5 times.
 One time 1(or2) pixels to the left in black
 One time 1(or2) pixels to the right in black
 One time 1(or2) pixels above it in black
 One time 1(or2) pixels below it in black
 and the final time in white on the place where you want it

Upvotes: 7

Related Questions