c# Fitting an image in a square detected in another image - c#

So basically i need to make an app that fits a painting in a frame on a wall that's square. I'm using aforge to detect the square and with it's corners i place and resize the image i want to the frame. This is done by pressing the third button which triggers imageAdapt() method. Unfortunately the image is not rescaled to the right size and placed wrongly. Here's my code:
namespace MyFirstJob
{
public sealed partial class MainPage : Page
{
public static int a = -1;
public static int b = -1;
FolderPicker folderPicker1 = new Windows.Storage.Pickers.FolderPicker();
FolderPicker folderPicker2 = new Windows.Storage.Pickers.FolderPicker();
StorageFolder folder1;
StorageFolder folder2;
System.Collections.Generic.IReadOnlyList<StorageFile> filesList1;
System.Collections.Generic.IReadOnlyList<StorageFile> filesList2;
public MainPage()
{
InitializeComponent();
folderPicker1.FileTypeFilter.Add(".png");
folderPicker2.FileTypeFilter.Add(".png");
}
private async void button1_Click(object sender, RoutedEventArgs e)
{
a++;
folder1 = await folderPicker1.PickSingleFolderAsync();
filesList1 = await folder1.GetFilesAsync();
var stream = await
filesList1[a].OpenAsync(Windows.Storage.FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bitmapImage.SetSourceAsync(stream);
image1.Source = bitmapImage;
}
private async void button2_Click(object sender, RoutedEventArgs e)
{
b++;
folder2 = await folderPicker2.PickSingleFolderAsync();
filesList2 = await folder2.GetFilesAsync();
var stream = await
filesList2[b].OpenAsync(Windows.Storage.FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bitmapImage.SetSourceAsync(stream);
image2.Source = bitmapImage;
}
private async void adaptImage()
{
var stream = await
filesList1[a].OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
WriteableBitmap writableBitmap = new
WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
writableBitmap.SetSource(stream);
BlobCounter blobCounter = new BlobCounter();
blobCounter.MinHeight = 100;
blobCounter.MinWidth = 100;
blobCounter.MaxHeight = 600;
blobCounter.MaxWidth = 600;
blobCounter.ProcessImage((Bitmap)writableBitmap);
Blob[] blobs = blobCounter.GetObjectsInformation();
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
foreach (var blob in blobs)
{
List<IntPoint> edgePoints =
blobCounter.GetBlobsEdgePoints(blob);
List<IntPoint> cornerPoints;
if (shapeChecker.IsQuadrilateral(edgePoints, out cornerPoints))
{
if (shapeChecker.CheckPolygonSubType(cornerPoints) == PolygonSubType.Square)
{
double lenght = getLenght(cornerPoints[0].X,
cornerPoints[0].Y, cornerPoints[1].X, cornerPoints[1].Y);
image2.Height = lenght;
image2.Width = lenght;
image2.Margin = new Thickness(cornerPoints[0].X,
cornerPoints[0].Y, 0, 0);
}
}
}
}
private void button3_Click(object sender, RoutedEventArgs e)
{
adaptImage();
}
private double getLenght(int x1, int y1, int x2, int y2)
{
return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
}
}
When it starts: First button loads the background , second one the painting and then the last one makes it fit the painting
After loading the background everything is ok
Loading the painting (a random square)
The final image where the painting is not fit proprely in the square

Since you didn't upload the XAML code, I added the following XAML code for testing and it can work well on my side with your code snippet.
<Canvas>
<Image x:Name="image1" ></Image>
<Image x:Name="image2" ></Image>
<StackPanel Canvas.Top="20">
<Button x:Name="Button1" Click="button1_Click" Content="button1"></Button>
<Button x:Name="Button2" Click="button2_Click" Content="button2"></Button>
<Button x:Name="Button3" Click="button3_Click" Content="button3"></Button>
</StackPanel>
</Canvas>
Code behind are the same. I tested on build 15036. For aforge I'm using AForge Core 2.2.5.60302 and Imaging 2.2.5.60302.
But I can reproduce your issue with Grid panel as the parent container, and at the same time the cornerPoints of square doesn't begin from point 0,0. Inside a Grid panel, child elements are measured and arranged according to their row/column assignments.The image control may be positioned in the middle at default. But the cornerPoints of square is the coordinate relative to the top-left corner of background image, so it may be wrong to calculate the margin by cornerPoints. Canvas is suit for your scenarios. So please check if you are using a parent container for the Image controls that will arrange the image controls , for example, a StackPanel or a Grid. More details please reference Layout panels.

Related

Draw a Straight Line In Wpf C#

Hello I'm Drawing a line in my Application . I'm using Caliburn.Micro MVVM Framework . In my DICOM image I'm able to draw a line using Pointer and Calculate distance . I use 3 events MouseDown,MouseMove and MouseUp. I left click to my Mouse and then I move if I release I able to Draw . My problem is when I move my mouse may be it sometimes change direction that time using Graphics.Drawline draw line but when I'm in the last point it should the Straight line . But as I move my Mouse it has the other point the line too that does not belong to this Line . Please see the what I did
It should be a starigh line as Sometimes My mouse move the color still at that point .There is a famous DICOM Viewer App Name Radiant Here you can see
Line is Straight.
Here is My code
<Image Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="4"
x:Name="DIIMGFINAL" cal:Message.Attach="[Event MouseDown] = [Action MDownCalCulateDistance($source, $eventArgs)];
[Event MouseMove] = [Action MMoveCalCulateDistance($source, $eventArgs)];
[Event MouseUp] = [Action MUpCalCulateDistance($source, $eventArgs)]">
</Image>
And Here is MY C# Code in ViewModel Class. This is MouseDown Event
public void MDownCalCulateDistance(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!(sender is System.Windows.Controls.Image)) return;
_diIMGTemp = DIIMGFINAL;
if (_firstPoint.X == 0 && _firstPoint.Y == 0)
{
System.Windows.Point px1 = e.GetPosition((System.Windows.Controls.Image)sender);
_firstPoint = px1;
}
if (_secondPoint.X != 0 && _secondPoint.Y != 0)
{
System.Drawing.Bitmap drawbitmap = BitmapImage2Bitmap(DIIMGPrimary);
Graphics g;
using (g = Graphics.FromImage(drawbitmap))
{
g.DrawLine(Pens.Red, Convert.ToInt32(_firstPoint.X), Convert.ToInt32(_firstPoint.Y), Convert.ToInt32(_secondPoint.X), Convert.ToInt32(_secondPoint.Y));
g.Dispose();
}
Convert_BitMap_BitImage(drawbitmap);
DIIMGFINAL = DIIMGPrimary;
var geometry = new FrameGeometry(DicomDataSet);
var patientCoord1 = geometry.TransformImagePointToPatient(new Point2(Convert.ToInt32(_firstPoint.X), Convert.ToInt32(_firstPoint.Y)));
var patientCoord2 = geometry.TransformImagePointToPatient(new Point2(Convert.ToInt32(_secondPoint.X), Convert.ToInt32(_secondPoint.Y)));
double distanceInMM = patientCoord1.Distance(patientCoord2);
DisTanceInMM = distanceInMM;
//_firstPoint = new System.Windows.Point(0, 0);
//_secondPoint= new System.Windows.Point(0, 0);
// _isClicked = false;
}
}
This is MouseUp Event ..
public void MUpCalCulateDistance(object sender, System.Windows.Input.MouseEventArgs e)
{
_firstPoint = new System.Windows.Point(0, 0);
_secondPoint = new System.Windows.Point(0, 0);
}
And The last one is Mouse Move Event .
public void MMoveCalCulateDistance(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!(sender is System.Windows.Controls.Image)) return;
System.Windows.Point px = e.GetPosition((System.Windows.Controls.Image)sender);
XCoordinate = px.X;
YCoordinate = px.Y;
// if (_isClicked == false) return;
// MousePoint
if ((_firstPoint.X == 0 && _firstPoint.Y == 0))
{
return;
}
else
{
System.Windows.Point px2 = e.GetPosition((System.Windows.Controls.Image)sender);
_secondPoint = px2;
System.Drawing.Bitmap drawbitmap = BitmapImage2Bitmap(DIIMGPrimary);
Graphics g;
// g.Clear();
using (g = Graphics.FromImage(drawbitmap))
{
g.DrawLine(Pens.Red, Convert.ToInt32(_firstPoint.X), Convert.ToInt32(_firstPoint.Y), Convert.ToInt32(_secondPoint.X), Convert.ToInt32(_secondPoint.Y));
}
Convert_BitMap_BitImage(drawbitmap);
DIIMGFINAL = DIIMGPrimary;
var geometry = new FrameGeometry(DicomDataSet);
var patientCoord1 = geometry.TransformImagePointToPatient(new Point2(Convert.ToInt32(_firstPoint.X), Convert.ToInt32(_firstPoint.Y)));
var patientCoord2 = geometry.TransformImagePointToPatient(new Point2(Convert.ToInt32(_secondPoint.X), Convert.ToInt32(_secondPoint.Y)));
double distanceInMM = patientCoord1.Distance(patientCoord2);
DisTanceInMM = distanceInMM;
}
}
Please Help me Thanks in Advance.Sorry For lengthy question .
You should probably not draw directly on the image. This is quite inefficient, and you will also have problems like you have encountered. A better approach would be to create an overlay with lines and other graphics, See the question how to bind lines to a canvas on an example how to do this.
If you put your items control and your image in the same grid the items control should work like an overlay. i.e.
<Grid>
<Image>
<!--... -->
</Image>
<ItemsControl ItemsSource="{Binding Lines}">
<!--...-->
</ItemsControl>
</Grid>
You can use the same approach with an bitmap overlay, but that would be less efficient than letting wpf draw your primitives for you.

Drawing image using Blur effects in UWP is not properly set size for the image

I want to blur the image using slider. For this, I have used Win2D Blur effects and draw the image in CanvasControl and added the canvas over the actual image.
Download sample here
Steps.
1. Added CanvasControl in button click. It will add a child to grid over the actual element
2. Change Slider to apply the blur
3. Issue: Image stretched and it's size too large and look like cropped. Not in the given size (500, 400)
[XAML]
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="imageGrid">
<Image x:Name="image" Source="Flower1.jpg" Width="500" Height="400"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
<StackPanel Grid.Column="1" Orientation="Vertical">
<Button Content="AddCanvas" Width="100" x:Name="addCanvas"
Click="AddCanvas_Click"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Blur" Width="100"/>
<Slider x:Name="slider" Minimum="0" Maximum="5" Width="200"
ValueChanged="Slider_ValueChanged"/>
</StackPanel>
</StackPanel>
</Grid>
[C#]
bool isBlurred;
GaussianBlurEffect blur = new GaussianBlurEffect();
CanvasControl canv = new CanvasControl();
CanvasBitmap cbi;
public MainPage()
{
this.InitializeComponent();
}
private void AddCanvas_Click(object sender, RoutedEventArgs e)
{
canv.HorizontalAlignment = HorizontalAlignment.Left;
canv.VerticalAlignment = VerticalAlignment.Top;
canv.Draw += Canv_Draw;
canv.CreateResources += Canv_CreateResources;
canv.Height = 400;
canv.Width = 500;
imageGrid.Children.Add(canv);
}
private void Canv_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
{
args.DrawingSession.Units = CanvasUnits.Pixels;
if (isBlurred)
{
args.DrawingSession.DrawImage(blur, new Rect(0, 0, 500, 400), new Rect(0, 0, 500, 400));
}
}
private void Canv_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
{
args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
}
async Task CreateResourcesAsync(CanvasControl sender)
{
cbi = await CanvasBitmap.LoadAsync(sender, "Flower1.jpg");
}
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
isBlurred = true;
blur.Source = cbi;
blur.BlurAmount = (float)e.NewValue;
canv.Invalidate();
}
I would like to apply the Blur effects to the Image using slider dynamically. But i don't want to change the Actual image to Blur. So, I used Canvas over the Actual image and draw with Blur effect.
Regards,
Bharathi.
Drawing image using Blur effects in UWP is not properly set size for the image
The problem is that the size of CanvasControl is not suit for image source (Image: 960*640 CanvasControl:500*400). If you want to make CanvasControl could display the full image, please set available dpi when call CanvasBitmap.LoadAsync method. For my testing 185 is suit for your scenario.
async Task CreateResourcesAsync(CanvasControl sender)
{
cbi = await CanvasBitmap.LoadAsync(sender, "Flower1.jpg",185);
}
Update
//var dpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var display = DisplayInformation.GetForCurrentView();
// calculate your monitor's dpi
var dpi = Math.Sqrt(Math.Pow(display.ScreenWidthInRawPixels, 2) + Math.Pow(display.ScreenHeightInRawPixels, 2)) / display.DiagonalSizeInInches;
// get the CanvasControl inch
var inch = Math.Sqrt(Math.Pow(500, 2) + Math.Pow(400, 2)) / dpi;
// calculate last dpi with the image size
var lastdpi = Math.Sqrt(Math.Pow(960, 2) + Math.Pow(640, 2)) / inch;
Update 1
If could also set CanvasControl size with image size that could avoid to calculate Dpi.
Update 2
And you could also resize your image to suit for CanvasControl, Please refer the following code.
public async Task<IRandomAccessStream> ResizeImage(StorageFile file, int reqWidth, int reqHeight)
{
var memStream = new MemoryStream();
using (Stream stream = await file.OpenStreamForReadAsync())
{
stream.CopyTo(memStream);
}
IRandomAccessStream imageStream = memStream.AsRandomAccessStream();
var decoder = await BitmapDecoder.CreateAsync(imageStream);
if (decoder.PixelHeight > reqHeight || decoder.PixelWidth > reqWidth)
{
using (imageStream)
{
var resizedStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder);
double widthRatio = (double)reqWidth / decoder.PixelWidth;
double heightRatio = (double)reqHeight / decoder.PixelHeight;
double scaleRatio = Math.Min(widthRatio, heightRatio);
if (reqWidth == 0)
scaleRatio = heightRatio;
if (reqHeight == 0)
scaleRatio = widthRatio;
uint aspectHeight = (uint)Math.Floor(decoder.PixelHeight * scaleRatio);
uint aspectWidth = (uint)Math.Floor(decoder.PixelWidth * scaleRatio);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
encoder.BitmapTransform.ScaledHeight = aspectHeight;
encoder.BitmapTransform.ScaledWidth = aspectWidth;
await encoder.FlushAsync();
return resizedStream;
}
}
return imageStream;
}
Usage
async Task CreateResourcesAsync(CanvasControl sender)
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Flower1.jpg"));
cbi = await CanvasBitmap.LoadAsync(sender, await ResizeImage(file, 500, 400));
}

Clear A Bitmap in .Net

I'm using PictureBox control to draw complicated charts, and to optimize for performance i use a cache Bitmap for each layer of the drawing, and draw them on the control image, the upper layers have transparent backgrounds, i need to clear them and redraw on every change.
Assuming g instance of Graphics class of the Bitmap, using g.Clear(Color.White) draws a white rectangle over everything and so hiding lower layers, and g.Clear(Color.Transparent) draws Transparent rectangle over, what means doing nothing.
Isn't there a way to clear the Bitmap returning it to its original state?
private void btn_CancelImage_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Cancel and delete this Image?", "Cancel", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
ClearImage();
pictureBox1.Refresh();
}
else if (dialogResult == DialogResult.No)
{
return;
}
}
public void ClearImage()
{
Graphics g = Graphics.FromImage(ImageBitmap);
g.Clear(Color.White);
}
This is maybe not the answer you were looking for but I think it is an insteresting alternative to what you have.
Instead of having to draw all the layers upwards from every change, I stack as many layers on top of each other by nesting a number of PictureBoxes into one bottom PictureBox pBox0:
List<PictureBox> Layers = new List<PictureBox>();
private void Form1_Load(object sender, EventArgs e)
{
Layers.Add(pBox0);
setUpLayers(pBox0 , 20); // stacking 20 layers onto the botton one
timer1.Start(); // simulate changes
}
The stacking is set up like this:
void setUpLayers(Control parent, int count)
{
for (int i = 0; i < count; i++)
{
PictureBox pb = new PictureBox();
pb.BorderStyle = BorderStyle.None;
pb.Size = parent.ClientSize;
Bitmap bmp = new Bitmap(pb.Size.Width,pb.Size.Height,PixelFormat.Format32bppPArgb);
pb.Image = bmp;
pb.Parent = i == 0 ? pBox0 : Layers[i - 1];
Layers.Add(pb);
}
}
For best performance I use Format32bppPArgb as the pixel format.
For testing I run a Tick event that randomly draws onto a layer:
Random R = new Random(9);
private void timer1_Tick(object sender, EventArgs e)
{
int l = R.Next(Layers.Count-1) + 1;
Bitmap bmp = (Bitmap) Layers[l].Image;
using (Graphics G = Graphics.FromImage(Layers[l].Image))
{
G.Clear(Color.Transparent);
using (Font font = new Font("Consolas", 33f))
G.DrawString(l + " " + DateTime.Now.Second , font, Brushes.Gold,
R.Next(bmp.Size.Width), R.Next(bmp.Size.Height));
}
Layers[l].Image = bmp;
}
To collect all layers into one Bitmap you would make use of the DrawToBitmap method:
Bitmap GetComposite(Control ctl)
{
Bitmap bmp = new Bitmap(ctl.ClientSize.Width, ctl.ClientSize.Height,
PixelFormat.Format32bppArgb);
ctl.DrawToBitmap(bmp, ctl.ClientRectangle);
return bmp;
}
The result can then be saved or used in any other way..
Note that creating too many layers this way will hit a limit for window handles; I hit that limit at around 90 layers. If you need more that a few dozen layers a more intricate caching strategy is called for..

Change pixel null reference exception when image is not stored in local folder

I am trying to change the pixels of images to Red, the images are downloaded from server and are not stored in local folder. The below code I am using and it works perfectly fine when image is stored in local folder.
private ImageSource changeimagepixel(string p)
{
Uri uri = new Uri(p, UriKind.RelativeOrAbsolute);
ImageSource imgsource = new BitmapImage(uri);
image.Source = imgsource;
WriteableBitmap image1 = new WriteableBitmap((BitmapSource)image.Source);
WriteableBitmap image2 = ChangeColor(image1);
image.Source = image2;
return image.Source;
}
public static WriteableBitmap ChangeColor(WriteableBitmap scrBitmap)
{
//You can change your new color here. Red,Green,LawnGreen any..
Color newColor =Colors.Red;
Color actulaColor;
//make an empty bitmap the same size as scrBitmap
WriteableBitmap newBitmap = new WriteableBitmap(scrBitmap.PixelWidth, scrBitmap.PixelHeight);
for (int i = 0; i < scrBitmap.PixelWidth; i++)
{
for (int j = 0; j < scrBitmap.PixelHeight; j++)
{
//get the pixel from the scrBitmap image
actulaColor = scrBitmap.GetPixel(i, j);
// > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left.
if (actulaColor.A > 150)
newBitmap.SetPixel(i, j, (Color)newColor);
else
newBitmap.SetPixel(i, j, actulaColor);
}
}
return newBitmap;
}
Here, p is the URL of image obtained from server and I am getting NullReference Exception at
WriteableBitmap image1 = new WriteableBitmap((BitmapSource)image.Source);
Please anyone suggest a solution,to change the pixel of image which are not in local folder and obtained from server.
It would be a great help.
Thanks.
You need to wait for it to download completely before you do any operations to it.
Example:
<Grid x:Name="ContentPanel">
<Image x:Name="myImage"></Image>
</Grid>
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// download my dogecoin image
myImage.Source = new BitmapImage(new Uri("http://www.chubosaurus.com/dogecoin_wp8.jpg", UriKind.Absolute));
// hook the download complete
myImage.ImageOpened += bi_ImageOpened;
}
// image has downloaded completely, do your actions afterwards
void bi_ImageOpened(object sender, RoutedEventArgs e)
{
// ..... your code
// put a break point here, you will see it will break when the image has downloaded
}
}
If the event is not firing -- it is most likely because you created the Image dynamically without adding it to the Visual Tree, so to fix this do something like this
<!-- the default ContentPanel when creating the project -->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<!--- your content -->
</Grid>
// Constructor
public MainPage()
{
InitializeComponent();
Image mytestimage = new Image();
mytestimage.Visibility = System.Windows.Visibility.Collapsed;
mytestimage.Source = new BitmapImage(new Uri("http://www.chubosaurus.com/dogecoin_wp8.jpg", UriKind.Absolute));
// add it to the Visual Tree as a child of ContentPanel
this.ContentPanel.Children.Add(mytestimage);
// hook the download complete
mytestimage.ImageOpened += mytestimage_ImageOpened;
}
// image has been downloaded successfully
void mytestimage_ImageOpened(object sender, RoutedEventArgs e)
{
// your code
}

Saving canvas data to image file output is wrong

I want to place an image over a parent image and save the final image. So I used parent image inside Canvas and added the child image in the canvas.
Problems:
Right after when i loaded the thumbnail(child) image, if i click on the parent image, then the thumbnail(child) image become in-Visible.
I couldn't place the the thumbnail(child) image over the parent image precisely using the mouse left button up release.
I couldn't save the final image with the actual image Height & Width. The final saved image output height & width is wrong.
please guide me to fix the above problems.
SpecialEffects XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib"
x:Class="ImagePrintUtility.SpecialEffects"
Title="SpecialEffects" Height="768" Width="1024" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="125"/>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" HorizontalAlignment="Stretch" Margin="0" Background="AliceBlue" Name="DockPanel1">
<WrapPanel>
<StackPanel Margin="5">
<Button Content="AddLogo" Click="Button_Click" Height="50" Width="90" />
<Button Content="Reset Logo" x:Name="bresetLogo" Height="50" Width="90" Margin="0,5" />
</StackPanel>
<StackPanel Margin="5">
<Button Name="bSave" Width="90" Height="50" Foreground="White" Content="Save" Click="bSave_Click" />
<Button x:Name="btnClose" Content="Close" Height="50" Width="90" Margin="0,5" FontSize="20" Click="btnClose_Click" />
</StackPanel>
</WrapPanel>
</DockPanel>
<!--<GridSplitter Grid.Row="1" Grid.RowSpan="1" ResizeDirection="Rows" Width="Auto" Height="10" HorizontalAlignment="Stretch" Margin="0" Name="GridSplitter1" />-->
<Grid Grid.Row="1" Margin="0" Background="AliceBlue" Name="Grid1">
<StackPanel >
<Canvas x:Name="canvas" HorizontalAlignment="Stretch"
MouseLeftButtonDown="CanvasMouseLeftButtonDown"
MouseLeftButtonUp="CanvasMouseLeftButtonUp"
MouseMove="CanvasMouseMove" Margin="0,0,31,0">
<Image x:Name="SpecialPhoto" Source="IMG_0071.JPG" Height="586" Width="780"
Stretch="Uniform" VerticalAlignment="Top" HorizontalAlignment="Center" />
</Canvas>
</StackPanel>
</Grid>
</Grid>
</Window>
SpecialEffects.cs Code:
public partial class SpecialEffects : Window
{
private string FileNmae;
private int actualWidth;
private int actualHeight;
public SpecialEffects(string getTheFN) //Load the selected Image from ParentWindow
{
InitializeComponent();
FileNmae = getTheFN;
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(FileNmae, UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
SpecialPhoto.Source = src;
}
private Image draggedImage;
private Point mousePosition;
bool captured = false;
private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var image = e.Source as Image;
if (image != null && canvas.CaptureMouse())
{
mousePosition = e.GetPosition(canvas);
draggedImage = image;
Panel.SetZIndex(draggedImage, 1); // in case of multiple images
}
}
private void CanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (draggedImage != null)
{
canvas.ReleaseMouseCapture();
Panel.SetZIndex(draggedImage, 0);
draggedImage = null;
Mouse.Capture(null);
captured = false;
}
}
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
if (draggedImage != null)
{
var position = e.GetPosition(canvas);
var offset = position - mousePosition;
mousePosition = position;
double left = Canvas.GetLeft(draggedImage) + offset.X;
double top = Canvas.GetTop(draggedImage) + offset.Y;
if (left < 0)
{
left = 0;
}
if (top < 0)
{
top = 0;
}
if (left + draggedImage.ActualWidth > SpecialPhoto.ActualWidth)
{
left = SpecialPhoto.ActualWidth - draggedImage.ActualWidth;
}
if (top + draggedImage.ActualHeight > SpecialPhoto.ActualHeight)
{
top = SpecialPhoto.ActualHeight - draggedImage.ActualHeight;
}
Canvas.SetLeft(draggedImage, left);
Canvas.SetTop(draggedImage, top);
}
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void bSave_Click(object sender, RoutedEventArgs e)
{
string fileLocation = System.IO.Path.GetDirectoryName(FileNmae);// get the selected file location
string getFileName = System.IO.Path.GetFileName(FileNmae); //get the seleceted filename
DateTime time = DateTime.Now; // Use current time
string format = "MMMddddHHmmssyyyy";
string s2 = time.ToString(format) + getFileName; // add $ at front along with the folde name
string filenamecombined = System.IO.Path.Combine(fileLocation, s2);//combine path.
RenderTargetBitmap renderTarget = new RenderTargetBitmap(
(int)SpecialPhoto.Height,
(int)SpecialPhoto.Width,
96, 96, PixelFormats.Pbgra32);
//renderTarget.Render(ViewedPhoto);
ModifyPosition(canvas as FrameworkElement);
renderTarget.Render(canvas);
ModifyPositionBack(canvas as FrameworkElement);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
//string imagePath = System.IO.Path.GetTempFileName();
using (FileStream stream = new FileStream(filenamecombined, FileMode.Create))
{
encoder.Save(stream);
stream.Dispose();
}
}
private void ModifyPosition(FrameworkElement fe)
{
/// get the size of the visual with margin
System.Windows.Size fs = new System.Windows.Size(
fe.ActualWidth +
fe.Margin.Left + fe.Margin.Right,
fe.ActualHeight +
fe.Margin.Top + fe.Margin.Bottom);
/// measure the visual with new size
fe.Measure(fs);
/// arrange the visual to align parent with (0,0)
fe.Arrange(new Rect(
-fe.Margin.Left, -fe.Margin.Top,
fs.Width, fs.Height));
}
private void ModifyPositionBack(FrameworkElement fe)
{
/// remeasure a size smaller than need, wpf will
/// rearrange it to the original position
fe.Measure(new System.Windows.Size());
}
private void Button_Click(object sender, RoutedEventArgs e) // To load another image
{
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.Filter =
"Image Files (*.jpg;*.png; *.jpeg; *.gif; *.bmp)|*.jpg;*.png; *.jpeg; *.gif; *.bmp";
if ((bool)dialog.ShowDialog())
{
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(dialog.FileName, UriKind.Relative);
src.DecodePixelHeight = 120;
src.DecodePixelWidth = 120;
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
var image = new Image { Source = src };
Canvas.SetLeft(image, 0);
Canvas.SetTop(image, 0);
canvas.Children.Add(image);
}
}
}
Problem 1 - In your xaml for the Image, add IsEnabled="False". This will stop the clicking from hiding the child image.
<Image x:Name="SpecialPhoto" Source="IMG_0071.JPG" Height="586" Width="780"
IsEnabled="False"
Stretch="Uniform" VerticalAlignment="Top" HorizontalAlignment="Center" />
Problem 2 - I didn't experience this, maybe you have some sort of mouse acceleration turned on in windows?
Problem 3 - You are using the height for the width and the width for the height. Change:
RenderTargetBitmap renderTarget = new RenderTargetBitmap(
(int)SpecialPhoto.Height,
(int)SpecialPhoto.Width,
96, 96, PixelFormats.Pbgra32);
To:
RenderTargetBitmap renderTarget = new RenderTargetBitmap(
(int)SpecialPhoto.Width,
(int)SpecialPhoto.Height,
96, 96, PixelFormats.Pbgra32);
The code for the comment question you asked:
private void bSave_Click(object sender, RoutedEventArgs e)
{
string fileLocation = System.IO.Path.GetDirectoryName(FileNmae);// get the selected file location
string getFileName = System.IO.Path.GetFileName(FileNmae); //get the seleceted filename
DateTime time = DateTime.Now; // Use current time
string format = "MMMddddHHmmssyyyy";
string s2 = time.ToString(format) + getFileName; // add $ at front along with the folde name
string filenamecombined = System.IO.Path.Combine(fileLocation, s2);//combine path.
#region Change the SpecialPhoto to be the size of its image and adjust the other images to match
double w = SpecialPhoto.Width;
double h = SpecialPhoto.Height;
SpecialPhoto.Width = SpecialPhoto.Source.Width;
SpecialPhoto.Height = SpecialPhoto.Source.Height;
// Get the ratio of the change in width/height
double rw = SpecialPhoto.Width / w;
double rh = SpecialPhoto.Height / h;
// Adjust the logos added to keep in the same relative position and size
foreach (Image img in canvas.Children)
{
if (img == SpecialPhoto)
continue;
double left = Canvas.GetLeft(img);
double top = Canvas.GetTop(img);
Canvas.SetLeft(img, left * rw);
Canvas.SetTop(img, top * rh);
img.RenderTransform = new ScaleTransform(rw, rh);
}
#endregion
RenderTargetBitmap renderTarget = new RenderTargetBitmap(
(int)SpecialPhoto.Width,
(int)SpecialPhoto.Height,
96, 96, PixelFormats.Pbgra32);
//renderTarget.Render(ViewedPhoto);
ModifyPosition(canvas as FrameworkElement);
renderTarget.Render(canvas);
ModifyPositionBack(canvas as FrameworkElement);
#region Undo the changes we did to the SpecialPhoto/logos
SpecialPhoto.Width = w;
SpecialPhoto.Height = h;
foreach (Image img in canvas.Children)
{
if (img == SpecialPhoto)
continue;
double left = Canvas.GetLeft(img);
double top = Canvas.GetTop(img);
Canvas.SetLeft(img, left / rw);
Canvas.SetTop(img, top / rh);
img.RenderTransform = new ScaleTransform(1, 1);
}
#endregion
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
//string imagePath = System.IO.Path.GetTempFileName();
using (FileStream stream = new FileStream(filenamecombined, FileMode.Create))
{
encoder.Save(stream);
stream.Dispose();
}
}
Code for the 2nd comment question (keeping child image in the parent image):
We need to change two methods. The first method is the CanvasMouseMove:
private void CanvasMouseMove(object sender, MouseEventArgs e)
{
if (draggedImage != null)
{
var position = e.GetPosition(canvas);
var offset = position - mousePosition;
mousePosition = position;
double left = Canvas.GetLeft(draggedImage) + offset.X;
double top = Canvas.GetTop(draggedImage) + offset.Y;
Point tl = SpecialPhoto.TranslatePoint(new Point(0, 0), canvas);
Point br = SpecialPhoto.TranslatePoint(new Point(SpecialPhoto.ActualWidth, SpecialPhoto.ActualHeight), canvas);
if (left < tl.X)
{
left = tl.X;
}
if (top < tl.Y)
{
top = tl.Y;
}
if (left + draggedImage.ActualWidth > br.X)
{
left = br.X - draggedImage.ActualWidth;
}
if (top + draggedImage.ActualHeight > br.Y)
{
top = br.Y - draggedImage.ActualHeight;
}
Canvas.SetLeft(draggedImage, left);
Canvas.SetTop(draggedImage, top);
}
}
The 2nd method is the Button_Click:
private void Button_Click(object sender, RoutedEventArgs e) // To load another image
{
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.Filter =
"Image Files (*.jpg;*.png; *.jpeg; *.gif; *.bmp)|*.jpg;*.png; *.jpeg; *.gif; *.bmp";
if ((bool)dialog.ShowDialog())
{
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(dialog.FileName, UriKind.Relative);
src.DecodePixelHeight = 120;
src.DecodePixelWidth = 120;
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
var image = new Image { Source = src };
Point p = SpecialPhoto.TranslatePoint(new Point(0, 0), canvas);
Canvas.SetLeft(image, p.X);
Canvas.SetTop(image, p.Y);
canvas.Children.Add(image);
}
}

Categories