UWP get shell icon for a file - c#

Most solutions here use System.Drawing which is not available in UWP afaik. GetThumbnailAsync() does the job but only for non-image files. With image files i always get a scaled preview, regardless of passed arguments.
I'd like to have a shell file icon instead of a tiny preview to the left of the file name, like here:
Any thoughts?
Thanks
PS: I have found a hack: create a 0 byte temp file with the same extension and make a thumbnail of it. I hope though there is a better solution...

Well here's a helper metod which uses the dummy file approach (place it in some static class):
public async static Task<StorageItemThumbnail> GetFileIcon(this StorageFile file, uint size = 32)
{
StorageItemThumbnail iconTmb;
var imgExt = new[] { "bmp", "gif", "jpeg", "jpg", "png" }.FirstOrDefault(ext => file.Path.ToLower().EndsWith(ext));
if (imgExt != null)
{
var dummy = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("dummy." + imgExt, CreationCollisionOption.ReplaceExisting); //may overwrite existing
iconTmb = await dummy.GetThumbnailAsync(ThumbnailMode.SingleItem, size);
}
else
{
iconTmb = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, size);
}
return iconTmb;
}
Usage example:
var icon = await file.GetFileIcon();
var img = new BitmapImage();
img.SetSource(icon);

Related

Can i get all thumbnails in my specific folder?

I want to get a thumbnail image of all photo files in a specific folder.
(Example: My C: \ Mypic)
I found another way to get a single thumbnail image, but this isn't exactly what i want
async private Task<BitmapImage> Thumbnail_call()
{
var files = await KnownFolders.PicturesLibrary.GetFilesAsync();
var thumb = await files[0].GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.PicturesView);
var bitm = new BitmapImage();
bitm.SetSource(thumb);
return bitm;
}
I think that i have to use foreach sentence
Can you give me a solution to this problem?
In UWP app, you can access certain file system locations by default. Apps can also access additional locations through the file or folder picker, or by declaring capabilities. See File access permissions for more details about accessing the folders or files.
After you get the specific folders, you can get all thumbnails in it as the following code.
async private Task<List<BitmapImage>> GetThumbnails(StorageFolder folder)
{
List<BitmapImage> BitmapImageList = new List<BitmapImage>();
var files = await folder.GetFilesAsync();
foreach (var file in files)
{
var thumb = await file.GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.PicturesView);
var bitmap = new BitmapImage();
bitmap.SetSource(thumb);
BitmapImageList.Add(bitmap);
}
return BitmapImageList;
}

xamarin.forms save file/image

coding xamarin form project and also using pcl storage. have problem with saving image or file on device all examples i found show how to save stream of byte array into file but non of them show how to turn convert image into usable format for saving.
var webImage = new Image();
webImage.Source = new UriImageSource
{
CachingEnabled = false,
Uri = new Uri("http://server.com/image.jpg"),
};
byte[] image = ????(what i need)????(webImage.Source);
// get hold of the file system
IFolder folder = rootFolder ?? FileSystem.Current.LocalStorage;
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
// populate the file with image data
using (System.IO.Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
{
stream.Write(image, 0, image.Length);
}
In other words looking for code to save image/file on device from url.
Tried ffimageloading since it contain converter to byte[], but always get error:"Object reference not set to an instance of an object." for GetImageAsJpgAsync and GetImageAsPngAsync method. problem might be that image isn't fully loaded. but finish event and finish command never get called even trough image is fully loaded on screen and bound to cachedImage.
var cachedImage = new CachedImage()
{
Source = "https://something.jpg",
FinishCommand = new Command(async () => await TEST()),
};
cachedImage.Finish += CachedImage_Finish;
var image = await cachedImage.GetImageAsJpgAsync();
With FFImageLoading (I noticed you use it):
await ImageService.Instance.LoadUrl("https://something.jpg").AsJpegStream();
If you want to get original file location, use this:
await ImageService.Instance.LoadUrl("https://something.jpg").Success((imageInfo) => { //TODO imageInfo.FilePath } ).DownloadOnly();

How to save media element's current frame?

I am developing a media player like vlc. One of it's features is saving snapshot during playback. I am able to successfully save the snapshot of any element using rendertargetbitmap class, using the following c# code.
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(RenderedGrid, width, height);
RenderedImage.Source = renderTargetBitmap;
But it does not allow to capture media element. Please help me with a workaround. I guess, I am not sure, may it be possible by extracting a thumbnail from a specific position using position of StorageItemThumbnail Class. If even so, it will be a thumbnail not an image of current frame. Someone help please. It is essential feature of my app!
in a digital signage uwp app that I developed I had also a similar requirement. Searching the web on how I can do I found that in UWP you can't directly take a screenshot of a media element due to a protection policy (for example you could create a small app that captures all the frames of a video file without DRM management).
I came up with a workaround: I have the video file locally so I can extract a single frame at a certain point and save it to disk with the same dimensions of the video rendered on screen (in this way I had a full image of the frame to use later). To doing this I wrote this function:
private async Task<string> Capture(StorageFile file, TimeSpan timeOfFrame, Size imageDimension)
{
if (file == null)
{
return null;
}
//Get FrameWidth & FrameHeight
List<string> encodingPropertiesToRetrieve = new List<string>();
encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
IDictionary<string, object> encodingProperties = await file.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];
//Get image stream
var clip = await MediaClip.CreateFromFileAsync(file);
var composition = new MediaComposition();
composition.Clips.Add(clip);
var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
//Create BMP
var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
writableBitmap.SetSource(imageStream);
//Get stream from BMP
string mediaCaptureFileName = "IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg";
var saveAsTarget = await CreateMediaFile(mediaCaptureFileName);
Stream stream = writableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writableBitmap.PixelWidth,
(uint)writableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
return saveAsTarget.Name;
}
This function save the frame to disk as image and return his filename.
In my application I had more "widget" (some of those with images, some with video) so I used this function to get the video frames and put a new image on top of the media element with the same dimensions and a higher Canvas Z-Index in order to use RenderTargetBitmap for take the final screenshot.
It's not a clean solution but it was a workaround for RenderTargetBitmap not considering MediaElement.
Edit:
I forgot a reference to an internal function in my application so I canghed the previous code and the line var file = await _mediaEngine.CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg"); is now var file = await CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg");
The async function CreateMediaFile(string fileName) simply create a new file on the disk:
public async Task<StorageFile> CreateMediaFile(string filename)
{
StorageFolder _mediaFolder = KnownFolders.PicturesLibrary;
return await _mediaFolder.CreateFileAsync(filename);
}

Creating Array of Images with source from a given folder C# Windows Desktop

Hello Everyone as the title says im trying to create array of type Image and set the source of the images in it from a folder because i have 52 png's in the folder and i dont want to add them one by one.. so is there a way to do this ?
That's what i got so far:
void DeckCard()
{
Image []Deck=new Image[52];
for(int i=0;i<=Deck.Length;i++)
{
Deck[i] = new Image();
LayoutRoot.Children.Add(Deck[i]);
Deck[i].Margin = new Thickness(0, 0, 0, 0);
Deck[i].Height = 400;
Deck[i].Width = 200;
}
}
P.S. the folder location is Assets//Cards/(here are the pictures)
How about using LINQ and Directory.GetFiles:
Image[] deck = System.IO.Directory.GetFiles("Assets\\Cards\\")
.Select(file => System.Drawing.Image.FromFile(file))
.ToArray();
EDIT
I have never developed a Windows Store application, but here is my try (note that I did not attempt to compile the following code):
Image[] cards = ApplicationData.Current.LocalFolder.GetFolderAsync("Assets\\Cards").GetResults()
.GetFilesAsync().GetResults()
.Select(file =>
{
using(IRandomAccessStream fileStream = file.OpenAsync(Windows.Storage.FileAccessMode.Read).GetResults())
{
Image image = new Image();
BitmapImage source = new BitmapImage();
source.SetSourceAsync(fileStream).GetResults();
image.Source = source;
// Modify Image properties here...
// image.Margin = new Thicknes(0, 0, 0, 0);
// ....
// You can also do LayoutRoot.Children.Add(image);
return image;
}
}).ToArray();
Phew, that was harsh!
Of course this code can be nicely refactored using async/await.
Well you've got to find the images in the directory.
Have a look at System.IO.Directory.GetFiles especially the SearchPattern overload. And if they are png's it might look something like this:
string[] straImageLocations = System.IO.Directory.GetFiles("DirectoryLocation", "*.png", SearchOption.TopDirectoryOnly);
The Search pattern is * -> Wildcard to match any characters, .png where it ends in ".png".
You then have the locations of all the files and all you need to do is load them into an image array. Along the lines of the following:
Image[] Deck = new Image[straImageLocations.Length];
for (int i = 0; i < straImageLocations.Length; i++)
{
Deck[i] = Image.FromFile(straImageLocations[i]));
}
Check this out it's speaks on Enumerating Files within a given directory: Enumerate Files
This is more efficient than GetFiles due to the fact that you have to wait until all the file names are returned from GetFiles to start using it. Enumerate allows you to start before this.
Enumerate Vs GetFiles

Taking a Picture, and saving it to Disk in a Windows 8 Metro-style App

I am ABLE to take a picture, but I am having trouble saving it to one of the KnownFolders.
Yes, I have declared the Picture Library Access Capability in Package.appxmanifest.
var ui = new CameraCaptureUI();
ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
StorageFile file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
var bitmap = new BitmapImage();
bitmap.SetSource(stream);
Photo.Source = bitmap;
StorageFolder storageFolder = KnownFolders.PicturesLibrary;
var result = await file.CopyAsync(storageFolder, "tps.jpg");
}
The code stops on the last line. What am I doing wrong?
I think you also need declare the file types!
In the Declarations tab, choose File Type Associations from Available
Declarations and click Add.
Under Properties, set the Name property to image.
In the Supported File Types box, add .jpg as a supported file type by
entering .jpg in the FileType field.

Categories