c# transparency picturebox

C#Picturebox fondo transparente no parece funcionar



transparency (6)

Hay una excelente solución en el sitio web de CodeProject en

Haciendo controles transparentes - Sin parpadeo

esencialmente, el truco consiste en anular el evento paintbackground para recorrer todos los controles subyacentes en el picturebox y volver a dibujarlos. La función es: -

protected override void OnPaintBackground(PaintEventArgs e) // Paint background with underlying graphics from other controls { base.OnPaintBackground(e); Graphics g = e.Graphics; if (Parent != null) { // Take each control in turn int index = Parent.Controls.GetChildIndex(this); for (int i = Parent.Controls.Count - 1; i > index; i--) { Control c = Parent.Controls[i]; // Check it''s visible and overlaps this control if (c.Bounds.IntersectsWith(Bounds) && c.Visible) { // Load appearance of underlying control and redraw it on this background Bitmap bmp = new Bitmap(c.Width, c.Height, g); c.DrawToBitmap(bmp, c.ClientRectangle); g.TranslateTransform(c.Left - Left, c.Top - Top); g.DrawImageUnscaled(bmp, Point.Empty); g.TranslateTransform(Left - c.Left, Top - c.Top); bmp.Dispose(); } } } }

Para un proyecto mío necesito imágenes para mostrar con un fondo transparente. Hice algunas imágenes .png que tienen un fondo transparente (para comprobar esto, las abrí en Photoshop). Ahora tengo una clase que extiende PictureBox:

class Foo : PictureBox { public Foo(int argument) : base() { Console.WriteLine(argument);//different in the real application of course. //MyProject.Properties.Resources.TRANSPARENCYTEST.MakeTransparent(MyProject.Properties.Resources.TRANSPARENCYTEST.GetPixel(1,1)); //<-- also tried this this.Image = MyProject.Properties.Resources.TRANSPARENCYTEST; ((Bitmap)this.Image).MakeTransparent(((Bitmap)this.Image).GetPixel(1, 1)); this.SizeMode = PictureBoxSizeMode.StretchImage; this.BackColor = System.Drawing.Color.Transparent; } }

sin embargo, esto solo muestra la picturebox con un fondo blanco, parece que no puedo hacer que funcione con un fondo transparente.


Las respuestas anteriores parecen resolver su problema. De hecho, está viendo lo que hay detrás del control de cuadro de imagen: el formulario en sí mismo con el color de fondo blanco. Aquí he creado una función simple que primero convierte una imagen de tipo byte (matriz) en un mapa de bits y luego configura colores específicos (de la imagen del mapa de bits) a transparentes. Algo que también podrías usar:

using System; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms;

public void LogoDrawTransparent(PaintEventArgs e) { // Create a Bitmap object from an image file. Image myImg; Bitmap myBitmap; try { myImg = cls_convertImagesByte.GetImageFromByte(newImg); myBitmap = new Bitmap(myImg); // @"C:/Temp/imgSwacaa.jpg"); // Get the color of a background pixel. Color backColor = myBitmap.GetPixel(0, 0); // GetPixel(1, 1); Color backColorGray = Color.Gray; Color backColorGrayLight = Color.LightGray; Color backColorWhiteSmoke = Color.WhiteSmoke; Color backColorWhite = Color.White; Color backColorWheat = Color.Wheat; // Make backColor transparent for myBitmap. myBitmap.MakeTransparent(backColor); // OPTIONALLY, you may make any other "suspicious" back color transparent (usually gray, light gray or whitesmoke) myBitmap.MakeTransparent(backColorGray); myBitmap.MakeTransparent(backColorGrayLight); myBitmap.MakeTransparent(backColorWhiteSmoke); // Draw myBitmap to the screen. e.Graphics.DrawImage(myBitmap, 0, 0, pictureBox1.Width, pictureBox1.Height); //myBitmap.Width, myBitmap.Height); } catch { try { pictureBox1.Image = cls_convertImagesByte.GetImageFromByte(newImg); } catch { } //must do something } }

Puedes activar esta función en Paint de la pictureBox. Esta es mi clase a la que se hace referencia en la función anterior:

class cls_convertImagesByte { public static Image GetImageFromByte(byte[] byteArrayIn) { MemoryStream ms = new MemoryStream(byteArrayIn); Image returnImage = Image.FromStream(ms); return returnImage; } public static byte[] GetByteArrayFromImage(System.Drawing.Image imageIn) { MemoryStream ms = new MemoryStream(); imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); return ms.ToArray(); } }

Gracias. Chagbert


Probablemente funciona perfectamente. Estás viendo lo que está detrás del control de cuadro de imagen. Cual es la forma. Cuyo BackColor es probablemente blanco. Puede configurar la propiedad BackgroundImage del formulario para asegurarse, debería ver la imagen a través del cuadro de imagen. Me gusta esto:

Perforar un agujero a través del cuadro de imagen y la forma requiere un arma más grande, Form.TransparencyKey


Sé que su pregunta se basa en C # , pero debido a la similitud y la facilidad de conversión de VB.NET , agregaré una versión completa de VB que también permite actualizar el fondo del control a medida que lo mueve.

Ya tiene una respuesta, pero esto es para otros que encuentran esta publicación en los motores de búsqueda, y les gustaría una versión de VB , o simplemente quieren encontrar una muestra convertible COMPLETA si también la necesitan en C # .

Crea una nueva Clase de Control Personalizada , y pega lo siguiente en ella ... sobrescribiendo las cosas de la clase predeterminada:

Clase de control personalizado:

Public Class TransparentPictureBox Private WithEvents refresher As Timer Private _image As Image = Nothing Public Sub New() '' This call is required by the designer. InitializeComponent() '' Add any initialization after the InitializeComponent() call. refresher = New Timer() ''refresher.Tick += New EventHandler(AddressOf Me.TimerOnTick) refresher.Interval = 50 refresher.Start() End Sub Protected Overrides ReadOnly Property CreateParams() As CreateParams Get Dim cp As CreateParams = MyBase.CreateParams cp.ExStyle = cp.ExStyle Or &H20 Return cp End Get End Property Protected Overrides Sub OnMove(ByVal e As EventArgs) MyBase.OnMove(e) MyBase.RecreateHandle() End Sub Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) MyBase.OnPaint(e) ''Add your custom paint code here If _image IsNot Nothing Then e.Graphics.DrawImage(_image, CInt(Width / 2) - CInt(_image.Width / 2), CInt(Height / 2) - CInt(_image.Height / 2)) End If End Sub Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs) '' Paint background with underlying graphics from other controls MyBase.OnPaintBackground(e) Dim g As Graphics = e.Graphics If Parent IsNot Nothing Then '' Take each control in turn Dim index As Integer = Parent.Controls.GetChildIndex(Me) For i As Integer = Parent.Controls.Count - 1 To index + 1 Step -1 Dim c As Control = Parent.Controls(i) '' Check it''s visible and overlaps this control If c.Bounds.IntersectsWith(Bounds) AndAlso c.Visible Then '' Load appearance of underlying control and redraw it on this background Dim bmp As New Bitmap(c.Width, c.Height, g) c.DrawToBitmap(bmp, c.ClientRectangle) g.TranslateTransform(c.Left - Left, c.Top - Top) g.DrawImageUnscaled(bmp, Point.Empty) g.TranslateTransform(Left - c.Left, Top - c.Top) bmp.Dispose() End If Next End If End Sub Public Property Image() As Image Get Return _image End Get Set(value As Image) _image = value MyBase.RecreateHandle() End Set End Property Private Sub refresher_Tick(sender As Object, e As System.EventArgs) Handles refresher.Tick MyBase.RecreateHandle() refresher.Stop() End Sub End Class

... salve la clase, luego limpie su proyecto y vuelva a construir. El nuevo control debería aparecer como un nuevo elemento de herramienta. Encuéntralo, y arrástralo a tu formulario.

Aunque he tenido problemas con este control ... Ocurre cuando intento cargar una imagen animada "Cargando" .gif .

La imagen no se anima, y ​​también tiene problemas de visualización cuando oculta el control y luego intenta mostrarlo nuevamente.

Clasifique esos problemas y tendrá una clase de control personalizado perfecta. :)

EDITAR:

No tengo idea si lo siguiente funcionará en el IDE de C # o no, pero aquí está mi intento de conversión:

using Microsoft.VisualBasic; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; public class TransparentPictureBox { private Timer withEventsField_refresher; private Timer refresher { get { return withEventsField_refresher; } set { if (withEventsField_refresher != null) { withEventsField_refresher.Tick -= refresher_Tick; } withEventsField_refresher = value; if (withEventsField_refresher != null) { withEventsField_refresher.Tick += refresher_Tick; } } } private Image _image = null; public TransparentPictureBox() { // This call is required by the designer. InitializeComponent(); // Add any initialization after the InitializeComponent() call. refresher = new Timer(); //refresher.Tick += New EventHandler(AddressOf Me.TimerOnTick) refresher.Interval = 50; refresher.Start(); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x20; return cp; } } protected override void OnMove(EventArgs e) { base.OnMove(e); base.RecreateHandle(); } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { base.OnPaint(e); //Add your custom paint code here if (_image != null) { e.Graphics.DrawImage(_image, Convert.ToInt32(Width / 2) - Convert.ToInt32(_image.Width / 2), Convert.ToInt32(Height / 2) - Convert.ToInt32(_image.Height / 2)); } } protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) { // Paint background with underlying graphics from other controls base.OnPaintBackground(e); Graphics g = e.Graphics; if (Parent != null) { // Take each control in turn int index = Parent.Controls.GetChildIndex(this); for (int i = Parent.Controls.Count - 1; i >= index + 1; i += -1) { Control c = Parent.Controls(i); // Check it''s visible and overlaps this control if (c.Bounds.IntersectsWith(Bounds) && c.Visible) { // Load appearance of underlying control and redraw it on this background Bitmap bmp = new Bitmap(c.Width, c.Height, g); c.DrawToBitmap(bmp, c.ClientRectangle); g.TranslateTransform(c.Left - Left, c.Top - Top); g.DrawImageUnscaled(bmp, Point.Empty); g.TranslateTransform(Left - c.Left, Top - c.Top); bmp.Dispose(); } } } } public Image Image { get { return _image; } set { _image = value; base.RecreateHandle(); } } private void refresher_Tick(object sender, System.EventArgs e) { base.RecreateHandle(); refresher.Stop(); } }

Pruébalo, y verás por ti mismo, supongo: P

pd: no soy un gurú, así que espere todo tipo de errores en las versiones C # y VB.NET. jajaja


Si desea superponer imágenes sobre imágenes (y no imágenes sobre la forma), esto haría el truco:

overImage.Parent = backImage; overImage.BackColor = Color.Transparent; overImage.Location = thePointRelativeToTheBackImage;

Donde overImage y backImage son PictureBox con png (con fondo transparente).

Esto se debe a que, como se dijo anteriormente, la transparencia de una imagen se representa utilizando el color de fondo del contenedor principal. Los PictureBoxes no tienen una propiedad "principal", por lo que debes hacerlo manualmente (o crear un control sencillo, por supuesto).


Si está mostrando png con transparencia en el cuadro de imagen, se tendrá en cuenta automáticamente la transparencia, por lo que no es necesario establecer un color transparente.