Basically I'm trying to set a Windows 8 account picture from a "Console Application". The only API to set the picture that I found is in the WinRT API. Basically the same question (Windows 8 Set User Account Image) led me at least being able to build the hybrid, but it doesn't seem to be working.
private static async Task SetAccountPicture(string employeeId)
{
// Download image
string imagePath = DownloadImage(employeeId);
// Set account picture
Stream fileStream = File.Open(imagePath, FileMode.Open);
IRandomAccessStream winRTStream = await DotNetToWinRTStream(fileStream);
SetAccountPictureResult result = await UserInformation.SetAccountPicturesFromStreamsAsync(null, winRTStream, null);
// Clean up download file
File.Delete(imagePath);
}
public static async Task<IRandomAccessStream> DotNetToWinRTStream(Stream dotNetStream)
{
IBuffer buffer;
var inputStream = dotNetStream.AsInputStream();
using (var reader = new DataReader(inputStream))
{
await reader.LoadAsync((uint)dotNetStream.Length);
buffer = reader.DetachBuffer();
}
var memoryStream = new InMemoryRandomAccessStream();
await memoryStream.WriteAsync(buffer);
return memoryStream;
}
The SetAccountPictureResult says 'failure' without any other information. What could be happening here?
Related
I'm a newbie in UWP and i want to open a file of any type and transmit the bytes of it to the reciever. forexample for a jpg file i wrote this code:
// Create FileOpenPicker instance
FileOpenPicker fileOpenPicker = new FileOpenPicker();
// Set SuggestedStartLocation
fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
// Set ViewMode
fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
fileOpenPicker.FileTypeFilter.Clear();
fileOpenPicker.FileTypeFilter.Add(".jpg");
// Open FileOpenPicker
StorageFile file = await fileOpenPicker.PickSingleFileAsync();
byte[] bytesRead = File.ReadAllBytes(file.Path);
string Paths =
#"C:\\Users\zahraesm\Pictures\sample_reconstructed.jpg";
File.WriteAllBytes(Paths, bytesRead);
the two last lines are for writing the bytes into a file supposing in the receiver. However i keep getting the following exception:
System.InvalidOperationException: 'Synchronous operations should not be performed on the UI thread. Consider wrapping this method in Task.Run.'
Try this Code.
try {
FileOpenPicker openPicker = new FileOpenPicker {
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
FileTypeFilter = { ".jpg", ".jpeg", ".png" }
};
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null) {
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read)) {
var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0));
var LoadReader = await reader.LoadAsync((uint)fileStream.Size);
byte[] pixels = new byte[fileStream.Size];
reader.ReadBytes(pixels);
}
}
} catch (Exception ex) {
}
consider wrapping last operation in Task.Run()
await Task.Run(()=>{
byte[] bytesRead = File.ReadAllBytes(file.Path);
string Paths =
#"C:\\Users\zahraesm\Pictures\sample_reconstructed.jpg";
File.WriteAllBytes(Paths, bytesRead);
});
You should directly read the bytes from the StorageFile returned from your FilePicker, lest you end up with File permission errors in the future.
StorageFile file = await fileOpenPicker.PickSingleFileAsync();
var buffer = await FileIO.ReadBufferAsync(file);
byte[] bytes = System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(buffer);
You should also use await FileIO.WriteBytesAsync(targetFile, myBytes) to write.
Unless you have broadFileSystemAccess in your package Manifest, you should generally avoid using the System.IO API unless you know your application explicitly has permission to access files in that area (i.e., your application's local storage), and instead use Windows.Storage API's
Check MSDN for File Access Permissions for UWP apps for more information on file permissions.
And if you do use System.IO, always perform the work on the background thread via await Task.Run(() => { ... }
In my windows phone application i'm trying to create a new contact and add an image that taken from the camera, but it didn't seems to work.
No matter what i do the photo is blank.
The only way it works for me is by using an image that i added in the assets folder (and not from camera), even trying to add the image to the local assets folder and then to upload it - don't work...
(there is no error, but the contact that was added don't have a photo).
await contact.SetDisplayPictureAsync(stream.AsStream().AsInputStream());
Here is my code:
when i get the selected image from store i save it to a bitmapImage and use its pixel buffer.
public async void AddContact(string displayName, string mobile, string email, byte[] data)
{
var store = await ContactStore.CreateOrOpenAsync();
var contact = new StoredContact(store)
{
DisplayName = displayName
};
var props = await contact.GetPropertiesAsync();
props.Add(KnownContactProperties.Email, email);
props.Add(KnownContactProperties.MobileTelephone, mobile);
using (var stream = bitmap.PixelBuffer.AsStream())
{
await contact.SetDisplayPictureAsync(stream.AsInputStream());
}
await contact.SaveAsync();
}
Please help!
I was doing the same to set profile picture in for contact and it was not working. But when I get IRandomAccessStream from storage file it worked here is what I am doing
var file = await folder.GetFileAsync("filename.jpeg"));
//Or you can get file direclty from localfolder
// var file = await ApplicationData.Current.LocalFolder.GetFileAsync("filename.jpeg");
using (Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await contact.SetDisplayPictureAsync(fileStream);
}
await contact.SaveAsync();
Edit
How to Save picture to local storage using media capture.
ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg();
//Save file to local storage
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(
"MyPhoto.jpg", CreationCollisionOption.ReplaceExisting);
await mediaCapture.CapturePhotoToStorageFileAsync(imgFormat, file);
Once the image is saved in local storage you can get that image from me first example
Edit 2
If you are using File open picker you can try this.
public async void ContinueFileOpenPicker(Windows.ApplicationModel.Activation.FileOpenPickerContinuationEventArgs args)
{
if (args.Files.Count > 0)
{
var filePath = args.Files[0].Path;
StorageFile file = await Windows.Storage.StorageFile.GetFileFromPathAsync(filePath);
using (Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await contact.SetDisplayPictureAsync(fileStream);
}
}
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.
I am working on a WinRT app that is a local network playable game. I can read the user's DisplayName, and AccountPicture within the app, and display them both locally to the user via xaml. I am using the following code to get the account picture into a BitmapImage for binding within the xaml page:
private async Task<BitmapImage> GetDisplayImage()
{
BitmapImage image = null;
if (CoreApplication.MainView != null)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, async () =>
{
var stream = await Windows.System.UserProfile.UserInformation.GetAccountPicture(Windows.System.UserProfile.AccountPictureKind.LargeImage).OpenReadAsync();
image = new BitmapImage();
image.SetSource(stream);
});
}
return image;
}
I thought that it would be possible to read the stream into a byte array, and ship it when the app connects to others, and then reconstitute the byte array on the other end like so:
public static async Task<byte[]> ToArray(this IRandomAccessStream stream)
{
IBuffer buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
await stream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.ReadAhead);
await stream.FlushAsync();
return buffer.ToArray();
}
However, on the line:
await stream.FlushAsync();
I am receiving an UnauthorizedAccessException:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
It must be possible to share the profile pic with others, because I see it done elsewhere, but I cannot seem to find any information on how to do this. If anyone could point me in the right direction on this (I wonder if there is a different api I need to hook into, or if I need to set something in the App manifest..), I would be most appreciative.
You could directly read the IStorageFile returned by GetAccountPicture:
var file = UserInformation.GetAccountPicture(AccountPictureKind.LargeImage);
var buffer = await FileIO.ReadBufferAsync(file);
var bytes = buffer.ToArray();
I'm currently trying to save an stream containing a jpeg image I got back from the camera to the local storage folder. The files are being created but unfortunately contain no data at all. Here is the code I'm trying to use:
public async Task SaveToLocalFolderAsync(Stream file, string fileName)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await localFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(UsefulOperations.StreamToBytes(file));
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
public static class UsefulOperations
{
public static byte[] StreamToBytes(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
Any help saving files this way would be greatly appreciated - all help I have found online refer to saving text. I'm using the Windows.Storage namespace so it should work with Windows 8 too.
Your method SaveToLocalFolderAsync is working just fine. I tried it out on a Stream I passed in and it copied its complete contents as expected.
I guess it's a problem with the state of the stream that you are passing to the method. Maybe you just need to set its position to the beginning beforehand with file.Seek(0, SeekOrigin.Begin);. If that doesn't work, add that code to your question so we can help you.
Also, you could make your code much simpler. The following does exactly the same without the intermediate classes:
public async Task SaveToLocalFolderAsync(Stream file, string fileName)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await localFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream outputStream = await storageFile.OpenStreamForWriteAsync())
{
await file.CopyToAsync(outputStream);
}
}