Amplificador de detalles de captura de pantalla en tiempo real de cortador gratuito de avatar de imagen WPF

Este artículo hace referencia a la publicación del blog: Cortador de imágenes personalizado de WPF: corte de avatar (extensión y mejora, captura de pantalla en tiempo real)

Busqué en Internet durante mucho tiempo pero no pude encontrar un marco de captura de pantalla adecuado, por lo que solo puedo usar el cortador de imagen personalizado WPF : corte de avatar (captura de pantalla en tiempo real ampliada y perfeccionada)

Mostrar resultados

La imagen de la pantalla está muy atascada, pero en realidad es muy fluida.

Semejanzas y diferencias con el autor original

1. Cambie el marco cuadrado a un marco variable, que se puede estirar (el tamaño del marco no se verifica aquí, y el ancho y la altura del marco se pueden estirar a 0 o negativo. Sé que hay un error, pero soy demasiado perezoso para cambiarlo)

2. La verificación se realiza al arrastrar y el marco no se arrastrará fuera de la imagen.

3. Optimizado algunos algoritmos para hacer los cálculos más eficientes.

4. Algunas otras optimizaciones (como configurar el tamaño del marco al cargar, calcular la imagen de vista previa, etc.)

Análisis de lógica de código

El diseño del código usa Grid como contenedor, muestra la imagen en el contenedor y llena toda la cuadrícula de forma adaptativa. El cuadro de selección es en realidad un borde, y la parte seleccionada para ser interceptada es en realidad para acercar y alejar y traducir el borde. Hay tantos archivos de diseño. El siguiente es el código del archivo de diseño

<UserControl x:Class="AUTOTest.Widgets.Common.ImageDealer.ImageDealerUnsafe"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="280" Background="Transparent"
             SnapsToDevicePixels="True" 
             PreviewMouseDown="UserControl_MouseDown" 
             PreviewMouseUp="UserControl_MouseUp" 
             MouseLeave="UserControl_MouseLeave" 
             PreviewMouseMove="UserControl_MouseMove"
             Loaded="onViewLoad">
    <Grid Name="MainGrid" Height="300" Width="280" Background="#DCDCDC">
        <Image Name="SoureceImage" Stretch="Uniform"></Image>
        <Border Name="ImageArea"  BorderBrush="#046BE1" BorderThickness="1,1,1,1" Panel.ZIndex="5" Margin="100" SizeChanged="ImageArea_SizeChanged">
            <Grid >
                <Rectangle Name="R_LeftUp"    Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
                <Rectangle Name="R_Up"        Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
                <Rectangle Name="R_RightUp"   Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
                <Rectangle Name="R_Right"     Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
                <Rectangle Name="R_RightDown" Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
                <Rectangle Name="R_Down"      Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
                <Rectangle Name="R_LeftDown"  Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
                <Rectangle Name="R_Left"      Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
            </Grid>
        </Border>

    </Grid>
</UserControl>

Después de escribir el diseño, veamos cómo controlar el archivo de diseño. Primero, considere el tamaño de la marquesina de zoom. Cuando el mouse arrastra un punto de selección, la X, Y o Ancho, Altura del borde se recalculará de acuerdo con el punto de selección.

/// <summary> 计算区域圆点及宽高 </summary>
/// <param name="MouseButtonLocate">鼠标相对背景MainGrid位置</param>
/// <param name="IsRectangle">是否正方形</param>
/// <returns>NULL 或 具体值</returns>
private RectangleAreaModel CalculatedArea(Point MouseButtonLocate, bool IsRectangle, Point Locate)
{
	//边框宽度
	double BorderWidth = this.BorderWidth;
	//整体宽度
	double RectWidth = ImageArea.ActualWidth;
	//整体高度
	double RectHeight = ImageArea.ActualHeight;

	//裁剪区域
	Point OriginalPoint = new Point(0, 0);//圆点坐标
	Point TheoryPoint = new Point(0, 0);  //理论坐标
	double TheoryWidth = 0;   //理论宽度
	double TheoryHeight = 0;  //理论高度
	switch (MouseLocation)
	{
		case MouseLocationEnum.Left:
			{
				Cursor = Cursors.SizeWE;
				TheoryWidth = RectWidth + (Locate.X - MouseButtonLocate.X);
				TheoryHeight = RectHeight;
				TheoryPoint = new Point(MouseButtonLocate.X, Locate.Y);
			}
			break;
		case MouseLocationEnum.LeftUp:
			{
				Cursor = Cursors.SizeNWSE;
				TheoryWidth = RectWidth + (Locate.X - MouseButtonLocate.X);
				TheoryHeight = RectHeight + (Locate.Y - MouseButtonLocate.Y);
				TheoryPoint = new Point(MouseButtonLocate.X, MouseButtonLocate.Y);
			}
			break;
		case MouseLocationEnum.Up:
			{
				Cursor = Cursors.SizeNS;
				TheoryWidth = RectWidth;
				TheoryHeight = RectHeight + (Locate.Y - MouseButtonLocate.Y);
				TheoryPoint = new Point(Locate.X, MouseButtonLocate.Y);
			}
			break;
		case MouseLocationEnum.RightUp:
			{
				Cursor = Cursors.SizeNESW;
				TheoryWidth = MouseButtonLocate.X - Locate.X;
				TheoryHeight = RectHeight + (Locate.Y - MouseButtonLocate.Y);
				TheoryPoint = new Point(Locate.X, MouseButtonLocate.Y);
			}
			break;
		case MouseLocationEnum.Right:
			{
				Cursor = Cursors.SizeWE;
				TheoryWidth = MouseButtonLocate.X - Locate.X;
				TheoryHeight = RectHeight;
				TheoryPoint = new Point(Locate.X, Locate.Y);
			}
			break;
		case MouseLocationEnum.RightDown:
			{
				Cursor = Cursors.SizeNWSE;
				TheoryHeight = MouseButtonLocate.Y - Locate.Y;
				TheoryWidth = MouseButtonLocate.X - Locate.X;
				TheoryPoint = new Point(Locate.X, Locate.Y);
			}
			break;
		case MouseLocationEnum.Down:
			{
				Cursor = Cursors.SizeNS;
				TheoryHeight = MouseButtonLocate.Y - Locate.Y;
				TheoryWidth = RectWidth;
				TheoryPoint = new Point(Locate.X, Locate.Y);
			}
			break;
		case MouseLocationEnum.LeftDown:
			{
				Cursor = Cursors.SizeNESW;
				TheoryWidth = RectWidth + (Locate.X - MouseButtonLocate.X);
				TheoryHeight = MouseButtonLocate.Y - Locate.Y;
				TheoryPoint = new Point(MouseButtonLocate.X, Locate.Y);
			}
			break;
		default:
			return null;
	}
	return new RectangleAreaModel()
	{
		X = TheoryPoint.X,
		Y = TheoryPoint.Y,
		Width = TheoryWidth,
		Height = TheoryHeight
	};
}

A continuación, consideramos la lógica de la panorámica general. La panorámica solo cambia X e Y, y el ancho y la altura de la marquesina permanecen sin cambios, por lo que la lógica es relativamente simple. Cuánto se desplazan X, Y del mouse y cuánto se desplaza nuestro borde. Por supuesto, no podemos ignorar el cálculo del límite. Después de exceder el límite, aún no podemos arrastrar. El siguiente es el código al arrastrar

else if (Action == MouseActionEx.DragMove)//拖动
{
	double Left = MouseDownLocate.X + (MousePoint.X - MouseDownPoint.X);
	double Top = MouseDownLocate.Y + (MousePoint.Y - MouseDownPoint.Y);
	//不能超出边界区域 超出后纠正
	// 左边距
	double leftMargin = MaxMargin + (MainGrid.ActualWidth - SoureceImage.ActualWidth) / 2;
	// 上边距
	double topMargin = MaxMargin + (MainGrid.ActualHeight - SoureceImage.ActualHeight) / 2;
	// 右边距
	double rightMargin = SourceImagePoint.X + SoureceImage.ActualWidth;
	// 下边距
	double bottomMargin = SourceImagePoint.Y + SoureceImage.ActualHeight;
	// 选择框加边框宽
	double selectAreaWidth = ImageArea.ActualWidth + MaxMargin;
	// 选择框加边框高
	double selectAreaHeight = ImageArea.ActualHeight + MaxMargin;
	if (Left < leftMargin)
		Left = leftMargin;                
	if (Top < topMargin)                
		Top = topMargin;                
	if (Left + selectAreaWidth > rightMargin)                
		Left = rightMargin - selectAreaWidth;               
	if (Top + selectAreaHeight > bottomMargin)                
		Top = bottomMargin - selectAreaHeight;
	ImageArea.Width = ImageArea.ActualWidth;
	ImageArea.Height = ImageArea.ActualHeight;

	ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
	ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top);
	ImageArea.SetValue(MarginProperty, new Thickness(Left, Top, 0, 0));

	CutImage();
}

El problema principal está resuelto, nuestra función está básicamente completada, y el resto es tomar capturas de pantalla en proporción. El autor anterior aplicó una capa de interfaz de usuario, así que no cambié mucho, y también apliqué una capa. Solo necesitamos llamar a esa capa. Echemos un vistazo a la capa de interfaz de interfaz de usuario que se aplica.

<UserControl x:Class="AUTOTest.Widgets.Common.ImageDealer.ImageDealer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="280" Background="Transparent"
             SnapsToDevicePixels="True"
             Loaded="UserControl_Loaded">
    <Grid Name="MainGrid" MinHeight="300" MinWidth="280" />

</UserControl>

Modifiqué la lógica de la interfaz de usuario. El anterior era demasiado complicado. No puedo usarlo ni entenderlo. Ahora hay una interfaz para capturas de pantalla y una interfaz para configurar imágenes, lo que significa que las imágenes se pueden reemplazar. El código general es muy simple. Puede saber lo que hace mirando el nombre del método. Si desea expandirlo, puede expandirlo en esta clase

    public partial class ImageDealer : UserControl
    {
        public static readonly RoutedEvent OnCutImagingEventHandler = EventManager.RegisterRoutedEvent("OnCutImaging", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ImageDealer));

        #region 私有字段
        /// <summary> 截图控件 </summary>
        private ImageDealerUnsafe _ImageDealerControl = new ImageDealerUnsafe();
        /// <summary> 图片源 </summary>
        private BitmapImage _BitSource;
        #endregion

        #region 公共字段

        /// <summary> 图片源 </summary>
        public BitmapImage BitSource
        {
            get { return _BitSource; }
            set
            {
                _BitSource = value;
                _ImageDealerControl.BitSource = value;
            }
        }

        /// <summary> 截图事件 </summary>
        public event RoutedEventHandler OnCutImaging
        {
            add { AddHandler(OnCutImagingEventHandler, value); }
            remove { RemoveHandler(OnCutImagingEventHandler, value); }
        }

        #endregion

        #region ==方法==

        public ImageDealer()
        {
            InitializeComponent();
            _ImageDealerControl.OnCutImage += OnCutImage;
        }

        /// <summary> 手动设置范围 </summary>
        public void setImageAreaParemater(double x, double y, double width, double height)
        {
            _ImageDealerControl.setImageAreaParemater(x,y,width,height);
        }


        //外部截图
        public void CutImage()
        {
            if (IsLoaded == true || _ImageDealerControl == null)
                _ImageDealerControl.CutImage();
            else
                throw new Exception("尚未创建视图时无法截图!");
        }

        //截图回调
        private void OnCutImage(CutImgInfo cutImgInfo)
        {
            // BitmapSource bit
            RaiseEvent(new RoutedEventArgs(OnCutImagingEventHandler, cutImgInfo));
        }

        //加载完成
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (MainGrid.Children.Contains(_ImageDealerControl) == false)
                MainGrid.Children.Add(_ImageDealerControl);
        } 
 
        #endregion
    }

De hecho, nuestra función es muy simple, pero es molesto escribirlo usted mismo cuando lo usa. Lo grabaré para evitar que se use en el futuro, o mis amigos lo usarán. También cargué el código, y los amigos que lo necesiten pueden descargarlo.

Dirección del código: https://download.csdn.net/download/baoolong/86608595

Supongo que te gusta

Origin blog.csdn.net/baoolong/article/details/126747435
Recomendado
Clasificación