Exclude label text from border

I have a silver frame with text on top that I would like to exclude (cut the text away from the border) to see the background abroad, on which the dropshadow bitmapeffect method is applied. Is it possible, without resorting to Photoshop, to create an image that basically does the same without being flexible?

If possible, how can I solve this problem?

+4
source share
2 answers

I played around a bit with this and got the following. The hard part was to β€œinvert” the OpacityMask for the border. I created a class that derives from Image, which adds several dependency properties such as Text, FontFamily, and EmSize. He then turns the text into geometry using this link approach.

You can play with Text, FontFamily, EmSize, Width and Height until you get the desired result. Of course, you can also add additional DPs for InvertOpacityText to increase flexibility.

I ended up with this

alt text

<Grid Background="Blue"> <Border Background="Gray" CornerRadius="8,8,8,8" Width="240" Height="220"> <Border.Effect> <DropShadowEffect ShadowDepth="10" Direction="310" Color="Black" Opacity="0.8" BlurRadius="4"/> </Border.Effect> <Border.OpacityMask> <VisualBrush> <VisualBrush.Visual> <local:InvertOpacityText Text=" Now Playing" EmSize="70" Stretch="Fill" Width="510" Height="414" FontFamily="Broadway"> <local:InvertOpacityText.LayoutTransform> <RotateTransform Angle="-90"/> </local:InvertOpacityText.LayoutTransform> </local:InvertOpacityText> </VisualBrush.Visual> </VisualBrush> </Border.OpacityMask> <Image Margin="45,5,5,5" Source="C:\PhilCollins.png"/> </Border> </Grid> 

InvertOpacityText.cs

 public class InvertOpacityText : Image { public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(InvertOpacityText), new FrameworkPropertyMetadata(string.Empty, TargetPropertyChanged)); public static readonly DependencyProperty EmSizeProperty = DependencyProperty.Register("EmSize", typeof(double), typeof(InvertOpacityText), new FrameworkPropertyMetadata(70.0, TargetPropertyChanged)); public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register("FontFamily", typeof(FontFamily), typeof(InvertOpacityText), new FrameworkPropertyMetadata(new FontFamily(), TargetPropertyChanged)); private static void TargetPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { InvertOpacityText invertOpacityText = (InvertOpacityText)source; invertOpacityText.OnTextChanged(); } public string Text { get { return (string)base.GetValue(TextProperty); } set { base.SetValue(TextProperty, value); } } public double EmSize { get { return (double)base.GetValue(EmSizeProperty); } set { base.SetValue(EmSizeProperty, value); } } public FontFamily FontFamily { get { return (FontFamily)base.GetValue(FontFamilyProperty); } set { base.SetValue(FontFamilyProperty, value); } } private void OnTextChanged() { if (Source == null) { Source = CreateBitmapSource(); } FormattedText tx = new FormattedText(Text, Thread.CurrentThread.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(FontFamily, FontStyles.Normal, FontWeights.Bold, FontStretches.Normal), EmSize, Brushes.Black); Geometry textGeom = tx.BuildGeometry(new Point(0, 0)); Rect boundingRect = new Rect(new Point(-100000, -100000), new Point(100000, 100000)); RectangleGeometry boundingGeom = new RectangleGeometry(boundingRect); GeometryGroup group = new GeometryGroup(); group.Children.Add(boundingGeom); group.Children.Add(textGeom); Clip = group; } private BitmapSource CreateBitmapSource() { int width = 128; int height = width; int stride = width / 8; byte[] pixels = new byte[height * stride]; List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>(); colors.Add(System.Windows.Media.Colors.Red); colors.Add(System.Windows.Media.Colors.Blue); colors.Add(System.Windows.Media.Colors.Green); BitmapPalette myPalette = new BitmapPalette(colors); return BitmapSource.Create(width, height, 96, 96, PixelFormats.Indexed1, myPalette, pixels, stride); } } 
+3
source

Here's a solution that works by creating a new FrameworkElement called HollowTextBlock , which fills its selected size with its Background and breaks off the Text , leaving it transparent. A full implementation will require support for a much larger number of properties, but this proves that the concept works.

First, here are some examples of XAML:

 <Grid> <Grid> <Grid.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <GradientStop Color="#FF0000" Offset="0" /> <GradientStop Color="#0000FF" Offset="1" /> </LinearGradientBrush> </Grid.Background> </Grid> <Grid> <local:HollowTextBlock Width="200" Height="50" Text="Hello, world!" Background="White" HorizontalAlignment="Center"/> </Grid> </Grid> 

which defines the colorful gradient background behind the text so that we can see that it works. Then we create our HollowTextBlock and in the prototype Width , Height , Text and Background should be specified.

Then here is our implementation of HollowTextBlock :

 public class HollowTextBlock : FrameworkElement { public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(HollowTextBlock), new UIPropertyMetadata(string.Empty)); public Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } public static readonly DependencyProperty BackgroundProperty = TextElement.BackgroundProperty.AddOwner(typeof(HollowTextBlock), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); var extent = new RectangleGeometry(new Rect(0.0, 0.0, RenderSize.Width, RenderSize.Height)); var face = new Typeface("Arial"); var size = 32; var ft = new FormattedText(Text, Thread.CurrentThread.CurrentUICulture, FlowDirection.LeftToRight, face, size, Brushes.Black); var hole = ft.BuildGeometry(new Point((RenderSize.Width - ft.Width) / 2, (RenderSize.Height - ft.Height) / 2)); var combined = new CombinedGeometry(GeometryCombineMode.Exclude, extent, hole); drawingContext.PushClip(combined); drawingContext.DrawRectangle(Background, null, new Rect(0.0, 0.0, RenderSize.Width, RenderSize.Height)); drawingContext.Pop(); } } 

and the output is as follows:

HollowTextBlock

NB When you use it, you have to be careful not to put it on top of something that will hide the real background that you would like to show.

+2
source

Source: https://habr.com/ru/post/1333755/


All Articles