首页 > 其他分享 >WPF Canvas在Image 图像上绘图,自适应缩放.

WPF Canvas在Image 图像上绘图,自适应缩放.

时间:2024-05-11 13:53:52浏览次数:27  
标签:Canvas set tempRect 缩放 Image get private new public

效果如图

 

 

实现了绘图,自适应缩放

核心代码如下

    <Window.InputBindings>
        <KeyBinding Key="Z" Modifiers="Ctrl" Command="{Binding UndoCommand}" />
    </Window.InputBindings>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SizeChanged">
            <i:InvokeCommandAction Command="{Binding SizeChangedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid  Background="AliceBlue">
            <Grid.RowDefinitions>
                <RowDefinition Height="40" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.35*" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center"  Margin="10,0,0,0" Grid.ColumnSpan="2">
                <!--<Button Content="+" Command="{Binding DrawRectCommand}" />-->
                <Button Content=" + " Margin="10,0,0,0" Command="{Binding CreateCommand}" />
                <Button Content="Save" Margin="10,0,0,0" Command="{Binding SaveCommand}" />
                <Button Content="Clear" Margin="10,0,0,0" Command="{Binding ClearCommand}" />
                <Button Content="Cancel" Margin="10,0,0,0" Command="{Binding UndoCommand}" />
                <Button Content="Refresh" Margin="10,0,0,0" Command="{Binding RefreshCommand}" />
            </StackPanel>

            <StackPanel Grid.Row="1" Grid.Column="0">
                <ListBox  SelectedItem="{Binding SelectedSlide}">
                    <ListBox.Resources>
                        <CollectionViewSource x:Key="SlideControlParams" Source="{Binding SlideControlParams}" />
                    </ListBox.Resources>
                    <ListBox.ItemsSource>
                        <CompositeCollection>
                            <CollectionContainer Collection="{Binding Source={StaticResource SlideControlParams}}" />
                        </CompositeCollection>
                    </ListBox.ItemsSource>
              
                    <ListBox.ItemContainerStyle>
                        <Style TargetType="ListBoxItem">
                            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        </Style>
                    </ListBox.ItemContainerStyle>

                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid  Height="40" VerticalAlignment="Center">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition />
                                    <ColumnDefinition Width="50" />
                                </Grid.ColumnDefinitions>

                                <Grid.InputBindings>
                                    <MouseBinding Command="{Binding DataContext.OnListViewItemDoubleClick, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                                      MouseAction="LeftDoubleClick" CommandParameter="{Binding }" />
                                </Grid.InputBindings>
                                <TextBlock Text="{Binding Path= Name}">

                                    <TextBlock.VerticalAlignment>Center</TextBlock.VerticalAlignment>
                                    <TextBlock.Margin>5,0,0,0</TextBlock.Margin>
                                </TextBlock>
                                <TextBox Text="{Binding Name,Mode=TwoWay}" VerticalAlignment="Center" Margin="5,0,0,0" Visibility="{Binding EditStatus}" />

                                <Button Content="X" Grid.Column="1" Width="40"  VerticalAlignment="Center" Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" CommandParameter="{Binding }" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>

            <Image Source="{Binding SelectedSlide.ImagePath}" Grid.Row="1" x:Name="imgSlide" Grid.Column="1">            
            </Image>

            <Canvas Grid.Row="1" Name="canvas" Background="#19DAB1B1" Grid.Column="1">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonDown">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseDown}"  PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseLeftButtonUp">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseUp}" PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseMove">
                        <cmd:EventToCommand Command="{Binding CmdLeftMouseMove}" PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseRightButtonUp">
                        <cmd:EventToCommand Command="{Binding MouseRightButtonUp}"  PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Canvas>
        </Grid>
    </Grid>
</Window>
    public class UCP16ConfigVM : ViewModelBase
    {
        public UCP16ConfigVM(Canvas _canvas, Image _imgSlide)
        {
            canvas = _canvas;
            imgSlide = _imgSlide;
            InitEnv();
            InitCommand();
            LoadConfig();
            string rootPath = System.Environment.CurrentDirectory;
            jsonPath = System.IO.Path.Combine(rootPath, "ScanPara", "slideParms.json");
            imgDir = System.IO.Path.Combine(rootPath, "ScanPara", "SlideConfigImages");
            if (!Directory.Exists(imgDir))
            {
                Directory.CreateDirectory(imgDir);
            }
            if (!File.Exists(jsonPath))
            {
                SlideP16Parms prams = new SlideP16Parms();
                var str = JsonConvert.SerializeObject(prams, Formatting.Indented);
                File.WriteAllText(jsonPath, str);
            }
        }

        #region private param

        /// <summary>
        /// 是否正在绘图状态
        /// </summary>
        private bool isDrawing = false;

        /// <summary>
        /// 起始点
        /// </summary>
        private Point startPoint;

        /// <summary>
        /// 结束点
        /// </summary>
        private Point endPoint;

        /// <summary>
        /// canvas控件
        /// </summary>
        private Canvas canvas = null;

        /// <summary>
        /// image控件
        /// </summary>
        private Image imgSlide = null;

        /// <summary>
        /// 颜色刷
        /// </summary>
        private Brush brushDanger;

        /// <summary>
        /// rect效果
        /// </summary>
        private DropShadowEffect shadowEffect;

        /// <summary>
        /// 临时矩形
        /// </summary>
        private Rectangle tempRect = null;

        private readonly string jsonPath;
        private readonly string imgDir;

        //图像控件相对于canva的坐标
        private Point imgMarginPos;

        #endregion private param

        #region ViewModels

        private ObservableCollection<SlideP16ItemCombine> _SlideControlParams;

        /// <summary>
        /// 控件对应的坐标
        /// </summary>
        public ObservableCollection<SlideP16ItemCombine> SlideControlParams
        {
            get => _SlideControlParams;
            set { Set(ref _SlideControlParams, value); }
        }

        ///// <summary>
        ///// 图像坐标,需要同步更新
        ///// </summary>
        //public List<SlideP16Item> SlideImageParams { get; set; }

        private SlideP16ItemCombine _SelectedSlide;

        public SlideP16ItemCombine SelectedSlide
        {
            get => _SelectedSlide;
            set
            {
                if (value != _SelectedSlide)
                {
                    Set(ref _SelectedSlide, value);
                    foreach (var item in SlideControlParams)
                    {
                        if (item != value)
                            item.EditStatus = Visibility.Collapsed;
                    }
                    LoadPoints();
                }
            }
        }

        #endregion ViewModels

        #region Command

        /// <summary>
        /// 清空所有绘图
        /// </summary>
        public RelayCommand ClearCommand { get; private set; }

        /// <summary>
        /// 取消,撤销上一步操作
        /// </summary>
        public RelayCommand UndoCommand { get; private set; }

        public RelayCommand<MouseEventArgs> CmdLeftMouseDown { get; private set; }
        public RelayCommand<MouseEventArgs> CmdLeftMouseMove { get; private set; }
        public RelayCommand<MouseEventArgs> CmdLeftMouseUp { get; private set; }
        public RelayCommand<MouseEventArgs> MouseRightButtonUp { get; private set; }

        public RelayCommand<SlideP16ItemCombine> OnListViewItemDoubleClick { get; private set; }

        /// <summary>
        /// 刷新数据
        /// </summary>
        public RelayCommand RefreshCommand { get; private set; }

        /// <summary>
        /// 保存
        /// </summary>
        public RelayCommand SaveCommand { get; set; }

        /// <summary>
        /// 新建配方
        /// </summary>
        public RelayCommand CreateCommand { get; set; }

        public RelayCommand<SlideP16ItemCombine> DeleteCommand { get; set; }

        public RelayCommand SizeChangedCommand { get; private set; }

        #endregion Command

        private static readonly string SOURCE_DEFAULT =
            @"pack://application:,,,/TestWPF;component/Resources/Images/upload.png";

        /// <summary>
        /// 初始化界面主题
        /// </summary>
        private void InitEnv()
        {
            string hexColor = "#F56C6C";
            BrushConverter converter = new BrushConverter();
            brushDanger = (Brush)converter.ConvertFromString(hexColor);
            shadowEffect = new DropShadowEffect
            {
                Color = Colors.White, // 阴影颜色
                Direction = 0, // 阴影方向
                BlurRadius = 3, // 模糊半径
                Opacity = 0.6, // 阴影不透明度
                ShadowDepth = 0
            };
        }

        /// <summary>
        /// 初始化绑定命令
        /// </summary>
        private void InitCommand()
        {
            CmdLeftMouseDown = new RelayCommand<MouseEventArgs>(LeftMouseDown);
            CmdLeftMouseMove = new RelayCommand<MouseEventArgs>(LeftMouseMove);
            CmdLeftMouseUp = new RelayCommand<MouseEventArgs>(LeftMouseUp);
            MouseRightButtonUp = new RelayCommand<MouseEventArgs>(RightMouseUp);
            ClearCommand = new RelayCommand(() =>
            {
                ClearRectangle();
            });
            UndoCommand = new RelayCommand(() =>
            {
                if (canvas.Children.Count > 0)
                {
                    if (canvas.Children[canvas.Children.Count - 1] is Rectangle rect)
                    {
                        RemoveRectangle(rect);
                    }
                    // canvas.Children.RemoveAt(canvas.Children.Count - 1);
                }
            });
            SaveCommand = new RelayCommand(() =>
            {
                SaveResult();
            });
            CreateCommand = new RelayCommand(() =>
            {
                CreateNewItem(SOURCE_DEFAULT);
            });

            DeleteCommand = new RelayCommand<SlideP16ItemCombine>(
                (SlideP16ItemCombine param) =>
                {
                    SlideControlParams.Remove(param);
                    return;
                }
            );
            OnListViewItemDoubleClick = new RelayCommand<SlideP16ItemCombine>(
                (args) =>
                {
                    args.EditStatus = Visibility.Visible;
                }
            );
            RefreshCommand = new RelayCommand(RefreshData);
            SizeChangedCommand = new RelayCommand(Control_SizeChanged);
        }

        #region Command对应方法

        /// <summary>
        /// 左键按下事件
        /// </summary>
        /// <param name="e"></param>
        private void LeftMouseDown(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (SelectedSlide.ImagePath == SOURCE_DEFAULT)
            {
                LoadLocalImage();
                return;
            }
            isDrawing = true;

            if (e.OriginalSource is Canvas)
            {
                startPoint = e.GetPosition((IInputElement)e.Source);
            }
            else
            {
                startPoint = (e.Source as Rectangle).TranslatePoint(
                    e.GetPosition((IInputElement)e.Source),
                    canvas
                );
            }
            //   startPoint = e.GetPosition((IInputElement)e.Source);
            tempRect = CreateTempRect();
            Trace.WriteLine("down");
            canvas.Children.Add(tempRect);
        }

        private void RightMouseUp(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (e.OriginalSource is Rectangle)
            {
                var rect = e.OriginalSource as Rectangle;
                RemoveRectangle(rect);
            }
        }

        private void LeftMouseUp(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            isDrawing = false;
            AddRectangle();
            tempRect = null;
        }

        private void LeftMouseMove(MouseEventArgs e)
        {
            if (SelectedSlide == null)
                return;
            if (!isDrawing)
                return;
            if (e.OriginalSource is Canvas)
            {
                endPoint = e.GetPosition((IInputElement)e.Source);
            }
            else
            {
                endPoint = (e.Source as Rectangle).TranslatePoint(
                    e.GetPosition((IInputElement)e.Source),
                    canvas
                );
            }
            UpdateRectangle();
        }

        #endregion Command对应方法

        #region other func

        private Rectangle CreateTempRect()
        {
            Rectangle rect = new Rectangle
            {
                Width = 0,
                Height = 0,
                Stroke = brushDanger, // Brushes.Black,
                StrokeThickness = 2,
                Fill = Brushes.Transparent,
                IsHitTestVisible = true
            };

            rect.Effect = shadowEffect;
            Canvas.SetLeft(rect, startPoint.X);
            Canvas.SetTop(rect, startPoint.Y);

            return rect;
        }

        /// <summary>
        /// 刷新rect轨迹,并不会添加到数组
        /// </summary>
        private void UpdateRectangle()
        {
            AddRectangle(true);
            return;
        }

        private void AddRectangle(bool isUpdate = false)
        {
            try
            {
                double width = (endPoint.X - startPoint.X);
                double height = endPoint.Y - startPoint.Y;
                double left = startPoint.X;
                double top = startPoint.Y;
                if (width < 0)
                {
                    left = endPoint.X;
                    width = -width;
                }
                if (height < 0)
                {
                    top = endPoint.Y;
                    height = -height;
                }
                tempRect.Width = width;
                tempRect.Height = height;

                Canvas.SetLeft(tempRect, left);
                Canvas.SetTop(tempRect, top);

                if (!isUpdate) //如果完成,则添加到列表
                {
                    var tempPoint = new SlideP16ItemPoint
                    {
                        Height = height,
                        Width = width,
                        X = left,
                        Y = top,
                        IsImagePoint = false,
                    };
                    SelectedSlide.ItemPoints.Add(tempPoint);
                    AddControlPoint(SelectedSlide.ItemPoints[SelectedSlide.ItemPoints.Count - 1]);
                }
            }
            catch (Exception ex)
            {
                return;
            }
        }

        /// <summary>
        /// 删除界面指定rectangle对象,并从绑定的队列移除
        /// </summary>
        /// <param name="rect"></param>
        private void RemoveRectangle(Rectangle rect)
        {
            var imagePoint = ConvertToImageCoordinates(
                new SlideP16ItemPoint
                {
                    X = Canvas.GetLeft(rect),
                    Y = Canvas.GetTop(rect),
                    Width = rect.Width,
                    Height = rect.Height
                }
            );

            var toDeletePoint = this
                .SelectedSlide.ItemPoints.Where(x =>
                    x.IsImagePoint
                    && Math.Abs(x.Width - imagePoint.Width) <= 0.1
                    && Math.Abs(x.Height - imagePoint.Height) <= 0.1
                    && Math.Abs(x.X - imagePoint.X) <= 0.1
                    && Math.Abs(x.Y - imagePoint.Y) <= 0.1
                )
                .FirstOrDefault();
            if (toDeletePoint != null)
                SelectedSlide.ItemPoints.Remove(toDeletePoint);
            canvas.Children.Remove(rect);
        }

        /// <summary>
        /// 删除所有绘图
        /// </summary>
        private void ClearRectangle()
        {
            canvas.Children.Clear();
            this.SelectedSlide.ItemPoints.Clear();
        }


        /// <summary>
        /// 控件坐标转换为图像坐标
        /// </summary>
        /// <param name="pointControl"></param>
        /// <returns></returns>
        private SlideP16ItemPoint ConvertToImageCoordinates(SlideP16ItemPoint pointControl)
        {
            double scaleX =
                imgSlide.ActualWidth
                / (imgSlide.Source == null ? imgSlide.ActualWidth : imgSlide.Source.Width);
            double scaleY =
                imgSlide.ActualHeight
                / (imgSlide.Source == null ? imgSlide.ActualHeight : imgSlide.Source.Height);
            ;
            double imageRectX = pointControl.X / scaleX;
            double imageRectY = pointControl.Y / scaleY;
            double imageRectWidth = pointControl.Width / scaleX;
            double imageRectHeight = pointControl.Height / scaleY;
            return new SlideP16ItemPoint
            {
                Height = imageRectHeight,
                Width = imageRectWidth,
                X = imageRectX,
                Y = imageRectY,
            };
        }

        //private double scaleX;
        //private double scaleY;
        /// <summary>
        /// 图像坐标转控件坐标
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private SlideP16ItemPoint ConvertToControlCoordinates(SlideP16ItemPoint point)
        {
            var scaleX = imgSlide.ActualWidth / imgSlide.Source.Width;
            var scaleY = imgSlide.ActualHeight / imgSlide.Source.Height;
            // 根据缩放比例计算控件上的位置和尺寸
            double controlX = point.X * scaleX;
            double controlY = point.Y * scaleY;
            double controlWidth = point.Width * scaleX;
            double controlHeight = point.Height * scaleY;
            return new SlideP16ItemPoint
            {
                Height = controlHeight,
                Width = controlWidth,
                X = controlX,
                Y = controlY,
            };
        }

        private void LoadConfig()
        {
            string jsonPath = System.Environment.CurrentDirectory;
            jsonPath = System.IO.Path.Combine(jsonPath, "ScanPara", "slideParms.json");
            var json = File.ReadAllText(jsonPath);
            SlideP16Parms rt = JsonConvert.DeserializeObject<SlideP16Parms>(json);
            IEnumerable<SlideP16ItemCombine> items = rt.Items.Select(x => new SlideP16ItemCombine
            {
                EditStatus = Visibility.Collapsed,
                ID = x.ID,
                ImagePath = x.ImagePath,
                ItemPoints = x.ItemPoints,
                Name = x.Name
            });
            SlideControlParams = new ObservableCollection<SlideP16ItemCombine>(items);
        }

        /// <summary>
        /// 加载point坐标,并绘制到ui
        /// </summary>
        /// <param name="isControl"></param>
        private void LoadPoints()
        {
            imgSlide.Dispatcher.Invoke(
                new Action(() =>
                {
                    if (this.SelectedSlide == null)
                        return;
                    imgMarginPos = imgSlide.TranslatePoint(new Point(0, 0), canvas);
                    canvas.Children.Clear();
                    foreach (SlideP16ItemPoint p in SelectedSlide.ItemPoints)
                    {
                        SlideP16ItemPoint t_point = null;

                        if (p.IsImagePoint)
                            t_point = ConvertToControlCoordinates(p);
                        else
                            t_point = p;

                        Rectangle tempRect = new Rectangle
                        {
                            Width = t_point.Width,
                            Height = t_point.Height,
                            Stroke = brushDanger, // Brushes.Black,
                            StrokeThickness = 2,
                            Fill = Brushes.Transparent,
                            IsHitTestVisible = true
                        };

                        tempRect.Effect = shadowEffect;
                        Canvas.SetLeft(tempRect, t_point.X);
                        Canvas.SetTop(tempRect, t_point.Y);
                        //  Trace.WriteLine($"tempRect x:{t_point.X} y:{t_point.Y},width:{tempRect.Width},height:{tempRect.Height}");
                        canvas.Children.Add(tempRect);
                    }
                    //   Trace.WriteLine("cavnas.children.count:" + canvas.Children.Count);
                }),
                DispatcherPriority.Loaded
            );
        }

        private void AddControlPoint(SlideP16ItemPoint t_point)
        {
            Rectangle tempRect = new Rectangle
            {
                Width = t_point.Width,
                Height = t_point.Height,
                Stroke = brushDanger, // Brushes.Black,
                StrokeThickness = 2,
                Fill = Brushes.Transparent,
                IsHitTestVisible = true
            };

            tempRect.Effect = shadowEffect;
            Canvas.SetLeft(tempRect, t_point.X);
            Canvas.SetTop(tempRect, t_point.Y);
            //      canvas.Children.Add(tempRect);
            Trace.WriteLine("cavnas.children.count:" + canvas.Children.Count);
        }

        private void CreateNewItem(string imgPath)
        {
            int id = 0;
            if (this.SlideControlParams?.Count > 0)
                id = this.SlideControlParams.Max(x => x.ID) + 1;
            var item = new SlideP16ItemCombine()
            {
                ID = id,
                ImagePath = imgPath,
                Name = id.ToString(),
                ItemPoints = new List<SlideP16ItemPoint>() { },
                EditStatus = Visibility.Visible
            };

            this.SlideControlParams.Add(item);
            //this.SlideImageParams.Add(item);
            this.SelectedSlide = item;
        }

        private void LoadLocalImage()
        {
            // 创建 OpenFileDialog 对象
            OpenFileDialog openFileDialog = new OpenFileDialog();
            // 设置文件类型过滤器,只允许选择图片文件
            openFileDialog.Filter =
                "Image files (*.jpg;*.jpeg;*.bmp;*.png)|*.jpg;*.jpeg;*.bmp;*.png|All files (*.*)|*.*";
            // 设置默认文件类型筛选器
            openFileDialog.FilterIndex = 1;
            // 是否允许多选
            openFileDialog.Multiselect = false;
            // 显示对话框并获取用户的操作结果
            bool? result = openFileDialog.ShowDialog();
            // 如果用户点击了确认按钮
            if (result == true)
            {
                try
                {
                    // 获取选择的文件名
                    string fileName = openFileDialog.FileName;
                    FileInfo fn = new FileInfo(fileName);
                    string targeImgPath = System.IO.Path.Combine(
                        imgDir,
                        "P16_" + SelectedSlide.ID.ToString() + fn.Extension
                    );
                    File.Copy(fileName, targeImgPath, true);
                    // 将 BitmapImage 对象设置为界面上的 Image 控件的 Source
                    SelectedSlide.ImagePath = targeImgPath; // bitmapImage;
                }
                catch (Exception ex)
                {
                    // 处理异常情况
                    HandyControl.Controls.MessageBox.Show(
                        $"Error loading image: {ex.Message}",
                        "Error",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error
                    );
                }
            }
        }

        /// <summary>
        /// 保存结果到json
        /// </summary>
        private void SaveResult()
        {
            SlideP16Parms prams = new SlideP16Parms();
            prams.Items = this.SlideControlParams.Select(x => (SlideP16Item)x).ToList();
            foreach (var p in prams.Items)
            {
                for (int i = 0; i < p.ItemPoints.Count; i++)
                {
                    if (!p.ItemPoints[i].IsImagePoint)
                        p.ItemPoints[i] = ConvertToImageCoordinates(p.ItemPoints[i]); // ConvertToImageCoordinates();
                }
            }
            var str = JsonConvert.SerializeObject(prams, Formatting.Indented); // JsonConvert.SerializeObject(prams, Formatting.Indented);
            File.WriteAllText(jsonPath, str);
        }

        /// <summary>
        /// 刷新页面数据,重新读取
        /// </summary>
        private void RefreshData()
        {
            LoadConfig();
        }

        private void Control_SizeChanged()
        {
            if (imgSlide.Source == null || canvas.Children.Count == 0)
                return;
            var scaleX = imgSlide.ActualWidth / imgSlide.Source.Width;
            var scaleY = imgSlide.ActualHeight / imgSlide.Source.Height;
            imgMarginPos = imgSlide.TranslatePoint(new Point(0, 0), canvas); //将Image控件的(0,0)坐标点转换为相对于canvas的坐标点。返回的Point对象就表示了Image控件在canvas中的偏移量。
            var offetX = imgMarginPos.X;
            var offetY = imgMarginPos.Y;
            for (int i = 0; i < canvas.Children.Count; i++)
            {
                var element = canvas.Children[i] as Rectangle;

                var tempRect = SelectedSlide.ItemPoints[i];
                //if (!tempRect.IsImagePoint)
                //{
                //    tempRect = ConvertToImageCoordinates(tempRect); //不可行,因为此时转换的时候,已经是size-changed之后了,无法正确转换
                //}
                var cav = VisualTreeHelper.GetParent(imgSlide) as Canvas;

                double left = tempRect.X;
                double top = tempRect.Y;
                left = left * scaleX;
                top = top * scaleY;
                left += offetX;
                top += offetY;
                var width = tempRect.Width; // element.ActualWidth;
                var height = tempRect.Height; // element.ActualHeight;
                width *= scaleX;
                height *= scaleY;
                Trace.WriteLine("rq.scaleX:" + scaleX);
                Trace.WriteLine("rq.scaleY:" + scaleY);
                Trace.WriteLine("rq.element width:" + width);
                Trace.WriteLine("rq.element height:" + height);
                Canvas.SetLeft(element, left);
                Canvas.SetTop(element, top);
                element.Width = width;
                element.Height = height;
                Trace.WriteLine("rq.left:" + left);
                Trace.WriteLine("rq.top:" + top);
                Trace.WriteLine("rq.width:" + width);
                Trace.WriteLine("rq.height:" + height);
            }
        }

        #endregion other func
    }

    #region json映射类 P16玻片参数

    public class SlideP16ItemCombine : SlideP16Item
    {
        private Visibility _EditStatus;

        public Visibility EditStatus
        {
            get => _EditStatus;
            set => Set(ref _EditStatus, value);
        }
    }

    public class SlideP16Parms
    {
        public int ApplyID { get; set; }
        public List<SlideP16Item> Items { get; set; }
    }

    /// <summary>
    /// P16玻片配置信息
    /// </summary>
    public class SlideP16Item : ViewModelBase
    {
        public int ID { get; set; }
        public List<SlideP16ItemPoint> ItemPoints { get; set; }

        private string _Name;

        public string Name
        {
            get => _Name;
            set => Set(ref _Name, value);
        }

        private string _ImagePath;

        /// <summary>
        /// 图片路径
        /// </summary>
        public string ImagePath
        {
            get => _ImagePath;
            set => Set(ref _ImagePath, value);
        }
    }

    /// <summary>
    /// p16玻片子配置
    /// </summary>
    public class SlideP16ItemPoint
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }

        /// <summary>
        /// 是否为图像坐标,json读写忽略
        /// </summary>
        [JsonIgnore]
        public bool IsImagePoint { get; set; } = true;
    }

    #endregion json映射类
}

 

标签:Canvas,set,tempRect,缩放,Image,get,private,new,public
From: https://www.cnblogs.com/MarsPanda/p/18186351

相关文章

  • 采用flex布局,父组件width为百分比,解决子组件canvas画布width自适应问题
     创建EleResize.js文件(拷贝以下代码即可)varEleResize={ _handleResize:function(e){  varele=e.target||e.srcElement  vartrigger=ele.__resizeTrigger__  if(trigger){   varhandlers=trigger.__z_resizeListeners   if......
  • 【Azure Standard Logic App】Workflow积压非常严重的情况下, 执行实例居然不能自动缩
    问题描述测试标准版本的LogicApp应用,消费ServiceBus中的消息。当ServiceBus中堆积了大量消息的情况下,Workflow依旧只在一个实例上运行。而LogicApp的自动缩放设置的最大为20个,为什么没有自动缩放呢? 问题解答因为这个StandardLogicApp集成进入到一个虚拟网络中,默认情......
  • Lossless Recompression of JPEG Images Using Transform Domain Intra Prediction
    目录简介引入文章贡献对DCT系数残差进行编码比对原始DCT系数进行编码更有利于压缩模型框架简介\(\quad\)JPEG图像编码格式由于其简单高效在各种设备和网站上被广泛使用,但JPEG与性能与最先进的编码方法相差甚远。如果能对这些JPEG图像再压缩,将会缩减储存成本。该文章提出了......
  • 2024CVPR_Low-light Image Enhancement via CLIP-Fourier Guided Wavelet Diffusion(C
    一、Motivation1、单模态监督问题:大多数方法往往只考虑从图像层面监督增强过程,而忽略了图像的详细重建和多模态语义对特征空间的指导作用。这种单模态监督导致不确定区域的次优重建和较差的局部结构,导致视觉结果不理想的出现。------》扩散模型缺乏有效性约束,容易出现多种生成效......
  • Canvas简历编辑器-我的剪贴板里究竟有什么数据
    Canvas图形编辑器-我的剪贴板里究竟有什么数据在这里我们先来聊聊我们究竟应该如何操作剪贴板,也就是我们在浏览器的复制粘贴事件,并且在此基础上聊聊我们在Canvas图形编辑器中应该如何控制焦点以及如何实现复制粘贴行为。在线编辑:https://windrunnermax.github.io/CanvasEdito......
  • cv::Mat转QImage导致图像色彩异常
    问题:1QPixmapMainWindow::opencvToQImage(constQString&str)2{3cv::MatcvImage=cv::imread(str.toStdString(),cv::IMREAD_REDUCED_COLOR_2);4cv::MatresizeMat;5cv::resize(cvImage,resizeMat,cv::Size(ui->label->width(),u......
  • [Paper Reading] LSS: Lift, Splat, Shoot: Encoding Images from Arbitrary Camera R
    名称Lift,Splat,Shoot:EncodingImagesfromArbitraryCameraRigsbyImplicitlyUnprojectingto3D时间:20.08机构:NVIDIATL;DR后融合方法将每一目感知结果通过相机参数转换到BEV空间再后融合,LSS开启前融合的先河,将特征通过先lift再splat到BEV空间,通过BEV空间特征直接预......
  • SwiftUI Image 图片处理
    代码片段////ContentView.swift//SwiftUIImage////CreatedbyCHENHaoon2024/5/6.//importSwiftUIstructContentView:View{varbody:someView{Image("paris").resizable()//延伸模式,平铺整个屏幕/......
  • k8s - ERROR: image can't be pulled
       Testedtheimage:zzh@ZZHPC:/zdata/Github/zgrpc-go-professionals$kubectlrunmytest--image=zgrpc-go-professionals:serverpod/mytestcreatedzzh@ZZHPC:/zdata/Github/zgrpc-go-professionals$kubectlgetpodsNAMEREADYSTATUSRESTART......
  • Android开发 Jetpack Compose Canvas
    版权声明本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17657716.html本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。前言  此篇博客讲解Canvas的使用 画线正常的线条效果图......