I am attempting to create a file in the Pictures Library as documented in Microsofts UWP api.
The Pictures Library typically has the following path.
%USERPROFILE%\Pictures
I have enabled the Pictures library capability in the app manifest.
Like so:
File.WriteAllBytes("%USERPROFILE%/Pictures", fileData);
It returns:
DirectoryNotFoundException: Could not find a part of the path 'C:\Data\Users\DefaultAccount\AppData\Local\DevelopmentFiles\HoloViewerVS.Debug_x86.jtth.jh\%USERPROFILE%\Pictures'
`
When I try using my username hard-coded, like so:
File.WriteAllBytes("jtth.jh/Pictures", fileData);
it returns the same DirectoryNotFound exception:
DirectoryNotFoundException: Could not find a part of the path 'C:\Data\Users\DefaultAccount\AppData\Local\DevelopmentFiles\HoloViewerVS.Debug_x86.jtth.jh\jtth.jh\Pictures'`
So, how do you access the Pictures Library and write files to it? Clearly I must be missing something small here as the path its trying to access the pictures library at seems quite odd here.
I see it says how to 'Get the Pictures library.' using a StorageFolder:
public static StorageFolder PicturesLibrary { get; }
But I'm not sure how to add files to this folder variable like the way I'm doing it using the file write.
Can I do it the way I am trying to do it, or do I need to jump through StorageFolder and/or async hoops?
Example for clarification:
string imgName = currentFolderLoaded + "/" + temp.GetComponentInChildren<Text>().text;
//example imgName to enhance clairty
imgName = C:\dev\Users\jtth\Hololens\ProjectFolder\App\HoloApp\Data\myFiles\pics\example.png
//load image
byte[] fileData;
Texture2D tex = null;
fileData = File.ReadAllBytes(imgName);
tex = new Texture2D(2, 2);
tex.LoadImage(fileData);
//test hololens access
//previous attempt -> File.WriteAllBytes("%USERPROFILE%/Pictures", fileData);
//New attempt
AsStorageFile(fileData, imgName);
//Read Texture into RawImage component
ImgObject.GetComponent<RawImage>().material.mainTexture = tex;
//Enable component to render image in game
ImgObject.GetComponent<RawImage>().enabled = true;
Function:
private static async Task<StorageFile> AsStorageFile(byte[] byteArray, string fileName)
{
Windows.Storage.StorageFolder storageFolder = Windows.Storage.KnownFolders.PicturesLibrary;
Windows.Storage.StorageFile sampleFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
await Windows.Storage.FileIO.WriteBytesAsync(sampleFile, byteArray);
return sampleFile;
}
I'm checking the Photos app on the Hololens after running through this code and it doesn't seem to be creating the picture?
If you want your pictures showed in the Photos app on Hololens, actually you may need to save the pictures into CameraRoll folder.
But it seems like it cannot be directly saved, you may need to move the picture file as a workaround.
var cameraRollFolder = Windows.Storage.KnownFolders.CameraRoll.Path;
File.Move(_filePath, Path.Combine(cameraRollFolder, _filename));
Details please reference this similar thread.
It is because UWP applications work under isolated storage. Like the first example in your linked MSDN article says, do something like this:
StorageFolder storageFolder = KnownFolders.PicturesLibrary;
StorageFile file = await storageFolder.CreateFileAsync("sample.png", CreationCollisionOption.ReplaceExisting);
// Do something with the new file.
Plain File.Xxx() calls will be isolated to your application's own little world.
Related
I am using the media plugin for xamarin forms (by james montemagno) and the actual taking of the picture and storing it works fine, I have debugged the creation of the image on the emulator and it is stored in
/storage/emulated/0/Android/data/{APPNAME}.Android/files/Pictures/{DIRECTORYNAME}/{IMAGENAME}
however in my app it will get a list of file names from an API I want to check if the image exists in that folder.
The following works fine on IOS
var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string jpgFilename = System.IO.Path.Combine(documentsDirectory, App.IMAGE_FOLDER_NAME);
jpgFilename = System.IO.Path.Combine(jpgFilename, name);
I have tried the 2 following methods for getting it on android but both are incorrect
var documentsDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
string jpgFilename = System.IO.Path.Combine(documentsDirectory, App.IMAGE_FOLDER_NAME);
jpgFilename = System.IO.Path.Combine(jpgFilename, name);
Java.IO.File dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DataDirectory + "/" + App.IMAGE_FOLDER_NAME + "/" + name);
dir ends up as
/storage/emulated/0/data/{DIRECTORY}/{IMAGENAME}
jpgFileName ends up as /data/data/{APPNAME}.Android/files/{DIRECTORYNAME}/{IMAGENAME}
I dont want to hardcode anything in the paths but neither of these are right. I could not find anything in the GIT documentation for getting the file path except by looking at the path of the file created when taking a picture
The problem
I had the same kind of issue with Xamarin Media Plugin. For me, the problem is:
we don't really know where the plugin save the picture on android.
After reading all documentation I found, I just noted this:
... When your user takes a photo it will still store temporary data, but also if needed make a copy to the public gallery (based on platform). In the MediaFile you will now see a AlbumPath that you can query as well.
(from: Github plugin page)
so you can save your photo to your phone gallery (it will be public) but the path is known.
and we don't know what means "store the temporary data".
Solution
After investigating on how/where an app can store data, I found where the plugin stores photos on Android >> so I can generate back the full file names
In your Android app, the base path you are looking for is:
var basePath = Android.App.Application.Context.GetExternalFilesDir(null).AbsolutePath
It references your app's external private folder. It looks like that:
/storage/emulated/0/Android/data/com.mycompany.myapp/files
So finally to get your full file's path:
var fullPath = basePath + {DIRECTORYNAME} + {FILENAME};
I suggest you to make a dependency service, for instance 'ILocalFileService', that will expose this 'base path' property.
Please let me know if it works for you !
I resolved a similar problem. I wanted to collect all files for my app in a folder visible to all users.
var documentsDirectory = Android.OS.Environment.GetExternalStoragePublicDirectory(
Android.OS.Environment.DirectoryDocuments);
If you want to create Directory, add to your class using System.IO; and you have the same functions in a normal .NET application.
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
If you want to create files or directory, you can use PCLStorage.
public async Task<bool> CreateFileAsync(string name, string context)
{
// get hold of the file system
IFolder folder = FileSystem.Current.LocalStorage;
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync(name,
CreationCollisionOption.ReplaceExisting);
// populate the file with some text
await file.WriteAllTextAsync(context);
return true;
}
to get the private path
var privatePath = file.Path;
to get the public Album path
var publicAlbumPath = file.AlbumPath;
se the documentation here https://github.com/jamesmontemagno/MediaPlugin
I'm currently having trouble finding out how to implement isolated storage in a windows universal project.
All I want to do is safe some text in isolated storage when a button is clicked and the be able to retrieve it later on a different page for use.
You can use ApplicationData.Current.LocalSettings as a dictionary where you can save some primitive object.
ApplicationData.Current.LocalSettings.Values["MyKey"] = MyValue;
if (ApplicationData.Current.LocalSettings.Values.ContainsKey("MyKey"))
MyValue = ApplicationData.Current.LocalSettings.Values["MyKey"];
You can store your app data locally in UWP, e.g. ApplicationData.Current.LocalFolder, and this is 'Isolated storage' what you are talking about. Here is a code sample for you:
//Create dataFile.txt in LocalFolder and write “My text” to it
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await localFolder.CreateFileAsync("dataFile.txt");
await FileIO.WriteTextAsync(sampleFile, "My text");
//Read the first line of dataFile.txt in LocalFolder and store it in a String
StorageFile sampleFile = await localFolder.GetFileAsync("dataFile.txt");
String fileContent = await FileIO.ReadTextAsync(sampleFile);
You can also see here for more details: Getting started storing app data locally
I am in trouble with some issue about FileSavePicker. Is there any solution about saving a StorageFile without showing any popup or dialog to ask user. I want to give the current path of the storage file from code behind.
var byteArray = Convert.FromBase64String(Base64);
StorageFile file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("file.jpg", CreationCollisionOption.ReplaceExisting);
await Windows.Storage.FileIO.WriteBytesAsync(file, byteArray);
var savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("JPEG-Image", new List<string>() { ".jpg" });
savePicker.SuggestedSaveFile = file;
savePicker.PickSaveFileAsync();
...We have to use a few paths which are defined under
'Windows.Storage.KnownFolders'...
it is not so. In fact your app can access any folder on device but it will need additional permissions. The most straightforward way to obtain permission you should do next:
1) ask user to pick folder from FolderPicker
2) store selected folder to StorageApplicationPermissions.FutureAccessList
After this your app can do anything with this folder.
Code that demonstrate how to obtain permissions:
var picker = new FolderPicker();
var pfolder = await picker.PickSingleFolderAsync();
StorageApplicationPermissions.FutureAccessList.Add(pfolder);
Code that demonstrate how to create file in desired folder:
var folder = await StorageFolder.GetFolderFromPathAsync("your path");
var file = await folder.CreateFileAsync("text.txt");
using (var writer = await file.OpenStreamForWriteAsync())
{
await writer.WriteAsync(new byte[100], 0, 0);
}
But keep in mind that "your path" is folder or any of subfolder that was stored to StorageApplicationPermissions.FutureAccessList. More details here FutureAccessList
StorageFile.GetFileFromPathAsync() is probably what you are looking for. I think the file must be created beforehand for this method to work. Be aware that creating the file in some locations might need additional permissions or is even impossible (I don't know how UWP and UAC interact).
Another possibility is to use Win32 APIs inside UWP apps. Maybe this can solve your problem if the desired API is available.
I want to thank you all for your interest. I figured out the solution. If you do not want to use any dialog or prompting you can not use FileSavePicker. Here are the simple codes you need to converting Base64 string to image and save.
var byteArray = Convert.FromBase64String(Base64);
StorageFile file = await Windows.Storage.KnownFolders.SavedPictures.CreateFileAsync(
"file.jpg", CreationCollisionOption.ReplaceExisting);
await Windows.Storage.FileIO.WriteBytesAsync(file, byteArray);
I guess there is no way to give specific path. We have to use a few paths which are defined under Windows.Storage.KnownFolders. If it is not, please give some information about it.
I'm building an app that needs to take a photo with webcam and save it to the local disk, so far I have this:
async private void CapturePhoto_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg();
// create storage file in local app storage
StorageFile file = await localFolder.CreateFileAsync("TestPhoto.jpg", CreationCollisionOption.GenerateUniqueName);
StorageFile localFile = await localFolder.CreateFileAsync("webcamPhotoTest.jpg", CreationCollisionOption.ReplaceExisting);
// take photo
// save to app storage
await captureManager.CapturePhotoToStorageFileAsync(imgFormat, file);
// save to local storage
await captureManager.CapturePhotoToStorageFileAsync(imgFormat, localFile);
// Get photo as a BitmapImage
BitmapImage bmpImage = new BitmapImage(new Uri(file.Path));
// imagePreview is a <Image> object defined in XAML
imagePreview.Source = bmpImage;
}
I am able to save the jpg image both to app storage and local storage but I need to be able to
a) Specify the path to save to
b) do so without requiring user interaction (e.g windows save file prompt)
There are no support for System.Drawing in Windows 8 apps which complicates things. Most answers I've found have either been using System.Drawing features or windows' save file prompt.
You can't really use any location that you want. There is the list of locations that you can access from your app: File access and permissions in Windows Store apps. Some locations require additional declarations in the manifest file of your project.
I need to play Music Library files using file URL, that I will set to MediaPlayer object in a XAML c# object.
I constructed URI as followed
StorageFile file = await KnownFolders.MusicLibrary.GetFileAsync(track.Id);
return new Uri("file:///" + file.Path);
URI looks like this: streamingUri = {file:///C:/Users/user/Music/04 - A Train Makes A Lonely Sound.mp3}
I need URL based scheme to play so that I can reuse same logic for web streaming too.
How do I make this work?
Take a look at
this sample. It should give you some ideas of how to do media playback from file.
While I notice you are saying you need a URI-based, you should use a stream for a local file. The only part you need to extract is a call to set the MediaElement's Source. You can just make a function with 2 overrides and it should be relatively clean.
So, for a web stream:
void SetMediaElementSource(Uri webStreamUri)
{
MyMediaElement.Source = webStreamUri;
}
And for a local file:
void SetMediaElementSource(StorageFile file)
{
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
MyMediaElement.SetSource(stream, file.ContentType);
}