Можно ли выделить только определенную часть изображения (непрозрачность)? - PullRequest
3 голосов
/ 31 декабря 2010

Я применил непрозрачность к изображению.Вот код: -

<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 ]

2 голосов
/ 02 января 2011

Одним из способов сделать это универсальным и многократно используемым способом является использование OpacityMask с VisualBrush и привязка значений в VisualBrush к изображению и сетке. Таким образом, он будет работать, когда изображение и сетка перемещаются и изменяют размер и т. Д. VisualBrush может содержать Canvas и Rectangle для достижения непрозрачности 0,8 и 1,0. Непрозрачность не может быть использована на холсте, однако, это повлияет на непрозрачность прямоугольника, так что фон будет делать вместо этого. 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. есть очень хорошее решение для этого .
VisualBrush также отсутствует, но у Криса С. есть хорошее решение для этого . Мне пришлось внести некоторые изменения в VisualImage, чтобы сделать эту работу.

Изменения были в OnVisualChanged, я добавил EventHandler для LayoutUpdated и изменил 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 голосов
/ 31 декабря 2010

Вы можете использовать другой 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 голос
/ 04 января 2011

Вот боковое решение: -

    <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, например, сетка из прозрачных прямоугольников может обеспечить некоторые функции определения размера.

Принятый ответ здесь значительно сложнее по сравнению с более прямым ответом на ваш актуальный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...