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

H H
  • 263,252
  • 30
  • 330
  • 514
codythecoder
  • 376
  • 5
  • 17
  • 1
    "Also when I make the labels BackColor transparent it works fine". If it works fine, then do that, surely? – David Arno Oct 31 '13 at 09:17
  • 4
    @DavidArno They mean transparent background works fine, but they want transparent foreground. – user2586804 Oct 31 '13 at 09:19
  • I'm pretty sure you're going to have to custom-draw the foreground on this one. – Mike Perrenoud Oct 31 '13 at 09:21
  • Try setting the transparency map on your form to an unused color, then setting label text that color? Totally untested, just a thought. – Lotok Oct 31 '13 at 09:30
  • Looks like winforms doesn't really support transparency see here for some help: http://stackoverflow.com/questions/6622052/label-backcolor-not-going-transparent. – TheKingDave Oct 31 '13 at 09:45
  • 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. – H H Oct 31 '13 at 09:46

1 Answers1

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

King King
  • 61,710
  • 16
  • 105
  • 130
  • 3
    Your answers are getting hard to read, go easy on the backtick and the bold for an old guy like me, please. – Hans Passant Oct 31 '13 at 19:46
  • @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. – King King Oct 31 '13 at 19:50
  • 1
    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. – Hans Passant Oct 31 '13 at 19:57
  • Could you maybe also add an image which shows how exactly is it "like a randomly dotted curve"? – C.B. Oct 31 '13 at 20:28
  • @C.B. could you try it yourself? it's easy. – King King Oct 31 '13 at 20:29
  • @C.B. also added snap shot for `non-working BackColor` as you want. – King King Oct 31 '13 at 20:35