是否可以仅突出显示图像的某些部分(不透明度)?

时间:2010-12-31 16:09:10

标签: wpf silverlight

我已将不透明度应用于图像。这是代码: -

<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="DelSilverlightApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="600" d:DesignWidth="800">

    <Canvas x:Name="LayoutRoot" Background="White">
        <Image Source="Vista.jpg"  Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.8"/>
        <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143"  Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
    </Canvas>
</UserControl>

我希望只有Grid内部图像的区域应设置为1的不透明度,否则它应保持为0.8。任何想法我怎么能这样做?这对我的应用程序非常重要,但不知怎的,我找不到解决方案。

提前致谢:)

3 个答案:

答案 0 :(得分:2)

您可以使用Image设置为OpacityMask的其他VisualBrush,从而产生如下剪裁矩形:

<Canvas x:Name="LayoutRoot" Background="White">
    <Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.5"/>
    <Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
        <Image.OpacityMask>
            <VisualBrush Stretch="None">
                <VisualBrush.Visual>
                    <Rectangle Width="254" Height="143" Fill="Black"/>
                </VisualBrush.Visual>
            </VisualBrush>
        </Image.OpacityMask>
    </Image>
    <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143"  Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
</Canvas>

这是使用Image.Clip的另一种方法:

<Canvas x:Name="LayoutRoot" Background="White">
    <Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.5"/>
    <Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
        <Image.Clip>
            <RectangleGeometry Rect="23,72,254,143"/>
        </Image.Clip>
    </Image>
    <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143"  Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
</Canvas>

答案 1 :(得分:2)

以通用和可重用的方式执行此操作的一种方法是使用带有VisualBrush的OpacityMask,并将VisualBrush中的值绑定到Image和Grid。这样,当图像和网格四处移动并改变大小等时,它将起作用.VisualBrush可以包含Canvas和Rectangle来实现0.8和1.0不透明度。不能在Canvas上使用不透明度,因为它会影响矩形的不透明度,因此背景将会改变。 0.8等于#CC000000。我使用#50000000来更清楚地显示效果。

alt text

<强>更新
Silverlight版本需要一些解决方法,所以我在这里上传了我的示例应用程序:http://www.mediafire.com/?8pbj5b9t72m5191

WPF版本(Silverlight版本也适用于WPF)

<Canvas x:Name="LayoutRoot" Background="White">
    <Canvas.Resources>
        <local:SubtractMultiConverter x:Key="SubtractMultiConverter"/>
        <local:MaxValueMultiConverter x:Key="MaxValueMultiConverter"/>
    </Canvas.Resources>
    <Image Name="image" Source="C:\FG.png" Stretch="Fill" Height="300" Width="310" Canvas.Left="100" Canvas.Top="200">
        <Image.OpacityMask>
            <VisualBrush>
                <VisualBrush.Visual>
                    <Canvas Background="#50000000"
                            Width="{Binding ElementName=image, Path=ActualWidth}"
                            Height="{Binding ElementName=image, Path=ActualHeight}">
                        <Rectangle Fill="#FF000000">
                            <Rectangle.Width>
                                <MultiBinding Converter="{StaticResource MaxValueMultiConverter}">
                                    <Binding ElementName="rectToGetXAndY" Path="ActualWidth"/>
                                    <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Left)"/>
                                    <Binding ElementName="image" Path="ActualWidth"/>
                                </MultiBinding>
                            </Rectangle.Width>
                            <Rectangle.Height>
                                <MultiBinding Converter="{StaticResource MaxValueMultiConverter}">
                                    <Binding ElementName="rectToGetXAndY" Path="ActualHeight"/>
                                    <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Top)"/>
                                    <Binding ElementName="image" Path="ActualHeight"/>
                                </MultiBinding>
                            </Rectangle.Height>
                            <Canvas.Left>
                                <MultiBinding Converter="{StaticResource SubtractMultiConverter}">
                                    <Binding ElementName="rectToGetXAndY" Path="(Canvas.Left)"/>
                                    <Binding ElementName="image" Path="(Canvas.Left)"/>
                                </MultiBinding>
                            </Canvas.Left>
                            <Canvas.Top>
                                <MultiBinding Converter="{StaticResource SubtractMultiConverter}">
                                    <Binding ElementName="rectToGetXAndY" Path="(Canvas.Top)"/>
                                    <Binding ElementName="image" Path="(Canvas.Top)"/>
                                </MultiBinding>
                            </Canvas.Top>
                        </Rectangle>
                    </Canvas>
                </VisualBrush.Visual>
            </VisualBrush>
        </Image.OpacityMask>
    </Image>
    <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Canvas.Left="123" Canvas.Top="272" Opacity="0.6"/>
</Canvas>

SubtractMultiConverter

public class SubtractMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double value = (double)values[0];
        double subtractValue = (double)values[1];
        return value - subtractValue;
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

MaxValueMultiConverter

public class MaxValueMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double desiredWidth = (double)values[0];
        double canvasValue = (double)values[1];
        double actualWidth = (double)values[2];
        return Math.Min(desiredWidth, actualWidth - canvasValue);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

<强>更新
我注意到你也想在Silverlight中使用它。 Silverlight没有MultiBinding,但很幸运的是Colin E.有一个very nice solution for this VisualBrush也缺失了,但Chris C.有一个nice solution to that。我必须对VisualImage进行一些更改才能使其工作。

更改在OnVisualChanged中,我为LayoutUpdated添加了一个EventHandler,并将RenderSize更改为ActualWidth / ActualHeight

private FrameworkElement visual = null;
private void OnVisualChanged(DependencyPropertyChangedEventArgs args)
{
    //if (args.OldValue != null) ((FrameworkElement)args.OldValue).SizeChanged -= VisualImage_SizeChanged;
    if (args.NewValue != null)
    {
        visual = (FrameworkElement)args.NewValue;
        visual.SizeChanged += VisualImage_SizeChanged;
        visual.LayoutUpdated += new EventHandler(visual_LayoutUpdated);
        PrepareBitmap((int)visual.ActualWidth, (int)visual.ActualHeight);
    }
}
void visual_LayoutUpdated(object sender, EventArgs e)
{
    PrepareBitmap((int)visual.ActualWidth, (int)visual.ActualHeight);
}

Silverlight Xaml

<UserControl.Resources>
    <local:SubtractMultiConverter x:Key="SubtractMultiConverter"/>
    <local:MaxValueMultiConverter x:Key="MaxValueMultiConverter"/>

    <Canvas x:Key="testBorder"
            Background="#50000000"
            Width="{Binding ElementName=image, Path=ActualWidth}"
            Height="{Binding ElementName=image, Path=ActualHeight}">
        <Rectangle Fill="#FF000000">
            <binding:BindingUtil.MultiBindings>
                <binding:MultiBindings>
                    <binding:MultiBinding TargetProperty="Width"
                                          Converter="{StaticResource MaxValueMultiConverter}">
                        <binding:MultiBinding.Bindings>
                            <binding:BindingCollection>
                                <Binding ElementName="rectToGetXAndY" Path="ActualWidth"/>
                                <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Left)"/>
                                <Binding ElementName="image" Path="ActualWidth"/>
                            </binding:BindingCollection>
                        </binding:MultiBinding.Bindings>
                    </binding:MultiBinding>
                    <binding:MultiBinding TargetProperty="Height"
                                          Converter="{StaticResource MaxValueMultiConverter}">
                        <binding:MultiBinding.Bindings>
                            <binding:BindingCollection>
                                <Binding ElementName="rectToGetXAndY" Path="ActualHeight"/>
                                <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Top)"/>
                                <Binding ElementName="image" Path="ActualHeight"/>
                            </binding:BindingCollection>
                        </binding:MultiBinding.Bindings>
                    </binding:MultiBinding>
                    <binding:MultiBinding TargetProperty="Canvas.Left"
                                          Converter="{StaticResource SubtractMultiConverter}">
                        <binding:MultiBinding.Bindings>
                            <binding:BindingCollection>
                                <Binding ElementName="rectToGetXAndY" Path="(Canvas.Left)"/>
                                <Binding ElementName="image" Path="(Canvas.Left)"/>
                            </binding:BindingCollection>
                        </binding:MultiBinding.Bindings>
                    </binding:MultiBinding>
                    <binding:MultiBinding TargetProperty="Canvas.Top"
                                          Converter="{StaticResource SubtractMultiConverter}">
                        <binding:MultiBinding.Bindings>
                            <binding:BindingCollection>
                                <Binding ElementName="rectToGetXAndY" Path="(Canvas.Top)"/>
                                <Binding ElementName="image" Path="(Canvas.Top)"/>
                            </binding:BindingCollection>
                        </binding:MultiBinding.Bindings>
                    </binding:MultiBinding>
                </binding:MultiBindings>
            </binding:BindingUtil.MultiBindings>
        </Rectangle>
    </Canvas>

</UserControl.Resources>
<Canvas x:Name="LayoutRoot" Background="White">
    <local:VisualImage x:Name="visualImage"
                       Visual="{Binding Source={StaticResource testBorder}}"
                       ImageBrush="{Binding ElementName=brush}"/>
    <Image Name="image" Source="/GridImageOpacityMask;component/Images/FG.png" Stretch="Fill" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
        <Image.OpacityMask>
            <ImageBrush x:Name="brush" />
        </Image.OpacityMask>
    </Image>
    <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143"  Opacity="0.6" Canvas.Left="223" Canvas.Top="272"/>
</Canvas>

答案 2 :(得分:1)

这是一个横向解决方案: -

    <Canvas x:Name="LayoutRoot" Background="White">
        <Grid x:Name="ImageContainer" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
            <Image Source="Vista.jpg" />
            <Border x:Name="rectToGetXAndY" Background="Transparent" BorderThickness="23, 72, 85, 33" BorderBrush="#99FFFFFF" />
        </Grid>
    </Canvas>

这提供了褪色图像中充满活力的矩形的相同视觉外观。可以通过修改BorderThickness属性来操纵明显的矩形。此矩形中的事件可能会被Border捕获,因为已添加透明背景,因此可以拖动它。其他内容可以添加到Border的内部,例如透明矩形网格可以提供一些尺寸特征。

通过比较,这里接受的答案要复杂得多,尽管对你的实际问题有更直接的答案。