How to get dragover image from webView to Bitmap (UWP C#) - c#

I want to drag&drop image on website to Canvas on Xaml.
But it is not acceptable, because dragged data is not image data but html data.
So I try to get dragover thumbnail image.
But I don't know how to access dragover thumbnail image.
How can I access dragover thumbnail image. I want to know those code. C#.
--Xaml--
<WebView x:Name="WebView" Source="https://google.com" ScriptNotify="Notify" NavigationCompleted="Completed" ></WebView>
<Canvas x:Name="Board" AllowDrop="True" DragOver="dragOver" Drop="drop" Background="White"></Canvas>
--C#--
private void dragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
e.DragUIOverride.IsContentVisible = true; // I want to get this content data. To bitmap.
}

You can use the following code to get the BitmapImage from DragEventArgs
if (e.DataView.Contains(StandardDataFormats.Bitmap))
{
try
{
var a = await e.DataView.GetBitmapAsync();
var c = await a.OpenReadAsync();
BitmapImage b = new BitmapImage();
b.SetSource(c);
MyCanvasImage.Source = b;
}
catch (Exception) { }
}

Related

Get Image source from Image after uploading

I am currently following walk through on how to upload an image from a phone's photo gallery link here to allow users to upload an image to my application which they can set as their profile picture. I am able to get an image from the phone's gallery however when I try and save, I cannot retrieve the image source from the xaml.
Below is the xaml for the image and the button that the user clicks on to upload an image.
<Button Text="Pick a Profile Image"
Clicked="OnPictureButton_Clicked"
Grid.Column="0"></Button>
<Image Source="{Binding Employee.ProfilePicture}"
Grid.Column="1"
x:Name="profilePicture"
Grid.RowSpan="2"
WidthRequest="200"></Image>
Here is the corresponding c# code:
private async void OnPictureButton_Clicked(object sender, EventArgs e)
{
(sender as Button).IsEnabled = false;
// _stream is a private global variable
// Allow the user to view images on the phone
_stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamASync();
// If they select an image, set it as the source for profilePicture
if (_stream != null)
{
profilePicture.Source = ImageSource.FromStream(() => _stream);
}
(sender as Button).IsEnabled = true;
}
private async void Clicked_EmployeeSaved(object sender, EventArgs e)
{
var data = (EmployeeFull)BindingContext;
var uploadedPicture = profilePicture.Source; // Should be uploaded image
// Testing how to get the source for the image (Can disregard for question)
Bitmap bitmap = BitmapFactory.DecodeStream(_stream);
MemoryStream ms = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, ms);
byte[] byteArray;
byteArray = ms.ToArray();
}
Now, I know that once the user selects an image from the gallery on their device, the stream closes and so I will be unable to access it later on in the code, like I have tried in the second function shown.
However, I am unable to retrieve the name of the image that I have selected to upload. On the screen, the user is able to see this image as I have set the selected image as the source for the profilePicture tag but when I try and get that source when the user clicks 'save', it shows an ImageSource` object, not a string which I expected.
Is there another way I can get the uploaded image's name?
If you are sure the ImageSource is a stream, you can use a cast ImageSource to StreamImageSource, and then get the stream from that.
Example:
var imageStreamSource = (StreamImageSource)profilePicture.Source;
Stream actualStream = await imageStreamSource.Stream(new CancellationToken());

UI freezes at the moment Image control loads BitmapImage [duplicate]

This question already has an answer here:
Load a large BitmapImage asynchronously
(1 answer)
Closed 2 years ago.
My WPF MVVM application loads an image from the given URL asynchronously, through Webclient.DownloadFileAsync(url, fileLocation). That process goes fine and smooth, no freezes at all when downloading a picture. But the problem occurs when I present the image file to the user - an application becomes unresponsive.
After file is downloaded, I assign the image file to the BitmapImage:
public async void LoadFileToBitmapImage(string filePath)
{
_isDownloading = false;
await FileToBitmapImage(filePath);
}
public Task FileToBitmapImage(string filePath)
{
return Task.Run(() =>
{
var executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var imageLocation = Path.Combine(executableLocation, filePath);
var bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(imageLocation);
bi.EndInit();
bi.Freeze();
Image = bi;
});
}
Image.cs:
private BitmapImage _image;
public BitmapImage Image
{
get => _image;
set
{
_image = value;
NotifyOfPropertyChange("Image");
}
}
XAML Image Binding:
<Image Source="{Binding Image, IsAsync=True}" Margin="3"/>
The problem occurs when the image is downloaded and presenting it to the user. The bigger an image, the more time it takes to present an image to the user and the more time an application is unresponsive.
I tried clicking pause at that very time when the application freezes to check threads and get the following info and unfortunately it doesn't provide me with any information.
Any help will be much appreciated!
Edit
Worth noting that application becomes unresponsive after PropertyChanged event is raised, not before. Maybe it's something to do with rendering an image to the UI?
first, if you save the image, change the binding to a string/uri directly, no BitmapImage, no nned to create it, Wpf handle that for you
public BitmapImage Image ===> public Uri Image
and remove FileToBitmapImage.
I spent a few days to find a simple solution to this problem. I needed to display over a hundred images in high quality without UI freezing.
I tried various modifications of the binding and so on in the end only the creation of the Image control through the code and set of the Source property worked before Image appeared in the tree of interface elements.
In XAML only empty ContentControl:
<ContentControl x:Name="ImageContent"/>
In code:
static readonly ConcurrentExclusiveSchedulerPair _pair = new ConcurrentExclusiveSchedulerPair();
// Works for very big images
public void LoadImage(Uri imageUri)
{
var image = new System.Windows.Controls.Image(); // On UI thread
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
Task.Factory.StartNew(() =>
{
var source = new BitmapImage(imageUri); // load ImageSource
Dispatcher.RunOnMainThread(() =>
{
image.Source = source; // Set source while not in UI
// Add image in UI tree
ImageContent.Content = image; // ImageContent is empty ContentControl
ImageContent.InvalidateVisual();
});
}, default, TaskCreationOptions.LongRunning, _pair.ExclusiveScheduler);
}
Works better with loading image with CacheOption OnLoad.
public static ImageSource BitmapFromUri(Uri source)
{
if (source == null)
return new BitmapImage(source);
using (var fs = new FileStream(source.LocalPath, FileMode.Open))
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = fs;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
}

WebView to WebViewBrush - XAML

I am trying to convert my WebView to a WebViewBrush in order to print it, in my UWP (C#/XAML) app.
I've set up my WebView, and the Brush such that when I click a button the WebView is hidden and the WebViewBrush gets displayed.
This is the XAML:
<WebView ext:Extension.HtmlString="{Binding Html}"
x:Name="saveWebView"
Grid.Row="1"
Grid.Column="0" />
<Rectangle Height="400" x:Name="saveWebViewBrush" />
When I click the button to show the Brush, basically it's only taking a snapshot of what was visible in the WebView. What I want is to take a snapshot of the entire WebView (and not the scrollbars either!).
The only other person I've seen attempt this was https://stackoverflow.com/a/17222629/2884981 - but unfortunately that's a few years old, and when I try that solution I get a million errors stemming from InvokeScript being obsolete and InvokeScriptAsync causes breaking changes.
The C# code when I press the button is this:
private async void OnButtonClick(object sender, RoutedEventArgs e)
{
//make the rectangle visible when you want something over the top of the web content
saveWebViewBrush.Visibility = Windows.UI.Xaml.Visibility.Visible;
//if the rectangle is visible, then hit the webview and put the content in the webviewbrush
if (saveWebViewBrush.Visibility == Windows.UI.Xaml.Visibility.Visible)
{
WebViewBrush b = new WebViewBrush();
b.SourceName = "saveWebView";
b.Redraw();
saveWebViewBrush.Fill = b;
saveWebView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
If anyone knows how to convert this whole WebView to a WebView brush I'd be most grateful.
EDIT
To explain the "why", I am trying to print the contents of a WebView. It seems from what I have read that this is not possible, unless I convert it to a WebViewBrush. But if anyone has any alternative ideas I am all ears!
If anyone knows how to convert this whole WebView to a WebView brush I'd be most grateful.
To achieve this, you can try with following method:
private async void OnButtonClick(object sender, RoutedEventArgs e)
{
int width;
int height;
// get the total width and height
var widthString = await saveWebView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });
var heightString = await saveWebView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
if (!int.TryParse(widthString, out width))
{
throw new Exception("Unable to get page width");
}
if (!int.TryParse(heightString, out height))
{
throw new Exception("Unable to get page height");
}
// resize the webview to the content
saveWebView.Width = width;
saveWebView.Height = height;
WebViewBrush b = new WebViewBrush();
b.SourceName = "saveWebView";
b.Redraw();
saveWebViewBrush.Fill = b;
}
Please note that WebViewBrush.Redraw method happens asynchronously. So to make sure we can get the complete snapshot, we'd better not hide the WebView or we can add some delay before hide the WebView like:
await Task.Delay(500);
saveWebView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
Once we have the "saveWebViewBrush" Rectangle, we can refer to the Printing sample or this answer to print it.

Xaml Image.Source is not updating in C#

I have some trouble with updating the source of an Image in Xaml. Im making a Windows Store App, and Im trying to set the source in my C# code. Basically, what my small program is doing is to let the user select a JPG file, and then copy this over to AppData folder. In my App, I want the picture the user have uploaded to show. Everything is working except the part where I show the image, this image does not want to change even if I provide a new source.
C# Code:
public sealed partial class MainPage : Page
{
FileOpenPicker pickerSelect;
FileSavePicker pickerSave;
StorageFolder folder;
StorageFile pic;
public MainPage()
{
this.InitializeComponent();
InitializePickers();
InitializeProfilePicture();
}
private async void InitializeProfilePicture()
{
folder = Windows.Storage.ApplicationData.Current.LocalFolder;
pic = await folder.GetFileAsync("profile.jpg");
BitmapImage uri = new BitmapImage(new Uri(pic.Path, UriKind.Absolute));
ProfilePic.Source = uri;
}
private void InitializePickers()
{
pickerSelect = new FileOpenPicker();
pickerSave = new FileSavePicker();
pickerSelect.FileTypeFilter.Add(".jpg");
}
private async void Upload_Click(object sender, RoutedEventArgs e)
{
StorageFile pictureSelect = await pickerSelect.PickSingleFileAsync();
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
await pictureSelect.CopyAsync(folder, "profile.jpg", NameCollisionOption.ReplaceExisting);
InitializeProfilePicture();
}
}
In the method "InitializeProfilePicture" I create a new BitmapImage and I set ProfilePic to this. This code is just working once, if I run the InitializeProfilePicture in the start as I do now, and the user selects a new picture and uploads to the AppData folder, the image does not change (even though the picture is indeed uploaded). If I remove the method from the start and just keep it in the Button_Click method, the new uploaded picture will be the one showing. But uploading a new picture after ProfilePic have set it's source, it will not change.
Image in Xaml is just like this
Image Width="480" Height="640" x:Name="ProfilePic" Grid.Row="1" Grid.RowSpan="2"
.. And there is also a button here to run Upload_Click method, but thats it.
Any idea why this is happening?? Should it not be updated??
You could load a BitmapImage directly from file like this:
var imageFile = await picker.PickSingleFileAsync();
var bitmap = new BitmapImage();
using (var stream = await imageFile.OpenReadAsync())
{
await bitmap.SetSourceAsync(stream);
}
ProfilePic.Source = bitmap;

WPF - How to get the URI Source of an Image?

I want to get the URI Source of an image that has been created in XAML. The source of the image is a BitmapFrame. I know you can use BitmapImage.UriSource for BitmapImages, but what about BitmapFrames?
To get the BitmapFrame I use:
private void imgs_Loaded(object sender, MouseEventArgs e)
{
Image img = (Image)sender;
BitmapFrame frame = (BitmapFrame)img.Source;
//How to get frame's UriSource?
}

Categories