views:

190

answers:

4

Hey,

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

+1  A: 

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.

Drew Noakes
Doesn't that look horrible?
peSHIr
It works well on relatively bland backgrounds but will give you very ugly colors.
Henk Holterman
+4  A: 
 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
Toad
Excellent solution and simple, nicely done.
Kazar
This looks like applying an outline to the text
Bogdan Maxim
Seems so. My suggestion too. :)
Vilx-
I suggest doing this on the 4 diagonals instead of north/south east/west. It seems like it should be almost the same, but with many fonts your corners are much more readable doing diagonals.
Dinah
A: 

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.

Bogdan Maxim
A: 

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.

peSHIr
suggestion number 2 doesn't work. By taking a bigger textsize, the whole sentence gets wider. In effect that means that only the middle character of a sentence has an outline, all the characters to the left and right of it are actually getting more and more illegible.To make this trick work, one has to plot every letter individually. (but this is quite tricky to do good).
Toad
also suggestion number 2 is not very good. If you constantly change the color to the underlying image, this will give a very annoying flickering text. My suggestion with the black outline works on any background. Even on pure white, where you'd just see the black outline.
Toad
@reinier 1: Hence my comment on probably needing to do text rendering per character and needing a lot of coordinate fiddling to avoid ugly results. You did read the entire text, I hope? @reinier 2: I don't suggest changing the color to the underlying image, but changing the contrasting color to the foreground color of the text. So: draw white outline for black text and black outline for white text, regardless of what you are drawing over.
peSHIr