Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making the text of a label transparent in C#

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

like image 375
codythecoder Avatar asked Oct 31 '13 09:10

codythecoder


1 Answers

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

like image 122
King King Avatar answered Sep 23 '22 07:09

King King