I'm trying to create a Paint Application in WPF using Canvas. I want to increase the thickness of my shape while drawing so I try increasing StrokeThickness.
This is how I want it to be:
And this is what I get:
As you can see the outline only extends inside the boundary. How can I make it extends on both side?
Here is my code:
In MouseDown Event:
Rectangle rect = new Rectangle();
rect.Stroke = _color;
rect.StrokeThickness = _size;
Canvas.SetLeft(rect, _startPoint.X);
Canvas.SetTop(rect, _startPoint.Y);
cv_PaintBoard.Children.Add(rect);
isDrawing = true;
In MouseMove Event:
if (isDrawing == true && e.LeftButton == MouseButtonState.Pressed)
{
Canvas canvas = (Canvas)sender;
Rectangle rect = canvas.Children.OfType<Rectangle>().LastOrDefault();
if (rect != null)
{
Point endPoint = e.GetPosition((IInputElement)sender);
Point startPoint = new Point(
Math.Min(endPoint.X, _startPoint.X),
Math.Min(endPoint.Y, _startPoint.Y)
);
rect.Width = Math.Max(endPoint.X, _startPoint.X) - startPoint.X;
rect.Height = Math.Max(endPoint.Y, _startPoint.Y) - startPoint.Y;
Canvas.SetLeft(rect, startPoint.X);
Canvas.SetTop(rect, startPoint.Y);
}
}
You need to update width/height and left/top too for your specific needs.
The below example demonstrates your needs. If it is ok with you, let me know.
MainWindow.xaml
<Window x:Class="WpfDrawing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="447.368" Width="606.579">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="13*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<Canvas Grid.RowSpan="1">
<Rectangle x:Name="Rect1" Fill="Transparent" HorizontalAlignment="Left" Height="70" Canvas.Left="248" Canvas.Top="104" Stroke="Black" Width="94" Opacity="0.5" />
<Rectangle x:Name="Rect2" Fill="#FF52E03C" HorizontalAlignment="Left" Height="70" Canvas.Left="248" Canvas.Top="104" Stroke="Black" Width="94" Opacity="0.5" />
</Canvas>
<TextBox x:Name="tbThickness" HorizontalAlignment="Left" Height="23" Margin="84,27,0,0" Grid.Row="1" TextWrapping="Wrap" Text="5" VerticalAlignment="Top" Width="120"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="237,28,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfDrawing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
double designWidth;
double designHeight;
double designLeft, designTop;
public MainWindow()
{
InitializeComponent();
designWidth = Rect2.Width;
designHeight = Rect2.Height;
designLeft = Canvas.GetLeft(Rect2);
designTop = Canvas.GetTop(Rect2);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Rect2.StrokeThickness = double.Parse(tbThickness.Text);
Canvas.SetLeft(Rect2,designLeft - (Rect2.StrokeThickness / 2));
Canvas.SetTop(Rect2, designTop - (Rect2.StrokeThickness / 2));
Rect2.Width = designWidth + Rect2.StrokeThickness;
Rect2.Height = designHeight + Rect2.StrokeThickness;
}
}
}
There is no need to do any calculations to correct the size of a rectangle by half of its stroke thickness.
Just use Path controls with RectangleGeometries instead of Rectangle controls:
private Brush stroke = Brushes.Red;
private double strokeThickness = 10;
private Path currentPath;
private Point startPoint;
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
var canvas = (Canvas)sender;
if (canvas.CaptureMouse())
{
startPoint = e.GetPosition(canvas);
currentPath = new Path
{
Data = new RectangleGeometry(new Rect(startPoint, startPoint)),
Stroke = stroke,
StrokeThickness = strokeThickness
};
canvas.Children.Add(currentPath);
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (currentPath != null)
{
((RectangleGeometry)currentPath.Data).Rect
= new Rect(startPoint, e.GetPosition((UIElement)sender));
}
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
((UIElement)sender).ReleaseMouseCapture();
currentPath = null;
}
Related
I need the functionality of an image scale, translate and cropping just like what a photo chooser task do in windows phone 8.1. I can not use photo chooser task because I will not select the photo from media photo library or capture the image. For my purpose the image will be selected from a server saved picture list. I have written some code for this but it's not working as I desire. I am working on it for 4 weeks but hardly find the perfect solution. Here is my code.
This is the xaml code
<phone:PhoneApplicationPage
x:Class="TransformationLearning.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Transformation" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid Grid.Row="1" Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Name="grid"
Grid.Row="0"
Height="400"
Width="400"
>
<Image x:Name="myImage" Source="/Assets/Lion.jpg"
Stretch="UniformToFill"
ManipulationCompleted="CompleteManipulation"
ManipulationDelta="DeltaManipulation"
Loaded="ImageLoaded"
Grid.Row="1"
>
<Image.RenderTransform>
<CompositeTransform x:Name="myComposite"
/>
</Image.RenderTransform>
</Image>
<Rectangle Width="200"
Height="200"
Name="myRectangle"
Margin="100 100"
Stroke="White"
StrokeThickness="3" Grid.Row="1">
</Rectangle>
</Grid>
<Image Name="myCropPicture" Grid.Row="1"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
and this is the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using TransformationLearning.Resources;
using Microsoft.Xna.Framework;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using Lumia.Imaging;
using Lumia.Imaging.Transforms;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Storage;
using System.Windows.Controls.Primitives;
using System.Runtime.InteropServices.WindowsRuntime;
namespace TransformationLearning
{
public partial class MainPage : PhoneApplicationPage
{
WriteableBitmap WB_CapturedImage;//for original image
WriteableBitmap WB_CroppedImage;//for cropped image
double width, height;
WriteableBitmap wb;
CompositeTransform transform;
GeneralTransform gt, gt1;
System.Windows.Point absolutePosition, absolutePosition1;
public MainPage()
{
InitializeComponent();
transform = new CompositeTransform();
}
private void ImageLoaded(object sender, RoutedEventArgs e)
{
wb = new WriteableBitmap(myImage, null);
myComposite.CenterX = 150;
myComposite.CenterY = 150;
}
private double BoundaryCheck(double value)
{
if (value < 1.0)
return 1.0;
else if (value > 2.0)
return 2.0;
else
return value;
}
private void DeltaManipulation(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
transform = myComposite;
if (e.DeltaManipulation.Scale.X == 0.0 || e.DeltaManipulation.Scale.Y == 0.0)
{
myComposite.ScaleX *= 1.0;
myComposite.ScaleY *= 1.0;
}
else if (e.DeltaManipulation.Scale.X > 0.0)
{
double value = BoundaryCheck(myComposite.ScaleX*e.DeltaManipulation.Scale.X);
myComposite.ScaleX = myComposite.ScaleY = value;
gt = myImage.TransformToVisual(grid);
absolutePosition = gt.Transform(new System.Windows.Point(0, 0));
gt1 = myRectangle.TransformToVisual(grid);
absolutePosition1 = gt1.Transform(new System.Windows.Point(0, 0));
if ((absolutePosition1.X <= absolutePosition.X)
|| (absolutePosition1.Y <= absolutePosition.Y)
|| (absolutePosition1.X + myRectangle.Width >= absolutePosition.X + wb.PixelWidth)
|| (absolutePosition1.Y + myRectangle.Height >= absolutePosition.Y + wb.PixelHeight))
{
myComposite = transform;
}
}
gt = myImage.TransformToVisual(grid);
absolutePosition = gt.Transform(new System.Windows.Point(0, 0));
gt1 = myRectangle.TransformToVisual(grid);
absolutePosition1 = gt1.Transform(new System.Windows.Point(0, 0));
if (e.DeltaManipulation.Translation.Y > 0.0 && (absolutePosition1.Y >= (absolutePosition.Y + e.DeltaManipulation.Translation.Y)))
{
myComposite.TranslateY += (e.DeltaManipulation.Translation.Y-2);
}
if (e.DeltaManipulation.Translation.X > 0.0 && (absolutePosition1.X >= (absolutePosition.X + e.DeltaManipulation.Translation.X)))
{
myComposite.TranslateX += (e.DeltaManipulation.Translation.X - 2);
}
if (e.DeltaManipulation.Translation.Y < 0.0 && ((absolutePosition1.Y + myRectangle.Height) <= (absolutePosition.Y + e.DeltaManipulation.Translation.Y + wb.PixelHeight)))
{
myComposite.TranslateY += (e.DeltaManipulation.Translation.Y + 2);
}
if (e.DeltaManipulation.Translation.X < 0.0 && ((absolutePosition1.X + myRectangle.Width) <= (absolutePosition.X + e.DeltaManipulation.Translation.X + wb.PixelWidth)))
{
myComposite.TranslateX += (e.DeltaManipulation.Translation.X + 2);
}
wb = new WriteableBitmap(myImage, myComposite);
gt = myImage.TransformToVisual(grid);
absolutePosition = gt.Transform(new System.Windows.Point(0, 0));
}
private void CompleteManipulation(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
App.RootFrame.RenderTransform = new CompositeTransform();
grid.UpdateLayout();
CropImage();
App.RootFrame.RenderTransform = new CompositeTransform();
grid.UpdateLayout();
}
private async void CropImage()
{
var ms = new MemoryStream();
wb.SaveJpeg(ms, wb.PixelWidth, wb.PixelHeight, 0, 100);
ms.Position = 0;
gt1 = myRectangle.TransformToVisual(myImage);
absolutePosition1 = gt1.Transform(new System.Windows.Point(0, 0));
using (var source = new StreamImageSource(ms))
{
using (var filterEffect = new FilterEffect(source))
{
var filter = new CropFilter(new Windows.Foundation.Rect(absolutePosition1.X, absolutePosition1.Y, myRectangle.Width, myRectangle.Height));
filterEffect.Filters = new IFilter[] { filter };
var target = new WriteableBitmap((int)(myRectangle.Width), (int)(myRectangle.Height));
using (var renderer = new WriteableBitmapRenderer(filterEffect, target))
{
try
{
await renderer.RenderAsync();
}
catch (Exception t)
{
System.Diagnostics.Debug.WriteLine(t.InnerException);
System.Diagnostics.Debug.WriteLine(t.Message);
}
}
myCropPicture.Source = target;
}
}
}
}
}
Here I have used Lumia Imaging SDK crop filter for cropping the image. "myImage" is the source image and "myCropPicture" is used for showing the cropped image. For transformation I have used composite transform. When I scale the source image this code can not crop that image accordingly.I need the help badly.
did you check this post. it might come in handy
Image crop control for Silverlight or Windows Phone
I just started learning C# and I want to plot a cosine when user presses the radiobutton using WPF GUI interface. I think I am having trouble how to use call objects within different class. Thanks in advance and below is my code:
namespace WpfApplication2
{
using OxyPlot;
using OxyPlot.Annotations;
using OxyPlot.Axes;
using OxyPlot.Series;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click_2(object sender, RoutedEventArgs e)
{
if (radioButton1.IsChecked == true)
{
MessageBox.Show("Plot Cosine");
//I think solution should be something like this
//MainViewModel.MyModel.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.01, "cos(x)"));
}
}
}
public class MainViewModel : Window
{
//Plotting without any user input
public const double Pi = 3.14159265358979323846;
public const int SpeedOfLight = 3 * 10 ^ 8; // m per sec.
//OxyPlot.Wpf.PlotModel plot = new OxyPlot.Wpf.PlotView();
public MainViewModel()
{
MyModel = new PlotModel { Title = "Your Equation", LegendTitle = "Equations" };
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Distance" });
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Height" });
//Determine your range for the plot
//MyModel.Axes.Add(new LinearAxis(AxisPosition.Bottom, -10, 10));
//MyModel.Axes.Add(new LinearAxis(AxisPosition.Left, -5, 5));
MyModel.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.01, "cos(x)"));
MyModel.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.01, "sin(x)"));
LineSeries linePoints = new LineSeries() { };
double x, y;
DataPoint XYpoint = new DataPoint();
for (x = -10; x <= 10; x += 0.01)
{
//Make sure not 1/3 since C# will read it as integer divided by integer hence 1/3=0
//Use Math.Pow for powers
//Definately Matlab is easier to plot stuff XD
y = 1.0 / 2.0 * Math.Pow(x, 2) + 1;
XYpoint = new DataPoint(x, y);
linePoints.Points.Add(XYpoint);
}
MyModel.Series.Add(linePoints);
MyModel.InvalidatePlot(true);
}
public PlotModel MyModel { get; private set; }
}
}
Below is XAML code:
<Window x:Name="plot" x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:oxy="http://oxyplot.org/wpf"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication2"
mc:Ignorable="d"
Title="Plots" Height="450.307" Width="955.532" Background="White">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="73*"/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="145*"/>
<ColumnDefinition Width="329*"/>
</Grid.ColumnDefinitions>
<oxy:PlotView Title="{Binding Title}" Margin="4,0,0,0" Model="{Binding MyModel}" Grid.Column="1" >
<oxy:PlotView.Series>
<oxy:LineSeries ItemsSource="{Binding Points}"/>
</oxy:PlotView.Series>
</oxy:PlotView>
<Label x:Name="label" HorizontalAlignment="Left" Height="30" Margin="120,185,0,0" VerticalAlignment="Top" Width="142"/>
<RadioButton x:Name="radioButton1" Content="Plot Cosine" Grid.Column="1" HorizontalAlignment="Left" Height="20" Margin="50,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="85" />
<Button x:Name="button1" Content="Clear" HorizontalAlignment="Left" Height="35" Margin="120,7,0,0" Grid.Row="1" VerticalAlignment="Top" Width="142" Click="button_Click_2"/>
</Grid>
</Window>
C#
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Axes;
namespace WpfApplication2
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public PlotModel MyModel { get; private set; }
public MainWindow()
{
InitializeComponent();
MyModel = new PlotModel { Title = "Your Equation", LegendTitle = "Equations" };
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Distance" });
MyModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Height" });
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (radioButton1.IsChecked == true)
{
//MessageBox.Show("Plot Cosine");
graph();
}
}
public double getValue(int x, int y)
{
return (10 * x * x + 11 * x * y * y + 12 * x * y);
}
//setting the values to the function
public FunctionSeries GetFunction()
{
int n = 100;
FunctionSeries serie = new FunctionSeries();
for (int x = 0; x < n; x++)
{
for (int y = 0; y < n; y++)
{
//adding the points based x,y
DataPoint data = new DataPoint(x, getValue(x, y));
//adding the point to the serie
serie.Points.Add(data);
}
}
//returning the serie
return serie;
}
public void graph()
{
MyModel = new PlotModel { Title = "example" };
MyModel.LegendPosition = LegendPosition.RightBottom;
MyModel.LegendPlacement = LegendPlacement.Outside;
MyModel.LegendOrientation = LegendOrientation.Horizontal;
MyModel.Series.Add(GetFunction());
var Yaxis = new OxyPlot.Axes.LinearAxis();
OxyPlot.Axes.LinearAxis XAxis = new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Bottom, Minimum = 0, Maximum = 100 };
XAxis.Title = "X";
Yaxis.Title = "10 * x * x + 11 * x*y*y + 12*x*y";
MyModel.Axes.Add(Yaxis);
MyModel.Axes.Add(XAxis);
this.plot.Model = MyModel;
}
}
}
XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="73*"/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="145*"/>
<ColumnDefinition Width="329*"/>
</Grid.ColumnDefinitions>
<oxy:PlotView Margin="4,0,0,0" Grid.Column="1" Name="plot" >
<!--<oxy:PlotView.Series>
<oxy:LineSeries ItemsSource="{Binding Points}"/>
</oxy:PlotView.Series>-->
</oxy:PlotView>
<Label x:Name="label" HorizontalAlignment="Left" Height="30" Margin="120,185,0,0" VerticalAlignment="Top" Width="142"/>
<RadioButton x:Name="radioButton1" IsChecked="True" Content="Plot Cosine" Grid.Column="1" HorizontalAlignment="Left" Height="20" Margin="50,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="85" />
<Button x:Name="button1" Content="Clear" HorizontalAlignment="Left" Height="35" Margin="120,7,0,0" Grid.Row="1" VerticalAlignment="Top" Width="142" Click="button1_Click"/>
</Grid>
</Window>
I have this peculiar problem. I am having a user control . I am making an app for Windows 8.1 where I would choose an image from my Picture gallery. The image would open in my app with Stretch is Uniform and Horizontal And vertical alignment to center.
My user control will appear where I tap on the image. Now the problem is , when the image Stretch was none , I was able to magnify the correct region (around my click) , but now when I make it Stretch to Uniform and Set the horizontal and vertical Alignment to Center , I am getting other pixel information in my user control.
I want to know how to fix it.Any how , the images can be of 2*Full HD also or they can be HD or even less.
Secondly , I want to know the boundaries of the image . With boundaries I want to say that , my user control shouldnt go above the boundaries of the image .
How to implement that. If my code is needed , I would paste it , If required.
Have this video for reference . This is what I have to develop ! I have the user control ready and I am getting exact pixels for Stretch=NONE , and no Horizontal And Vertical Alignment set.
This is my code for my app
I believe the issue is with how you use the control, rather than the image. If you avoid doing the bitmap cropping and replacing, it would speed up dramatically and likely work for all stretch types.
I've modified the source to show this - removing the Cropping completely. If you need cropping for other reasons, you should consider using the unsafe keyword (and property setting to allow) in order to dramatically speed up its use.
Also, to avoid the lagging/jumping upward, I added IsHitTestVisible="False" so that your delta wouldn't be interrupted by hovering over your image.
I see you have the 45-degree code already - since it wasn't in your source, I only added an example of 90 degree rotation when you get to the sides - so you can see how to set a RenderTransformOrigin point.
MainPage.xaml:
<Page x:Name="page1"
x:Class="controlMagnifier.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ParentGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerReleased="ParentGrid_OnPointerReleased" >
<Canvas x:Name="InkPresenter" Height="auto" Width="auto">
<Image Stretch="Uniform" x:Name="image2" >
<Image.Source >
<BitmapImage UriSource="/Assets/wallpaper.jpg" />
</Image.Source>
</Image>
</Canvas>
<local:MagnifierUsercontrol x:Name="MagnifyTip" Visibility="Collapsed" ManipulationMode="All"
IsHitTestVisible="False" Height="227" Width="171"
VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center">
</local:MagnifierUsercontrol>
</Grid>
</Page>
MainPage.xaml.cs:
using System;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace controlMagnifier
{
public sealed partial class MainPage : Page
{
public const int XAxis = 200;
public const int YAxis = 435;
private readonly RotateTransform myRotateTransform = new RotateTransform {CenterX = 0.5, CenterY = 1};
private readonly ScaleTransform myScaleTransform = new ScaleTransform {ScaleX = 1, ScaleY = 1};
private readonly TransformGroup myTransformGroup = new TransformGroup();
private readonly TranslateTransform myTranslateTransform = new TranslateTransform();
public WriteableBitmap CurrentBitmapObj, CurrentCroppedImage = null;
public Point currentContactPt, GridPoint;
public Thickness margin;
public PointerPoint pt;
public double xValue, yValue;
public MainPage()
{
InitializeComponent();
ParentGrid.Holding += Grid_Holding;
image2.PointerMoved += InkCanvas_PointerMoved;
image2.PointerReleased += ParentGrid_OnPointerReleased;
margin = MagnifyTip.Margin;
image2.CacheMode = new BitmapCache();
myTransformGroup.Children.Add(myScaleTransform);
myTransformGroup.Children.Add(myRotateTransform);
myTransformGroup.Children.Add(myTranslateTransform);
MagnifyTip.RenderTransformOrigin = new Point(0.5, 1);
MagnifyTip.RenderTransform = myTransformGroup;
}
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
try
{
GridPoint = e.GetPosition(image2);
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
MagnifyTip.Visibility = Visibility.Visible;
}
catch (Exception)
{
throw;
}
}
private void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
pt = e.GetCurrentPoint(image2);
currentContactPt = pt.Position;
xValue = currentContactPt.X;
yValue = currentContactPt.Y;
if (xValue > 300)
{
myRotateTransform.Angle = -90;
}
else if (xValue < 100)
{
myRotateTransform.Angle = 90;
}
else
{
myRotateTransform.Angle = 0;
}
MagnifyTip.RenderTransform = myRotateTransform;
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
}
catch (Exception)
{
throw;
}
finally
{
e.Handled = true;
}
}
private async void StoreCrrentImage()
{
try
{
var storageFile =
await
StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg",
UriKind.RelativeOrAbsolute));
using (
var fileStream =
await storageFile.OpenAsync(FileAccessMode.Read))
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
var writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
CurrentBitmapObj = writeableBitmap;
writeableBitmap.Invalidate();
}
}
catch (Exception)
{
// Graphics g=new Graphics();
throw;
}
finally
{
}
}
private void ParentGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifyTip.Visibility = Visibility.Collapsed;
}
}
}
MagnifierUsercontrol.xaml:
<UserControl
x:Class="controlMagnifier.MagnifierUsercontrol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Height="227" Width="171">
<Canvas x:Name="controlCanvas" x:FieldModifier="public" Height="Auto" Width="Auto" >
<Grid Height="227" Width="171" HorizontalAlignment="Center" Canvas.Left="0" Canvas.Top="0">
<Border x:FieldModifier="public" x:Name="imgBorder" Width="150" CornerRadius="50,50,50,50" Margin="13,25,13,97">
<Border.Background>
<ImageBrush x:FieldModifier="public" x:Name="image1" />
</Border.Background>
</Border>
<TextBlock x:Name="txtreading" Height="30" Width="80" Margin="0,-145,0,0" FontWeight="Bold" Foreground="Red" FontSize="20" Text="ABC" TextAlignment="Center" />
<!--<Image Height="120" Width="150" Margin="0,-50,0,0" Source="Assets/SmallLogo.scale-100.png" ></Image>-->
<Path x:Name="MagnifyTip" Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Height="227" Width="171" />
</Grid>
</Canvas>
</UserControl>
Let me know if this helps or if there is further toward your specific question.
I'm very new to WPF and I'm trying to create a picture cropping application. The program has a rectangle that can be dragged to crop the picture (like in Microsoft Paint). The way its set up is that both image and canvas which holds the rectangle are children of grid container. Grid has events for mousemove, mouseleftbuttondown and up to calculate the cropped image. My program is cropping the image fine but the problem occurs when the window is maximized which throws an exception error below:
An unhandled exception of type 'System.ArgumentException' occurred in PresentationCore.dll
Additional information: Value does not fall within the expected range.
This exception is caused by a line in my Go_Click method:
BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);
I stepped into the program and found out that at first it was caused by setting the width and height of Image (LoadedImage.Width and LoadedImage.Height) to auto or NAN. This makes the value NAN which mess up the calculation and throws of the exception. I changed it to ActualWidth (LoadedImage.ActualWidth and ActualHeight) and I only got it work partially since it still throws an exception whenever I crop the image while window is maximized.
Below is source code for my project.
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<GroupBox Header="Loaded Image:" Grid.Column="0">
<Grid x:Name="LoadedImage" MouseLeftButtonDown="image1_MouseLeftButtonDown" MouseMove="image1_MouseMove" MouseLeftButtonUp="image1_MouseLeftButtonUp" ShowGridLines="True">
<Image x:Name="loaded" Margin="10" Stretch="Fill"/>
<Canvas x:Name="BackPanel" Margin="10">
<Rectangle x:Name="selectionRectangle" Stroke="LightBlue" Fill="#220000FF" Visibility="Collapsed"/>
</Canvas>
</Grid>
</GroupBox>
<StackPanel Grid.Column="1" x:Name="MyPanel" HorizontalAlignment="Left" Orientation="Vertical" Height="340" Width="262">
<GroupBox x:Name="Box2" Header="Preview Box:">
<Image x:Name="PreviewImage" MaxWidth="240" MaxHeight="240" Stretch="Fill" MinWidth="240" MinHeight="240"/>
</GroupBox>
<StackPanel Height="61" Orientation="Horizontal" HorizontalAlignment="Center">
<Button MinWidth="93" Height="32" Click="Import_Click">Import</Button>
<Button Name="Crop" MinWidth="93" Height="32" Margin="10,0,0,0" Click="Go_Click">Crop</Button>
</StackPanel>
</StackPanel>
</Grid>
And this is the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool isDragging = false;
private Point anchorPoint = new Point();
public MainWindow()
{
InitializeComponent();
}
//Import Button event handler which opens an open file dialog
//to choose an image file. If the return value from ShowDialog
//is true (user choose image and click's OK)it will store the image to file,
//else it would exit open file dialog.
private void Go_Click(object sender, RoutedEventArgs e)
{
if (loaded.Source != null)
{
Rect rect1 = new Rect(Canvas.GetLeft(selectionRectangle), Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
Int32Rect rcFrom = new Int32Rect();
rcFrom.X = (int)((rect1.X) * (loaded.Source.Width) / `enter code here`(loaded.ActualWidth));
rcFrom.Y = (int)((rect1.Y) * (loaded.Source.Height) / (loaded.ActualHeight));
rcFrom.Width = (int)((rect1.Width) * (loaded.Source.Width) / (loaded.ActualWidth));
rcFrom.Height = (int)((rect1.Height) * (loaded.Source.Height) / (loaded.ActualHeight));
BitmapSource bs = new CroppedBitmap(loaded.Source as BitmapSource, rcFrom);
PreviewImage.Source = bs;
}
}
private void image1_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
double x = e.GetPosition(BackPanel).X;
double y = e.GetPosition(BackPanel).Y;
selectionRectangle.SetValue(Canvas.LeftProperty, Math.Min(x, anchorPoint.X));
selectionRectangle.SetValue(Canvas.TopProperty, Math.Min(y, anchorPoint.Y));
selectionRectangle.Width = Math.Abs(x - anchorPoint.X);
selectionRectangle.Height = Math.Abs(y - anchorPoint.Y);
if (selectionRectangle.Visibility != Visibility.Visible)
selectionRectangle.Visibility = Visibility.Visible;
}
}
private void image1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (isDragging == false)
{
anchorPoint.X = e.GetPosition(BackPanel).X;
anchorPoint.Y = e.GetPosition(BackPanel).Y;
isDragging = true;
}
}
private void image1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
isDragging = false;
if (selectionRectangle.Width > 0)
{
Crop.Visibility = System.Windows.Visibility.Visible;
Crop.IsEnabled = true;
}
if (selectionRectangle.Visibility != Visibility.Visible)
selectionRectangle.Visibility = Visibility.Visible;
}
}
private void RestRect()
{
selectionRectangle.Visibility = Visibility.Collapsed;
isDragging = false;
}
private void Import_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.FileName = "Picture";
dlg.Filter = "All Pictures (*.jpeg)|*.jpg";
if (dlg.ShowDialog() == true)
{
loaded.Source = new BitmapImage(new Uri(dlg.FileName));
}
}
}
}
Like I said i'm new to programming WPF and I apologize if the way i have my code written may not be the best. But any advise would help on how I should handle this issue.
Thanks in advance.
You need to get LoadedImage position relative to GridLoadedImage, and use it when creating crop:
private void Go_Click(object sender, RoutedEventArgs e)
{
if (LoadedImage.Source != null)
{
var imagePosition = loaded.TransformToAncestor(LoadedImage).Transform(new Point(0, 0));
Rect rect1 = new Rect(Math.Max(Canvas.GetLeft(selectionRectangle) - imagePosition.X, 0), Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
Int32Rect rcFrom = new Int32Rect();
rcFrom.X = (int)((rect1.X) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
rcFrom.Y = (int)((rect1.Y) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
rcFrom.Width = (int)((rect1.Width) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
rcFrom.Height = (int)((rect1.Height) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);
PreviewImage.Source = bs;
}
}
I have an Image viewer that displays an image. I want to draw a rectangle using the mouse over the image and get the x and y coordinates of the rectangle (X1, X2, Y1, and Y2). I will use these coordinates to create a search region and find the max and min values in an array that have the exact number of pixels as the image in both axes.
Can anyone guide me to a direction to start please?
You should use a canvas to display the image and draw a rectangle over it.
Example:
MainWindow.xaml:
<Window x:Class="CanvasRectangleSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<Canvas x:Name="SampleImageCanvas"
MouseMove="SampleImageCanvas_MouseMove"
MouseDown="SampleImageCanvas_MouseDown"
Width="512" Height="389">
<Canvas.Background>
<!--Here you set the image to display -> You probably want to bind it to something. -->
<ImageBrush x:Name="SampleImage" Stretch="Uniform" ImageSource="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg">
</ImageBrush>
</Canvas.Background>
<!-- Here you draw whatever you want on the canvas. -->
<!-- You'll probably want to bind its width and height to something too. -->
<Rectangle x:Name="ROI" Stroke="#FFF1133E" Width="50" Height="50"/>
</Canvas>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
namespace CanvasRectangleSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
// Handling the redrawing of the rectangle according to mouse location
private void SampleImageCanvas_MouseMove(object sender, MouseEventArgs e)
{
//get mouse location relative to the canvas
Point pt = e.MouseDevice.GetPosition(sender as Canvas);
//here you set the rectangle loction relative to the canvas
Canvas.SetLeft(ROI, pt.X - (int)(ROI.Width / 2));
Canvas.SetTop(ROI, pt.Y - (int)(ROI.Height / 2));
}
private void SampleImageCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
//Here you should handle saving the rectangle location
//don't forget to calculate the proportion between Canvas's size and real Image's size.
}
}
}
If you want you can limit the rectangle relocation to the canvas area with an if expression checking if the canvas area containes the mouse locaion
Thanks for the pointers and help:
Here is my finished code and it works. You place the mouse anywhere on the canvas hold mouse down and drag to create the rectangle. It could use some more improvement to drag and create the rectangle in any direction.
XAML:
<Canvas Name="ImageCanvas"
MouseMove="ImageCanvas_MouseMove"
MouseDown="ImageCanvas_MouseDown"
Height="240" Width="320"
HorizontalAlignment="Left"
Margin="87,514,0,0" VerticalAlignment="Top" MouseLeftButtonUp="ImageCanvas_MouseLeftButtonUp">
<Canvas.Background>
<ImageBrush x:Name="Image" Stretch="Uniform" ImageSource="C:\image.bmp">
</ImageBrush>
</Canvas.Background>
<Rectangle x:Name="ROI" Stroke="#FFF1133E" Width="20" Height="20" Canvas.Left="155" Canvas.Top="115" />
</Canvas>
Code:
double topLeftX = 0;
double topLeftY = 0;
double bottomRightX = 0;
double bottomrigthY = 0;
bool setRect = false;
private void ImageCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
topLeftY = topLeftX = bottomrigthY = bottomRightX = 0;
setRect = true;
System.Windows.Point pt = e.MouseDevice.GetPosition(sender as Canvas);
topLeftX = pt.X; topLeftY = pt.Y;
}
private void ImageCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (setRect == true)
{
//get mouse location relative to the canvas
System.Windows.Point pt = e.MouseDevice.GetPosition(sender as Canvas);
Canvas.SetLeft(ROI, topLeftX);
Canvas.SetTop(ROI, topLeftY);
ROI.Width = System.Math.Abs((int)(pt.X - topLeftX));
ROI.Height = System.Math.Abs((int)(pt.Y - topLeftY));
commandReturnTB.Text = (Convert.ToString(pt.X) + "," + Convert.ToString(pt.Y))+"\n";
}
}
private void ImageCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
System.Windows.Point pt = e.MouseDevice.GetPosition(sender as Canvas);
bottomRightX = pt.X;
bottomrigthY = pt.Y;
ROI.Width = System.Math.Abs((int)(bottomRightX - topLeftX));
ROI.Height = System.Math.Abs((int)(bottomrigthY - topLeftY));
Canvas.SetLeft(ROI, topLeftX);
Canvas.SetTop(ROI, topLeftY);
setRect = false;
commandReturnTB.Text = topLeftX + "," + topLeftY + "--" + bottomRightX + "," + bottomrigthY;
}