I display the images on canvas and I want to be able to move all the images. Currently I am only able to move the last image which I brought on canvas. I also want to be able to zoom these images. Please help me in this.
private TranslateTransform dragTranslation;
// Constructor
void Drag_ManipulationDelta(object sender,ManipulationDeltaRoutedEventArgs e)
{
// Move the rectangle.
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
}
private void Stickers1_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
var selecteditem = e.AddedItems[0] as StickersImageListModel;
Stickers1.Visibility = Visibility.Collapsed;
Image imageitem = new Image();
BitmapImage image = new BitmapImage(new System.Uri(selecteditem.Imageurl, UriKind.Absolute));
imageitem.Source = image;
my_canvas.Children.Add(imageitem);
imageitem.AllowDrop = true;
imageitem.ManipulationMode = ManipulationModes.All;
imageitem.ManipulationDelta += Drag_ManipulationDelta;
dragTranslation = new TranslateTransform();
imageitem.RenderTransform = this.dragTranslation;
var st = (ScaleTransform)imageitem.RenderTransform;
double zoom = e.Delta > 0 ? .2 : -.2;
st.ScaleX += zoom;
st.ScaleY += zoom;
my_canvas.Visibility = Visibility.Visible;
}
You dont have to use dragTranslation property
void Drag_ManipulationDelta(object sender,ManipulationDeltaRoutedEventArgs e)
{
// Move the rectangle.
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < 1.0) ct.ScaleX = 1.0;
if (ct.ScaleY < 1.0) ct.ScaleY = 1.0;
if (ct.ScaleX > 4.0) ct.ScaleX = 4.0;
if (ct.ScaleY > 4.0) ct.ScaleY = 4.0;
//Checking with canvas boundary so that image wont go behind canvas
if ((ct.TranslateX + e.Delta.Translation.X) <= (mycanvas.ActualWidth - img.ActualWidth) && ct.TranslateX + e.Delta.Translation.X>=0)
ct.TranslateX += e.Delta.Translation.X;
if ((ct.TranslateY + e.Delta.Translation.Y) <= (mycanvas.ActualHeight - img.ActualHeight) && ct.TranslateY + e.Delta.Translation.Y >= 0)
ct.TranslateY += e.Delta.Translation.Y;
}
private void Stickers1_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
...
//Using CompositeTransform instead of TranslateTransform
CompositeTransform ct = new CompositeTransform();
imageitem.RenderTransform = ct;
}
Related
I made a program that lets you do a random selection then the selected area to save into a new image, but I got a problem it doesn't work how it's supposed to... I will post my code here so you can have a look:
private List<Point> Points = null;
private bool Selecting = false;
private Bitmap SelectedArea = null;
private void pictureBox5_MouseDown(object sender, MouseEventArgs e)
{
Points = new List<Point>();
Selecting = true;
}
private void pictureBox5_MouseMove(object sender, MouseEventArgs e)
{
if (!Selecting) return;
Points.Add(new Point(e.X, e.Y));
pictureBox5.Invalidate();
}
private void pictureBox5_MouseUp(object sender, MouseEventArgs e)
{
Selecting = false;
// Copy the selected area.
SelectedArea = GetSelectedArea(pictureBox5.Image, Color.Transparent, Points);
SelectedArea.Save(#"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg", ImageFormat.Jpeg);
string filename = #"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg";
if(File.Exists(filename))
{
button1.Visible = true;
pictureBox5.Visible = false;
}
}
private void pictureBox5_Paint(object sender, PaintEventArgs e)
{
if ((Points != null) && (Points.Count > 1))
{
using (Pen dashed_pen = new Pen(Color.Black))
{
dashed_pen.DashPattern = new float[] { 5, 5 };
e.Graphics.DrawLines(Pens.White, Points.ToArray());
e.Graphics.DrawLines(dashed_pen, Points.ToArray());
}
}
}
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
// Make a new bitmap that has the background
// color except in the selected area.
Bitmap big_bm = new Bitmap(source);
using (Graphics gr = Graphics.FromImage(big_bm))
{
// Set the background color.
gr.Clear(bg_color);
// Make a brush out of the original image.
using (Brush br = new TextureBrush(source))
{
// Fill the selected area with the brush.
gr.FillPolygon(br, points.ToArray());
// Find the bounds of the selected area.
Rectangle source_rect = GetPointListBounds(points);
// Make a bitmap that only holds the selected area.
Bitmap result = new Bitmap(
source_rect.Width, source_rect.Height);
// Copy the selected area to the result bitmap.
using (Graphics result_gr = Graphics.FromImage(result))
{
Rectangle dest_rect = new Rectangle(0, 0,
source_rect.Width, source_rect.Height);
result_gr.DrawImage(big_bm, dest_rect,
source_rect, GraphicsUnit.Pixel);
}
// Return the result.
return result;
}
}
}
private Rectangle GetPointListBounds(List<Point> points)
{
int xmin = points[0].X;
int xmax = xmin;
int ymin = points[0].Y;
int ymax = ymin;
for (int i = 1; i < points.Count; i++)
{
if (xmin > points[i].X) xmin = points[i].X;
if (xmax < points[i].X) xmax = points[i].X;
if (ymin > points[i].Y) ymin = points[i].Y;
if (ymax < points[i].Y) ymax = points[i].Y;
}
return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
}
This is how I am doing and saving the cropped images.
And also this is how I am uploading the pictures:
OpenFileDialog f = new OpenFileDialog();
f.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";
if (f.ShowDialog() == DialogResult.OK)
{
currentImage = Image.FromFile(f.FileName);
pictureBox1.Image = currentImage;
}
pictureBox1.Image.Save(#"C:\Users\User\Desktop\Gallery\image1.jpeg", ImageFormat.Jpeg);
DialogResult result = MessageBox.Show("Crop your image", "Information", MessageBoxButtons.OK);
if(result == DialogResult.OK)
{
pictureBox5.Visible = true;
button1.Visible = false;
pictureBox5.Image = pictureBox1.Image;
}
In pictureBox5 I am selecting and cropping the picture.
mySelection
croppedImage
You need to calculate the zoom and the offset of the image when it is zoomed.
Here is how to do that; this assumes the PictureBox is indeed in Zoom mode, not in Stretch mode. If you stretch it you need to calculate the zooms for x and y separately..
SizeF sp = pictureBox5.ClientSize;
SizeF si = pictureBox5.Image.Size;
float rp = sp.Width / sp.Height; // calculate the ratios of
float ri = si.Width / si.Height; // pbox and image
float zoom = (rp > ri) ? sp.Height / si.Height : sp.Width / si.Width;
float offx = (rp > ri) ? (sp.Width - si.Width * zoom) / 2 : 0;
float offy = (rp <= ri)? (sp.Height - si.Height * zoom) / 2 : 0;
Point offset = Point.Round(new PointF(offx, offy));
You calculate this after setting the Image and after resizing the PictureBox..
Now you can transform each drawn point into a zoomed or an unzoomed coordinate:
PointF zoomed(Point p1, float zoom, Point offset)
{
return (new PointF(p1.X * zoom + offset.X, p1.Y * zoom + offset.Y));
}
PointF unZoomed(Point p1, float zoom, Point offset)
{
return (new PointF((p1.X - offset.X) / zoom, (p1.Y - offset.Y) / zoom));
}
Here is a demo the draws on to either a normal (left) or a zoomed in (middle) image. To the right is the result of placing your GetSelectedArea bitmap onto a PictureBox with a checkerbox background:
Case 1: If you store the points as they come in: In your GetSelectedArea method use this point list instead:
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
var unzoomedPoints =
points.Select(x => Point.Round((unZoomed(Point.Round(x), zoom, offset))))
.ToList();
// Make a new bitmap that has the background
After this replace each reference to points in the method by one to unzoomedPoints. Actually there are just two of them..
Case 2: If you store the points already 'unZoomed' :
Points.Add(unZoomed(e.Location, zoom, offset));
you can use the list directly..
Into Copystransform, if I removed 2 in the end of line then I will could zoom in and out but could not drag while that have zoom in.
what else I did not remove then can't zoom and can't drag. It just zoom when the picture is small else if the picture is full screen then did not that.
Link:http://blogs.msdn.com/b/wsdevsol/archive/2014/06/10/constraining-manipulations.aspx
double mincale = 0.5;
//double maxscale = 10.0;
CompositeTransform savedtransform = new CompositeTransform();
private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// FrameworkElement elemt = sender as FrameworkElement;
Image elemt = sender as Image;
CompositeTransform transform = elemt.RenderTransform as CompositeTransform;
//
copytransform(transform,savedtransform);
//apply
transform.ScaleX *= e.Delta.Scale;
transform.ScaleY *= e.Delta.Scale;
transform.TranslateX += e.Delta.Translation.X;
transform.TranslateY += e.Delta.Translation.Y;
if (transform.ScaleX < mincale) transform.ScaleX = mincale;
if (transform.ScaleY < mincale) transform.ScaleY = mincale;
// if (transform.ScaleX > maxscale) transform.ScaleX = maxscale;
// if (transform.ScaleY > maxscale) transform.ScaleY = maxscale;
if(elemt!=null)
{
if(!intersetElemnets(elemt,this.content,true))
{
copytransform(savedtransform, transform);
}
}
/*
double scalewidth = Zoomimages.ActualWidth * ct.ScaleX;
double scleheight = Zoomimages.ActualHeight * ct.ScaleY;
double xdiff = Math.Max(0, (scalewidth - this.content.ActualWidth) / 2);
double ydiff = Math.Max(0, (scleheight - this.content.ActualHeight) / 2);
if (Math.Abs(ct.TranslateX) > xdiff)
ct.TranslateX = xdiff * Math.Sign(e.Delta.Translation.X);
if (Math.Abs(ct.TranslateY) > ydiff)
ct.TranslateY = ydiff * Math.Sign(e.Delta.Translation.Y);
* */
}
private bool intersetElemnets(FrameworkElement inner, FrameworkElement outer,bool contains)
{
GeneralTransform testTransform = inner.TransformToVisual(outer);
//
Rect boundsinner = new Rect(0,0,inner.ActualWidth,inner.ActualHeight);
Rect bboxouter = new Rect(0, 0, outer.ActualWidth, outer.ActualHeight);
Rect bboxinner = testTransform.TransformBounds(boundsinner);
if(contains)
{
return bboxinner.X > bboxouter.Y &&
bboxinner.Y > bboxouter.Y &&
bboxinner.Right < bboxouter.Right &&
bboxinner.Bottom < bboxouter.Bottom;
}
else
{
bboxouter.Intersect(bboxinner);
return !bboxouter.IsEmpty;
}
}
private void copytransform(CompositeTransform orig,CompositeTransform copy)
{
copy.TranslateX = orig.TranslateX;
copy.TranslateY = orig.TranslateY;
copy.ScaleX = orig.ScaleX;
copy.ScaleY = orig.ScaleY;
}
I'm going to finish a application but I have a problem about scroll selection. I has zoom in and out that's ok.I has asked so many question but no one are not reply.Help me about scroll... This picture is zooming in:
<ListView Name="lst_intro">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding link}"
Stretch="Uniform"
RenderTransformOrigin="0.5,0.5"
ManipulationDelta="img_intro_ManipulationDelta"
ManipulationMode="Scale">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void img_intro_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < mincale) ct.ScaleX = mincale;
if (ct.ScaleY < mincale) ct.ScaleY = mincale;
ScaleTransform scale=new ScaleTransform();
}
You set ManipulationMode="Scale", meaning you cannot drag it left/right/down/up - that is call a translation, set it as ManipulationMode="Scale,TranslateX,TranslateY".
In the event handler, similar to what you did for the Scale transform, you do a Translate transform.
private void img_intro_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (ct == null) return;
//Scale transform
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < mincale) ct.ScaleX = mincale;
if (ct.ScaleY < mincale) ct.ScaleY = mincale;
//Translate transform
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
//Confine boundary
BringIntoBounds();
}
After the transformation, brings the image back if it is out of the boundary. You can detect if the image is out of boundary by comparing the values of TranslateX/TranslateY and the width/height of the boundary. The boundary is the parent of the image (it is a Grid?), you need to debug the code to determine the boundary for TranslateX and TranslateY.
public void BringIntoBounds()
{
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (ct == null) return;
//out of screen, left edge
if (ct.TranslateX < 10 - img.ActualWidth * ct.ScaleX)
{
ct.TranslateX = 10 - img.ActualWidth * ct.ScaleX;
}
//out of screen, right edge
if (ct.TranslateX > Container.ActualWidth - 10 )
{
ct.TranslateX = Container.ActualWidth - 10;
}
...do the same for Y.
}
kennyzx gave a very good answer but the part where you test if the image is out of boundaries isn't working for me... that's my solution:
private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
ct.ScaleX = Math.Min(4, Math.Max(1, ct.ScaleX));
ct.ScaleY = Math.Min(4, Math.Max(1, ct.ScaleY));
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
var translateY = (img.ActualHeight * ct.ScaleY - img.ActualHeight) / 2;
ct.TranslateY = Math.Min(translateY, Math.Max(0 - translateY, ct.TranslateY));
var translateX = (img.ActualWidth * ct.ScaleX - img.ActualWidth) / 2;
ct.TranslateX = Math.Min(translateX, Math.Max(0 - translateX, ct.TranslateX));
}
I have pinch & zoom effect on an image. Is there a way I can reflect the changes in height and width of that image? I want to store the changes user has made to the size of image for later use.
or is there any other way I can make my image resizable for user that can allow me to save its width and height?
EDIT: The code I have is:
private void ResourceImage_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Point flipViewScreenCoords = models_list.TransformToVisual(Window.Current.Content).TransformPoint(new Point(0, 0));
Image currentImage = sender as Image;
Point currentImageCoords = currentImage.TransformToVisual(Window.Current.Content).TransformPoint(new Point(0, 0));
CompositeTransform transform = currentImage.RenderTransform as CompositeTransform;
if ((currentImageCoords.X + currentImage.Width < flipViewScreenCoords.X + models_list.ActualWidth) && e.Delta.Translation.X > 0)
{
transform.TranslateX += e.Delta.Translation.X;
}
if (currentImageCoords.X > flipViewScreenCoords.X && e.Delta.Translation.X < 0)
{
transform.TranslateX += e.Delta.Translation.X;
}
if (currentImageCoords.Y + currentImage.Height < flipViewScreenCoords.Y + models_list.ActualHeight && e.Delta.Translation.Y > 0)
{
transform.TranslateY += e.Delta.Translation.Y;
}
if (currentImageCoords.Y > flipViewScreenCoords.Y && e.Delta.Translation.Y < 0)
{
transform.TranslateY += e.Delta.Translation.Y;
}
transform.ScaleX *= e.Delta.Scale;
transform.ScaleY *= e.Delta.Scale;
}
I have my image inside a flipview and the image is movable but should not leave the dimensions of flipview therefore I am using the if/else statements in this code. Now I am looking for a way to save the changed width/height of the image. Something like currentImage.Width = ??
I've got the drag'n'drop image, which is located in ContentPanel. In MouseLeave event i get the position of image and then i need to align it to my grid. Tried to do it with Canvas, but nothing happens. When I try to do it changing the margin, the position is totally wrong.
Code:
private void MouseLeave(object sender, MouseEventArgs e)
{
Image rs = (Image)sender;
GeneralTransform gt = rs.TransformToVisual(ContentPanel);
Point offset = gt.Transform(new Point(0, 0));
double controlTop = offset.Y;
double controlLeft = offset.X;
tb.Text = Convert.ToInt16(controlLeft / 40).ToString();
tb2.Text = Convert.ToInt16(controlTop / 40).ToString();
double newLeft = Convert.ToInt16(controlLeft / 40)*40;
double newTop = Convert.ToInt16(controlTop / 40)*40;
//rs.Margin = new Thickness(newLeft, newTop, 0, 0);
//((Image)ContentPanel.Children[11]).SetValue(Canvas.LeftProperty, newLeft);
//((Image)ContentPanel.Children[11]).SetValue(Canvas.TopProperty, newTop);
}
So how can I set the position of image?
One way could be to apply a translate transformation to your image?
Something like that should work:
Image rs = (Image)sender;
GeneralTransform gt = rs.TransformToVisual(ContentPanel);
Point offset = gt.Transform(new Point(0, 0));
//create a translate transform
TranslateTransform tt = new TranslateTransform();
//apply the required offset
tt.X = offset.X;
tt.Y = offset.Y;
//apply the transform to the image
rs.RenderTransform = tt;
double controlTop = offset.Y;
double controlLeft = offset.X;
tb.Text = Convert.ToInt16(controlLeft / 40).ToString();
tb2.Text = Convert.ToInt16(controlTop / 40).ToString();
double newLeft = Convert.ToInt16(controlLeft / 40) * 40;
double newTop = Convert.ToInt16(controlTop / 40) * 40;