Autor Tema: Rellenar con FloodFill usando GDI+ en VB6  (Leído 38 veces)

0 Usuarios y 1 Visitante están viendo este tema.

TOLO68

  • Bytes
  • *
  • Mensajes: 28
  • Reputación: +2/-0
    • Ver Perfil
Rellenar con FloodFill usando GDI+ en VB6
« en: Febrero 16, 2017, 07:05:38 pm »
Buenas a Todos
Tengo este codigo en VB6 que crea un poligono con lineas
he probado en otro codigo tambien con lineas seguidas de arcos y demas y funciona
lo que hace es rellenar el interior del dibujo en un color

-------------------------------------------------------------------------

Private Declare Function FloodFill Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long

Sub Form_Click()

   ScaleMode = 3
   ForeColor = vbBlue
   Line (50, 50)-(300, 50)
   Line -(200, 200)
   Line -(50, 150)
   Line -(50, 50)
   FillStyle = 0
   FillColor = vbBlue
   FloodFill Form1.hdc, 53, 53, vbBlue

End Sub

-------------------------------------------------------------------------

La pregunta es si conoceis alguna manera de hacerlo en VB6 pero con GDI+ por el tema del antialias, ya que he buscado por internet y dicen que no existe el FloodFill en GDI+, algunos dicen que hay que hacerlo con una funcion usando getpixel y setpixel

Esto es porque tengo que hacer dibujos irregulares con diferentes formas, por ejemplo algo como una estrella con puntas redondeadas( las puntas serian arcos), y el resto lineas, por eso necesito lo del floodfill para primero crear el dibujo y luego rellenarlo dandole las coordenadas X,Y en el interior como lo hace en el ejemplo anterior

Muchas Gracias a Todos


LeandroA

  • Administrador
  • Petabyte
  • *****
  • Mensajes: 1063
  • Reputación: +147/-8
    • Ver Perfil
Re:Rellenar con FloodFill usando GDI+ en VB6
« Respuesta #1 en: Febrero 16, 2017, 10:25:35 pm »
yo no conosco con GDI+, pero la pregunta es si no es el usuario quien decidiria el punto donde pintar, no tiene mucho sentido, se puede hacer algo mediante el array de bits de la imagen pero despues te enfrentarias a el problema del antialias donde o se perderia o quedaria para el traste.

No sera que vos queres rellenar un polígono? si es eso es lo que puse el otro dia y ahi si lo veo mas viable.

NEBIRE

  • Bytes
  • *
  • Mensajes: 39
  • Reputación: +5/-0
    • Ver Perfil
Re:Rellenar con FloodFill usando GDI+ en VB6
« Respuesta #2 en: Febrero 16, 2017, 10:47:11 pm »
Tolo68, cuando hablábamos de la transparencia (una semanas atrás), te decía que no te habías quedado con la lección importante... las máscaras.

Una vez que aprendes a crear máscaras y usar transparencias se puede hacer infinidad de cosas, con solo un poco de imaginación (y también prueba y error, por supuesto).

El caso es que dada una figura, y que la quieras rellenar de algo, se debe crear una máscara partiendo de la figura. La máscara es como un molde positivo, luego se crea el molde negativo, esto es se invierte la máscara, entonces ahora la superficie ocupada es precisamente la que quieres rellenar, entonces ahora esa superficie si necesitas pintarla, rellenarla con una brocha, etc... lo haces, y luego fundes ambas imágenes (en este caso sin transparencia (pero de igual modo es una operación ROP, de fusión))... la original con la que original modificada a máscara, invertida y coloreada/enbrochada... y todas esas operaciones se hacen con funciones que más o menos ya debes conocer en GDI+ o al menos GDI.

El uso de máscaras y transparencias, es como sumas y restas de superficies, tienes que mirarlo que es igual a las operaciones lógicas (or and, not, xor, not and, not or, not xor), con los bytes.... la unica diferencia es que es a una escala mayor, y que definen una superficie, etc.... Si aprendes a sumar, restar superficies, invertirlas, hacerlas negras y blancas, etc... habras aprendido la mitad o más delo que necesitas para dominar gráficos (la otra mitad es entender las funciones que ya existen en alguna librería o crearlas por tu propia cuenta). y... bueno, un pequeño porcentaje también es necesario para entender los píxeles, el color... que también son bytes y aplicar operaciones lógicas...

Yo no estoy muy puesto en GDI+, normalmente me basta con GDI, pero GDI+ es una vuelta más de rosca, en cuanto a calidad, velocidad y más funcionalidad...
Si entiendes el proceso, de lo que hay que hacer, es sólo cuestión de apilar las funciones que necesitas usar.... aunque no exista una función específica, aplicando varias funciones en pasos sucesivos, se consiigue la funcionalidad deseada.... de eso trata GDI, de tener 'funciones primitivas' para hacer cosas complejas partiendo de funciones más simples y archiconocidas.
« última modificación: Febrero 16, 2017, 10:53:49 pm por NEBIRE »

NEBIRE

  • Bytes
  • *
  • Mensajes: 39
  • Reputación: +5/-0
    • Ver Perfil
Re:Rellenar con FloodFill usando GDI+ en VB6
« Respuesta #3 en: Febrero 16, 2017, 11:16:42 pm »
Si quieres porgramar tu mismo el allgoritmo a bajo nivel, puede interesarte una pagina como esta:
https://es.wikipedia.org/wiki/Algoritmo_de_relleno_por_difusi%C3%B3n

Nota que Flood fill, tiene muchas variaciones, la más conocida se llamaa Boundary fill, y si tiene degradado, incluso se llama Fountain Fill...

La ventaja de hacerlo manualmente, es que solo requiere una única operación, frente a las varias consecutivas trabajando con máscaras, por tanto al final tu algoritmo puede ser más rápido incluso aunque el algoritmo no esté optimizado del todo... Aún así, requiere una buena optimización...

Si quieres implementarlas por tu cuenta, he aquí un esquema del algoritmo (muy, muy sencillito):
http://web.cs.ucdavis.edu/~ma/ECS175_S00/Notes/0411_a.pdf

Aquí un enlace, que explica similar al pdf:
http://www.siggraph.org/education/materials/HyperGraph/scanline/outprims/polygn6a.htm

TOLO68

  • Bytes
  • *
  • Mensajes: 28
  • Reputación: +2/-0
    • Ver Perfil
Re:Rellenar con FloodFill usando GDI+ en VB6
« Respuesta #4 en: Febrero 17, 2017, 07:05:00 am »
Hola a todos de nuevo, gracias por las respuestas, lo que dice LEANDRO de ser el usuario que decide el punto donde pintar, eso seria para un programa de dibujo tipo paint, pero aqui lo elijo yo porque es para los controles que estoy haciendo, pero veo que has entendido lo que queria :), que seria parecido al bote de pintura del paint.

Lo de rellenar el poligono ya lo estoy usando para hacer una aguja de un Gauge, ( un circulo con relleno en el centro , y luego un triangulo fino y largo con el poligono para la aguja, y voy rotando los puntos con Sin y Cos del triangulo), a ver si os puedo hacer una captura de pantalla para que lo veais

Lo que comenta NEBIRE sobre las mascaras tambien las he usado en algunos controles como el Display hexadecimal o el Display Matrix, para poder elegir entre 16 millones de colores para el color del LED, fue lo mejor porque antes tenia solo 3 colores, los 3 bitmaps)

os dejo aqui el link de la web para que podais ver las capturas de pantalla.
http://windevelop.hol.es

La pagina esta en desarrollo pero poco a poco la voy haciendo, asi como voy acabando los controles y creando algunos nuevos, asi ya se va posicionando en GOOGLE.

El unico que puede descargarse es el DisplayHEX.

Lo de usar el algoritmo para el antialias tambien se me habia ocurrido. :)
o incluso usar Bezier para hacer curvas, que creo que si se puede rellenar igual que el poligono

En el Knob hice el circulo antialias con solo GDI32 , con un algoritmo que encontre por la red, creo que era el sistema de WU o algo asi.

La cuestion es ir buscando ideas

Bueno, gracias de nuevo por vuestra ayuda. :)

 

Virgil Tracy

  • Kilobyte
  • **
  • Mensajes: 64
  • Reputación: +38/-1
    • Ver Perfil
Re:Rellenar con FloodFill usando GDI+ en VB6
« Respuesta #5 en: Febrero 17, 2017, 02:20:53 pm »
¿ Y usando path ?  :P

Código: Visual Basic
  1. Option Explicit
  2.  
  3.  
  4. Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Dest As Any, Src As Any, ByVal cb As Long) As Long
  5. Private Declare Function GdiplusStartup Lib "gdiplus" (token As Long, inputbuf As GDIPlusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
  6. Private Declare Function GdiplusShutdown Lib "gdiplus" (ByVal token As Long) As Long
  7. Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hDC As Long, graphics As Long) As Long
  8. Private Declare Function GdipSetSmoothingMode Lib "gdiplus" (ByVal graphics As Long, ByVal SmoothingMd As SmoothingMode) As Long
  9. Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As Long) As Long
  10. Private Declare Function GdipCreatePath Lib "gdiplus" (ByVal brushmode As FillMode, path As Long) As Long
  11. Private Declare Function GdipAddPathLine Lib "gdiplus" (ByVal path As Long, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single) As Long
  12. Private Declare Function GdipFillPath Lib "gdiplus" (ByVal graphics As Long, ByVal Brush As Long, ByVal path As Long) As Long
  13. Private Declare Function GdipDrawPath Lib "gdiplus" (ByVal graphics As Long, ByVal pen As Long, ByVal path As Long) As Long
  14. Private Declare Function GdipCreateSolidFill Lib "gdiplus" (ByVal argb As Long, Brush As Long) As Long
  15. Private Declare Function GdipCreatePen1 Lib "gdiplus" (ByVal color As Long, ByVal Width As Single, ByVal unit As GpUnit, pen As Long) As Long
  16. Private Declare Function GdipDeleteBrush Lib "gdiplus" (ByVal Brush As Long) As Long
  17. Private Declare Function GdipDeletePen Lib "gdiplus" (ByVal pen As Long) As Long
  18. Private Declare Function GdipDeletePath Lib "gdiplus" (ByVal path As Long) As Long
  19.  
  20.  
  21. Private Type GDIPlusStartupInput
  22.     GdiPlusVersion                      As Long
  23.     DebugEventCallback                  As Long
  24.     SuppressBackgroundThread            As Long
  25.     SuppressExternalCodecs              As Long
  26. End Type
  27.  
  28.  
  29.  
  30. Private Enum FillMode
  31.    FillModeAlternate        ' 0
  32.   FillModeWinding          ' 1
  33. End Enum
  34.  
  35. Private Enum GpUnit  ' aka Unit
  36.   UnitWorld      ' 0 -- World coordinate (non-physical unit)
  37.   UnitDisplay    ' 1 -- Variable -- for PageTransform only
  38.   UnitPixel      ' 2 -- Each unit is one device pixel.
  39.   UnitPoint      ' 3 -- Each unit is a printer's point, or 1/72 inch.
  40.   UnitInch       ' 4 -- Each unit is 1 inch.
  41.   UnitDocument   ' 5 -- Each unit is 1/300 inch.
  42.   UnitMillimeter ' 6 -- Each unit is 1 millimeter.
  43. End Enum
  44.  
  45. ' Quality mode constants
  46. Private Enum QualityMode
  47.    QualityModeInvalid = -1
  48.    QualityModeDefault = 0
  49.    QualityModeLow = 1       ' Best performance
  50.   QualityModeHigh = 2      ' Best rendering quality
  51. End Enum
  52.  
  53. Private Enum SmoothingMode
  54.    SmoothingModeInvalid = QualityModeInvalid
  55.    SmoothingModeDefault = QualityModeDefault
  56.    SmoothingModeHighSpeed = QualityModeLow
  57.    SmoothingModeHighQuality = QualityModeHigh
  58.    SmoothingModeNone
  59.    SmoothingModeAntiAlias
  60. End Enum
  61.  
  62. Dim GdipToken As Long
  63.  
  64. Private Sub Form_Click()
  65. Dim pGraphics As Long
  66. Dim path As Long
  67. Dim crSolid As Long
  68. Dim penOutLine As Long
  69.  
  70. Call GdipCreateFromHDC(Me.hDC, pGraphics)
  71. Call GdipSetSmoothingMode(pGraphics, SmoothingModeHighQuality)
  72.  
  73. Call GdipCreatePath(FillModeAlternate, path)
  74. Call GdipAddPathLine(path, 50, 50, 300, 50)
  75. Call GdipAddPathLine(path, 300, 50, 200, 200)
  76. Call GdipAddPathLine(path, 200, 200, 50, 150)
  77. Call GdipAddPathLine(path, 50, 150, 50, 50)
  78.  
  79. Call GdipCreateSolidFill(ConvertColor(vbBlue, 100), crSolid)
  80. Call GdipCreatePen1(ConvertColor(vbBlue, 255), 0.8, UnitWorld, penOutLine)
  81.  
  82. Call GdipFillPath(pGraphics, crSolid, path)
  83. Call GdipDrawPath(pGraphics, penOutLine, path)
  84.  
  85.  
  86. Call GdipDeleteBrush(crSolid)
  87. Call GdipDeletePen(penOutLine)
  88. Call GdipDeletePath(path)
  89.  
  90. Me.Refresh
  91.  
  92. Call GdipDeleteGraphics(pGraphics)
  93.  
  94. End Sub
  95.  
  96. Private Sub Form_Load()
  97.  
  98. InitGDI
  99.  
  100. Me.ScaleMode = vbPixels
  101. Me.AutoRedraw = True
  102. Me.BackColor = vbWhite
  103.  
  104. End Sub
  105.  
  106. Private Sub Form_Unload(Cancel As Integer)
  107.  
  108. TerminateGDI
  109.  
  110. End Sub
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119. Private Function ConvertColor(color As Long, alpha As Long) As Long
  120. Dim argb(0 To 3) As Byte
  121.  
  122. argb(3) = CByte(alpha)
  123. argb(0) = ((color \ &H10000) And &HFF) 'blue
  124. argb(1) = ((color \ &H100) And &HFF) 'green
  125. argb(2) = (color And &HFF) 'red
  126. CopyMemory ConvertColor, argb(0), 4&
  127.  
  128. End Function
  129.  
  130.  
  131. 'Inicia GDI+
  132. Private Sub InitGDI()
  133.     Dim GdipStartupInput As GDIPlusStartupInput
  134.     GdipStartupInput.GdiPlusVersion = 1&
  135.     Call GdiplusStartup(GdipToken, GdipStartupInput, ByVal 0)
  136. End Sub
  137.  
  138. 'Termina GDI+
  139. Private Sub TerminateGDI()
  140.     Call GdiplusShutdown(GdipToken)
  141. End Sub
  142.  
  143.