【问题标题】:Saving canvas data to image file output is wrong将画布数据保存到图像文件输出是错误的
【发布时间】:2014-07-02 15:58:24
【问题描述】:

我想将图像放在父图像上并保存最终图像。所以我在 Canvas 中使用了父图像,并在画布中添加了子图像。

问题:

  1. 在我加载缩略图(子)图像后,如果我单击父图像,则缩略图(子)图像变为不可见。
  2. 我无法使用 mouse left button up 版本将缩略图(子)图像精确地放置在父图像上。
  3. 我无法使用实际图像高度和宽度保存最终图像。最终保存的图片输出高宽有误。

请指导我解决上述问题。

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 代码:

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);
            }
        }
}

【问题讨论】:

    标签: c# wpf image canvas rendertargetbitmap


    【解决方案1】:

    问题 1 - 在图像的 xaml 中,添加 IsEnabled="False"。这将停止单击隐藏子图像。

    <Image x:Name="SpecialPhoto" Source="IMG_0071.JPG" Height="586" Width="780"
            IsEnabled="False"
        Stretch="Uniform" VerticalAlignment="Top" HorizontalAlignment="Center" />
    

    问题 2 - 我没有遇到这种情况,也许你在 Windows 中打开了某种鼠标加速功能?

    问题 3 - 您使用高度作为宽度,使用宽度作为高度。变化:

    RenderTargetBitmap renderTarget = new RenderTargetBitmap(
                 (int)SpecialPhoto.Height,
                 (int)SpecialPhoto.Width,
                 96, 96, PixelFormats.Pbgra32);
    

    收件人:

    RenderTargetBitmap renderTarget = new RenderTargetBitmap(
                 (int)SpecialPhoto.Width,
                 (int)SpecialPhoto.Height,
                 96, 96, PixelFormats.Pbgra32);
    

    您提出的评论问题的代码:

    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();
        }
    }
    

    第二个评论问题的代码(将子图像保留在父图像中):

    我们需要改变两种方法。第一种方法是 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);
        }
    }
    

    第二种方法是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);
        }
    }
    

    【讨论】:

    • 感谢第一个问题的解决方案。宽度和高度非常好。如何保存具有实际图像宽度和高度的图像?
    • 您需要将 SpecialPhoto 的宽度/高度设置为其图像的宽度/高度。此外,您需要调整从“添加徽标”按钮添加的图像。您需要根据 SpecialPhoto 的大小更改更改画布左侧/顶部和图像的大小,以使图像保持在相同位置且具有相同的相对大小。没有什么比代码更清晰的了,所以我会在一分钟内修改我的答案。
    • 你的代码更有意义..它比我的代码更好。最后一个问题/需要建议,我怎样才能使子图像在父图像中移动? (对于 ex:vertical 图像的某些图像,子图像放置在父图像之外)。
    • 我不确定你在问什么。你能改写一下这个问题吗?
    • 哦,我明白你的意思了。给我几分钟(实际上是几分钟),我会为你解决的。
    猜你喜欢
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 2012-07-08
    • 2021-03-24
    • 2012-09-08
    相关资源
    最近更新 更多