Zoom Cropped pixels in a user control

2020-03-31 06:59发布

I have developed a user control. The user control is like a magnifier glass . The user control has an image button which shows images cropped pixel by pixel .

StorageFile storageFile =
     await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg", UriKind.RelativeOrAbsolute));
            using (Windows.Storage.Streams.IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.Read))
            {
                BitmapImage bitmapImage = new BitmapImage();
                await bitmapImage.SetSourceAsync(fileStream);


                WriteableBitmap writeableBitmap =
                    new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
                fileStream.Seek(0);
                await writeableBitmap.SetSourceAsync(fileStream);
                writeableBitmap = writeableBitmap.Crop(Convert.ToInt32(xValue), Convert.ToInt32(yValue), 100, 100);
                MagnifyTip.image1.ImageSource = writeableBitmap;

Now the MagnifyTip.image1 has an image source that is set to a cropped image . My requirenment is to zoom the cropped region and then assign it to the image source. The user control looks like this enter image description here Help would be appreciated

2条回答
Ridiculous、
2楼-- · 2020-03-31 07:16

Maybe this works for you, it is as efficient as WPF allows I suppose since there is no image cropping in the code, it just uses the RenderTransform to do the magic. Run the code below and press the mouse over the image so the magnifying glass appears like this:

enter image description here

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Width="512"
        Height="512">
    <Grid>
        <Canvas MouseDown="FullImage_OnMouseDown"
                MouseMove="FullImage_OnMouseMove"
                MouseUp="FullImage_OnMouseUp">
            <Image Name="FullImage"
                   Source="http://www.mupin.it/wp-content/uploads/2012/06/lenna1.png" />
            <Border Name="BorderZoom"
                    Visibility="Visible"
                    Width="{Binding ImageZoomSize, FallbackValue='200'}"
                    Height="{Binding ImageZoomSize, FallbackValue='200'}">
                <Border.Clip>
                    <EllipseGeometry RadiusX="{Binding ImageZoomSizeHalf, FallbackValue=100}"
                                     RadiusY="{Binding ImageZoomSizeHalf, FallbackValue=100}"
                                     Center="{Binding CenterPoint, FallbackValue='100,100'}">

                    </EllipseGeometry>
                </Border.Clip>
                <Image Source="{Binding ElementName=FullImage, Path=Source}"
                       RenderTransformOrigin="0.5,0.5">
                    <Image.RenderTransform>
                        <TransformGroup>
                            <TranslateTransform X="{Binding Xt}"
                                                Y="{Binding Yt}" />
                            <ScaleTransform ScaleX="{Binding ZoomFactor, FallbackValue='8'}"
                                            ScaleY="{Binding ZoomFactor, FallbackValue='8'}" />
                        </TransformGroup>
                    </Image.RenderTransform>
                </Image>
            </Border>
        </Canvas>
    </Grid>
</Window>

And this is the code behind:

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace WpfApplication1
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            ZoomFactor = 8;
            ImageZoomSize = 200;
            InitializeComponent();

            BorderZoom.Visibility = Visibility.Hidden;
        }

        public double Xt { get; private set; }
        public double Yt { get; private set; }
        public double ZoomFactor { get; private set; }
        public int ImageZoomSize { get; private set; }
        public int ImageZoomSizeHalf { get { return ImageZoomSize/2; } }
        public Point CenterPoint { get { return new Point(ImageZoomSizeHalf, ImageZoomSizeHalf);} }


        private void FullImage_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            BorderZoom.Visibility = Visibility.Visible;
            FullImage_OnMouseMove(sender, e);
        }

        private void FullImage_OnMouseMove(object sender, MouseEventArgs e)
        {
            if (BorderZoom.Visibility == Visibility.Visible)
            {
                BorderZoom.Visibility = Visibility.Visible;
                var pos = e.GetPosition(FullImage);
                Canvas.SetLeft(BorderZoom, pos.X - ImageZoomSizeHalf);
                Canvas.SetTop(BorderZoom, pos.Y - ImageZoomSizeHalf);

                var isrc = FullImage.Source as BitmapSource;
                if(isrc == null) return;

                var h = (double)isrc.PixelHeight;
                var w = (double)isrc.PixelWidth;              

                Xt = pos.X* (-ImageZoomSize/w) + ImageZoomSize/2.0;
                Yt = pos.Y * (-ImageZoomSize / h) + ImageZoomSize / 2.0;

                OnNotifyPropertyChanged("Xt");
                OnNotifyPropertyChanged("Yt");
            }
        }

        private void FullImage_OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            BorderZoom.Visibility = Visibility.Hidden;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnNotifyPropertyChanged(string propName)
        {
            if(PropertyChanged!= null) PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

UPDATE

As requested see the code below wrapping the magnifying tip in a user control that looks like this:

Embedding user control

XAML for MagifiyingTipCtrl:

<UserControl x:Class="WpfApplication1.MagifiyingTipCtrl"
             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" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>

        <Grid Name="ZoomedArea"  VerticalAlignment="Top"
              Visibility="Visible"
              Margin="15,15"
              Width="{Binding ZoomWidth, FallbackValue='136'}"
              Height="{Binding ZoomHeight, FallbackValue='128'}">
            <Grid.Clip>
                <EllipseGeometry RadiusX="{Binding ZoomWidthHalf, FallbackValue=68}"
                                 RadiusY="{Binding ZoomHeightHalf, FallbackValue=64}"
                                 Center="{Binding CenterPoint, FallbackValue='100,100'}">
                </EllipseGeometry>
            </Grid.Clip>
            <Image Source="{Binding SourceImage}"
                   RenderTransformOrigin="0.5,0.5">
                <Image.RenderTransform>
                    <TransformGroup>
                        <TranslateTransform X="{Binding Xt}"
                                            Y="{Binding Yt}" />
                        <ScaleTransform ScaleX="{Binding ZoomFactor, FallbackValue='8'}"
                                        ScaleY="{Binding ZoomFactor, FallbackValue='8'}" />
                    </TransformGroup>
                </Image.RenderTransform>
            </Image>
        </Grid>

        <Path Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z"
              Fill="#FFF4F4F5"
              Stretch="Fill"
              Stroke="Black"
              UseLayoutRounding="False"
              Height="227"
              Width="171" />
    </Grid>
</UserControl>

Code-behind for MagifiyingTipCtrl:

using System.Windows.Media.Imaging;

namespace WpfApplication1
{
    public partial class MagifiyingTipCtrl : UserControl
    {
        public MagifiyingTipCtrl()
        {
            ZoomFactor = 8;
            ZoomWidth = 136;
            ZoomHeight = 128;

            InitializeComponent();
        }

        public static readonly DependencyProperty SourceImageProperty =
            DependencyProperty.Register("SourceImage", typeof (BitmapSource), typeof (MagifiyingTipCtrl));

        public static readonly DependencyProperty XtProperty =
            DependencyProperty.Register("Xt", typeof(double), typeof(MagifiyingTipCtrl));

        public static readonly DependencyProperty YtProperty =
            DependencyProperty.Register("Yt", typeof(double), typeof(MagifiyingTipCtrl));


        public BitmapSource SourceImage
        {
            get { return (BitmapSource)GetValue(SourceImageProperty); }
            set { SetValue(SourceImageProperty, value); }
        }

        public double Xt
        {
            get { return (double)GetValue(XtProperty); }
            set { SetValue(XtProperty, value); }
        }

        public double Yt
        {
            get { return (double)GetValue(YtProperty); }
            set { SetValue(YtProperty, value); }
        }

        public void SetPosition(Point pos)
        {
            if (SourceImage == null) return;

            var h = (double)SourceImage.PixelHeight;
            var w = (double)SourceImage.PixelWidth;

            Xt = pos.X * (-ZoomWidth / w) + ZoomWidth / 2.0;
            Yt = pos.Y * (-ZoomHeight / h) + ZoomHeight / 2.0;
        }

        public double ZoomFactor { get; private set; }
        public int ZoomWidth { get; private set; }
        public int ZoomHeight { get; private set; }

        public int ZoomWidthHalf { get { return ZoomWidth / 2; } }
        public int ZoomHeightHalf { get { return ZoomHeight / 2; } }

        public Point CenterPoint { get { return new Point(ZoomWidthHalf, ZoomHeightHalf); } }
    }
}

XAML for the MainWindow:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        Title="MainWindow"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Width="512"
        Height="512">
    <Grid>
        <Canvas MouseDown="FullImage_OnMouseDown"
                MouseMove="FullImage_OnMouseMove"
                MouseUp="FullImage_OnMouseUp">
            <Image Name="FullImage"
                   Source="http://www.mupin.it/wp-content/uploads/2012/06/lenna1.png" />

            <wpfApplication1:MagifiyingTipCtrl x:Name="MagnifiyingTip"
                                               SourceImage="{Binding ElementName=FullImage, Path=Source}" />
        </Canvas>
    </Grid>
</Window>

Code-behind for MainWindow:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void FullImage_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            MagnifiyingTip.Visibility = Visibility.Visible;
            FullImage_OnMouseMove(sender, e);
        }

        private void FullImage_OnMouseMove(object sender, MouseEventArgs e)
        {
            if (MagnifiyingTip.Visibility == Visibility.Visible)
            {
                MagnifiyingTip.Visibility = Visibility.Visible;
                var pos = e.GetPosition(FullImage);
                Canvas.SetLeft(MagnifiyingTip, pos.X - MagnifiyingTip.ActualWidth/2);
                Canvas.SetTop(MagnifiyingTip, pos.Y - MagnifiyingTip.ActualHeight);
                MagnifiyingTip.SetPosition(pos);
            }
        }

        private void FullImage_OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            MagnifiyingTip.Visibility = Visibility.Hidden;
        }
    }
}
查看更多
欢心
3楼-- · 2020-03-31 07:18

Just as i wrote in my comment, a quick demoapp in WPF for your PictureZoom.

https://github.com/hrkrx/PictureZoomExample

its just an examle so there can be a lot optimized, but i hope it is helping you

查看更多
登录 后发表回答