I want to build a small image and text editor.
I have two Images in a UserControl.
On the left side is the editor and looks momentarily (thanks to some try and error) a little bit overstated, but it works nonetheless. (I will clean up the code later)
<Canvas x:Name="EditCanvas" Grid.Column="0"
Height="{Binding AreaHeight}" Width="{Binding AreaWidth}"
MaxWidth="426"
MouseLeftButtonDown="EditCanvas_MouseLeftButtonDown">
<Canvas.Background>
<VisualBrush TileMode="Tile" Viewport="0, 0, 1, 1" Stretch="{Binding SelectedStretch}">
<VisualBrush.Visual>
<Image x:Name="EditorImage"
Height="{Binding AreaHeight}" Width="{Binding AreaWidth}"
Source="{Binding FileImagePath}" Margin="1"/>
</VisualBrush.Visual>
</VisualBrush>
</Canvas.Background>
</Canvas>
Here I bind the Image to a UriSource. The stretching will change the Image itself, not the underlying source. Now I want to crop this image 'as it is'! So, when it is set to Stretch.UniformToFill or Stretch.Fill (for example) I want the cropped image to look exactly as it is shown in the left area. That means, the cropped image can be cropped on the bottom, the right, not at all or something like this. The formula to calculate this by myself would be a little bit greater.
Now I wonder if there isn't a better way. I have to draw text later on to this cropped image, so I cannot simply convert it to a DrawingContext, DrawingVisual, and so on and draw text in it, because that would also stretch the text later on the right side.
And if possible it would be nice to get a fast method, that can be redrawn a few times per second without killing the GPU.
For showing the preview image I use this XAML at the moment:
<Canvas Grid.Column="1"
Height="{Binding AreaHeight}" Width="{Binding AreaWidth}"
MaxWidth="426">
<Canvas.Background>
<VisualBrush TileMode="Tile"
Viewport="0, 0, 1, 1"
Stretch="{Binding SelectedStretch}">
<VisualBrush.Visual>
<Image Height="{Binding AreaHeight}" Width="{Binding AreaWidth}"
Source="{Binding PreviewImage}"
Margin="1" x:Name="TestImage"/>
</VisualBrush.Visual>
</VisualBrush>
</Canvas.Background>
</Canvas>
<Border Grid.Column="1"
BorderThickness="1" BorderBrush="Black"
Height="{Binding AreaHeight}" Width="{Binding AreaWidth}" />
And this code behind to calculate the image and fill it with the desired text (even if it is faulted at this moment):
BitmapSource imageSource = EditorImage.Source as BitmapSource;
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawImage(imageSource, new Rect(0, 0, imageSource.PixelWidth, imageSource.PixelHeight));
List<TextPosition> textPositions = GetTextPositions();
if (textPositions.Any())
{
textPositions.ForEach(x =>
drawingContext.DrawText(new FormattedText(x.Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
new Typeface(x.FontFamily, x.Style, x.Weight, FontStretch), x.FontSize, new SolidColorBrush(x.ForegroundColor),
VisualTreeHelper.GetDpi(drawingVisual).PixelsPerDip), x.Position)
);
}
}
PreviewImage = new RenderTargetBitmap(imageSource.PixelWidth, imageSource.PixelHeight, 96, 96, PixelFormats.Pbgra32);
PreviewImage.Render(drawingVisual);
TestImage.InvalidateVisual();
Ok, it doesn't seem to be possible. So I took a detour and do it now like this (if ever someone else does have a similar problem):
And in the XAML I use two images. The first one stretched, the other one not: