Making the text of a label transparent in C#
Asked Answered
T

1

6

I have a label with a black BackColor and I have set the ForeColor to Transparent. The label is over a mostly blue PictureBox which I have set as its parent.
For some reason, the text, which should show blue, is white.
It doesn't seem to have any relation to the form color or the color of the picture box.
Also when I make the labels BackColor transparent it works fine.
Thanks

Teishateixeira answered 31/10, 2013 at 9:11 Comment(6)
"Also when I make the labels BackColor transparent it works fine". If it works fine, then do that, surely?Yahoo
@DavidArno They mean transparent background works fine, but they want transparent foreground.Philan
I'm pretty sure you're going to have to custom-draw the foreground on this one.Metope
Try setting the transparency map on your form to an unused color, then setting label text that color? Totally untested, just a thought.Incipient
Looks like winforms doesn't really support transparency see here for some help: #6622552.Dagoba
I'm pretty sure this is a "feature" of the Label class. If transparency was allowed, it would show the text in the Labels background colour (transparent or not) and your text would by definition be invisible.Germinal
P
8

I've tried customizing a Label supporting Transparent ForeColor but I've done it partially successfully. It does work great for many BackColors but it also doesn't work as expected for fairly many other BackColors. However using it with some working BackColor is acceptable if you like the BackColor. This code has to deal with Image, first we have to draw string on an Image (using high quality drawing), then we have to convert all the Text (which should be drawn with Color.Black) to the Color.Transparent. We also have to take all the colors between the Color.Black and the BackColor) into account, these medium colors (centralized mainly on the text curves) make the most trouble thing to solve. That's why there are some BackColors making it work unexpectedly. It can be solved if we have some better algorithm to scan through all the possible medium colors and convert them to the corresponding transparent colors (with alpha being less than 255). To convert from source color to destination color, we use many ColorMaps together with an ImageAttribute, this attribute will be used to determine how to draw the Image. In fact we can read each source pixel and draw the corresponding destination pixel but doing so requires more code (it's worth trying that way). Here is the complete code for the CustomLabel:

public class CustomLabel : Label {
    public CustomLabel() {
        BackColor = base.BackColor;
        base.BackColor = Color.Transparent;
        DoubleBuffered = true;                     
    }
    Color backColor;
    int alpha;
    public new Color BackColor {
        get { return Color.FromArgb(alpha, backColor); }
        set { 
           alpha = value.A;
           backColor = Color.FromArgb(value.R, value.G, value.B);
           UpdateVisual(true);               
        }
    }        
    protected override void OnForeColorChanged(EventArgs e) {
        base.OnForeColorChanged(e);
        if (ForeColor == Color.Transparent) {
            base.BackColor = Color.Transparent;
            UpdateVisual(true);
        } else {
            base.BackColor = BackColor;
            BackgroundImage = null;
        }
    }
    Image img;        
    private void UpdateVisual(bool applyChange) {     
        img = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppPArgb);
        using (Graphics g = Graphics.FromImage(img)){
            g.Clear(backColor);             
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;                
            g.DrawString(Text, Font, Brushes.Black, ClientRectangle);
        }
        Bitmap bm = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppPArgb);
        using (Graphics g = Graphics.FromImage(bm)) {
            g.SmoothingMode = SmoothingMode.HighSpeed;
            ImageAttributes ia = new ImageAttributes();
            List<ColorMap> cms = new List<ColorMap>();                
            for (decimal f = 0; f < 1; f += 0.001M) {
                ColorMap cm = new ColorMap();
                cm.NewColor = Color.FromArgb((int)((1 - f) * alpha), backColor);
                cm.OldColor = GetNormalBlendColor(backColor,Color.Black, f);                    
                cms.Add(cm);
            }              
            ia.SetRemapTable(cms.ToArray());                                
            g.DrawImage(img, new Point[] {Point.Empty, new Point(img.Width, 0), new Point(0,img.Height) }, new Rectangle() {Size = bm.Size}, GraphicsUnit.Pixel, ia);
        }
        img.Dispose();          
        img = bm;
        if (applyChange) BackgroundImage = img;
    }
    public Color GetNormalBlendColor(Color baseColor, Color blendColor, decimal opacity) {
        int R = Math.Min((int)((1 - opacity) * baseColor.R + blendColor.R * opacity), 255);
        int G = Math.Min((int)((1 - opacity) * baseColor.G + blendColor.G * opacity), 255);
        int B = Math.Min((int)((1 - opacity) * baseColor.B + blendColor.B * opacity), 255);                        
        return Color.FromArgb(R, G, B);
    }
    protected override void OnPaint(PaintEventArgs e) {
        if (ForeColor != Color.Transparent) {
            using (Brush brush = new SolidBrush(BackColor)) {
                e.Graphics.FillRectangle(brush, ClientRectangle);
            }
            base.OnPaint(e);
        }                        
    }      
    protected override void OnTextChanged(EventArgs e) {
        base.OnTextChanged(e);
        if(ForeColor == Color.Transparent) UpdateVisual(true);
    }
    protected override void OnFontChanged(EventArgs e) {
        base.OnFontChanged(e);
        if(ForeColor == Color.Transparent) UpdateVisual(true);
    }
    protected override void OnSizeChanged(EventArgs e) {
        base.OnSizeChanged(e);
        if (ForeColor == Color.Transparent) UpdateVisual(true);          
    }

}

enter image description here

PS: I hope someone will find a fix to complete this code, it works almost great but for some BackColor, the text curve becomes distinct and is like a randomly dotted curve. The worst back color to see that bug is Color.Chocolate :)

For some non-working BackColor :) here is for Color.Chocolate:

enter image description here

Prodrome answered 31/10, 2013 at 19:35 Comment(6)
Your answers are getting hard to read, go easy on the backtick and the bold for an old guy like me, please.Bib
@HansPassant sorry, I don't think it's hard to read, using backtick or bold even makes me type more (which is not what everyone wants), I just think it's more readable.Prodrome
Most people are used to reading books and news papers, they just don't look like that in my neck of the world. Do they in Vietnam? I find it personally impossible to see the words between the ones yelling for attention. It is certainly entirely up to you to do it the way you like, just giving a heads-up that you're losing a common reader (and voter) of your answers.Bib
Could you maybe also add an image which shows how exactly is it "like a randomly dotted curve"?Tweed
@Tweed could you try it yourself? it's easy.Prodrome
@Tweed also added snap shot for non-working BackColor as you want.Prodrome

© 2022 - 2024 — McMap. All rights reserved.