Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: FJDA en 21 Abril 2019, 22:03 pm



Título: substraer color
Publicado por: FJDA en 21 Abril 2019, 22:03 pm
estoy intentado substraer el color de una imagen.

El objetivo es superponer un objeto PictureBox y hacer transparentar una parte de color verde de modo que se puedan ver objetos que hay debajo del PictureBox.

He intentado esto, pero lo único que consigo es un agujero en el formulario, ya que al transparentar el color verde de la imagen que está en el picture, también transparenta el formulario y se ve el escritorio, o cualquier cosa que haya debajo del formulario de la aplicación.


Código
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Imports System.Security
  4. Imports System.Drawing.Imaging
  5.  
  6. Public Class Form1
  7.    <DllImport("User32.dll", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  8.    Private Shared Function SetLayeredWindowAttributes(ByVal HWND As IntPtr, ByVal crKey As Integer, ByVal bAlpha As Byte, ByVal dwFlags As Integer) As Integer
  9.    End Function
  10.    <DllImport("User32.dll", EntryPoint:="GetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  11.    Private Shared Function GetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer) As Integer
  12.    End Function
  13.    <DllImport("User32.dll", EntryPoint:="SetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  14.    Private Shared Function SetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
  15.    End Function
  16.  
  17.    Const GWL_EXSTYLE = (-20)
  18.    Const WS_EX_LAYERED = &H80000
  19.    Const GreenColor = &HFF00
  20.  
  21.    Private Function SubstractColor(ByVal HWND As IntPtr, Color As Integer) As Integer
  22.  
  23.        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  24.        SetLayeredWindowAttributes(HWND, Color, 0, &H1)
  25.        Return Nothing
  26.    End Function
  27.  
  28.    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  29.        SubstractColor(Me.Handle, GreenColor)
  30.    End Sub
  31. End Class

Mi Net no tiene la System.Windows.Media que creo serviría para esto.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.color.subtract?view=netframework-4.8 (https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.color.subtract?view=netframework-4.8)

Tampoco me funciona lo de backcolor = color. transparent, ni aún colocando imágenes con transparencia. Recuerdo que el objetivo es recortar o substraer una parte del PictureBox en la sección marcada por un determinado color.

Parece complicado


Título: Re: substraer color
Publicado por: Serapis en 22 Abril 2019, 00:10 am
Qé tal si cambias tu código:
Citar
Private Function SubstractColor(ByVal HWND As IntPtr, Color As Integer) As Integer
 
        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
        SetLayeredWindowAttributes(HWND, Color, 0, &H1)
        Return Nothing
    End Function

...por algo como lo siguiente:
Código
  1. Private sub SubstractColor(ByVal HWND As IntPtr, Color As Integer, optional byval GradoTr as byte=128)
  2.    SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  3.    SetLayeredWindowAttributes(HWND, Color, GradoTr , &H1)
  4. End Function

Esto es, le estás diciendo que el nivel de transparencia sea total (valor 0), de momento prueba a invocarlo a mitad de transparencia entre el contenido y lo que haya debajo, es decir cada uno pone el 50% de la fuerza de su color. Puedes variar el valor entre 0 (transparente) y 255 (opaco).

p.d.: Prueba con valores de flags, 2 y 3 (no solo 1), de la api SetLayeredWindowAttributes, pués afectan a como se aplica a la imagen origen y la imagen subyacente...


Título: Re: substraer color
Publicado por: FJDA en 22 Abril 2019, 00:42 am
Qé tal si cambias tu código:
...por algo como lo siguiente:
Código
  1. Private sub SubstractColor(ByVal HWND As IntPtr, Color As Integer, optional byval GradoTr as byte=128)
  2.    SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  3.    SetLayeredWindowAttributes(HWND, Color, GradoTr , &H1)
  4. End Function

Esto es, le estás diciendo que el nivel de transparencia sea total (valor 0), de momento prueba a invocarlo a mitad de transparencia entre el contenido y lo que haya debajo, es decir cada uno pone el 50% de la fuerza de su color. Puedes variar el valor entre 0 (transparente) y 255 (opaco).


Se agradece la respuesta pero esto que propones es incorrecto en todo caso.

Te lo explico
Citar
   <DllImport("User32.dll", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
    Private Shared Function SetLayeredWindowAttributes(ByVal HWND As IntPtr, ByVal crKey As Integer, ByVal bAlpha As Byte, ByVal dwFlags As Integer) As Integer
    End Function


El último valor que he marcado en rojo (dwFlags) de la función  SetLayeredWindowAttributes, puede tener dos valores según el objetivo a aplicar. Que serían

Código
  1.  
  2. Const LWA_COLORKEY As Long = &H1
  3. Const LWA_ALPHA As Long = &H2
  4.  

Si uso &H1  el valor de bAlpha para la función sólo significa una asignación de color para sustraer

Si aplico &H2  es decir LWA_COLORKEY, entonces  bAlpha representaría un valor de nivel de transparencia que afectaría a TODO el formulario y no solo al color.

Código
  1.  
  2.    Private Sub SubstractColor(ByVal HWND As IntPtr, Optional ByVal GradoTr As Byte = 128)
  3.        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  4.        SetLayeredWindowAttributes(HWND, IntPtr.Zero, GradoTr, LWA_ALPHA)
  5.    End Sub
  6.  



El código quedaría de la siguiente manera:
Código
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Imports System.Security
  4. Imports System.Drawing.Imaging
  5.  
  6. Public Class Form1
  7.    <DllImport("User32.dll", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  8.    Private Shared Function SetLayeredWindowAttributes(ByVal HWND As IntPtr, ByVal crKey As Integer, ByVal bAlpha As Byte, ByVal dwFlags As Integer) As Integer
  9.    End Function
  10.    <DllImport("User32.dll", EntryPoint:="GetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  11.    Private Shared Function GetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer) As Integer
  12.    End Function
  13.    <DllImport("User32.dll", EntryPoint:="SetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  14.    Private Shared Function SetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
  15.    End Function
  16.  
  17.    Const GWL_EXSTYLE = (-20)
  18.    Const WS_EX_LAYERED = &H80000
  19.    Const GreenColor = &HFF00
  20.    Const LWA_COLORKEY As Long = &H1
  21.    Const LWA_ALPHA As Long = &H2
  22.  
  23.    Private Sub SubstractColor(ByVal HWND As IntPtr, Optional ByVal GradoTr As Byte = 128)
  24.        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  25.        SetLayeredWindowAttributes(HWND, IntPtr.Zero, GradoTr, LWA_ALPHA)
  26.    End Sub
  27.    'Private Function SubstractColor(ByVal HWND As IntPtr, Color As Integer) As Integer
  28.    '    SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  29.    '    SetLayeredWindowAttributes(HWND, Color, 0, LWA_COLORKEY)
  30.    '    Return Nothing
  31.    'End Function
  32.  
  33.    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
  34.        SubstractColor(CType(Me.Handle, IntPtr), 210)
  35.    End Sub
  36. End Class
  37.  


Pero esto aplica el nivel de transparencia a todo el formulario. Por desgracia no se puede limitar  a un determinado color.




y si hago lo siguiente hace las dos cosas, sustrae el color asignado al 100% dejándolo todo transparente, excepto el resto del formulario que queda semi-transparente

Código
  1. Private Sub SubstractColor(ByVal HWND As IntPtr, Optional ByVal GradoTr As Byte = 128)
  2.        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  3.        SetLayeredWindowAttributes(HWND, GreenColor, GradoTr, LWA_ALPHA + LWA_COLORKEY)
  4.    End Sub
  5.  


mejor:
Código
  1.    Private Sub SubstractColor(ByVal HWND As IntPtr, ByVal Color As Integer, Optional ByVal GradoTr As Byte = 128)
  2.        SetWindowLong(HWND, GWL_EXSTYLE, GetWindowLong(HWND, GWL_EXSTYLE) Or WS_EX_LAYERED)
  3.        SetLayeredWindowAttributes(HWND, Color, GradoTr, LWA_ALPHA + LWA_COLORKEY)
  4.    End Sub
  5.  



Encontré una persona que quiso hacer lo mismo aquí
http://forums.codeguru.com/showthread.php?477962-Tranparent-color (http://forums.codeguru.com/showthread.php?477962-Tranparent-color)


no se puede hacer, al menos de una forma sencilla, tengo alguna idea pero va para rato. Sería creando un objeto COM o una nueva ventana incrustada en la aplicación mediante código.


Título: Re: substraer color
Publicado por: Serapis en 22 Abril 2019, 20:08 pm
Se agradece la respuesta pero esto que propones es incorrecto en todo caso.

Te lo explico...


Ante tu queja, te vuelvo a leer... y sí, leo tu no quieres que la transparencia se aplique sobre el escritorio. Me dejé llevar por las API que estás usando y que en general se utilizan para generar ventanas con forma irregular y transparencias en bordes, etc...

Hay varias formas de proceder, según lo que precises...
Por ejemplo puedes tener un objeto que admita gráficos (para el ejemplo un picturebox con una imagen precargada en su 'backgroundimage', si lo prefieres puede no tenerla y entonces lo que se verá será su BackColor), y puedes dibujar una imagen procedente de (por ejemplo) otro picturebox, aplicando transparencia a un color...

Aquí un código de ejemplo (y debajo algunas notas):
Código
  1. Private Sub BtnTransparentar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnTransparentar.Click
  2.    Dim Iat As New System.Drawing.Imaging.ImageAttributes
  3.    Dim dstRect As Rectangle = PictureBox1.DisplayRectangle
  4.    Dim d2rect As Rectangle
  5.    Dim g As System.Drawing.Graphics = PictureBox1.CreateGraphics
  6.  
  7.    Iat.SetColorKey(Color.Fuchsia, Color.Fuchsia) ' un 1 unico color, puede definirse un rango...
  8.  
  9.    ' Nota como solo se transaprentará lo que se pegue de color rosa chicle, no lo que en destino ya hubiere de dicho color.
  10.    d2rect.Size = New Size(dstRect.Width \ 8, dstRect.Height \ 8)
  11.    d2rect.Location = New Point(60, dstRect.Height \ 6)
  12.    g.FillEllipse(Brushes.Fuchsia, d2rect)
  13.  
  14.    g.DrawImage(PictureBox2.Image, dstRect, 0, 0, PictureBox2.Width, PictureBox2.Height, GraphicsUnit.Pixel, Iat)
  15. End Sub
  16.  

La imagen 1 muestra ambos picturebox, en realidad el 2º está oculto en tiempo de ejcución, da igual si no existe y lo tomas desde recursos, o lo cargas directamente desde fichero, yo he ido a los simple para el ejemplo, por lo mismo ambas imágenes son casi del mismo tamaño (creo), hay varias sobrecargas para elegir el método que mejor se ajuste a tus necesidades, nota sin embargo que la sobrecarga que eleijas debe tener el parámetro "imageattributes", para aplicar como color transparente (colorKey), el color o el rango entre colores deseados.
También para el ejemplo, la imagen de origen es bmp, así para el color rosa chicle existe la seguridad que es ese, si se comprime la imagen a jpg, habrá múltiples colores muy similares...
(https://i.imgur.com/OXSmIvq.jpg)

La segunda imagen,  es como aparece al iniciar la ventana... nota que el tamaño de la ventana ahora está reducida, en la imagen anterior tenía el único propósito de mostrar el picturebox2.
(https://i.imgur.com/xAoprJK.jpg)

La tercera imagen contiene ya aplicado pegar la imagen y aplicada la transparencia...
Nota que antes de pegar la imagen dibujamos una elipse del mismo color que el transparente (sobre una zona que luego queda transparente), para dejar claro que el color transparente se aplica solo sobre la imagen de origen.
(https://i.imgur.com/xQDyP6N.jpg)

Nota que el destino, puede ser igualmente cualquier otro objeto que admita control gráfico, el form, un panel, etc... y nota que siempre se mantiene el orden gráfico, es decir esto al ser un método, se pegará sienpre en la capa del fondo, es decir en el hDC del control, luego si hay un contenedor que tiene por ejemplo un botón encima, no afecta a su hDc, ese botón está por encima en la capa gráfica que el hDC del contenedor... por eso este método, no soluciona todos los casos, solo cuando es dentro del mismo objeto con gráficos al mismo nivel gráfico.

Pueden hacerse diferentes cosas, pero según de que se trate debe tomarse una orientación distinta, en general deberá usarse máscaras y utilizar operaciones de blitting usando las operaciones de rasterización adecuadas.


Título: Re: substraer color
Publicado por: FJDA en 23 Abril 2019, 01:50 am
NEBIRE muchas gracias antes de nada.

Pero eso no es lo que intentaba. El objetivo es recortar, eliminar una porción de un control Picturebox dejándolo transparente de tal modo que se puedan ver otros controles que hubieran debajo del Picturebox,  SetLayeredWindowAttributes solo funciona con ventanas no funciona por ejemplo usando Picturebox1.Handle. DrawImage solo afecta a imágenes aplicadas al Picturebox pero no al objeto en cuestión.  

No existe en NET ningún método para hacer eso que yo sepa, la única manera es recurrir a APIs de Windows. Conozco una forma de recortar partes de un control pero si quiero darle una forma concreta es complicado, de ahí que partiera usando un color. Quizás con éste método pudiera eliminar solo los píxeles que contengan un determinado color.

Otra forma sería  creando un objeto COM y a esperar que SetLayeredWindowAttributes  solo afecte a este y no al formulario que lo contiene. También se me ocurre crear un formulario mediante código e incrustarlo en el formulario principal. A ver si esto funciona. Creo que otra forma sería usar GDI32 pero no se nada de eso parece complicado.




ya he probado la primera opción se podría decir que hace lo que quiero pero tiene una extraño comportamiento, además una vez elimino la zona verde se vuelve el picture se vuelve a dibujar, tiene autoredraw. También realiza el proceso muy lentamente ya que va eliminando pixel por pixel. Igualmente lo posteo por si alguien tiene curiosidad o lo puede arreglar.

Código
  1. Imports System
  2. Imports System.Runtime.InteropServices
  3. Imports System.Text
  4. Imports System.Drawing.Color
  5. Public Class Form1
  6.    <DllImport("gdi32")> _
  7.    Private Shared Function CreateRectRgn(ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer
  8.    End Function
  9.    <DllImport("gdi32.dll", CharSet:=CharSet.Auto)> _
  10.    Private Shared Function CreateEllipticRgn(ByVal X1 As Integer, _
  11.                    ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer
  12.    End Function
  13.  
  14.    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
  15.    Private Shared Function SetWindowRgn(ByVal hwnd As IntPtr, ByVal hRgn As Integer, ByVal bRedraw As Boolean) As Integer
  16.    End Function
  17.  
  18.    <DllImport("user32.dll", Entrypoint:="SendMessageA", CharSet:=CharSet.Auto)>
  19.    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As StringBuilder) As IntPtr
  20.    End Function
  21.  
  22.    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
  23.    Private Shared Function ReleaseCapture() As Integer
  24.    End Function
  25.  
  26.    <DllImport("gdi32.dll")>
  27.    Private Shared Function CreatePolygonRgn(ByVal lppt As Point(), ByVal cPoints As Integer, ByVal fnPolyFillMode As Integer) As IntPtr
  28.    End Function
  29.  
  30.  
  31.    Const WM_NCLBUTTONDOWN = &HA1
  32.    Const HTCAPTION = 2
  33.    Public Const ALTERNATE = 1
  34.  
  35.  
  36.    Public Structure POINTAPI
  37.        Dim x As Integer
  38.        Dim y As Integer
  39.    End Structure
  40.    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  41.        PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
  42.  
  43.  
  44.  
  45.    End Sub
  46.  
  47.    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  48.  
  49.        '//Obtiene la localización X Y de los píxeles de color Verde RGB(0, 255, 0)
  50.        Dim b As Bitmap = New Bitmap(PictureBox1.Image)
  51.        Dim xPosPixel As Integer = Nothing
  52.        Dim yPosPixel As Integer = Nothing
  53.  
  54.        Dim gp As New Bitmap(b.Width, b.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
  55.        For Y As Integer = 0 To gp.Height - 1
  56.            For X = 0 To gp.Width - 1
  57.                Dim cw As New Color
  58.                cw = Color.Lime 'Verde RGB(0, 255, 0)
  59.                Dim curPixColor As Color = b.GetPixel(X, Y)
  60.                If curPixColor.ToArgb() = cw.ToArgb() Then
  61.                    'Elimina el píxel
  62.                    ClipPixel(X, Y)
  63.                End If
  64.            Next
  65.        Next
  66.  
  67.    End Sub
  68.  
  69.    Public Sub ClipPixel(ByVal X As Integer, ByVal Y As Integer)
  70.        Dim lpPts(12) As Point
  71.  
  72.        Dim hRustedRgn As Long  ' Rusted region
  73.        Dim WPicture As Integer
  74.        Dim HPicture As Integer
  75.        Dim X1, X2, Y1, Y2 As Integer
  76.       WPicture = PictureBox1.Width
  77.        HPicture = PictureBox1.Height
  78.        X1 = X : X2 = Y : Y1 = Y : Y2 = Y + 1
  79.  
  80.        ' Fill out the Rusted region points
  81.        ' The starting point
  82.        lpPts(0).X = 0 : lpPts(0).Y = 0
  83.        ' The width from the starting point
  84.        lpPts(1).X = WPicture : lpPts(1).Y = 0
  85.        ' The height from the Width
  86.        lpPts(2).X = WPicture : lpPts(2).Y = HPicture
  87.        ' The Height from the starting point
  88.        lpPts(3).X = 0 : lpPts(3).Y = HPicture
  89.        ' Create half of the square as a Triangle
  90.        lpPts(4).X = 0 : lpPts(4).Y = X1
  91.        lpPts(5).X = X1 : lpPts(5).Y = X1
  92.        lpPts(6).X = X1 : lpPts(6).Y = Y1
  93.        lpPts(7).X = X2 : lpPts(7).Y = Y1
  94.        lpPts(8).X = X2 : lpPts(8).Y = Y2
  95.        lpPts(9).X = X1 : lpPts(9).Y = Y2
  96.        lpPts(10).X = X1 : lpPts(10).Y = X1
  97.        lpPts(11).X = 0 : lpPts(11).Y = X1
  98.  
  99.        hRustedRgn = CreatePolygonRgn(lpPts, lpPts.Length, ALTERNATE)
  100.        Call SetWindowRgn(PictureBox1.Handle, hRustedRgn, True)
  101.    End Sub
  102. End Class
  103.  

Curiosamente este código en VB6 funciona mejor. En VB6 los objetos que hay debajo del Picture, como un botón se ven correctamente cuando eliminas la zona de color verde, además una vez eliminado el efecto se mantiene, pero en VB.NET justamente los objetos se vuelven de color verde y el picture se vuelve a redibujar. No funciona  :-\







Título: Re: substraer color
Publicado por: Serapis en 23 Abril 2019, 16:19 pm
Más que lo que estás haciendo, ayudaría saber qué es lo que quieres conseguir, porque con lo primero solo puede uno indicarte para corregir, mejorar, con lo segundo es posible reorientarlo de otra forma.

Yo veo (a bote pronto) 3 opciones a ver cual te interesa más.
- Se puede recurrir a las APIs de windows, no es tan complicado... aunque nunca queda tan elegante como usar 2 o 3 propiedades. El principal obstáculo es que solo sirve para ese 'proyecto' cuando lo quieras usar en otra parte, nuevamente tienes que copiar todo el código y posiblemente modificar, y posiblemente cualquier cambio de nuevo te vuelva a presentar complicaciones que quizás no tuvieres tan claro como solventar.

- Si como veo en tu código del mensaje anterior estás dispuesto a operar con los  píxels, el procedimiento se puede hacer mucho más rápido, pero no tengo claro que haces exactamente; trazar líneas, figuras geométricas 'pintadas de verde' donde se te antoje y que de inmediato se transaparente?. formas apilables que quitas y pones?. poner una imagen estática y recortar alrededor lo que no es la imagen?.
Básicamente se trataría de tener un backbuffer, con cada repaint que se exija se regenera y vuelca el contenido del backbuffer. el funcionamiento es idéntuico a usar una lupa... La ventaja sobre lo anterior es que quedará más claro qué hace cada cosa y eso te permite modificar a futuro pos si se precisa hacer cambios...

- También es posible usar controles OCX (de vb6) en NET (no sé hasta que versión sigue siendo posible porque no tengo instaladas las últimas). En tal caso tengo por ahí algún que otro control (de vb6) de muchos años atrás precisamente con transparencia para permitir varias cosas. sería cuestión de saber que propiedades necesitas para ajustar alguno a tales necesidades... luego lo usarías más o menos igual que usas el picturebox...

Pero aclaro, es mejor que señales que quieres conseguir y no tanto que estás haciendo, si no limitas la capacidad de ayudarte, porque lo focalizas en un punto que luego al final no tiene salida, porque no es lo que queires conseguir.


Título: Re: substraer color
Publicado por: FJDA en 27 Abril 2019, 17:10 pm
perdona si no fui claro amigo

ahora he conseguido instalar vb6 para hacer un control ocx pero no consigo que funciona la propiedad picture, he seguido tutoriales pero cuando establezco el picture me dice uso de la propiedad no válida. aún estoy en elllo.


Título: Re: substraer color
Publicado por: Serapis en 27 Abril 2019, 19:37 pm
Explícate mejor con eso de que "no consigo que funciona la propiedad picture".

La propiedad picture, permite alojar un bitmap.
en vb6, puedes asignar una imagen directamente desde fichero:

Código
  1. set objeto.picture = loadpicture(ruta)
Nota que en vb6 solo acepta bmp, rle, jpg, gif, si usas png, entonces hay que cargarla con APIs.

y luego puedes reasignarla entre objetos (son referencias no duplicados):
Código
  1. Set objeto2.picture = objeto1.picture
tambien puedes tener un picture sin asignarla a ningún objeto:
Código
  1. dim img as IpictureDisp
  2. set img= loadpicture(rutaimagen)
  3. ' o...
  4. Set img = objeto.picture
  5. ' o también...
  6. Set img = otroImg

Puede pegar parcialmente una imagen con paintpicture (es similar a bitblt)
Código
  1. objeto.paintpicture(objeto.picture, x,y, ancho, alto, orgX, orgY, orgAncho, OrgAlto, rasterOp) // típicamente vbCrscCopy

...si te atrancas con algo avisa...


Título: Re: substraer color
Publicado por: FJDA en 28 Abril 2019, 15:40 pm
Con vb6 para crear el OCX hice esto.
Código
  1. Option Explicit
  2.  
  3. Public Property Get Picture() As Picture
  4.    Set Picture = UserControl.Picture
  5. End Property
  6.  
  7. Public Property Set Picture(ByVal New_Picture As Picture)
  8.    Set UserControl.Picture = New_Picture
  9.    PropertyChanged "Picture"
  10. End Property
  11.  
  12. 'Cargar valores de propiedad desde el almacén
  13. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  14.  
  15.    Set Picture = PropBag.ReadProperty("Picture", Nothing)
  16. End Sub
  17.  
  18. 'Escribir valores de propiedad en el almacén
  19. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  20.  
  21.    Call PropBag.WriteProperty("Picture", Picture, Nothing)
  22. End Sub

Esto funciona si asigno la imagen desde la página de propiedades de pero cuando hago esto con códgo:

Código
  1. Private Sub Command1_Click()
  2. UserControl_1.Picture = LoadPicture("")
  3. End Sub

Me dice eso de uso no válido de la propiedad



justo acabo de solucionar el problema viendo este foro que encontré en google
http://www.vbforums.com/showthread.php?560245-RESOLVED-Problem-with-LoadPicture-in-an-ActiveX-Control (http://www.vbforums.com/showthread.php?560245-RESOLVED-Problem-with-LoadPicture-in-an-ActiveX-Control)

Para que funcionara tenía que añadir SET
Código
  1. Private Sub Command1_Click()
  2. Set UserControl_1.Picture = LoadPicture("")
  3. End Sub
  4.  


Para evitar usar el procedimiento set añadí esto al código del activex y ya funcionó bien

Código
  1. Public Property Let Picture(ByVal New_Picture As Picture)
  2.    Picture1.Picture = New_Picture
  3.    PropertyChanged "Picture"
  4. End Property

ahora ya puedo seguir  :)
publicaré los resultados a ver si lo consigo. pero me gustaría no tener que usar un ocx y hacerlo todo desde net. Tengo alguna idea pero por ahora probaré esto.

javascript:void(0);


he creado ya el ActiveX pero SetLayeredWindowAttributes no aplica cambios en el ActiveX, no elimina la parte coloreada. paso a la siguiente opción  :-\


Título: Re: substraer color
Publicado por: Eleкtro en 5 Mayo 2019, 15:33 pm
Sin leer más que el post principal, te respondo algunas cosas que no se si ya te habrán respondido:



estoy intentado substraer el color de una imagen.

Para volver transparente el color de una imagen no necesitas nada más que utilizar el método Bitmap.MakeTransparent...
  • Bitmap.MakeTransparent Method (System.Drawing) | Microsoft Docs (https://docs.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.maketransparent?view=netframework-4.8)

Ejemplo:
Código
  1. Dim bmp As Bitmap = DirectCast(Bitmap.FromFile("C:\image.png"), Bitmap)
  2.  
  3. Dim clrs As Color() = { ' Colores específicos a substraer.
  4.    Color.FromArgb(255, 0, 0, 0),
  5.    Color.FromArgb(255, 255, 255, 255)
  6. }
  7.  
  8. For Each clr As Color In clrs
  9.    bmp.MakeTransparent(clr)
  10. Next
  11.  
  12. Me.PictureBox1.Image = bmp



El objetivo es superponer un objeto PictureBox y hacer transparentar una parte de color verde de modo que se puedan ver objetos que hay debajo del PictureBox.

Una forma sofisticada sería utilizando la clase Region. De este modo crearías a tu antojo la región visible del control, y la que no sería visible (es decir, la parte transparente de tu PictureBox).

Para crear la región de forma óptima, me refiero, para determinar que debe ser visible y que no, probablemente deberías analizar los píxeles de la imagen, cosa que puedes hacer mediante el método Bitmap.LockBits / Bitmap.UnlockBits y un búcle for. Hay muchos ejemplos en Internet. Para aplicar la región utilizarías la propiedad PictureBox.Region del control...

  • Control.Region Property (System.Windows.Forms) | Microsoft Docs (https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.region?view=netframework-4.8)
  • Region Class (System.Drawing) | Microsoft Docs (https://docs.microsoft.com/en-us/dotnet/api/system.drawing.region?view=netframework-4.8)

Una forma más rudimentaria pero igualmente eficaz dependiendo de tus requisitos, sería asignarle un control padre a los controles que quieres superponer a ese PictureBox. Simplemente utiliza la propiedad Control.Parent...

Ejemplo:
Código
  1. Button1.Parent = PictureBox1
  2. Button1.Location = New Point(0, 0)



Mi Net no tiene la System.Windows.Media que creo serviría para esto.

Doy por hecho que estás trabajando bajo la tecnología Windows Forms, pero nada te impide agregar una referencia a los ensamblados principales de la tecnología WPF (PresentationCore.dll, PresentationFramework.dll y WindowsBase.dll) para poder acceder al espacio de nombres System.Windows.Media y usar los miembros que provee.

De todas formas, para hacer eso, mejor sería que directamente lo hagas en WPF ya que te beneficiarás en lo que respecta a "transprencia real".



Código
  1.    <DllImport("User32.dll", EntryPoint:="GetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  2.    Private Shared Function GetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer) As Integer
  3.    End Function
  4.  
  5.    <DllImport("User32.dll", EntryPoint:="SetWindowLongA", CharSet:=CharSet.Unicode), SuppressUnmanagedCodeSecurityAttribute>
  6.    Private Shared Function SetWindowLong(ByVal HWND As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
  7.    End Function

Las definiciones de esas funciones son incorrectas. Carece de sentido que asignes como punto de entrada la versión ANSI de una función, y luego le asignes el set de caracteres Unicode al marshaler. No es un problema en este caso, pero en funciones que manejen strings te daría problemas de codificación de texto al enviar o recibir argumentos, o directamente error al intentar llamar a la función. No hagas eso. Si no sabes muy bien como funcionan estas cosas entonces deberías informarte sobre la correcta utilización de los servicios de invocación de plataforma en .NET (Platform Invoke o P/Invoke en Inglés)...

  • Consuming Unmanaged DLL Functions (https://docs.microsoft.com/en-us/dotnet/framework/interop/consuming-unmanaged-dll-functions)
  • Interop Marshaling (https://docs.microsoft.com/en-us/dotnet/framework/interop/interop-marshaling)
  • Platform Invoke Examples (https://docs.microsoft.com/en-us/dotnet/framework/interop/platform-invoke-examples)

Aparte, esas funciones en teoría solo te funcionarán correctamente bajo un proceso en modo de 32 bits. En su lugar deberías usar las funciones GetWindowLongPtr y SetWindowLongPtr para compatibilizar tu código bajo un proceso en modo 64 bits o neutral (AnyCPU), mientras que en 32 bits te seguiría funcionando igual...

  • GetWindowLongPtr - Microsoft Docs (https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowlongptra)
  • SetWindowLongPtr - Microsoft Docs (https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowlongptra)

Un saludo.


Título: Re: substraer color
Publicado por: Serapis en 7 Mayo 2019, 23:50 pm
Si necesitas hacerlo desde NET, prueba con las sugerencias de Elektro...

Respecto de vb6 (perdona que no te haya respondido antes, no me he percatado que respondiste hasta ahora).

Citar
Código
  1.    Private Sub Command1_Click()
  2.     Set UserControl_1.Picture = LoadPicture("")
  3.    End Sub
  4.  
Exacto, en vb6 la asignación de objetos es a través de Set objeto = loquesea
    


Citar
Para evitar usar el procedimiento set añadí esto al código del activex y ya funcionó bien
Set no es ningún procedimiento, es una instrucción propia de la sintaxis del lenguaje.
Un procedimiento implica código asociado que se ejecuta por debajo.
Una instrucción (como su nombre indica), simplemente instruye/advierte/notifica al compilador... (en este caso concreto) que se trata de un objeto, para que tenga en consideración el puntero de memoria, las referencias, y lo valide todo, etc... y de cara al programador para indicarle con claridad una diferencia tangible entre variables 'nativas' y las 'extendidas'...

Citar
Código
  1.    Public Property Let Picture(ByVal New_Picture As Picture)
  2.        Picture1.Picture = New_Picture
  3.        PropertyChanged "Picture"
  4.    End Property
  5.  
En definitiva, omitir el Set carece de consecuencias prácticas referentes al rendimiento, más bien es al revés, exige comprobaciones de tipo retrasadas a la compilación. Usando el Set, al compilar se verifica la asignación de objetos y por ende, una vez compilado evita hacer comprobaciones innecesarias...

Esto no es deseable, por que lo pasas por valor, que si tiene una pérdida de eficiencia. Fuerza a realizar más comprobaciones "Late In Time", de las necesarias...


Ten en cuenta que desde que la programación existe, la instrucción de asignar un valor a una variable es LET. La mayoría de los lenguajes la usaban en su tiempo y poco a poco fueron de sapareciendo de la mayoría (aún queda alguno que la utiliza).

Antes se usaban estas instrucciones de asignación, que hacen exactamente lo mismo que eliminando el Let.
Código
  1. Let b = 5
  2. Let a = b
  3. Let c = (a + 3)
  4.  
  5. Let picture1.picture = New_Picture
  6.  
Pero al final el 'let' dejó de ser obligatorio... es opcional. Para aquellos que proceden del C, y se lían por el uso de los símbolos '=' en referencia a la distinción entre asignación y comparación, la conveniente aparición y uso del 'let' les resolvería muchas dudas... pero se perdió en BASIC a finales de los 80, por obviedad... igual que el 'Set' en NET, por la misma razón (solo que en NET 'Set' ni siquiera es opcional en tanto que el 'Let' si lo sigue siendo... si lo pones, NET no canta error, simplemente lo borra inmediatamente, para indicarte que 'no es necesario'...

Así tu código debiera ser:
Código
  1.    'Public Property Let Picture(ByVal New_Picture As Picture)
  2.    Public Property Set Picture(ByRef New_Picture As Picture) ' ó mejor as IPictureDisp
  3.        Set Picture1.Picture = New_Picture
  4.        PropertyChanged "Picture"
  5.    End Property
  6.  

p.d.: Olvidaba responderte a esto:
Citar
he creado ya el ActiveX pero SetLayeredWindowAttributes no aplica cambios en el ActiveX, no elimina la parte coloreada. paso a la siguiente opción
La idea de crear el ActiveX, es que ya por sí solo y sin mediación de nada más (cero APIs) tenga intrínsecamente la transparencia, tu solo te preocupará de cambiar  alguna propiedad, como la propiedad 'Picture' y la propiedad 'MaskColor' y punto (y eventualmente alguna propiedad más, relacionada, por ejemplo para que deje de actuar transparente y en un momento dado sea opaco, o vuelta a transparente... vamos según en algún momento interese que sea así o asá...).

P.d2: Te dije que si me señalabas que necesitas exactamente o qué propiedades precisas tener, podría modificarte un control para que se adapte a lo que necesitas...

Te pongo alguna captura de ejemplo:
En el primero se ven varias intancias de un control DisplayLCD, que permite tener una serie de dígitos, y señalar en otro color los decimales, elegir la base numérica (octal, decimal y hexadecimal, hacerlo transparente o no, el relieve del borde admite hundido, elevado, plano (de un color específico) o sin borde, así mismo se puede sincronizar con un timer para reflejar la hora (el timer se pone a 1000 ms. y cuando vence el tiempo, actualiza el contenido con el valor de la hora, luego cambia cada segundo), etc...
(https://i.imgur.com/FFHolsA.png)


En este otro se ven dos controles uno es un array de vértices 3d, que conecta a otros vértices, también transparente, que admite el giro en las 3 dimensiones... al caso muestra una figura dle ajedrez.
El otro es de texto... en la siguiente imagen se hace uso de desactivar/activar la transparencia cuando se pulsa/suelta el botón sobre las partes visibles de dicho control...
(https://i.imgur.com/oML5EjM.png)

(https://i.imgur.com/Xppl4Ne.png)


Título: Re: substraer color
Publicado por: FJDA en 8 Mayo 2019, 17:11 pm
ahora estoy con otro programa este tema lo dejé apartado temporalmente cuando pueda me probaré lo que me habéis comentado

En cuanto a lo del ActiveX si le puse APIs.


tened paciencia porque dedico muy poquito tiempo a la programación