【问题标题】:WPF How to set desired color for Shadow?WPF 如何为阴影设置所需的颜色?
【发布时间】:2017-08-22 17:51:24
【问题描述】:

这是绘制椭圆的示例代码,启用了阴影。我将填充和阴影颜色设置为相同。但在视图中阴影颜色是不同的。这可能是 WPF 功能,但在我的场景中,我想为对象设置所需的阴影颜色。

<Window x:Class="Test.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">   

    <Grid>
      <Canvas>
            <Ellipse  Width="200" Height="300" Fill="#7D00FE">
                <Ellipse.Effect>
                    <DropShadowEffect   
                      ShadowDepth="5" 
                      Color="#7D00FE"/>                    
                </Ellipse.Effect>                
            </Ellipse>
        </Canvas>
    </Grid>
</Window>

【问题讨论】:

标签: wpf


【解决方案1】:

似乎 DropShadowEffect 在渲染自身时会以某种方式影响颜色。原色似乎不存在此问题(所谓的颜色,如红色、蓝色、水色等 - 但您不必使用名称,您也可以通过#AARRGGBB 格式指定它们。)

我无法弄清楚它所做的确切修改,也无法提供解决方法(除了使用命名颜色...),但我认为在答案中可能值得注意。

查看其他问题,这些问题可能指向 DropShadowEffect 的相同“错误”或未记录的功能:

更新: 所以,这是作弊,但对于你的具体问题,它可能会解决问题:

<Grid>
  <Canvas>
        <Ellipse  Width="200" Height="300" Fill="#7D00FE">
            <Ellipse.Effect>
                <DropShadowEffect
                  ShadowDepth="5" 
                  Color="#BA00FE"/>                    
            </Ellipse.Effect>                
        </Ellipse>
    </Canvas>
</Grid>

只要投入一点工作,就可以想出一个转换器,它可以将一种颜色转换为另一种颜色,这将是给定颜色所需的 DropShadowEffect 颜色。如果我有一点时间,我会回到这个。

我的直觉表明问题可能出在特定效果的着色器代码中,并且输出可能在不同的硬件(和/或驱动程序版本)上有所不同,但目前我无法证明这一点。

更新:

我对命名颜色的看法是错误的,它不适用于所有这些,例如:绿色有缺陷,但问题并不 - 完全 - 取决于颜色的绿色部分。有趣。

更新 2:

所以这是我之前谈到的转换器:

using System;
using System.Windows.Data;
using System.Windows.Media;

namespace MyCustomConverters
{
    public class ColorToShadowColorConverter: IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // Only touch the shadow color if it's a solid color, do not mess up other fancy effects
            if (value is SolidColorBrush)
            {
                Color color = ((SolidColorBrush)value).Color;
                var r = Transform(color.R);
                var g = Transform(color.G);
                var b = Transform(color.B);

                // return with Color and not SolidColorBrush, otherwise it will not work
                // This means that most likely the Color -> SolidBrushColor conversion does the RBG -> sRBG conversion somewhere...
                return Color.FromArgb(color.A, r, g, b); 
            }

            return value;
        }

        private byte Transform(byte source)
        {
            // see http://en.wikipedia.org/wiki/SRGB
            return (byte)(Math.Pow(source / 255d, 1 / 2.2d) * 255);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("ColorToShadowColorConverter is a OneWay converter.");
        }

        #endregion
    }
}

下面是它的使用方法:

资源部分:

<namespaceDefinedByXmlnsProperty:ColorToShadowColorConverter x:Key="ColorConverter" />

实际用法:

<Ellipse Width="50" Height="100" Fill="#7D00FE">
    <Ellipse.Effect>
        <DropShadowEffect ShadowDepth="50" 
                          Color="{Binding Fill, RelativeSource={RelativeSource 
                                  Mode=FindAncestor, AncestorType={x:Type Ellipse}}, 
                                  Converter={StaticResource ColorConverter}}"/>
    </Ellipse.Effect>
</Ellipse>

感谢 Michal Ciechan 的回答,因为它引导我朝着正确的方向前进。

【讨论】:

    【解决方案2】:

    它将 DropShadowEffect 转换为特定的 Sc 值。

    您越接近 1,差异越小(因此 FF/255/1 工作得非常好)因为 1 的第 n 个根是 1

    通过对 ScRGB 的研究和研究,ScRGB 的 Gamma 值在 2.2 左右。因此,从 RGB 转换为 ScRGB 时,您可能需要除以 255,然后将值的 nth(2.2) 根除以得出最终值。

    例如

    value 5E is 94
    
    94 / 255 = 0.36862745098039215686274509803922
    
    2.2root of 94/255 = 0.635322735100355
    
    0.635322735100355 * 255 = ~162 = A2
    

    因此,当您将前景的Green设置为5E时,您需要将DropShadowEffect设置为A2。

    这只是我的观察和研究得出的结论。

    为什么微软要这样实现它?我不知道

    来源:

    因此,在您的示例中,要使用相同的颜色,您需要使用#B800FE

    【讨论】:

      【解决方案3】:

      正如Ciechan's answer(感谢 Ciechan 先生)中所述,Microsoft 将 DropShadowEffect 转换为特定的 Sc 值。

      那么如何解决呢?

      只需将 RGB 值输入到 sRGB 中,让 Microsoft 重新计算即可。

      //Where the variable color is the expected color.
      Color newColor = new Color();
      newColor.ScR = color.R;
      newColor.ScG = color.G;
      newColor.ScB = color.B;
      //the converted color value is in newColor.R, newColor.G, newColor.B
      

      请参阅@qqbenq's answer 中的Update 2,了解绑定转换器的技术细节(感谢@qqbenq)。

      public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
          // Only touch the shadow color if it's a solid color, do not mess up other fancy effects
          if (value is SolidColorBrush)
          {
              Color color = ((SolidColorBrush)value).Color;
              //Where the variable color is the expected color.
              Color newColor = new Color();
              newColor.ScR = (float)color.R / 255;
              newColor.ScG = (float)color.G / 255;
              newColor.ScB = (float)color.B / 255;
      
              return newColor;
          }
      
          return value;
      }
      

      【讨论】:

        【解决方案4】:

        这是针对@qqbenq 's answer 改进的公式。

        变化在变换函数中。它更准确,差异约为 1 个值。 因此,在发问者示例中,要具有相同的颜色,您需要使用#BA00FF,您将得到#7D00FF(发问者请求#7D00FE)。

        https://www.nayuki.io/page/srgb-transform-library中的公式参考来源

                private byte Transform(byte source)
                {
                    // see http://en.wikipedia.org/wiki/SRGB
                    return (byte)(Math.Pow(source / 255d, 1 / 2.2d) * 255);
                    double x = (double)source / 255;
                    if (x <= 0)
                        return 0;
                    else if (x >= 1)
                        return 1;
                    else if (x < 0.0031308f)
                        return (byte)(x * 12.92f * 255);
                    else
                        return (byte)((Math.Pow(x, 1 / 2.4) * 1.055 - 0.055) * 255);
                }
        

        【讨论】:

          猜你喜欢
          • 2012-10-31
          • 2020-09-19
          • 2010-11-22
          • 2012-09-18
          • 2011-12-19
          • 2019-06-30
          • 2015-07-14
          • 1970-01-01
          相关资源
          最近更新 更多