0

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

Apoorv
  • 2,023
  • 1
  • 19
  • 42
  • Can you post a snapshot of your user control? I'm still trying to figure out what you want exactly. Anyway, it seems to me that you have two options: Either create `CroppedBitmap` objects passing the source image and the source rectangle or use the`RenderTransform` and `Clip` property of the `Image` WPF control. – Darien Pardinas Mar 06 '15 at 03:28
  • Hey Darien. My main requirenment is to Zoom pixels on mouse hover event. See , I have a background image of car. when i move my mouse cursor near the front tyre and tap and hold my finger , my user control appears and it zooms and displays the tyre region without pixelation. Secondly , I can zoom in everywhere around the image until my finger is pressed and dragging. I will add the user control image for you – Apoorv Mar 06 '15 at 05:32
  • And please remember , this is a Windows 8.1 Metro Application. Most of the WPF controls are not working here ! – Apoorv Mar 06 '15 at 05:34
  • So you have a picture and its resolution is higher than the Screen/Window? and you want to show details of that image on mouse hover? – Sebastian L Mar 06 '15 at 08:21
  • Ok let me tell you this. their would be an image control in the background with Stretch set to uniform and the horizontal and vertical alignments to center . The image can be a 3000*3000 image also or an HD or a 1366*768 image also. to zoom a region in my control , I have to press and hold my finger on the image. The position where I tap would be zoomed in the user control . If i dont release my finger and keep on moving my finger ,the new areas would be zoomed. So its like on pointermoved() have to keep generating zoomed region – Apoorv Mar 06 '15 at 08:35
  • I made a demoApp in WPF, but its a little to big to post here i can give it to you if you want – Sebastian L Mar 06 '15 at 11:33
  • need Api support for windows 8.1. kindly post your zip file on some server !!will check and get back :) – Apoorv Mar 18 '15 at 16:55

2 Answers2

2

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;
        }
    }
}
Darien Pardinas
  • 5,910
  • 1
  • 41
  • 48
  • Darien , It looks awesome to me actually , But I would like you to look if there is a possibility that the whole code base runs on Windows 8.1 Application ?Secondly , I want to use my user control to show the magnification . – Apoorv Mar 07 '15 at 06:26
  • Darien , I was wondering , How to put this all XAML into a user control. I have made one user control like this . Want the image to be popped up inside the in the border. Kindly check – Apoorv Mar 07 '15 at 06:38
  • http://stackoverflow.com/questions/28713081/accessing-the-borderbackground-of-a-user-control-in-winrt-application – Apoorv Mar 07 '15 at 06:38
  • I want to put this whole magnifier that u made in the User control – Apoorv Mar 07 '15 at 07:58
  • Can you double-check the Path's Data? I'm getting "Unexpected token encountered at position '74'" when pasting your code in XAML – Darien Pardinas Mar 07 '15 at 09:19
  • Darien, Would it be possible for you to copy path from the link : here check the path http://stackoverflow.com/questions/28713081/accessing-the-borderbackground-of-a-user-control-in-winrt-application – Apoorv Mar 07 '15 at 10:34
  • secondly Darien, I want to add one feature that whenever my finger reaches the borders of the image , the controls should turn right /left by 45 degree angle. if my touch points are inside the image , even if the control pops out , there is no problem but if I am dragging my finger and keep moving it until i reach the borders , the control should rotate right /left according to me – Apoorv Mar 07 '15 at 10:38
  • Well Apoorv, I wish I could have more time to help you with your new requirements, but unfortunately I don't. If you believe the work I've done so far fulfil your initial requirements please don't forget to up-vote the question. All the best, Darien – Darien Pardinas Mar 07 '15 at 10:57
  • Sure Darien , the only thing is that if you could possibly put up the Path for the xaml control which i provided and just tell me how to enable rotation into the control. I will vote up and would like to thank you from all my heart. ! – Apoorv Mar 07 '15 at 11:06
  • Hey ! thats awesome ! One thing I would request you to check ! when you move your finger on the user control , and move it up , do you feel any lag for that ? – Apoorv Mar 07 '15 at 11:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72460/discussion-between-apoorv-and-darien-pardinas). – Apoorv Mar 07 '15 at 11:19
  • What happens is that if you get your mouse over the control then the base canvas image that handles the mouse events stop receiving them. You'll need to route the mouse events from the MagnifiyingTipCtrl to the hosting canvas if that becomes a problem for you. I'll leave that to you as homework. – Darien Pardinas Mar 07 '15 at 11:21
  • I have not tried this code on my windows 8 app but because you helped me alot I would give you a bounty. And I have made this previously and used WriteableBitmapEx library to get the cropped image assigned to the control. Made the performance better but would like to try your code too.. – Apoorv Mar 07 '15 at 11:27
  • Darien , I am trying this code on my Windows 8.1 app and the Usercontrol is giving errors like Cannot assign 'EllipseGeometry' into property 'Clip', type must be assignable to 'RectangleGeometry' . Can u see into it – Apoorv Mar 09 '15 at 03:41
  • and I tried this to run on a WPF app also , Its not showing the backgroundimage and the user control is moving awkrwardly. I am sorry to say that . – Apoorv Mar 09 '15 at 04:42
  • For the first issue, I don't develop for Windows 8.1, so I won't be able to help you much. If it says that it has to be a `RectangleGeometry` that might probably mean that you won't be able to wrap the component in a UserControl and you will have to blend both XAML into the same component, i.e. the canvas displaying the full image and the magnifying tip XAML. I do understand though how providing support for an EllipseGeometry is more complex and a simple rectangle from the framework point of view. – Darien Pardinas Mar 09 '15 at 09:15
  • For the second issue please post your code and and will look into it. This is the solution I made and it works just fine: https://dl.dropboxusercontent.com/u/31977801/Magnifying-Tip-WPF.7z. It is currently displaying around the mouse position, but you can select exactly what area you want to magnify. If your image is stretched in the canvas (pixel width != canvas width) then you'll need to scale the mouse position by multiplying by Canvas.ActualWidth/SourceImage.PixelWidth – Darien Pardinas Mar 09 '15 at 09:26
  • Its getting to much complicated !! tell me your email Id , I would send you the solution Darien. the one which I developed ! – Apoorv Mar 09 '15 at 09:44
  • Is the above link has the same code that you pasted above? Even the DependencyProperty parameters are changed for Windows 8.1 app. What you did was matching my requirenment . Its like There is a backround image, if i longtap(PointerPressed Event in W8) , I get the user control that zooms /clips the area. now keeping the fingers pressed , whereever I move my finger(PointerMoved) , The control should move and crop the area of my finger tap. I should be able to move top , left , right , bottom and the user control should move along with it . – Apoorv Mar 09 '15 at 16:21
  • Darien , I need your email ID to send the project – Apoorv Mar 10 '15 at 08:16
  • Find the video https://www.youtube.com/edit?o=U&video_id=0Ie1Z-vk4aE and my code here(http://stackoverflow.com/questions/28895307/overriding-manipulation-delta-of-a-user-control) ! the video shows what exactly needs to be done – Apoorv Mar 10 '15 at 18:12
  • Darien , Were you able to do something? Now I have pasted my code too ! I am having terrible issues with Stretch property when set to Uniform !! – Apoorv Mar 11 '15 at 16:17
  • I somehow was able to develop something . I need to integrate the clipping ellipse into my user control . Kindly see this link and help please http://dl.dropboxusercontent.com/u/1192076/MagnifierApp.zip – Apoorv Mar 26 '15 at 16:23
-1

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

Sebastian L
  • 838
  • 9
  • 29
  • I will try it , but basically What I see is that you are cropping an image area using rectangle? The same thing I am doing by using WriteableBitmapExtensionEx library. I am not on a Windows PC now , will try it and let you know ! Thanks for trying . I am really thankful to you ! – Apoorv Mar 06 '15 at 17:35
  • Sebastian - I would check the code and give an upvote if Its exactly what I need ! I see that I have developed the same solution though ! But u helped and put in your time so I would like to give an upvote if the solution works ! Do leave a reply ! Thanks – Apoorv Mar 07 '15 at 13:14
  • Sebastian , I am working on Windows Store app.I have specific requirenments. I need to have a base image on a canvas and then click on it to display the magnifying user control with the cropped image. the control moves along with the fingerpressed event – Apoorv Mar 09 '15 at 07:14
  • something like the answer I accepted here ! But that too is not working in Windows 8.1 app . EllipseGeometry not supported and all – Apoorv Mar 09 '15 at 07:14
  • I never worked with WinRT in the first place, so i thought WPF would help but i read a bit about WinRT ^^ so i think i do understand your problem now. I try to rework my example and update the githublink when im done ^^ – Sebastian L Mar 09 '15 at 10:28
  • hey Sebastian , check the answer above. I am loading an image and then wherever I am tapping my finger , the user control appears and it moves unless my finger is pressed and moved and it crops the areas . when it reaches the image boundary(my finger ) the control rotates slowly to an angle. – Apoorv Mar 09 '15 at 10:31
  • youtube.com/edit?o=U&video_id=0Ie1Z-vk4aE want something like this . Have developed the user control but using WriteableBitmapEx library . Want to make it efficient using Crop method of Rectangle . Check my code (http://stackoverflow.com/questions/28895307/overriding-manipulation-delta-of-a-user-control) – Apoorv Mar 10 '15 at 18:14