How to zoom in and zoom out Images in WP7? - c#

I have made an application which displays Images .Now I want to implement zoom in and zoom out feature(by using two fingertip's) as in native windows phone photo viewer application.Any idea on how to proceed .
Thanks in Advance.

Perhaps the most expedient approach would be to include the Silverlight for Windows Phone Toolkit. This contains a GestureService that will help with pinch and rotate touch gestures. You could apply it to an image like this:-
<Image Source="someSourceUrl" RenderTransformOrigin="0.5, 0.5" CacheMode="BitmapCache">
<Image.RenderTransform>
<CompositeTransform x:Name="transform" />
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener PinchStarted="OnPinchStarted" PinchDelta="OnPinchDelta" />
</toolkit:GestureService.GestureListener>
</Image>
Then in code-behind:-
private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
{
initialAngle = transform.Rotation;
initialScale = transform.ScaleX;
}
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
transform.Rotation = initialAngle + e.TotalAngleDelta;
transform.ScaleX = initialScale * e.DistanceRatio;
transform.ScaleY = initialScale * e.DistanceRatio;
}

Check out Laurent Bugnion's multitouch sample - http://multitouch.codeplex.com/

if you want simple image viewer that supports multi-touch, I recommend you to use WebBrowser control to display image.
It supports multi-touch zoom and smooth scrolling as well by default. But you must have to copy file to isolated storage from project folder. Here's how I've done:
<Grid x:Name="LayoutRoot" Background="Transparent">
<phone:WebBrowser
Name="MyWebBrowserControl"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" />
</Grid>
IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
// if image file does not exist in isolated storage, copy it to there~!
if (!isf.FileExists(filename))
{
StreamResourceInfo sr = Application.GetResourceStream(new Uri(filename, UriKind.Relative));
using (BinaryReader br = new BinaryReader(sr.Stream))
{
byte[] data = br.ReadBytes((int)sr.Stream.Length);
using (BinaryWriter bw = new BinaryWriter(isf.OpenFile(filename, FileMode.OpenOrCreate)))
{
bw.Write(data);
bw.Close();
}
br.Close();
}
}
Dispatcher.BeginInvoke(() => { MyWebBrowserControl.Navigate(new Uri(filename, UriKind.Relative)); });
※ You must set the Build Action of image file to Content

Related

Scaling InkStrokes in UWP

I've got a simple demo application that uses an image as the background of an InkCanvas and I scale the strokes when the display of the image is resized so that they remain in the same place relative to the image. Since you can draw -> resize -> draw -> resize -> draw this means I have to scale each stroke a different amount each time by assigning the PointTransform on each stroke.
float thisScale = (float)(scale / _prevScale);
foreach (InkStroke stroke in myCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
float thisPointScale = thisScale * stroke.PointTransform.M11;
stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
}
This resizes the length of the strokes perfectly well. However, it does nothing to the thickness of the strokes. This is even more evident when you use a thick or non-uniform pen (eg the highlighter pen).
These link to two screen clips which show the results.
Full-screen - https://1drv.ms/i/s!ArHMZAt1svlBiZZDfrxFqyGU1bJ6MQ
Smaller window - https://1drv.ms/i/s!ArHMZAt1svlBiZZCqHHYaISPfWMMpQ
Any ideas on how I can resize the thickness of the strokes?
Apply a ScaleTransform to the InkCanvas control. That'll take care of scaling the ink stroke,the stroke locations and the background image. Essentially the transform applies to everything contained in the InkCanvas. No need to use the Matrix with the StrokeCollection.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="Red Highlighter "
x:Name="InkRedAttributesButton"
Click="InkRedAttributesButton_Click" />
<Button Content="Blue Highlighter "
x:Name="InkBlueAttributesButton"
Click="InkBlueAttributesButton_Click" />
<Button Content="Scale Down"
x:Name="ScaleDownButton"
Click="ScaleDownButton_Click" />
<Button Content="Scale Up"
x:Name="ScaleUpButton"
Click="ScaleUpButton_Click" />
</StackPanel>
<InkCanvas x:Name="myCanvas"
Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
<InkCanvas.Background>
<ImageBrush ImageSource="/SO_Questions;component/Images/Star02.jpg"
Stretch="Fill" />
</InkCanvas.Background>
<InkCanvas.RenderTransform>
<ScaleTransform x:Name="InkCanvasScaleTransform" />
</InkCanvas.RenderTransform>
</InkCanvas>
</Grid>
Code
private void ScaleUpButton_Click(object sender, RoutedEventArgs e) {
InkCanvasScaleTransform.ScaleX += .2;
InkCanvasScaleTransform.ScaleY += .2;
}
private void ScaleDownButton_Click(object sender, RoutedEventArgs e) {
InkCanvasScaleTransform.ScaleX -= .2;
InkCanvasScaleTransform.ScaleY -= .2;
}
private void InkRedAttributesButton_Click(object sender, RoutedEventArgs e) {
DrawingAttributes inkAttributes = new DrawingAttributes();
inkAttributes.Height = 12;
inkAttributes.Width = 12;
inkAttributes.Color = Colors.Red;
inkAttributes.IsHighlighter = true;
myCanvas.DefaultDrawingAttributes = inkAttributes;
}
private void InkBlueAttributesButton_Click(object sender, RoutedEventArgs e) {
DrawingAttributes inkAttributes = new DrawingAttributes();
inkAttributes.Height = 12;
inkAttributes.Width = 12;
inkAttributes.Color = Colors.Blue;
inkAttributes.IsHighlighter = true;
myCanvas.DefaultDrawingAttributes = inkAttributes;
}
Screenshots
Scaled 100%
Scaled 60%
Scaling the InkCanvas doesn't always fix the problem especially if you are wanting to save the scaled ink into a gif image file.
Apparently an InkStroke's PointTransform only transforms the location of the stroke's points, but not the size of the PenTip used to draw the stroke. (Not documented anywhere that I can find, but discovered by trial and error. The name 'PointTransform' is a bit of a clue)
So as well as applying your scaling factor to the PointTransform, you also have to scale the PenTip as follows (modification to your original code):
float thisPointScale = thisScale * stroke.PointTransform.M11;
stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
stroke.DrawingAttributes.PenTipTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
Hope this helps someone...
To resize the thickness of the strokes you have to change the Size property of the DrawingAttributes. PenTipTransform doesn't work for pencil - it throws an exception.
The point is that you cannot set the DrawingAttributes property of the stroke directly: https://learn.microsoft.com/en-us/uwp/api/windows.ui.input.inking.inkdrawingattributes
Here is example how to get this:
static IEnumerable<InkStroke> GetScaledStrokes(IEnumerable<InkStroke> source, float scale)
{
var scaleMatrix = Matrix3x2.CreateScale(scale);
var resultStrokes = source.Select(x => x.Clone()).ToArray();
foreach (var inkStroke in resultStrokes)
{
inkStroke.PointTransform = scaleMatrix;
var da = inkStroke.DrawingAttributes;
var daSize = da.Size;
daSize.Width = daSize.Width * scale;
daSize.Height = daSize.Height * scale;
da.Size = daSize;
inkStroke.DrawingAttributes = da;
}
return resultStrokes;
}
Complete example: https://github.com/ycherkes/ScaledInks

Extended splash screen in Windows 10 UWP?

I have created an extended splash screen for Windows 10 UWP app using following XAML and C# Code.
XAML Code
<Grid Background="#036E55">
<Canvas>
<Image x:Name="extendedSplashImage" Source="Assets/620.scale-200.png"/>
</Canvas>
<ProgressRing Name="splashProgressRing"
IsActive="True"
Width="20"
Height="20"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Foreground="White"
Margin="20">
</ProgressRing>
</Grid>
C# Code
internal Rect splashImageRect;
private SplashScreen splash;
internal bool dismissed = true;
internal Frame rootFrame;
private double ScaleFactor;
ApplicationDataContainer userSettings = ApplicationData.Current.LocalSettings;
JsonDataHandler dataHandler;
//bool isZipUpdateInProgress = false;
public ExtendedSplashScreen(SplashScreen splashscreen, bool loadState)
{
this.InitializeComponent();
Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);
ScaleFactor = (double)DisplayInformation.GetForCurrentView().ResolutionScale/100;
//System.Diagnostics.Debug.WriteLine("ScaleFactor - " + ScaleFactor + "/n");
splash = splashscreen;
if (splash != null)
{
splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);
splashImageRect = splash.ImageLocation;
PositionImage();
//PositionRing();
}
rootFrame = new Frame();
}
void PositionImage()
{
extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
extendedSplashImage.Height = splashImageRect.Height / ScaleFactor;
extendedSplashImage.Width = splashImageRect.Width / ScaleFactor;
}
void PositionRing()
{
splashProgressRing.SetValue(Canvas.LeftProperty, splashImageRect.X + (splashImageRect.Width * 0.5) - (splashProgressRing.Width * 0.5));
splashProgressRing.SetValue(Canvas.TopProperty, (splashImageRect.Y + splashImageRect.Height + splashImageRect.Height * 0.1));
}
void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
{
// Safely update the extended splash screen image coordinates. This function will be executed when a user resizes the window.
if (splash != null)
{
// Update the coordinates of the splash screen image.
splashImageRect = splash.ImageLocation;
PositionImage();
// If applicable, include a method for positioning a progress control.
PositionRing();
}
}
Now, it works fine if I keep rotation mode on, but when I switch it off, and if I rotate the screen to landscape mode then the logo differs. I am using 620x300 image.
You can try with this code it might help you to get result as you want, First remove all positioning image code and only try with this
<Grid Background="#036E55">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="Assets/620.scale-200.png" Stretch="None"/>
<ProgressRing IsActive="True" Height="30" Width="30" Margin="0,10,0,0" Foreground="White"/>
</StackPanel>
</Grid>
Image and ProgressRing will manage by StackPanel in center of screen and also Image will not differ. Hope it will help you.

Analog Clock, Rotate Hands C# WPF

I am working on a WPF project, trying to create an analog clock. I have an image of a clock (without the hands) and have set it as a background. I also have images of two hands of clock, which I want to rotate keeping one end fixed (like it happens in a clock). How can I rotate the image keeping its one end fixed in C#.NET (WPF)? What I have tried is the following code:
namespace AnalogWatch
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dispatcherTimer;
private int degrees = 0;
public MainWindow()
{
InitializeComponent();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
degrees += 5;
if (degrees > 360)
{
degrees = 0;
}
RotateTransform transform = new RotateTransform(degrees,StickImg.Width/2,StickImg.Height/2);
//StickImg.RenderTransformOrigin = new System.Windows.Point(0, 0);
StickImg.RenderTransform = transform;
}
private void Window_ContentRendered_1(object sender, EventArgs e)
{
dispatcherTimer.Start();
}
}
}
It is rotating the image but not keeping its one end fixed. What is the problem here ?
XAML is:
<Window x:Class="AnalogWatch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" ContentRendered="Window_ContentRendered_1">
<Grid>
<Image x:Name="StickImg" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="207,70,0,0" Source="stick.png"/>
</Grid>
</Window>
Updated.
Your code should work if clock hand exactly in the center of rectangular image.
Like this one
You can do either like you did
RotateTransform transform =new RotateTransform(degrees, StickImg.Width/2,StickImg.Height/2);
or
RotateTransform transform = new RotateTransform(degrees);
StickImg.RenderTransformOrigin = new Point(0.5, 0.5);
Use the RenderTransformOrigin of the element to set the center of rotation.
Note that the coordinates are scaled to 0..1
So to rotate around the center:
RenderTransformOrigin="0.5, 0.5"
Just make sure that the pivot of the hand is in the center of the element.
here's the code i'm using and it works like charm..as qwr suggested clock hand should be exactly in the center of rectangular image
c# code
DispatcherTimer clock = new DispatcherTimer();
public AnalogClock()
{
InitializeComponent();
clock.Interval =TimeSpan.FromMilliseconds(100);
clock.Tick += clock_Tick;
clock.Start();
}
void clock_Tick(object sender, EventArgs e)
{
double milsec = DateTime.Now.Millisecond;
double sec = DateTime.Now.Second;
double min = DateTime.Now.Minute;
double hr = DateTime.Now.Hour;
seconds.LayoutTransform = new RotateTransform(((sec / 60) * 360)+((milsec/1000)*6));
minutes.LayoutTransform = new RotateTransform((min * 360 / 60)+((sec/60)*6));
hours.LayoutTransform = new RotateTransform((hr * 360 / 12)+(min/2));
}
and the XAML code for images
<Grid Margin="-100">
<Image x:Name="clockface" RenderOptions.BitmapScalingMode="HighQuality" Source="images/panel.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="hours" RenderOptions.BitmapScalingMode="HighQuality" Source="images/hours.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="minutes" RenderOptions.BitmapScalingMode="HighQuality" Source="images/minutes.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="seconds" RenderOptions.BitmapScalingMode="HighQuality" Source="images/seconds.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
</Grid>
note the i've used the code in a separate usercontrol..
just make sure that the margin between the clock hand image and the grid i'ts contained in should be enough to make room for the image to rotate else it will displace while rotating..
hope this helps..!

Local saved bitmap image displayed weird on physical device

I have a part of my application where I am saving photo from CameraCaptureTask. Photos from here in phone's Media Library are fine. I want to save photos also to IsolatedStorage. This is my method for saving:
private void SavePhoto(Stream image, string filename)
{
using (IsolatedStorageFile storageFolder = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = storageFolder.CreateFile(filename))
{
var bitmap = new BitmapImage();
bitmap.SetSource(image);
var wb = new WriteableBitmap(bitmap);
wb.SaveJpeg(fileStream, wb.PixelHeight, wb.PixelWidth, 0, 100);
fileStream.Close();
}
}
}
And this is the part of method displaying photo in another page:
{...
using (IsolatedStorageFile storageFolder = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = storageFolder.OpenFile(_url, FileMode.Open, FileAccess.Read))
{
BitmapImage image = new BitmapImage();
image.SetSource(fileStream);
}
this.fullImage.Source = image;
}
}
XAML code:
<ViewportControl x:Name="viewport"
ManipulationStarted="OnManipulationStarted"
ManipulationDelta="OnManipulationDelta"
ManipulationCompleted="OnManipulationCompleted"
ViewportChanged="viewport_ViewportChanged">
<Canvas x:Name="canvas">
<Image x:Name="fullImage" HorizontalAlignment="Center"
RenderTransformOrigin="0,0"
VerticalAlignment="Center"
CacheMode="BitmapCache"
Stretch="UniformToFill" >
<Image.RenderTransform>
<ScaleTransform x:Name="xform"/>
</Image.RenderTransform>
</Image>
</Canvas>
</ViewportControl>
Image is loaded and displayed but it's weird, it's kind of stretched on one side and narrowed on second side. I'm sorry, I can't take a screenshot since WP 8.1 upgrade, I don't know why. In Windows Phone Emulator it's working fine though.
I am facing a similar scenario. The image, which I am capturing using PhotoCaptureDevice, I am trying to display it in a separate page (which also implements the zoom pan feature), the image is being shown cropped. If I remove the CacheMode = "BitmapCache" attribute from Image, then the image is no longer cropped. However it makes the zoom & pan of the image very jittery.
It seems that there is a size limit (2000 x 2000) of image size in the Windows Phone environment. See this.
Do have a look at the PhotoPage.xaml and PhotoPage.xaml.cs files in the FilterExplorerWP project . It might help you.

Zoomable image in windows phone 7

I'm trying to make an image zoomable in my windows phone 7 application. (code below) however it dosent work, the image dosent display. Can someone put me on the right track, is this the right control to use? If it is then what am I doing wrong?
<controls:PivotItem Name="Header" Header="item1">
<Grid>
<MultiScaleImage Name="mainImage" />
</Grid>
</controls:PivotItem>
var imageurl = loginxml.Descendants("response").Elements("submissions").Elements("submission").Elements("file_url_screen").First().Value;
//imageurl = https://inkbunny.net///files/screen/165/165693_CobaltHusky_random_anatomy_doodles.png
Header.Header = loginxml.Descendants("response").Elements("submissions").Elements("submission").Elements("title").First().Value;
DeepZoomImageTileSource img = new DeepZoomImageTileSource(new Uri(imageurl));
mainImage.Source = img;
EDIT Reading the msdn on MultiScaleImage that isnt the control to use. It needs a specific image source (not a bitmap/jpg)
The URL for the DeepZoomImageTileSource is not an image url, but the url to a XML file listing the images to use for the deep zoom tiles.
I implemented a simple zoomable image as follows using the silverlight toolkit:
<Image Name="MainImage" RenderTransformOrigin="0.5,0.5" CacheMode="BitmapCache">
<Image.RenderTransform>
<CompositeTransform x:Name="transform" />
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener PinchStarted="OnPinchStarted" PinchDelta="OnPinchDelta" />
</toolkit:GestureService.GestureListener>
</Image>
and in code:
MainImage.Source = new BitmapImage(new Uri(url));
Then declare two variables for your angle and zoom:
double initialAngle;
double initialScale;
And then handle the gesture events:
private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
{
initialAngle = transform.Rotation;
initialScale = transform.ScaleX;
}
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
//transform.Rotation = initialAngle + e.TotalAngleDelta;
transform.ScaleX = initialScale * e.DistanceRatio;
transform.ScaleY = initialScale * e.DistanceRatio;
}
Uncomment the rotation line if you want to handle rotating the image as well.
Sam
http://gallery.expression.microsoft.com/MultiTouch

Categories