【WPF学习手记】UI保存成图片不全问题解决方案

    前面我们遇到了一个问题,就是将UI保存成图片时,图片不完整,需要将UI的HorizontalAlignment设置为left,VerticalAlignment设置为Top,原因可能是UI保存成图片时是从左上角开始计算宽和高。

    今天突然想到一个思路,如果我把包含目标图像在内的一张大图保存下来,然后从大图中提取目标图像,是不是可行,于是按照这个思路进行了尝试,发现问题就这么被解决了。

  • xaml代码
<Window x:Class="Image_Zoom_Save.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Image_Zoom_Save"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <ScrollViewer Name="svProcess" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Image Name="imgProcess" Stretch="Uniform" RenderOptions.BitmapScalingMode="HighQuality"/>
        </ScrollViewer>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Content="Load" Margin="5" Click="Load_Click"/>
            <Button Content="Save" Margin="5" Click="Save_Click"/>
            <Slider Name="sliderZoom" Minimum="0.2" Maximum="5" Value="1" VerticalAlignment="Center" Width="200"
                    ValueChanged="SliderZoom_ValueChanged"/>
            <Label Name="lblInfo"/>
            <Button Content="Change Position" Margin="5" Click="Position_Click"/>
        </StackPanel>
    </Grid>
</Window>
  • 后台代码
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;


namespace Image_Zoom_Save
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private BitmapImage bitmapImage;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void SliderZoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (bitmapImage == null)
            {
                return;
            }
            imgProcess.Width = sliderZoom.Value * bitmapImage.Width;
            imgProcess.Height = sliderZoom.Value * bitmapImage.Height;
            lblInfo.Content = "width = " + ((int)imgProcess.Width).ToString() + "; height = " + ((int)imgProcess.Height).ToString();
        }

        private void Load_Click(object sender, RoutedEventArgs e)
        {
            bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.UriSource = new Uri("D:/MyPrograms/图标/qq.png", UriKind.RelativeOrAbsolute);
            bitmapImage.EndInit();
            imgProcess.Source = bitmapImage;
            imgProcess.Width = bitmapImage.Width;
            imgProcess.Height = bitmapImage.Height;
            imgProcess.VerticalAlignment = VerticalAlignment.Center;
            imgProcess.HorizontalAlignment = HorizontalAlignment.Center;
            lblInfo.Content = "width = " + ((int)imgProcess.Width).ToString() + "; height = " + ((int)imgProcess.Height).ToString();
        }

        private void UISaveToImage(FrameworkElement ui, string fileName, int width, int height)
        {
            RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Pbgra32);
            bmp.Render(ui);
            BitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bmp));
            FileStream fs = new FileStream(fileName, FileMode.Create);
            encoder.Save(fs);
            fs.Close();
        }

        private Bitmap ImageSourceToBitmap(ImageSource imageSource)
        {
            BitmapSource bitmapSource = (BitmapSource)imageSource;
            Bitmap bmp = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            BitmapData data = bmp.LockBits(
                new Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
            bmp.UnlockBits(data);
            return bmp;
        }

        private void Save_Click(object sender, RoutedEventArgs e)
        {
            //UISaveToImage(imgProcess, "test.png", (int)imgProcess.Width, (int)imgProcess.Height);
            string tempPath = Path.GetTempPath() + Guid.NewGuid().ToString() + ".png";
            int offsetX = Math.Max((int)(0.5 * (svProcess.ActualWidth - imgProcess.ActualWidth)), 0);
            int offsetY = Math.Max((int)(0.5 * (svProcess.ActualHeight - imgProcess.ActualHeight)), 0);
            int bigX = Math.Max((int)svProcess.ActualWidth, (int)imgProcess.ActualWidth);
            int bigY = Math.Max((int)svProcess.ActualHeight, (int)imgProcess.ActualHeight);
            UISaveToImage(imgProcess, tempPath, bigX, bigY);
            BitmapSource bmpSource = new CroppedBitmap(BitmapFrame.Create(new Uri(tempPath, UriKind.Relative)), new Int32Rect(offsetX, offsetY, (int)imgProcess.ActualWidth, (int)imgProcess.ActualHeight));
            ImageSourceToBitmap(bmpSource).Save("test.png");
        }

        private void Position_Click(object sender, RoutedEventArgs e)
        {
            imgProcess.VerticalAlignment = VerticalAlignment.Top;
            imgProcess.HorizontalAlignment = HorizontalAlignment.Left;
        }
    }
}

    补充说明:这里新增了一个函数,将ImageSource转化成Bitmap;由于Image在ScrollViewer中默认是居中显示的,因此两者宽和高的一半即为目标图像的起点位置,主要是利用了CroppedBitmap函数来进行图像拷贝;至于为什么要保存到临时文件夹的唯一文件名,是考虑到重复保存可能会出现文件占用而无法保存的错误,并且也不想别人看到这个文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值