Reputation: 1691
I have an image inside a canvas, the user can click in the image and a green point appear where the user has clicked.
I would like to save the image on a memory stream for later use, all the image saving is fine, except for the point that seems to be not correctly drawn, my guess is regarding the screen ratio I had to apply to drew the green point because the image shown is smaller than the source image.
XAML:
<Canvas x:Name="ImageCanvas"
Grid.Column="1"
Background="Transparent">
<Image x:Name="SelectedPartImage"
Width="{Binding ElementName=ImageCanvas, Path=ActualWidth}"
Height="{Binding ElementName=ImageCanvas, Path=ActualHeight}"
Panel.ZIndex="0"
MouseLeftButtonDown="OnMouseLeftButtonDown"
Source="{Binding SelectedPartImageSource}" />
<Ellipse x:Name="EllipseClick"
Width="15"
Height="15"
Panel.ZIndex="1"
Fill="{StaticResource GreenColor}"
Visibility="Hidden" />
</Canvas>
DrawEllipse (The method I use to draw the ellipe, AdjustToCanvas simply avoid the user to click outside the canvas where the image is)
public void DrawEllipse()
{
// Adjust To Canvas
(double x, double y) = AdjustToCanvas(Mouse.GetPosition(ImageCanvas));
// Center Ellipse
x -= EllipseClick.Width / 2;
y -= EllipseClick.Height / 2;
Canvas.SetLeft(EllipseClick, x);
Canvas.SetTop(EllipseClick, y);
}
OnMouseLeftButtonDown (The click method to draw the ellipse)
public void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DrawEllipse();
Point point = Mouse.GetPosition(SelectedPartImage);
if (!(point.ConvertWPFPointToImagePoint(
SelectedPartImageSource.PixelWidth,
SelectedPartImageSource.PixelHeight,
SelectedPartImage.ActualWidth,
SelectedPartImage.ActualHeight))
{
return;
}
// CheckAlpha checks that the clicked point is inside the image and not outside of it.
SelectPositionSuccess = CheckAlpha((int)point.X, (int)point.Y);
EllipseClick.Visibility = SelectPositionSuccess ? Visibility.Visible : Visibility.Hidden;
if (SelectPositionSuccess)
{
//Saving the Canvas
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)SelectedPartImageSource.Width,
(int)SelectedPartImageSource.Height,
96d,
96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(ImageCanvas);
//endcode as PNG
PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
//save to memory stream
System.IO.MemoryStream ms = new System.IO.MemoryStream();
pngEncoder.Save(ms);
ms.Close();
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
System.IO.File.WriteAllBytes("test.png", ms.ToArray());
}
}
Any ideas how I can fix this behaviour?
Thanks in advance!
Upvotes: 1
Views: 384
Reputation: 859
The UIElement is not rendered as soon as you set its properties in your code behind. It will only be done after that method is returned.
In this case, trying to save the EllipseClick just after updating its position will not save the new position but its original position which is (0,0) since its not set!
To fix this, either move the Save() method to another event or call
ImageCanvas.UpdateLayout();
after updating the position of the EllipseClick.
Upvotes: 1