|
621
|
Programación / .NET (C#, VB.NET, ASP) / Re: Duda con PictureBox y Saturación de Color
|
en: 17 Septiembre 2016, 20:35 pm
|
Como dije en el post, solo es un código de ejemplo, un ejemplo que se debe adaptar a las necesidades que tengas, de todas formas aceptando tu petición le cambié el nombre a la función y también especifiqué que la matriz de color es una idea original tuya.
Saludos!
Esta tarde he podido ver más tranquilamente su código y probarlo. He visto un problema que miraré mas tarde no quiero darle trabajo pues ya a aportado una respuesta excelente. Lo único que no he visto correcto es sacar la operación factor+= 100 de la función pues forma parte de la misma. De todos modos he conseguido sintentizar las operaciones, y ya no hace falta el 'factor+= 100', quedando así: Dim r As Single = CSng(factor * (299 * -10 ^ -5)) Dim g As Single = CSng(factor * (587 * -10 ^ -5)) Dim b As Single = CSng(factor * (114 * -10 ^ -5)) factor = (factor / 100.0F) + 1 Dim matrix As Single()() = { New Single() {(r + factor), r, r, 0.0F, 0.0F}, New Single() {g, (g + factor), g, 0.0F, 0.0F}, New Single() {b, b, (b + factor), 0.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F} }
o también: Dim r As Single = CSng(factor * -(299 * 10 ^ -5)) Dim g As Single = CSng(factor * -(587 * 10 ^ -5)) Dim b As Single = CSng(factor * -(114 * 10 ^ -5)) ...
Dim r As Single = CSng(factor * -(299 / 100000.0F)) Dim g As Single = CSng(factor * -(587 / 100000.0F)) Dim b As Single = CSng(factor * -(114 / 100000.0F))
Conseguí eliminar otra ecuación más factor = (factor / 100.0F) ''' <summary> ''' Función para saturación de color //por @Elektro y @FJDA ''' </summary> ''' <param name="srcImg">Objeto de tipo System.Drawing.Image</param> ''' <param name="Factor">Valor de saturación de color; de -100 a 100</param> ''' <param name="highQuality">Composición de calidad</param> ''' <returns></returns> ''' <remarks></remarks> Public Function SetImageSaturation(ByVal srcImg As Image, ByVal Factor As Single, ByVal highQuality As Boolean) As Image Dim F As Single = Factor Dim R As Single = CSng(F * -(299 / 100000)) Dim G As Single = CSng(F * -(587 / 100000)) Dim B As Single = CSng(F * -(114 / 100000)) Dim bmp As New Bitmap(srcImg.Width, srcImg.Height, srcImg.PixelFormat) Dim matrix As Single()() = { New Single() {CSng((0.00701 * F) + 1), R, R, 0.0F, 0.0F}, New Single() {G, CSng((0.00413 * F) + 1), G, 0.0F, 0.0F}, New Single() {B, B, CSng((0.00886 * F) + 1), 0.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F} } Using ia As New ImageAttributes ia.ClearColorMatrix() ia.SetColorMatrix(New ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap) ia.SetGamma(1.0F, ColorAdjustType.Bitmap) Using gdi As Graphics = Graphics.FromImage(bmp) With gdi If highQuality Then .CompositingQuality = CompositingQuality.HighQuality .InterpolationMode = InterpolationMode.HighQualityBicubic .PixelOffsetMode = PixelOffsetMode.HighQuality .SmoothingMode = SmoothingMode.HighQuality Else .CompositingQuality = CompositingQuality.HighSpeed .InterpolationMode = InterpolationMode.NearestNeighbor .PixelOffsetMode = PixelOffsetMode.None .SmoothingMode = SmoothingMode.None End If .DrawImage(srcImg, New Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, srcImg.Width, srcImg.Height, GraphicsUnit.Pixel, ia) End With End Using ' gdi End Using ' ia Return bmp End Function
Buenas de nuevo. @Elektro. he estado analizando su código y lo he ejecutado. Como comenté había algún problema y es que a pesar de que introdujo el trabajo en modo asincrónico seguía habiendo una ligera lentitud para mostrar el cambio si se movía muy rápido el TrackBar, especialmente se percibía al mostrar el valor de saturación en el Label. Finalmente hemos conseguido eficiencia cien por cien, gracias a usted. ¡¡Buen trabajo!! Tan solo tuve que realizar pequeños cambios. sin importancia. También mediante matemáticas eliminar ecuaciones innecesarias. Aquí muestro los cambios y he reducido el código para que sea más fácil de entender y sea más corto. *Deben crear un PictureBox, un TrackBar1 y un Label* Coloquen el directorio para cargar la imagen en: .ImagenPrevia = Image.FromFile(".\Imagen.jpg") Imports System.Runtime.CompilerServices Imports System.ComponentModel Imports System.Drawing.Imaging Imports System.Drawing.Drawing2D Public NotInheritable Class Form1 Inherits Form Private ImagenPrevia As Image Private ImagenDeTrabajo As Image Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load With Me 'Propiedades para el TrackBar1 With .TrackBar1 .TickFrequency = 10 .TickStyle = TickStyle.TopLeft .Maximum = 100 .Minimum = -100 .Value = 0 End With 'Propiedades para el PictureBox1 With .PictureBox1 .BackColor = Color.DarkGray .SizeMode = PictureBoxSizeMode.Normal End With 'Carga la imagen desde un directorio .ImagenPrevia = Image.FromFile(".\Imagen.jpg") 'Tamaño de la imagen para trabajar Dim TamañoImagenDeTrabajo As Size = .PictureBox1.Size 'Obtiene imagen previa para trabajar .ImagenDeTrabajo = .ImagenPrevia.GetThumbnailImage(TamañoImagenDeTrabajo.Width, _ TamañoImagenDeTrabajo.Height, _ Nothing, Nothing) .PictureBox1.Image = .ImagenDeTrabajo End With End Sub Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Handles TrackBar1.ValueChanged 'Ejecutar de forma asincrónica Task.Factory.StartNew(Sub() Dim lockImg As Image = ImagenDeTrabajo SyncLock lockImg 'Bloqueo de instrucción antes de procesar Me.Invoke(Sub() Dim vSat As Single = TrackBar1.Value 'Obtiene el valor de saturación de color Label1.Text = CStr(vSat) 'Muestra el valor de saturación de color lockImg = lockImg.SetImageSaturation(sngSatVal:=vSat, highQuality:=False) Me.PictureBox1.Image = lockImg End Sub) 'Me.Invoke End SyncLock End Sub) 'Task End Sub End Class Public Module ImageExtensions ''' <summary> ''' Función para saturación de color //por @Elektro y @FJDA ''' </summary> ''' <param name="srcImg">Objeto de tipo System.Drawing.Image</param> ''' <param name="sngSatVal">Valor de saturación de -100 a 100</param> ''' <param name="highQuality">Composición de calidad</param> ''' <returns></returns> ''' <remarks></remarks> <DebuggerStepThrough> <Extension> <EditorBrowsable(EditorBrowsableState.Always)> Public Function SetImageSaturation(ByVal srcImg As Image, ByVal sngSatVal As Single, ByVal highQuality As Boolean) As Image Dim R As Single = CSng(sngSatVal * -(299 / 100000)) Dim G As Single = CSng(sngSatVal * -(587 / 100000)) Dim B As Single = CSng(sngSatVal * -(114 / 100000)) Dim FactR As Single = CSng(((0.00701F * sngSatVal) + 1)) Dim FactG As Single = CSng(((0.00413F * sngSatVal) + 1)) Dim FactB As Single = CSng(((0.00886F * sngSatVal) + 1)) Dim matrix As Single()() = { New Single() {FactR, R, R, 0, 0}, New Single() {G, FactG, G, 0, 0}, New Single() {B, B, FactB, 0, 0}, New Single() {0, 0, 0, 1, 0}, New Single() {0, 0, 0, 0, 1} } Dim bmp As New Bitmap(srcImg.Width, srcImg.Height, srcImg.PixelFormat) Using ia As New ImageAttributes ia.ClearColorMatrix() ia.SetColorMatrix(New ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap) ia.SetGamma(1.0F, ColorAdjustType.Bitmap) Using gdi As Graphics = Graphics.FromImage(bmp) With gdi If highQuality Then .CompositingQuality = CompositingQuality.HighQuality .InterpolationMode = InterpolationMode.HighQualityBicubic .PixelOffsetMode = PixelOffsetMode.HighQuality .SmoothingMode = SmoothingMode.HighQuality Else .CompositingQuality = CompositingQuality.HighSpeed .InterpolationMode = InterpolationMode.NearestNeighbor .PixelOffsetMode = PixelOffsetMode.None .SmoothingMode = SmoothingMode.None End If .DrawImage(srcImg, New Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, srcImg.Width, srcImg.Height, GraphicsUnit.Pixel, ia) End With End Using ' gdi End Using ' ia Return bmp End Function End Module
Hoy he modificado un poco la matriz para que sea más ordenado y legible. Ya que el uso del punto fijo 'F' junto con la variable single F (mal puesta por mi parte), lo hacía confuso. No veo necesario su uso en valores 0 o 1, así que lo he suprimido en estos valores. También he sacado las ecuaciones de la matriz pasándolas a FactR, FactG y FactB, nombrandolos Fact(Letra color) porque son los verdaderos factores de rojo, verde y azul. Dim R As Single = CSng(sngSatVal * -(299 / 100000)) Dim G As Single = CSng(sngSatVal * -(587 / 100000)) Dim B As Single = CSng(sngSatVal * -(114 / 100000)) Dim FactR As Single = CSng(((0.00701F * sngSatVal) + 1)) Dim FactG As Single = CSng(((0.00413F * sngSatVal) + 1)) Dim FactB As Single = CSng(((0.00886F * sngSatVal) + 1))
Dim matrix As Single()() = { New Single() {FactR, R, R, 0, 0}, New Single() {G, FactG, G, 0, 0}, New Single() {B, B, FactB, 0, 0}, New Single() {0, 0, 0, 1, 0}, New Single() {0, 0, 0, 0, 1} } y recuerden que para guardar la imagen deben usar la imagen previa (la original en tamaño y calidad) y modificar la saturación en alta calidad en el momento de guardar. Como bien ha hecho @Elektro, para realizar los cambios previos se trabaja con una imagen de bajo tamaño y calidad para acelerar el trabajo, pero a la hora de guardar hay que trabajar con la imagen original en tamaño y calidad que hemos cargado. Using img As Image = SetImageSaturation(ImagenPrevia, TrackBar1.Value, highQuality:=True) img.Save(".\Cambios.jpg", ImageFormat.Jpeg) End Using
Aquí dejo finalizado el tema, creo que se ha conseguido y espero sea de utilidad para otros programadores. Agradecimientos de nuevo a @Elektro por su gran ayuda. Hasta luego.
|
|
|
622
|
Programación / .NET (C#, VB.NET, ASP) / Re: Duda con PictureBox y Saturación de Color
|
en: 17 Septiembre 2016, 11:03 am
|
Bueno, como te prometí, vamos al tema... Desconozco cual es el código original que estarás usando, pero el código de ejemplo que has compartido tiene varios problemas, e imagino que los mismos problemas estarán replicados en el código original... Por orden de importancia:
El problema principal (y el más grave) por el cual se aprecia una elevada lentitud de respuesta al mover el TrackBar, es por que estás manipulando la imagen a tamaño real cada vez que mueves la posición del TrackBar, y eso causa un gran impacto negativo en el rendimiento de la aplicación. Si tenemos un PictureBox donde quieres previsualizar la imagen, entonces lo primero que debemos hacer para evitar problemas de rendimiento es redimensaionar la imagen original al tamaño de ese PictureBox, eso lo puedes hacer "manualmente" creando un objeto Bitmap del tamaño deseando y dibujando la imagen, o simplemente llamando a la función Image.GetThumbnailImage(), y entonces, manipular la imagen redimensionada.
El segundo problema es que estás utilizando los parámetros por defecto de calidad de imagen al dibujar la imagen modificada y, al tratarse de una previsualización, logicamente deberiamos personalizar esos parámetros para crear una imagen de baja calidad, es decir, más rápida de procesar. Los parámetros (o propiedades) que debes ajustar son las siguientes: - Graphics.CompositingQuality = CompositingQuality.HighSpeed
- Graphics.InterpolationMode = InterpolationMode.NearestNeighbor
- Graphics.PixelOffsetMode = PixelOffsetMode.None
- Graphics.SmoothingMode = SmoothingMode.None
Si a todo lo anterior le sumamos que cada vez que asignas la imagen modificada a tamaño real, ésta debe ser vuelta a modificar para ser estrechada, esto logicamente disminuirá todavía más el rendimiento ...de hecho el estrechamiento de cualquier imagen es expensivo de por si. La solución es sencilla y obvia, debemos restaurar el valor por defecto ( PictureBoxSizeMode.Normal) para no forzar otra redimensión adicional de la imagen, y en su lugar utilizar una imagen del tamaño del PictureBox, como ya expliqué más arriba.
El último problema (pero no menos importante), es que todo el procedimiento o algoritmo del código que has publicado se lleva a cabo de forma sincrónica, y esto supone que cada vez que mueves el TrackBar, el hilo de la interfáz de usuario debe esperar a que la imagen se procese y la modificación de imagen se genere para poder procesar el siguiente evento de "mover" del TrackBar, y esto se aprecia en forma de desagradables congelamientos de respuesta o "trompicones" al intentar mover el TrackBar demasiado rápido, puesto que se necesita mucho más tiempo para procesar todo lo que haces con esa imagen a tamaño real, que para mover el TrackBar. Tanto en C#/VB.NET como en cualquier otro lenguaje, a mayor cantidad de datos que procesar (y una imagen cotidiana contiene muchos datos que procesar) necesitará mayor tiempo de procesado, y hay que esperar ese tiempo, es así de simple. Dicho de otro modo: estás saturando el hilo de la interfáz de usuario.
También cabe mencionar que no estás haciendo un buen uso, o mejor dicho directamente no haces ningún uso de la correcta administración del Garbage Collector para ayudarle a recolectar los recursos de los objetos que ya no sean necesarios por tu aplicación. Debes asegurarte siempre, sin excepción, de liberar los objetos que sean deshechables llamando al método Object.Dispose(), incluso con los objetos que se liberen automáticamente al liberar un Form, no pierdas la costumbre. Esto no afecta en el rendimiento de la interfáz de usuario (al menos no en el código de ejemplo que has publicado), pero si que afectará al consumo de memoria, y mucho. Literalmente hablando hay una fuga muy grave de memoria en el código que has publicado, basta con cargar una imagen de varios megabytes (+/-10 mb) y mover la posición del trackbar un par de veces para ver como el espacio reservado va subiendo, y subiendo, y subiendo... y nunca baja, puesto que nunca liberas los recursos no-administrados (Win32) de las imágenes llamando al método Dispose.
No se a que te estarás refiriendo pero eso no es así. C# y VB.NET son dos lenguajes que trabajan bajo el mismo framework de Microsoft, por ende, ambos pueden utilizar todas las funciones que estén definidas en la librería de clases de .NET Framework. Ambos lenguajes son idénticos en esencia, excepto algunas peculiaridades muy concretas de cada lenguaje. Vaya es usted una auténtico maestro. Ahora mismo no tengo tiempo de probar los cambios y la información que me facilita más tarde lo haré y le comentaré cualquier problema o circunstancia. Ya pedí libros en otra pregunta pero no me respondió, nadie. Me interesa mucho sobre todo trabajar con imágenes pero es difícil encontrar. Ya imaginé que había que tratar la imagen adecuadamente para poder modificar de forma eficiente pero es difícil saber sin la información adecuada. En cuanto a C# y VB, he comprobado que en C# PictureBox tiene filtros en sus propiedades y miembros que no veo que aparezcan en VB. A eso me refería. hasta luego y gracias por su amabilidad.
No he podido evitar curiosear a falta de tiempo su modificación. Le agradecería cambie el nombramiento de esta función a SetImageSaturation: Public Function SetImageSaturation(ByVal srcImg As Image, ByVal factor As Single, ByVal highQuality As Boolean) As Image factor+= 100 Dim r As Single = (299 * (100 - factor) / 100000.0F) Dim g As Single = (587 * (100 - factor) / 100000.0F) Dim b As Single = (114 * (100 - factor) / 100000.0F) factor = (factor / 100.0F) Dim bmp As New Bitmap(srcImg.Width, srcImg.Height, srcImg.PixelFormat) Dim matrix As Single()() = { New Single() {(r + factor), r, r, 0.0F, 0.0F}, New Single() {g, (g + factor), g, 0.0F, 0.0F}, New Single() {b, b, (b + factor), 0.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F} }
Esta matriz la he desarrollado yo y es única. Imagino habrán otras pero yo no encontré ninguna buscando que funcionara igual que en API. Existen otras configuraciones, para brillo, escala de grises, gamma, etc. Es importante recalcar que esta matriz es exclusivamente para Saturación. Si lo nombra SetImageCorrection no es posible saber a simple vista para que se ha implementado dicha función. Es posible añadir 'If factor > 0 then', para multiplicar por diez el efecto cuando sea mayor que cero para conseguir una mayor saturación de color. hasta luego y gracias de nuevo
|
|
|
623
|
Programación / .NET (C#, VB.NET, ASP) / Re: Duda con PictureBox y Saturación de Color
|
en: 16 Septiembre 2016, 21:06 pm
|
lo estás complicando todo demasiado.
en un rato despues de cenar editaré este mensaje para mostrarte una solución completa y funcional (sin ningún tipo de "retraso" o "bloqueo") e indicarte (algunos de) los fallos del código actual que tienes.
hasta ahora!
Cambie el COLORADJUSTMENT todo a Short. Porque hace una hora edité mi mensaje y cambié caBlueGamma, caRedGamma, caGreenGamma, a Integer por que ví que como Short BlueGamma no funcionaba, pero si hago esto no funcionan los demás ajustes. Intenté usar funciones que PictureBox tiene en C# que simplifican mucho todo pero no están disponibles en VB El código del principio lo saqué de aquí, solo cambié la matriz para conseguir el efecto de saturación https://onedrive.live.com/?authkey=%21AGLMrn20g0JGtX0&id=C9DBA2BC5A16373B%21115&cid=C9DBA2BC5A16373BSon códigos de muestra, solo necesito saber que falla, gracias. No hace falta que modifique todo, no quisiera dar demasiado trabajo, pero vi en otras preguntas que se quejan que no ponen código. el 80% del código es sólo para que lo puedan ejecutar, sin tener que crear nada.
|
|
|
624
|
Programación / .NET (C#, VB.NET, ASP) / Duda con PictureBox y Saturación de Color
|
en: 16 Septiembre 2016, 16:45 pm
|
Buenas amigos, estoy intentando saturar una imagen y lo he conseguido pero el programa tarda mucho en procesar los cambios. Estoy orgulloso de lo que he conseguido porque no ha sido fácil averiguarlo, pero no va bien. He usado los miembro ColorMatrix y SetColorMatrix y he conseguido crear una matriz que realiza la saturación de una imagen, pero al usar un TrackBar el proceso de los cambios es demasiado lento. S = (TrackBar1.Value) + 100
Dim Rojo As Single = CSng(299 * (100 - S) / 100000) Dim Verde As Single = CSng(587 * (100 - S) / 100000) Dim Azul As Single = CSng(114 * (100 - S) / 100000)
S = CSng(S / 100) Dim colorMatrixVal As Single()() = { New Single() {Rojo + S, Rojo, Rojo, 0, 0}, _ New Single() {Verde, Verde + S, Verde, 0, 0}, _ New Single() {Azul, Azul, Azul + S, 0, 0}, _ New Single() {0, 0, 0, 1, 0}, _ New Single() {0, 0, 0, 0, 1}} Este lo he hecho como ejemplo para ponerlo aquí: Imports System.IO Imports System.Drawing.Imaging Public Class Form1 Private originalBitmap As Bitmap = Nothing Private previewBitmap As Bitmap = Nothing Private resultBitmap As Bitmap = Nothing Dim PictureBox1 As New PictureBox With {.Location = New Point(10, 10), .Size = New Size(400, 240), .SizeMode = PictureBoxSizeMode.StretchImage, .BackColor = Color.DarkGray} Dim Button1 As New Button With {.Location = New Point(PictureBox1.Width + 20, 10), .Text = "Cargar"} Dim Button2 As New Button With {.Location = New Point(PictureBox1.Width + 20, 40), .Text = "Guardar"} Dim TrackBar1 As New TrackBar With {.Location = New Point(10, PictureBox1.Height + 20), .AutoSize = True, .Size = New Size(PictureBox1.Width, 10), .TickStyle = TickStyle.TopLeft, .BackColor = Color.DarkGray, .TickFrequency = 50, .Maximum = 100, .Minimum = -100, .Value = 0, .Orientation = Orientation.Horizontal} Dim Label1 As New Label With {.Location = New Point(TrackBar1.Width + 20, TrackBar1.Top + 10), .AutoSize = True, .Text = "0", .Font = New Font("Arial", 20, FontStyle.Bold)} Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Me.Controls.Add(PictureBox1) Me.Controls.Add(Button1) Me.Controls.Add(Button2) Me.Controls.Add(TrackBar1) Me.Controls.Add(Label1) Label1.BringToFront() Me.Size = New Size(520, 400) AddHandler TrackBar1.ValueChanged, AddressOf TrackBar1_ValueChanged AddHandler Button1.Click, AddressOf Button1_Click AddHandler Button2.Click, AddressOf Button2_Click End Sub Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Label1.Text = TrackBar1.Value.ToString() AplicarSaturacion(True) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Dim ofd As New OpenFileDialog() ofd.Title = "Abrir imagen" ofd.Filter = "Jpeg Images(*.jpg)|*.jpg|Png Images(*.png)|*.png" ofd.Filter += "|Bitmap Images(*.bmp)|*.bmp" If ofd.ShowDialog() = System.Windows.Forms.DialogResult.OK Then Dim streamReader As New StreamReader(ofd.FileName) originalBitmap = DirectCast(Bitmap.FromStream(streamReader.BaseStream), Bitmap) streamReader.Close() previewBitmap = Image.FromFile(ofd.FileName) PictureBox1.Image = previewBitmap AplicarSaturacion(True) End If End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) AplicarSaturacion(False) If resultBitmap IsNot Nothing Then Dim sfd As New SaveFileDialog() sfd.Title = "Guardar imagen" sfd.Filter = "Jpeg Images(*.jpg)|*.jpg|Png Images(*.png)|*.png" sfd.Filter += "|Bitmap Images(*.bmp)|*.bmp" If sfd.ShowDialog() = System.Windows.Forms.DialogResult.OK Then Dim fileExtension As String = Path.GetExtension(sfd.FileName).ToUpper() Dim imgFormat As ImageFormat = ImageFormat.Png If fileExtension = "BMP" Then imgFormat = ImageFormat.Bmp ElseIf fileExtension = "JPG" Then imgFormat = ImageFormat.Jpeg End If Dim streamWriter As New StreamWriter(sfd.FileName, False) resultBitmap.Save(streamWriter.BaseStream, imgFormat) streamWriter.Flush() streamWriter.Close() resultBitmap = Nothing End If End If End Sub Public Sub AplicarSaturacion(Byval preview As Boolean) If previewBitmap Is Nothing Then Return End If Dim Imagen As Image = previewBitmap Dim Pic As PictureBox = PictureBox1 Dim Grafico As Graphics Dim Rectangulo As Rectangle Pic.Image = New Bitmap(Pic.Width, Pic.Height, PixelFormat.Format32bppArgb) Grafico = Graphics.FromImage(Pic.Image) Rectangulo = New Rectangle(0, 0, Pic.Width, Pic.Height) Grafico.DrawImage(Imagen, Rectangulo) Dim S As Single S = (TrackBar1.Value) + 100 Dim Rojo As Single = CSng(299 * (100 - S) / 100000) Dim Verde As Single = CSng(587 * (100 - S) / 100000) Dim Azul As Single = CSng(114 * (100 - S) / 100000) S = CSng(S / 100) Dim colorMatrixVal As Single()() = { New Single() {Rojo + S, Rojo, Rojo, 0, 0}, _ New Single() {Verde, Verde + S, Verde, 0, 0}, _ New Single() {Azul, Azul, Azul + S, 0, 0}, _ New Single() {0, 0, 0, 1, 0}, _ New Single() {0, 0, 0, 0, 1}} Dim colorMatrix As New ColorMatrix(colorMatrixVal) Dim ImagenAtributos As New ImageAttributes ImagenAtributos.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap) Grafico.DrawImage(Imagen, Rectangulo, 0, 0, Imagen.Width, Imagen.Height, GraphicsUnit.Pixel, ImagenAtributos) Pic.Refresh() resultBitmap = Pic.Image End Sub End Class
Va bien pero al deslizar el TrackBar se producen trompicones al moverlo. He conseguido convertir por mi cuenta un código de VB viejo a NET que usa API. Que no sé, seré el único que lo he hecho porque puse en google -SetColorAdjustment VB.NET- y ni rastro, las declaraciones que encontraba eran como en VB6. Conseguí crear un código basado en API con SetColorAdjustment y GetColorAdjustment , y funciona bien. Los cambios son suaves pero tiene un problema y es que no puedo guardar los cambios y no consigo refrescar el PictureBox correctamente. Este es el código: Imports System.IO Imports System.Drawing.Imaging Imports System.Runtime.InteropServices Imports WindowsApplication1.NativeMethods Public Class Form1 Private originalBitmap As Bitmap = Nothing Private previewBitmap As Bitmap = Nothing Private resultBitmap As Bitmap = Nothing Dim picLoad As Boolean Dim PictureBox1 As New PictureBox With {.Location = New Point(10, 10), .Size = New Size(400, 240), .SizeMode = PictureBoxSizeMode.StretchImage, .BackColor = Color.DarkGray} Dim Button1 As New Button With {.Location = New Point(PictureBox1.Width + 20, 10), .Text = "Cargar"} Dim Button2 As New Button With {.Location = New Point(PictureBox1.Width + 20, 40), .Text = "Guardar"} Dim TrackBar1 As New TrackBar With {.Location = New Point(10, PictureBox1.Height + 20), .AutoSize = True, .Size = New Size(PictureBox1.Width, 10), .TickStyle = TickStyle.TopLeft, .BackColor = Color.DarkGray, .TickFrequency = 50, .Maximum = 100, .Minimum = -100, .Value = 0, .Orientation = Orientation.Horizontal} Dim Label1 As New Label With {.Location = New Point(TrackBar1.Width + 20, TrackBar1.Top + 10), .AutoSize = True, .Text = "0", .Font = New Font("Arial", 20, FontStyle.Bold)} Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Me.Controls.Add(PictureBox1) Me.Controls.Add(Button1) Me.Controls.Add(Button2) Me.Controls.Add(TrackBar1) Me.Controls.Add(Label1) Label1.BringToFront() Me.Size = New Size(520, 400) AddHandler TrackBar1.ValueChanged, AddressOf TrackBar1_ValueChanged AddHandler Button1.Click, AddressOf Button1_Click AddHandler Button2.Click, AddressOf Button2_Click AddHandler PictureBox1.Paint, AddressOf PictureBox1_Paint End Sub Public Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) If picLoad = True Then AplicarSaturacion(True) End If End Sub Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Label1.Text = TrackBar1.Value.ToString() PictureBox1.Refresh() PictureBox1_Paint(1, Nothing) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Dim ofd As New OpenFileDialog() ofd.Title = "Guardar imagen" ofd.Filter = "Jpeg Images(*.jpg)|*.jpg|Png Images(*.png)|*.png" ofd.Filter += "|Bitmap Images(*.bmp)|*.bmp" If ofd.ShowDialog() = System.Windows.Forms.DialogResult.OK Then Dim streamReader As New StreamReader(ofd.FileName) originalBitmap = DirectCast(Bitmap.FromStream(streamReader.BaseStream), Bitmap) streamReader.Close() previewBitmap = Image.FromFile(ofd.FileName) PictureBox1.Image = previewBitmap picLoad = True AplicarSaturacion(True) End If End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) AplicarSaturacion(False) If resultBitmap IsNot Nothing Then Dim sfd As New SaveFileDialog() sfd.Title = "Abrir Imagen" sfd.Filter = "Jpeg Images(*.jpg)|*.jpg|Png Images(*.png)|*.png" sfd.Filter += "|Bitmap Images(*.bmp)|*.bmp" If sfd.ShowDialog() = System.Windows.Forms.DialogResult.OK Then Dim fileExtension As String = Path.GetExtension(sfd.FileName).ToUpper() Dim imgFormat As ImageFormat = ImageFormat.Png If fileExtension = "BMP" Then imgFormat = ImageFormat.Bmp ElseIf fileExtension = "JPG" Then imgFormat = ImageFormat.Jpeg End If Dim streamWriter As New StreamWriter(sfd.FileName, False) resultBitmap.Save(streamWriter.BaseStream, imgFormat) streamWriter.Flush() streamWriter.Close() resultBitmap = Nothing End If End If End Sub Public Sub AplicarSaturacion(ByVal preview As Boolean) Dim ca As COLORADJUSTMENT ca.caSize = CType(Marshal.SizeOf(ca), Short) Dim HDcPic As IntPtr = CType(PictureBox1.CreateGraphics.GetHdc, IntPtr) 'GetDC(PictureBox1.Handle) SetStretchBltMode(HDcPic, HALFTONE) GetColorAdjustment(HDcPic, ca) ca.caColorfulness = TrackBar1.Value SetColorAdjustment(HDcPic, ca) StretchBlt(HDcPic, 0, 0, PictureBox1.Image.Width, PictureBox1.Image.Height, _ HDcPic, 0, 0, PictureBox1.Image.Width, PictureBox1.Image.Height, TernaryRasterOperations.SRCCOPY) resultBitmap = PictureBox1.Image End Sub
NativeMethods > GetColorAdjustment y SetColorAdjustment para VB.NET<Security.SuppressUnmanagedCodeSecurity> Friend Class NativeMethods Inherits Attribute Private Sub New() End Sub <DllImport("gdi32.dll")> _ Public Shared Function BitBlt(hObject As IntPtr, nXDest As Integer, nYDest As Integer, nWidth As Integer, nHeight As Integer, hObjSource As IntPtr, nXSrc As Integer, nYSrc As Integer, dwRop As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("gdi32.dll")> Shared Function SetColorAdjustment(hdc As IntPtr, <MarshalAs(UnmanagedType.Struct)> ByRef lpca As COLORADJUSTMENT) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("gdi32.dll")> Shared Function GetColorAdjustment(ByVal hdc As IntPtr, <MarshalAs(UnmanagedType.Struct)> ByRef lpca As COLORADJUSTMENT) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("user32.dll")> Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr End Function <DllImport("gdi32.dll")> _ Public Shared Function StretchBlt(hdc As IntPtr, _ x As Integer, y As Integer, nHeight As Integer, hSrcDC As Integer, hObjSource As IntPtr, _ xSrc As Integer, ySrc As Integer, nSrcWidth As Integer, nSrcHeight As Integer, dwRop As TernaryRasterOperations) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <DllImport("gdi32.dll")> _ Public Shared Function SetStretchBltMode(ByVal hObject As IntPtr, ByVal nStretchMode As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function <StructLayout(LayoutKind.Sequential)> Public Structure COLORADJUSTMENT Public caSize As Short Public caFlags As Short Public caIlluminantIndex As Short Public caRedGamma As Short Public caGreenGamma As Short Public caBlueGamma As Short Public caReferenceBlack As Short Public caReferenceWhite As Short Public caContrast As Short Public caBrightness As Short Public caColorfulness As Short Public caRedGreenTint As Short End Structure Public Enum caIlluminantIndex ILLUMINANT_DEVICE_DEFAULT = 0 'Device's default. Standard used by output devices. ILLUMINANT_A = 1 'Tungsten lamp. ILLUMINANT_B = 2 'Noon sunlight. ILLUMINANT_C = 3 'NTSC daylight. ILLUMINANT_D50 = 4 'Normal print. ILLUMINANT_D55 = 5 'Bond paper print. ILLUMINANT_D65 = 6 'Standard daylight. Standard for CRTs and pictures. ILLUMINANT_D75 = 7 'Northern daylight. ILLUMINANT_F2 = 8 'Cool white lamp. ILLUMINANT_DAYLIGHT = ILLUMINANT_C 'Same as ILLUMINANT_C. ILLUMINANT_FLUORESCENT = ILLUMINANT_F2 'Same as ILLUMINANT_F2. ILLUMINANT_MAX_INDEX = ILLUMINANT_F2 'Same as ILLUMINANT_F2. ILLUMINANT_NTSC = ILLUMINANT_C 'Same as ILLUMINANT_C. ILLUMINANT_TUNGSTEN = ILLUMINANT_A 'Same as ILLUMINANT_A. End Enum Public Enum TernaryRasterOperations SRCCOPY = &HCC0020 ' dest = source SRCPAINT = &HEE0086 ' dest = source OR dest SRCAND = &H8800C6 ' dest = source AND dest SRCINVERT = &H660046 ' dest = source XOR dest SRCERASE = &H440328 ' dest = source AND (NOT dest) NOTSRCCOPY = &H330008 ' dest = (NOT source) NOTSRCERASE = &H1100A6 ' dest = (NOT src) AND (NOT dest) MERGECOPY = &HC000CA ' dest = (source AND pattern) MERGEPAINT = &HBB0226 ' dest = (NOT source) OR dest PATCOPY = &HF00021 ' dest = pattern PATPAINT = &HFB0A09 ' dest = DPSnoo PATINVERT = &H5A0049 ' dest = pattern XOR dest DSTINVERT = &H550009 ' dest = (NOT dest) BLACKNESS = &H42 ' dest = BLACK WHITENESS = &HFF0062 ' dest = WHITE End Enum Public Const HALFTONE = 4 <DllImport("gdi32.dll")> _ Public Shared Function SetBkColor(hdc As IntPtr, crColor As Integer) As Integer End Function End Class
Se ve muy largo el código pero tenía que ponerlo para que puedan analizar. Espero que me puedan ayudar. No puedo darles nada solo mi agradecimiento. gracias
He conseguido redibujar correctamente el PictureBox en la versión para API metiendo la saturación en el evento PAINT, pero sigo sin poder guardar los cambios Añadí la configuración al código anterior.
|
|
|
625
|
Programación / .NET (C#, VB.NET, ASP) / Re: Wait For Application To Load
|
en: 7 Septiembre 2016, 13:43 pm
|
una forma sencillita sería esta Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Process.Start("C:\Program Files\Adobe\Adobe Photoshop CS5 (64 Bit)\Photoshop.exe") Process.Start("C:\Program Files (x86)\Adobe\Adobe Photoshop CS5\Photoshop.exe") 'Subprocesoo Task.Factory.StartNew(Sub() Do 'Espera a obtener el handle de la ventana principal de Photoshop Dim pcs As Process() = Process.GetProcessesByName("Photoshop") For Each proceso As Process In pcs If proceso.MainWindowHandle <> IntPtr.Zero Then Exit Do End If Next Loop End Sub).ContinueWith(Sub() System.Threading.Thread.Sleep(1500) 'Espera un segundo y medio AppActivate(Process.GetCurrentProcess.Id) 'Activa esta ventana MessageBox.Show("Photoshop se ha iniciado") 'Muestra un mensaje End Sub) End Sub End Class
__________________________________________________________ y se puede usar HasExited de forma análoga para saber si la aplicación se ha cerrado. Devuelve True.
|
|
|
626
|
Programación / .NET (C#, VB.NET, ASP) / Libros para aprender NET
|
en: 7 Septiembre 2016, 12:24 pm
|
Serían tan amables de decirme libros de NET para aprender.
Me interesa en español porque no se inglés. En bibliotecas públicas he encontrado pero son unos tochos y dicen cosas muy, muy básicas y se recrean mucho en conceptos y explicaciones para cosas muy simples. Además que tiran mucho de VB antiguo. También he mirado en tiendas y más de lo mismo.
Buscando en google, veo que los buenos de verdad y que explican cosas interesantes pero son en inglés.
Me interesa especialmente vb.net y wpf.
gracias de antemano.
|
|
|
|
|
|
|