Farbverlauf von mehreren Farben ins Transparente

  • C#
  • .NET 2.0

Es gibt 41 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Farbverlauf von mehreren Farben ins Transparente

    Guten Morgen,

    ich habe vor, einen Farbverlauf mehrerer Farben zu zeichnen.
    Grundsätzlich nicht unbedingt schwer:

    C#-Quellcode

    1. LinearGradientBrush br = new LinearGradientBrush( this.ClientRectangle, Color.Black, Color.Black, 0, false );
    2. ColorBlend cb = new ColorBlend();
    3. cb.Positions = new[] { 0, 1 / 6f, 2 / 6f, 3 / 6f, 4 / 6f, 5 / 6f, 1 };
    4. cb.Colors = new[] { Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Indigo, Color.Violet };
    5. br.InterpolationColors = cb;
    6. //br.RotateTransform( 45 );
    7. e.Graphics.FillRectangle( br, this.ClientRectangle );

    Das Ergebnis:



    Allerdings möchte ich, dass es nach oben hin transparent wird, woran ich momentan scheitere.
    Ein einfarbiger Verlauf ins Transparente geht auch noch:



    Was ich eigentlich möchte:



    Ist soetwas mit GDI möglich?
    Und wenn ja, wie?

    Danke für Eure Ansätze...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Ich glaube das es nicht direkt möglich ist. Weil der Farbverlauf auf einer Achse ist, auf deinem Bild von Links nach Rechts oder anders rum, man bräuchte also eine weitere Dimension. Was man aber machen kann, render in ein Image, dann mit LockBits Zeilenweise die Transparanz reinmachen. Danach das Image rendern.
    Die Natur ist bekanntermaßen knallhart, sie sortiert aus was sich nicht bewährt hat.(Harald Lesch, 2021)

    Demnach müssten wir bald dran sein...
    Wenn der Farbverlauf 100% horizontal oder vertical ist geht es einfach, sobald andere Winkel ins Spiel kommen, wird es allerdings ein wenig aufwendiger. Dann musst du wohl Pixel für Pixel rechnen um eine "Linie" zu haben, wo du die Transparenz anpasst.
    Die Natur ist bekanntermaßen knallhart, sie sortiert aus was sich nicht bewährt hat.(Harald Lesch, 2021)

    Demnach müssten wir bald dran sein...
    @TRiViUM Du kannst einfach ein Farb-Array berechnen, indem Du die x-Achse aus dem HSV-Farbraum holst und der y-Achse die Transparenz-Werte zuweist:
    Der HSV-Farbraum
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    HSV kennenzulernen und anzuwenden ist in sehr kurzer Zeit möglich. Als ich mit damit auseinander gesetzte hab(wegen NeoPixel Stripe mit RegenBogen animationen), habe ich das nötigste in 10-15 Minuten gelernt.
    Die Natur ist bekanntermaßen knallhart, sie sortiert aus was sich nicht bewährt hat.(Harald Lesch, 2021)

    Demnach müssten wir bald dran sein...

    TRiViUM schrieb:

    Da ich mich nicht mit HSV auskenne
    Du bräuchtest dann nur die H-Komponente, 2. Spoiler in meinem Link.
    Du gehst mit nem H rein und bekommst die Color.

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Solange nur die Farben wie oben im Code genutzt werden schon, aber wenn z.B. Braun dargestellt werden soll, kommt man um Sättigung und Hellwert nicht drumrum.
    Die Natur ist bekanntermaßen knallhart, sie sortiert aus was sich nicht bewährt hat.(Harald Lesch, 2021)

    Demnach müssten wir bald dran sein...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    @Takafusa Stimmt, daran hatte ich noch gar nicht gedacht.
    Dieser Fall kann durchaus eintreten...

    Also hier mal mein Ergebnis, mit dem ich auch ganz zu frieden bin:


    Mein Vorhaben kurz erklärt:
    Ich möchte, wie bei dem AmbiLight von Phillips eine PictureBox platzieren, welche den Bildschirm darstellt.
    Drüber, drunter, links und rechts daneben befinden sich die von mir gezeichneten Bilder.

    Nun hab ich ein Bild geladen und festgestellt, dass der Verlauf zumindest optisch nicht korrekt positioniert wird:


    Da werden allerdings noch keine Positionen berechnet, die 3 Farben für den Verlauf wurden händisch hinzugefügt...

    Gibts eine Erklärung, weshalb das grün nicht mittig ist?

    Mein Code:
    Spoiler anzeigen

    C#-Quellcode

    1. using System.Drawing;
    2. using System.Windows.Forms;
    3. using System.Collections.ObjectModel;
    4. using System.ComponentModel;
    5. using AmbiFrame.Core;
    6. using System.Drawing.Drawing2D;
    7. namespace AmbiFrame.Ui.Controls
    8. {
    9. class AmbiFrameControl : Control
    10. {
    11. #region constructor
    12. public AmbiFrameControl()
    13. {
    14. SetStyle( ControlStyles.SupportsTransparentBackColor |
    15. ControlStyles.OptimizedDoubleBuffer |
    16. ControlStyles.UserPaint |
    17. ControlStyles.AllPaintingInWmPaint
    18. , true );
    19. BackColor = Color.Transparent;
    20. Size = new Size( 150, 50 );
    21. gradientColors = new ObservableCollection<Color>();
    22. gradientColors.CollectionChanged += GradientColors_CollectionChanged;
    23. gradientOrientation = Orientation.Horizontal;
    24. transparencySide = TransparencySides.None;
    25. //gradientColors.Add( Color.Red );
    26. //gradientColors.Add( Color.Orange );
    27. //gradientColors.Add( Color.Yellow );
    28. }
    29. #endregion
    30. #region enums
    31. public enum TransparencySides
    32. {
    33. None,
    34. Top,
    35. Bottom,
    36. Left,
    37. Right
    38. }
    39. #endregion
    40. #region properties
    41. private Orientation gradientOrientation;
    42. public Orientation GradientOrientation
    43. {
    44. get { return gradientOrientation; }
    45. set
    46. {
    47. gradientOrientation = value;
    48. Invalidate();
    49. }
    50. }
    51. private ObservableCollection<Color> gradientColors;
    52. [DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
    53. public ObservableCollection<Color> GradientColors
    54. {
    55. get { return gradientColors; }
    56. }
    57. private TransparencySides transparencySide;
    58. public TransparencySides TransparencySide
    59. {
    60. get { return transparencySide; }
    61. set
    62. {
    63. transparencySide = value;
    64. Invalidate();
    65. }
    66. }
    67. #endregion
    68. #region functions
    69. /// <summary>
    70. /// Maps a value to another range
    71. /// </summary>
    72. /// <param name="value">The value which be mapped.</param>
    73. /// <param name="fromSource">The minimum value of the source value.</param>
    74. /// <param name="toSource">The maximum value of the source value.</param>
    75. /// <param name="fromTarget">The minimum value of the mapped target value.</param>
    76. /// <param name="toTarget">The maximum value of the mapped target value.</param>
    77. /// <returns></returns>
    78. private float Map(float value, float fromSource, float toSource, float fromTarget, float toTarget)
    79. {
    80. return ( value - fromSource ) / ( toSource - fromSource ) * ( toTarget - fromTarget ) + fromTarget;
    81. }
    82. #endregion
    83. #region callbacks
    84. protected override void OnPaint(PaintEventArgs e)
    85. {
    86. base.OnPaint( e );
    87. Rectangle rect = new Rectangle( 0, 0, Width, Height );
    88. Bitmap bmp = new Bitmap( rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb );
    89. if (gradientColors.Count >= 2 && gradientColors[gradientColors.Count - 1] != Color.Empty)
    90. {
    91. #region gradient
    92. using (Graphics g = Graphics.FromImage( bmp ))
    93. {
    94. g.Clear( Color.Transparent );
    95. int angle = gradientOrientation == Orientation.Vertical ? 90 : 0;
    96. LinearGradientBrush br = new LinearGradientBrush( rect, Color.Transparent, Color.Transparent, angle, false );
    97. br.WrapMode = WrapMode.Tile;
    98. ColorBlend cb = new ColorBlend();
    99. float[] positions = new float[gradientColors.Count];
    100. Color[] colors = new Color[gradientColors.Count];
    101. for (int i = 0; i < gradientColors.Count; i++)
    102. {
    103. colors[i] = gradientColors[i];
    104. if (i == 0) positions[i] = 0;
    105. else if (i < gradientColors.Count - 1) positions[i] = i / (float)positions.Length;
    106. else if (i == gradientColors.Count - 1) positions[i] = 1;
    107. }
    108. cb.Positions = positions;
    109. cb.Colors = colors;
    110. br.InterpolationColors = cb;
    111. g.FillRectangle( br, rect );
    112. }
    113. #endregion
    114. #region transparency
    115. LockBitmap lockedBmp = new LockBitmap( bmp ); //https://www.codeproject.com/Tips/240428/Work-with-Bitmaps-Faster-in-Csharp-3
    116. lockedBmp.LockBits();
    117. if ( transparencySide == TransparencySides.Top )
    118. {
    119. int start = lockedBmp.Height -1;
    120. for (int x = 0; x < lockedBmp.Width; x++)
    121. {
    122. for (int y = start; y >= 0; y--)
    123. {
    124. byte currentTransparency = (byte)Map( y, start, 0, 255, 0 );
    125. Color pixel = lockedBmp.GetPixel( x, y );
    126. pixel = Color.FromArgb( currentTransparency, pixel.R, pixel.G, pixel.B );
    127. lockedBmp.SetPixel( x, y, pixel );
    128. }
    129. }
    130. }
    131. else if ( transparencySide == TransparencySides.Bottom )
    132. {
    133. int start = 0;
    134. for (int x = 0; x < lockedBmp.Width; x++)
    135. {
    136. for (int y = start; y < lockedBmp.Height; y++)
    137. {
    138. byte currentTransparency = (byte)Map( y, start, lockedBmp.Height, 255, 0 );
    139. Color pixel = lockedBmp.GetPixel( x, y );
    140. pixel = Color.FromArgb( currentTransparency, pixel.R, pixel.G, pixel.B );
    141. lockedBmp.SetPixel( x, y, pixel );
    142. }
    143. }
    144. }
    145. else if (transparencySide == TransparencySides.Left)
    146. {
    147. int start = lockedBmp.Width / 2;
    148. for (int x = start; x >= 0; x--)
    149. {
    150. for (int y = 0; y < lockedBmp.Height; y++)
    151. {
    152. byte currentTransparency = (byte)Map( x, 0, start, 0, 255 );
    153. Color pixel = lockedBmp.GetPixel( x, y );
    154. pixel = Color.FromArgb( currentTransparency, pixel.R, pixel.G, pixel.B );
    155. lockedBmp.SetPixel( x, y, pixel );
    156. }
    157. }
    158. }
    159. else if ( transparencySide == TransparencySides.Right)
    160. {
    161. int start = lockedBmp.Width / 2;
    162. for (int x = start; x < lockedBmp.Width; x++)
    163. {
    164. for (int y = 0; y < lockedBmp.Height; y++)
    165. {
    166. byte currentTransparency = (byte)Map( x, start, lockedBmp.Width, 255, 0 );
    167. Color pixel = lockedBmp.GetPixel( x, y );
    168. pixel = Color.FromArgb( currentTransparency, pixel.R, pixel.G, pixel.B );
    169. lockedBmp.SetPixel( x, y, pixel );
    170. }
    171. }
    172. }
    173. lockedBmp.UnlockBits();
    174. #endregion
    175. #region draw image
    176. e.Graphics.DrawImageUnscaled( bmp, rect );
    177. #endregion
    178. }
    179. }
    180. private void GradientColors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    181. {
    182. if (gradientColors.Count >= 2 && gradientColors[gradientColors.Count - 1] != Color.Empty)
    183. Invalidate();
    184. }
    185. #endregion
    186. }
    187. }

    @TRiViUM Wie genau wird denn dieser Farbverlauf generiert?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Folgendermaßen:

    C#-Quellcode

    1. #region gradient
    2. using (Graphics g = Graphics.FromImage( bmp ))
    3. {
    4. g.Clear( Color.Transparent );
    5. int angle = gradientOrientation == Orientation.Vertical ? 90 : 0;
    6. LinearGradientBrush br = new LinearGradientBrush( rect, Color.Transparent, Color.Transparent, angle, false );
    7. br.WrapMode = WrapMode.Tile;
    8. ColorBlend cb = new ColorBlend();
    9. float[] positions = new float[gradientColors.Count];
    10. Color[] colors = new Color[gradientColors.Count];
    11. for (int i = 0; i < gradientColors.Count; i++)
    12. {
    13. colors[i] = gradientColors[i];
    14. if (i == 0) positions[i] = 0;
    15. else if (i < gradientColors.Count - 1) positions[i] = i / (float)positions.Length;
    16. else if (i == gradientColors.Count - 1) positions[i] = 1;
    17. }
    18. cb.Positions = positions;
    19. cb.Colors = colors;
    20. br.InterpolationColors = cb;
    21. g.FillRectangle( br, rect );
    22. }
    23. #endregion
    @TRiViUM Was steht denn in der Liste gradientColors? Das scheint mir der "Übeltäter" zu sein.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Da stehen die 3 von mir festgelegten Farben drin:


    Bei gerader Anzahl an Farben scheinen die Positionen zu stimmen.
    Ist der "Übeltäter" evtl. doch die Berechnung?

    C#-Quellcode

    1. for (int i = 0; i < gradientColors.Count; i++)
    2. {
    3. colors[i] = gradientColors[i];
    4. if (i == 0) positions[i] = 0;
    5. else if (i < gradientColors.Count - 1) positions[i] = i / (float)positions.Length;
    6. else if (i == gradientColors.Count - 1) positions[i] = 1;
    7. }

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    @TRiViUM Probier ma:

    C#-Quellcode

    1. else if (i < gradientColors.Count - 1) positions[i] = i / (float)(positions.Length - 1);
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    kannst du vlt. ein lauffähiges uploaden?
    so vom draufgucken denke ich, man könnte noch ne Menge machen, aber ohne was lauffähiges natürlich nicht.

    zB sone Vereinfachung:

    C#-Quellcode

    1. for (int i = 0; i < gradientColors.Count; i++)
    2. {
    3. colors[i] = gradientColors[i];
    4. positions[i] = i / (float)(positions.Length - 1);
    5. }
    Aber wie gesagt: kanns nicht testen - und gibt noch mehr, genauer hinzugucken.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades Hätte es eigentlich auch schon sein sollen.. :/
    Jetzt ist es aber lauffähig ^^


    ErfinderDesRades schrieb:

    zB sone Vereinfachung

    Stimmt, ist das selbe. Frage mich, warum ich meist den komplizierteren Weg nehme :whistling:
    Hab ich optimiert :thumbup:
    Dateien