1

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:

  1. Right after when i loaded the thumbnail(child) image, if i click on the parent image, then the thumbnail(child) image become in-Visible.
  2. I couldn't place the the thumbnail(child) image over the parent image precisely using the mouse left button up release.
  3. 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);
            }
        }
}
linguini
  • 1,939
  • 5
  • 49
  • 79

1 Answers1

3

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);
    }
}
J.H.
  • 4,232
  • 1
  • 18
  • 16
  • Thank you for the solution for the first problem. Very good catch for the Width & Height. How can i save the image with the actual image Width & Height? – linguini May 14 '14 at 15:10
  • You'd need to set the SpecialPhoto width/height to its image's width/height. Also, you'd need to adjust the image added from the Add Logo button. You'd need to change the canvas left/top and the image's size based on the size change to the SpecialPhoto to keep the image in the same postion with the same relative size. Nothing is clearer than code so I'll edit my answer in a minute with the changes. – J.H. May 14 '14 at 16:15
  • It makes more sense from your code..it's better than my code. One last question/need suggestion, how can i make the child image movement within the parent image? (for certain images for ex:vertical images, the child placed outside of the parent image). – linguini May 14 '14 at 16:41
  • I'm not sure what you are asking. Can you rephrase the question? – J.H. May 14 '14 at 16:44
  • When i place the child image over the parent image, I want to make the image drag should happen over the parent image not in the canvas. – linguini May 14 '14 at 16:47
  • 1
    Oh, I see what you mean. Give me a few (actually, several) minutes and I'll figure it out for you. – J.H. May 14 '14 at 16:55