Get WriteableBitmap from url in UWP? - c#

So my app gets a BitmapImage from a url, which works, and I then need to assign that image to a writeablebitmap. For the moment I have this:
Debug.WriteLine("Poster opened for loading. Url=" + e);
BitmapImage img = new BitmapImage(new Uri(e));
Backdrop.Source = img;
img.ImageOpened += async (s, e1) =>
{
WriteableBitmap wbm = new WriteableBitmap(((BitmapImage)s).PixelWidth, ((BitmapImage)s).PixelHeight);
var storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(e));
using (var stream = await storageFile.OpenReadAsync())
{
await wbm.SetSourceAsync(stream);
}
};
Which is really awful code, but it all works until StorageFile.GetFileFromApplicationUriAsync(), where I'm told the Value falls within an unexpected range. I'm guessing this is because it only acceps the "ms-appx:///" format, and not "http://". Is there any way to get this working? And eventually in a cleaner way?
I thought this would be easy, but it's a nightmare. I've been trying to do this since yesterday.
P.S. I know this might appear like a duplicate, but I have found absolutely nothing on StackOverflow that actually works.

Try this:
var httpClient = new HttpClient();
var buffer = await httpClient.GetBufferAsync(pictureUri);
var writeableBitmap = new WriteableBitmap(width, height);
using (var stream = buffer.AsStream())
{
await writeableBitmap.SetSourceAsync(stream.AsRandomAccessStream());
}

Related

Converting a Win2D CanvasRenderTarget to a BitmapImage?

I'm trying to write a function which accepts my ICanvasEffect as a parameter (which in my case is a Win2D BlendEffect), and I want to convert the CanvasRenderTarget to a BitmapImage so that I can use it in a UWP Image control:
private async Task<BitmapImage> GetBitmapImage(CancellationToken ct, ICanvasImage effect)
{
using (var target = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), 320f, 240f, 96))
{
using (var ds = target.CreateDrawingSession())
{
// Draw the image with the supplied ICanvasImage
ds.DrawImage(effect);
}
//await target.SaveAsync(outputStream, CanvasBitmapFileFormat.Jpeg).AsTask(ct);
}
}
As you see in the commented code, CanvasRenderTarget has a SaveAsync method I can use to save it to a Stream, but how?
Figured it out:
using (var stream = new InMemoryRandomAccessStream())
{
await target.SaveAsync(stream, CanvasBitmapFileFormat.Jpeg).AsTask(ct);
var bmp = new BitmapImage();
stream.Seek(0);
await bmp.SetSourceAsync(stream);
}
As you see in the commented code, CanvasRenderTarget has a SaveAsync method I can use to save it to a Stream, but how?
If you want to save it to stream, you could refer to Win2D samples.
There's many samples show that how to use CanvasRenderTarget.SaveAsync() method.
For example, Win2D-Samples/ExampleGallery/Infrastructure/AppIconGenerator.cs#L217

MVC - Load an image from URL into a bitmap. (async await)

I want to load an image from a URL in the server side, and use the await syntax if possible.
In a WPF application I could do that:
var image = new BitmapImage(new Uri("http://..."));
image.ImageOpened += (s, e) =>
{
}
In MVC, instead, I have the by default System.Drawing.Bitmap which dose not have an option to load from a URL.
Should I :
Add reference to System.Windows.Media.Imaging and use BitmapImage
class wrapping it with TaskCompletionSource.
Somehow load the image using the Bitmap class.
A working code using one of the above with async/wait would be great.
Should be quite simple:
private Task<Stream> GetStreamAsync()
{
var httpClient = new HttpClient();
return httpClient.GetStreamAsync(#"http://urlhere");
}
and call it:
private async Task GetImageAndDoStuff()
{
Stream imageStream = await GetStreamAsync();
using (Bitmap bitmap = new Bitmap(Image.FromStream(imageStream)))
{
}
}

Windows Phone ScheduleAgent grabbing images on set period

I'm attempting to follow an Windows Phone tutorial, tweaking it a bit to fit my needs. I am trying to grab a new picture every X seconds (30 for debugging) and set it as the new lockscreen background. I created a ScheduleAgent object to call it, however, it seems to be skipping a function. It does not skip this when in the MainPage.xaml.cs, which runs the exact same function.
ScheduleAgent.cs
static ScheduledAgent()
{
....<irrelevant code>....
protected override void OnInvoke(ScheduledTask task)
{
.... < Code went here that shouldn't matter > ....
}
Debug.WriteLine("Imagename = " + imageName);
DownloadImagefromServer("https://s3-us-west-2.amazonaws.com/qoutescreen/0" + imageName + ".jpg");
m.ReleaseMutex();
}
// If debugging is enabled, launch the agent again in one minute.
// debug, so run in every 30 secs
#if(DEBUG_AGENT)
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
System.Diagnostics.Debug.WriteLine("Periodic task is started again: " + task.Name);
#endif
// Call NotifyComplete to let the system know the agent is done working.
NotifyComplete();
}
//===============================================================================
private async void LockScreenChange(string filePathOfTheImage, bool isAppResource)
{
if (!LockScreenManager.IsProvidedByCurrentApplication)
{
// If you're not the provider, this call will prompt the user for permission.
// Calling RequestAccessAsync from a background agent is not allowed.
await LockScreenManager.RequestAccessAsync();
}
// Only do further work if the access is granted.
if (LockScreenManager.IsProvidedByCurrentApplication)
{
// At this stage, the app is the active lock screen background provider.
// The following code example shows the new URI schema.
// ms-appdata points to the root of the local app data folder.
// ms-appx points to the Local app install folder, to reference resources bundled in the XAP package
var schema = isAppResource ? "ms-appx:///" : "ms-appdata:///Local/";
var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
// Set the lock screen background image.
LockScreen.SetImageUri(uri);
// Get the URI of the lock screen background image.
var currentImage = LockScreen.GetImageUri();
System.Diagnostics.Debug.WriteLine("The new lock screen background image is set to {0}", currentImage.ToString());
}
}
private async Task DownloadImagefromServer(string imgUrl)
{
Debug.WriteLine("Attempting to Get Image from Server...");
WebClient client = new WebClient();
try
{
// I GET A "Cannot await Void" problem here?!?!?
//=================================================================
var result = await client.OpenReadAsync(new Uri(imgUrl, UriKind.Absolute));
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(result);
return result;
}
catch (Exception e)
{
Debug.WriteLine(e);
}
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
//client.OpenReadAsync(new Uri(imgUrl, UriKind.Absolute));
}
//------------------------------------------------------------------
//THIS FUNCTION IS NEVER HIT WHEN RUN IN THE ScheduleAgent.cs CODE, HOWEVER
// WHEN IT IS RUN INT HE MainPage.xaml.cs CODE (Which is a copy/paste) IT RUNS FINE
// WHY IS IT NOT HITTING THIS? HOW CAN I FIX IT?
//------------------------------------------------------------------
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.Result);
//img.Source = bitmap;
// Create a filename for JPEG file in isolated storage.
String tempJPEG = "DownloadedWalleper.jpg";
// Create virtual store and file stream. Check for duplicate tempJPEG files.
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
//BitmapImage bitmap = new BitmapImage();
//bitmap.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
//wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
LockScreenChange("DownloadedWalleper.jpg", false);
}
}
I would recommend using the "await" keyword. This will cause the code to pause and wait for the action to complete without needing to worry about mutexes or other thread-blocking strategies.
Unfortunately Windows Phone is missing the non-async methods on WebClient, so there's a little bit of setup, blatantly stolen from this answer.
To use async with WebClient, install the Microsoft.Bcl.Async NuGet package, and then you can use OpenReadTaskAsync
private async void DownloadImagefromServer(string imgUrl)
{
Debug.WriteLine("Attempting to Get Image from Server...");
WebClient client = new WebClient();
var result = await client.OpenReadTaskAsync(new Uri(imgUrl, UriKind.Absolute));
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(result);
//img.Source = bitmap;
... rest of your code from OpenReadCompleted goes here
}
So what happens is that execution waits for the "OpenRead" call to complete before it processes the result and then returns control.

Programmatically set the Source of an Image (XAML)

I am working on a Windows 8 app. I need to know how to programmatically set the Source of an Image. I assumed that the Silverlight approach would work. However, it doesn't. Does anybody know how to do this? The following will not work:
string pictureUrl = GetImageUrl();
Image image = new Image();
image.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri(pictureUrl, UriKind.Relative));
image.Stretch = Stretch.None;
image.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Left;
image.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center;
I get an Exception that says: "The given System.Uri cannot be converted into a Windows.Foundation.Uri."
However, I can't seem to find the Windows.Foundation.Uri type.
I just tried
Image.Source = new BitmapImage(
new Uri("http://yourdomain.com/image.jpg", UriKind.Absolute));
And it works without problems... I'm using System.Uri here. Maybe you have a malformed URI or you have to use an absolute URI and use UriKind.Absolute instead?
This is what I use:
string url = "ms-appx:///Assets/placeHolder.png";
image.Source = RandomAccessStreamReference.CreateFromUri(new Uri(url));
Well, Windows.Foundation.Uri is documented like this:
.NET: This type appears as System.Uri.
So the tricky bit isn't converting it into a Windows.Foundation.Uri yourself - it looks like WinRT does that for you. It looks like the problem is with the URI you're using. What is it relative to in this case? I suspect you really just need to find the right format for the URI.
This example uses a FileOpenPicker object to obtain the storage file.
You can use whatever method you need to access your file as a StorageFile object.
Logo is the name of the image control.
Reference the following code:
var fileOpenPicker = new FileOpenPicker();
fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
fileOpenPicker.FileTypeFilter.Add(".png");
fileOpenPicker.FileTypeFilter.Add(".jpg");
fileOpenPicker.FileTypeFilter.Add(".jpeg");
fileOpenPicker.FileTypeFilter.Add(".bmp");
var storageFile = await fileOpenPicker.PickSingleFileAsync();
if (storageFile != null)
{
// Ensure the stream is disposed once the image is loaded
using (IRandomAccessStream fileStream = await storageFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// Set the image source to the selected bitmap
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
Logo.Source = bitmapImage;
}
}
check your pictureUrl since it was what resulted in the exception.
but this should work as well
img.Source = new BitmapImage(new Uri(pictureUrl, UriKind.Absolute));
it should have nothing to do with Windows.Foundation.Uri. since winrt will handle it for you.
Try this format:
ms-appx:/Images/800x600/BackgroundTile.bmp
The given System.Uri cannot be converted into a Windows.Foundation.Uri
<Image Name="Img" Stretch="UniformToFill" />
var file = await KnownFolders.PicturesLibrary.GetFileAsync("2.jpg");
using(var fileStream = (await file.OpenAsync(Windows.Storage.FileAccessMode.Read))){
var bitImg= new BitmapImage();
bitImg.SetSource(fileStream);
Img.Source = bitImg;
}

How to dynamically download and display images in Windows8 metro app

I get image URL at runtime from the xml file reader. This image URL is pass to the below method to download it dynamically.
public void Display_Image(string MyURL)
{
BitmapImage bi = new BitmapImage();
bi.UriSource = new Uri(this.BaseUri, MyURL);
Img_Poster.Source = bi;
}
But this doesn't work. I don't get any image source. The above code works fine with static URL provided at compile time. What do I need to do more?
The method I suggested below is obsolete. However, creating a new Bitmap image created dynamically with a Uri determined at runtime IS supported and working on the RTM build of Windows 8. Display_Image(url) should work as you expect.
You can get the image stream using the CreateFromUri helper: http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.streams.streamreference.createfromuri.aspx#Y0
var stream = RandomAccessStreamReference.CreateFromUri(new Uri(imageUrl))
You should then be able to set the source of your bitmap to the RandomAccessStream that the helper returns
I've had similar problems with previously-working Bitmap code not working on Windows RT, an early attempt convinces me that it refuses to download anything unless it is going to be displayed on the UI (here, I needed to insert a 1ms delay before assigning sources just to get it to trigger the image download):
var image = .... // reference to animage on the UI
var placeholder = ... // a placeholder BitmapImage
var source = ... // uri to download
image.Source = placeholder;
var src = new BitmapImage(new Uri(source));
src.ImageOpened += (s, e) =>
{
var bi = s as BitmapImage;
image.Source = bi;
};
image.Source = src;
// Delay required to trigger download
await Task.Delay(1);
image.Source = placeholder;
Here's another solution I've tried with success:
var image = .... // reference to animage on the UI
var source = ... // uri to download
var placeholder = ... // a placeholder BitmapImage
image.Source = placeholder;
var bytes = await new HttpClient().GetByteArrayAsync(source);
var img = new BitmapImage();
await img.SetSourceAsync(bytes.AsBuffer().AsStream().AsRandomAccessStream());
image.Source = img;

Categories