Side by side view of PDF files in UWP apps - xaml

I need the pdf viewer side by side of my app, so that i will be able to view the pdf generated when any changes made in app. In windows 8.1 app the PDF is opened using Reader app and by default it opens PDF side by side.
But the case in Win10 is not the same. In win 10 the reader app is opened seperately pushing back the app screen.Is there any similar viewer as like in win 8.1
Below image is from windows 8.1 app

Here is the solution to open PDF files inside the app
As usual I opened PDF from files as storage file.
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/pdffile.pdf"));
Windows.Data.Pdf.PdfDocument doc = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file);
Load(doc);
Now the PDF document is read page by page as BitmapImage and added to a list.
public async void Load(PdfDocument pdfDoc)
{
PdfPages.Clear();
for (uint i = 0; i < pdfDoc.PageCount; i++)
{
BitmapImage image = new BitmapImage();
var page = pdfDoc.GetPage(i);
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await page.RenderToStreamAsync(stream);
await image.SetSourceAsync(stream);
}
PdfPages.Add(image);
}
}
public ObservableCollection<BitmapImage> PdfDocPages
{
get;
set;
} = new ObservableCollection<BitmapImage>();
Binding the ObservableCollection to the ItemsControl we can view the PDF as images.
<ScrollViewer ZoomMode="Enabled" Background="DarkGray" Grid.Column="1">
<ItemsControl ItemsSource="{Binding PdfDocPages, ElementName=pageRoot}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Margin="0 2" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>

Related

Zoom a rendered PDF in VirtualCanvasControl

I am rendring a PDF Page to a CanvasBitmap and draw this Image on a VirtualCanvasControl. But whenever I zoom in the picture gets pixelated.
I tried to render just the part that is visible but that does not seem to work. What am I doing wrong?
<ScrollViewer Grid.RowSpan="2"
Grid.Row="0"
Name="PdfScrollViewer"
ZoomMode="Enabled"
MaxZoomFactor="4"
MinZoomFactor="0.8"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
BringIntoViewOnFocusChange="False">
<canvas:CanvasVirtualControl x:Name="PageRenderCanvas" RegionsInvalidated="PageRenderCanvas_OnRegionsInvalidated"
/>
</ScrollViewer>
The RegionsInvalidated EventHandler:
private async void PageRenderCanvas_OnRegionsInvalidated(CanvasVirtualControl sender,
CanvasRegionsInvalidatedEventArgs args)
{
PdfPageRenderOptions options = new PdfPageRenderOptions();
options.DestinationWidth = (uint) (PdfScrollViewer.ActualWidth*PdfScrollViewer.ZoomFactor);
options.DestinationHeight = (uint) (PdfScrollViewer.ActualHeight*PdfScrollViewer.ZoomFactor);
options.SourceRect = args.VisibleRegion;
var output = new MemoryStream().AsRandomAccessStream();
await page.RenderToStreamAsync(output, options); // page is the PDFPage
var image = await CanvasBitmap.LoadAsync(PageRenderCanvas, output);
using (var ds = sender.CreateDrawingSession(args.InvalidatedRegions[0]))
{
ds.DrawImage(image, args.VisibleRegion);
ds.Dispose();
}
}
The image is pixelated because you are performing the zoom on the rendered bitmap.
Since there is not much documentation on VirtualCanvasControl and RegionsInvalidated event I recommend to perform the rendering every time the zoom changes and just display the rendered image in the drawing event.
However this approach will generate memory problems at large zoom levels. Considering 96dpi for 100%, a letter page will be 816*1056 pixels and will take about 3MB. At 500% zoom the image will be 4080*5280 pixels and will take about 75MB.

Universal Windows InkCanvas strokes disappear on RenderTargetBitmap.RenderAsync

I try to render the strokes of a InkCanvas to a RenderTargetBitmap in a windows 10 universal App. Here is my xaml code:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="container">
<Rectangle Fill="LightBlue" />
<InkCanvas x:Name="InkCanvas" />
</Grid>
<Image Grid.Row="2" x:Name="TheImage" />
<Button Grid.Row="3" Content="CopyToRendertargt" Click="Button_Click" />
</Grid>
And here is my code to set the Image.Source property:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
InkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
RenderTargetBitmap renderTarget = new RenderTargetBitmap();
await renderTarget.RenderAsync(this.container);
this.TheImage.Source = renderTarget;
}
}
When i click to button the strokes i made on the InkCanvas disappear and the InkCanvas is forzen until i resize the app window. The strokes are not getting rendered to the RenderTargetBitmap. The Image shows just the LightBlue Rectangle.
Does sombody have a solution for this?
** UPDATE **
For those who are searching for the right way to save strokes to a bitmap on uwp. I found the UWP-way of saving InkCanvas Strokes to a Bitmap: The InkStrokeContainer Object has a method called SaveAsync(...) which saves the strokes to a stream. If you use this stream as source for a Bitmap you get the strokes as Bitmap.
InkStrokeContainer container = TheInkCanvas.InkPresenter.StrokeContainer;
WriteableBitmap bmp;
using (InMemoryRandomAccessStream ims =
new InMemoryRandomAccessStream())
{
await container.SaveAsync(ims);
bmp = await new WriteableBitmap(1, 1)
.FromStream(ims, BitmapPixelFormat.Bgra8);
}
*Note: WriteableBitmapEx is used in this sample code (https://www.nuget.org/packages/WriteableBitmapEx/)
You can use Win2D to render the Ink Strokes.
Add Win2D.uwp to the project from NuGet
Add this InkCanvasExtensions.cs file to your project
Change the namespace or add using Zoetrope; to your source
Create an image file or stream and pass it to the InkCanvas.RenderAsync()
InkCanvasExtensions.cs
namespace Zoetrope
{
using System;
using System.Threading.Tasks;
using Microsoft.Graphics.Canvas;
using Windows.Graphics.Display;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Xaml.Controls;
/// <summary>
/// InkCanvas Extensions
/// </summary>
public static class InkCanvasExtensions
{
/// <summary>
/// Render an InkCanvas to a stream
/// </summary>
/// <param name="inkCanvas">the ink canvas</param>
/// <param name="fileStream">the file stream</param>
/// <param name="backgroundColor">the background color</param>
/// <param name="fileFormat">the file format</param>
/// <returns>an async task</returns>
public static async Task RenderAsync(
this InkCanvas inkCanvas,
IRandomAccessStream fileStream,
Color backgroundColor,
CanvasBitmapFileFormat fileFormat)
{
// do not put in using{} structure - it will close the shared device.
var device = CanvasDevice.GetSharedDevice();
var width = (float) inkCanvas.ActualWidth;
var height = (float) inkCanvas.ActualHeight;
var currentDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
using (var offscreen = new CanvasRenderTarget(device, width, height, currentDpi))
{
using (var session = offscreen.CreateDrawingSession())
{
session.Clear(backgroundColor);
session.DrawInk(inkCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
await offscreen.SaveAsync(fileStream, fileFormat);
}
}
}
}
In the XAML visuals and RenderTargetBitmap section in the RenderTargetBitmap documentation, it describes: Content that can't be captured will appear as blank in the captured image, but other content in the same visual tree can still be captured and will render (the presence of content that can't be captured won't invalidate the entire capture of that XAML composition).So it could be that the content of InkCanvas is not captureable.
An alternative is to use Win2D (Direct2D .NET wrapper from Microsoft). Win2D can be used in an UWP app via a nuget package. You will be able to manage the ink strokes and save them to image (jpeg, png, and other formats).

Change button background image when click in Windows Phone using XAML only?

So basically I want to have a button with a certain background image.
For example, when the app is loaded you would see a button with it's background image as image1.png and then when it is clicked you see image2.png as the background image. Then when you click again, the background image is switched back to image1.png.
Even though I have done this in C#, I want to do it in XAML because every time you click a button it automatically lights up according to the theme color, and the only way to get rid of that is via XAML.
Here is my code so fa:
<Button x:Name="Buttons" Content="" HorizontalAlignment="Left" Margin="155,0,0,69" BorderBrush="Transparent" Width="140" Click="Button_Click" Height="141" VerticalAlignment="Bottom">
<Button.Background>
<ImageBrush Stretch="Fill" ImageSource="/Assets/image1.png"/>
</Button.Background>
</Button>
Thanks in advance!
Try this,
http://visualstudiomagazine.com/articles/2013/02/15/customize-windows-phone-togglebutton.aspx
Here, the ToggleButton that ships with the SDK has been templated to add a clicked and unclicked image.
Alternate Solution with a checkbox:
Creating own toggle button in WP8?
VisualStudio 2017 "Blank App"
XAML
<Button x:Name="button" Content="Button1" HorizontalAlignment="Left" Margin="400,20,0,0" VerticalAlignment="Top" RenderTransformOrigin="-1.258,-5" Click="Button_Click" Height="80" Width="80"/>
C# (Set the original image in the properties of the button: right-click -> Brush -> image)
private void Button1_Click(object sender, RoutedEventArgs e)
{
button1.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri("ms-appx:/Images/timerg.png", UriKind.RelativeOrAbsolute)) };
}
or C#
private void Button1_Click(object sender, RoutedEventArgs e)
{
BitmapImage bmp = new BitmapImage();
Uri u = new Uri("ms-appx:/Images/timer.png", UriKind.RelativeOrAbsolute);
bmp.UriSource = u;
// NOTE: change starts here
Image i = new Image();
i.Source = bmp;
button1.Content = i;
}

Image rotation as animation

I am making a Windows 8 application in visual studio 2012 c#.
I am having an image '1.png' and I want to rotate it at any angle as an animation along its center point.
But i want to do it with the help of c# code rather than XAML code.
Thank You in Advance.
In your XAML, have the following image:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Image Source="/Assets/Logo.png" Width="300" RenderTransformOrigin="0.5, 0.5">
<Image.RenderTransform>
<RotateTransform x:Name="rotateTransform"/>
</Image.RenderTransform>
</Image>
</Grid>
Then, in code, write the following when you want to animate (you create the Storyboard programmatically, then add to it a relevant Timeline. Note that you can also create the RotateTransform in code if you want.
async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
await Task.Delay(500);
Storyboard board = new Storyboard();
var timeline = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTarget(timeline, rotateTransform);
Storyboard.SetTargetProperty(timeline, "Angle");
var frame = new EasingDoubleKeyFrame() { KeyTime = TimeSpan.FromSeconds(1), Value = 360, EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut } };
timeline.KeyFrames.Add(frame);
board.Children.Add(timeline);
board.Begin();
}
This will rotate the object 360 degrees.
BTW: I am writing a set of posts that show an even better way of animating. It's not done yet, but it will give you a general idea on how to get a framework for certain types of animations..
First part of the series
Thanks Shahar! I took your example and made a custom control. It's actually an infinite spinning of one ring image.
Spinner.xaml:
<UserControl x:Class="MyControls.Spinner"
...
<Grid >
<Image Source="/Assets/Images/spinner.png" Width="194" RenderTransformOrigin="0.5, 0.5">
<Image.RenderTransform>
<RotateTransform x:Name="rotateTransform"/>
</Image.RenderTransform>
</Image>
</Grid>
</UserControl>
Spinner.cs:
namespace MyControls
{
public partial class Spinner: UserControl
{
public Spinner()
{
InitializeComponent();
this.Loaded += Spinner_Loaded;
}
private void PlayRotation()
{
Storyboard board = new Storyboard();
var timeline = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTarget(timeline, rotateTransform);
Storyboard.SetTargetProperty(timeline, new PropertyPath("(Angle)"));
var frame = new EasingDoubleKeyFrame() { KeyTime = TimeSpan.FromSeconds(5), Value = 360, EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut } };
timeline.KeyFrames.Add(frame);
board.Children.Add(timeline);
board.RepeatBehavior = RepeatBehavior.Forever;
board.Begin();
}
private async void Spinner_Loaded(object sender, RoutedEventArgs e)
{
PlayRotation();
}
}
}
Then when you want to use Spinner in another xaml, it's very simple:
Just add a line for it inside any Grid etc:
<include:Spinner/>
(of course you need to define include as something like:
xmlns:include="MyControls"
on top of your xaml)

Loading image into Image UI item in WinRT

I am trying to load a picture into the Image UI item of my win8 app. But so far i couldn't get the picked image to show on the UI.
can somebody please tell me how the proper way of doing it?
Windows.Storage.Pickers.FileOpenPicker OpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
OpenPicker.FileTypeFilter.Add(".jpg");
OpenPicker.FileTypeFilter.Add(".bmp");
Windows.Storage.StorageFile picture = await OpenPicker.PickSingleFileAsync();
imgPreview.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri(picture.Path, UriKind.Absolute));
imgPreview.Stretch = Stretch.Fill;
imgPreview.Visibility = Windows.UI.Xaml.Visibility.Visible;
See my post on this here.
It should be something like this:
xaml:
<Image Margin="5" Source="{Binding BMImage}" Height="100"/>
C#:
BitmapImage bmImage;
public BitmapImage BMImage
{
get
{
return bmImage;
}
}
bmImage = new BitmapImage();
bmImage.UriSource = new Uri(new Uri(
Windows.Storage.ApplicationData.Current.TemporaryFolder.Path + "\\" +
Windows.Storage.ApplicationData.Current.TemporaryFolder.Name),
"favicon.scale-100.ico");