Access Denied when trying to replace file with binding in WinRT - c#

I have a WinRT app that takes pictures and displays them in an Image. The first picture correctly takes and displays the Image. However, subsequent pictures, which are set to overwrite the original picture, throw an UnauthorizedAccessException with ACCESSDENIED. I'm also binding the Image source to the Uri of the student. I'm also positive the binding is what is causing the issue in that WinRT doesn't like me replacing a file that is currently in use. I've tried setting the source to null before the file replace, etc, but that is not working. What is an elegant way to handle this? Also note that I bind this file on the page before this one also and I needed to remove the binding on that page also in order to avoid the error.
private async void btnTakePic_Click(object sender, RoutedEventArgs e)
{
await CameraCapture();
}
private async Task CameraCapture()
{
CameraCaptureUI camUI = new CameraCaptureUI();
camUI.PhotoSettings.AllowCropping = true;
camUI.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.MediumXga;
camUI.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
Windows.Storage.StorageFile imageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (imageFile != null)
{
IRandomAccessStream stream = await imageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapCamera = new BitmapImage();
bitmapCamera.SetSource(stream);
// Use unique id for image name since name could change
string filename = student.StudentID + "Photo.jpg";
await imageFile.MoveAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);
student.UriPhoto = new Uri(string.Format("ms-appdata:///local/{0}", filename), UriKind.Absolute);
}
}
Here is the binding portion just for fun:
<Image x:Name="imgStudent" Grid.Row="0" Width="400" Height="300" Margin="15" Grid.ColumnSpan="2">
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="{Binding UriPhoto}" />
</Image.Source>
</Image>

Ok, well after several hours of research, I've concluded that it is near impossible to bind to a Uri, and the alternative is to bind a BitmapImage. I couldn't find the exact reason, but it has something to do with the fact that using a Uri leaves the BitmapImage open and binding quickly breaks this paradigm. The solution is to bind the BitmapImage and set the BitmapImage to a stream, which seems to support binding quite well.
I liked the idea of the Uri since its easily seriliazable, while the BitmapImage is more difficult and takes up significantly more space (since you are serializing the picture data as opposed to a link). The solution that I decided on and that works is to serialize the Uri, and use the OnDeserialized attribute to create the BitmapImage on startup. I then needed a method/event to reset the BitmapImage whenever the Uri changed.
Here's the final code to recap:
private async Task CameraCapture()
{
CameraCaptureUI camUI = new CameraCaptureUI();
camUI.PhotoSettings.AllowCropping = true;
camUI.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.MediumXga;
camUI.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
Windows.Storage.StorageFile imageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (imageFile != null)
{
// Use unique id for image name since name could change
string filename = student.StudentID + "Photo.jpg";
// Move photo to Local Storate and overwrite existing file
await imageFile.MoveAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);
// Open file stream of photo
IRandomAccessStream stream = await imageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapCamera = new BitmapImage();
bitmapCamera.SetSource(stream);
student.BitmapPhoto = bitmapCamera // BitmapImage
// Save Uri to photo since we can serialize this and re-create BitmapPhoto on startup/deserialization
student.UriPhoto = new Uri(string.Format("ms-appdata:///local/{0}", filename), UriKind.Absolute);
}
}
And the new XAML binding to the student BitmapImage
<Image x:Name="imgStudent" Source="{Binding BitmapPhoto}" Grid.Row="0" Width="400" Height="300" Margin="15" Grid.ColumnSpan="2"/>

Related

UWP app show image from the Local folder in the WebView

I am working on a UWP app that supports both Windows 8.1 and 10. There I have a WebView to which I set some html generated in the code using NavigateToString. There I need to show some images which are in the Appdata folder e.g. AppData\Local\Packages\1bf5b84a-6650-4124-ae7f-a2910e5e8991_egahdtqjx9ddg\LocalState\c9dfd4d5-d8a9-41c6-bd08-e7f4ae70e423\4f31f54f-1b5b-4812-9463-ba23ea7988a0\Images
I have tried using ms-appdata:///local/ , file:/// , forward slashes, back slashes everything in the img src. But none of them are loading the images.
Since the above path is too long, I have a sample image at AppData\Local\Packages\1bf5b84a-6650-4124-ae7f-a2910e5e8991_egahdtqjx9ddg\LocalState\1.png and trying to access it in different ways and none of them are showing that image in the web view. But I can access that from a browser.
And if I give a http url for the img src in the below code it works.
Please let me know how I can show images in the LocalState folder in a WebView.
e.g 1.
string figures = "<figure><img src=\"ms-appdata:///local/1.png\" alt =\"aaa\" height=\"400\" width=\"400\"/><figcaption>Figure : thumb_IMG_0057_1024</figcaption></figure>";
procedureWebView.NavigateToString(figures);
e.g. 2
string figures = "<figure><img src='file:///C://Users//xxx//AppData//Local//Packages//1bf5b84a-6650-4124-ae7f-a2910e5e8991_egahdtqjx9ddg//LocalState//1.png' alt=\"thumb_IMG_0057_1024\" height=\"100\" width=\"100\"/><figcaption>Figure : thumb_IMG_0057_1024</figcaption></figure>";
Since the above path is too long, I have a sample image at AppData\Local\Packages\1bf5b84a-6650-4124-ae7f-a2910e5e8991_egahdtqjx9ddg\LocalState\1.png and trying to access it in different ways and none of them are showing that image in the web view.
WebView holds a web context,which won't have access to WinRT API or using WinRT Scheme.
But you can convert the Image to Base64 DataUri and pass it to your webview. For details about converting a picture to Base64 DataUri you can refer to Reading and Writing Base64 in the Windows Runtime.
After reading the Blog, I made a basic demo and successfully pass the image to webview.
MainPage.xaml.cs:
private async Task<String> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY= 96)
{
var encoded = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
await encoder.FlushAsync();
encoded.Seek(0);
var bytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes);
}
private async Task<String> ToBase64(WriteableBitmap bitmap)
{
var bytes = bitmap.PixelBuffer.ToArray();
return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}
private async void myBtn_Click(object sender, RoutedEventArgs e)
{
StorageFile myImage = await GetFileAsync();
ImageProperties properties = await myImage.Properties.GetImagePropertiesAsync();
WriteableBitmap bmp = new WriteableBitmap((int)properties.Width, (int)properties.Height);
bmp.SetSource(await myImage.OpenReadAsync());
String dataStr=await ToBase64(bmp);
String fileType = myImage.FileType.Substring(1);
String str = "<figure><img src=\"data:image/"+myImage.FileType+";base64,"+dataStr+"\" alt =\"aaa\" height=\"400\" width=\"400\"/><figcaption>Figure : thumb_IMG_0057_1024</figcaption></figure>";
myWebView.NavigateToString(str);
}
private async Task<StorageFile> GetFileAsync()
{
StorageFile myImage = await ApplicationData.Current.LocalFolder.GetFileAsync("myImage.jpg");
return myImage;
}
MainPage.xaml:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Center">
<WebView Name="myWebView" Width="500" Height="500" ></WebView>
<Button Name="myBtn" Click="myBtn_Click">Click Me to Load WebView</Button>
</StackPanel>
</Grid>
And here is the output:

WinRT binding an Image to a string or StorageFile

I am trying to display an image from a StorageFile after selecting it from a FilePicker. Since the Source of an Image has to be either a URI or an ImageSource, I am trying to get either of those from the StorageFile.
I am having a hard time getting data binding to work on an Image in XAML. I have tried the following:
<Image Width="300"
Height="300"
x:Name="LogoImage">
<Image.Source>
<BitmapImage UriSource="{Binding ImagePath}" />
</Image.Source>
</Image>
This way doesn't work, as the Path property of a StorageFile is not a URI. Also, I can't bind directly to the StorageFile itself, as it is not an ImageSource.
I tried to use this method:
public async Task<Image> GetImageAsync(StorageFile storageFile)
{
BitmapImage bitmapImage = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read);
bitmapImage.SetSource(stream);
Image image = new Image();
image.Source = bitmapImage;
return image;
}
But, it returns a Task<Image>, which is also not an ImageSource or URI. It seems like it should be something more straightforward than what I am trying to do, but I am just not seeing it. Also, I have tried just specifying a file in the XAML for the Image.Source and it works fine. I just haven't been able to link it up based on the selected file from the FilePicker.
My ultimate goal is: select a file from FilePicker, update the ImageSource of the displayed Image, encode to base64 for storage in database. Then later, load existing base64 string from database, convert back to Image to be displayed.
Edit:
I was able to accomplish this task using the solution I posted below. Thanks in great part to Jerry Nixon's blog post: http://blog.jerrynixon.com/2014/11/reading-and-writing-base64-in-windows.html
The best solution would be to set the source in code behind instead of using a binding as it would let you handle things like cancellation in case the ImagePath gets updated while the previous image is still loading.
Alternatively, you could create a bitmap, start a task of loading it and return before that task is complete, e.g.
public Image GetImage(StorageFile storageFile)
{
var bitmapImage = new BitmapImage();
GetImageAsync(bitmapImage, storageFile);
// Create an image or return a bitmap that's started loading
var image = new Image();
image.Source = bitmapImage;
return image ;
}
private async Task GetImageAsync(BitmapImage bitmapImage, StorageFile storageFile)
{
using (var stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read))
{
await bitmapImage.SetSource(stream);
}
}
If anyone else comes across this question looking for an answer, what I ultimately ended up doing for my situation, is take the StorageFile that is selected from the FilePicker, encode that as a base64 string (which I will save to my database for later retrieval).
Once I have the base64 string, I can decode that string into an ImageSource to set in code-behind. Here is my full ButtonClick event handler:
private async void ChooseImage_Click(object sender, RoutedEventArgs e)
{
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".jpg");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.SettingsIdentifier = "picker1";
filePicker.CommitButtonText = "Open File to Process";
var files = await filePicker.PickMultipleFilesAsync();
if (files.Count > 0)
{
// encode the storage file to base64
var base64 = await Encoding.ToBase64(files[0]);
// asynchronously save base64 string to database
// ...
// decode the base64 and set the image source
LogoImage.Source = await Encoding.FromBase64(base64);
}
}
The base64 encoding/decoding I found at the great Jerry Nixon's blog here: http://blog.jerrynixon.com/2014/11/reading-and-writing-base64-in-windows.html

Accessing images from isolated storage in XAML using "isostore:/" scheme

I've downloaded images from the web and saved them to the Isolated Storage and now I want to access those images in my XAML file, giving a Uri as a reference to them.
I have verified with IsoStoreSpy that they are stored properly where I would expect them to be and I can create BitmapImages from them if I open the file and read in the byte stream. But now I want to optimize my image handling by passing just a Uri from my model to the IsolatedStorage location and letting my XAML load the image.
<Image Height="120" Width="120" Stretch="Uniform" HorizontalAlignment="Left">
<Image.Source>
<BitmapImage UriSource="{Binding PodcastLogoUri}" DecodePixelHeight="120" DecodePixelWidth="120" />
</Image.Source>
</Image>
This is the PodcastLogoUri Uri value that is bound to BitmapImage.UriSource:
"isostore:/PodcastIcons/258393889fa6a0a0db7034c30a8d1c3322df55696137611554288265.jpg"
Here's how I've constructed it:
public Uri PodcastLogoUri
{
get
{
Uri uri = new Uri(#"isostore:/" + PodcastLogoLocation);
return uri;
}
}
Still, I can't see an image in my UI. And I am sure the image is at PodcastLogoLocation.
Should it be possible to reference images to the UI from the isolated storage like this in Windows Phone 8? What am I doing wrong?
Edit: If I create the BitmapImage directly using the same path and use the BitmapImage in XAML, it works fine and I can see the image I expect to see there:
<Image Height="120" Source="{Binding PodcastLogo}" Width="120" Stretch="Uniform" HorizontalAlignment="Left"/>
public BitmapImage PodcastLogo
{
get
{
Stream stream = null;
BitmapImage logo = new BitmapImage();
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoStore.FileExists(PodcastLogoLocation))
{
stream = isoStore.OpenFile(PodcastLogoLocation, System.IO.FileMode.Open, FileAccess.Read);
try
{
logo.SetSource(stream);
}
catch (Exception e)
{
}
}
}
return logo;
}
}
I think I've done exactly the same thing that you're trying to do. What I've found is the absolute location where the Isolated Storage stores the file using IsolatedStorageFile.GetUserStoreForApplication(). This is something like "C:/Data/Users/DefApps/AppData/<App Product ID>/Local/<YourFile.png>";
I've tested this workaround on Windows Phone 8 and it works for me...
1. XAML
<Image Width="40">
<Image.Source>
<BitmapImage DecodePixelWidth="40" DecodePixelHeight="40" UriSource="{Binding Path=Icon}" />
</Image.Source>
</Image>
2. ViewModel
private string _icon;
public string Icon
{
get
{
return _icon;
}
set
{
if (value != _icon)
{
_icon = value;
NotifyPropertyChanged("Icon");
}
}
}
3. Load data
filename = "Myicon.png";
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
if (!store.FileExists(filename))
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filename, FileMode.Create, FileAccess.Write, store))
stream.Write(imgBytes, 0, imgBytes.Length);
}
//get Product ID from manifest. Add using System.Linq; if you haven't already
Guid productId = new Guid((from manifest in System.Xml.Linq.XElement.Load("WMAppManifest.xml").Descendants("App") select manifest).SingleOrDefault().Attribute("ProductID").Value);
string storeFile = "C:/Data/Users/DefApps/AppData/" + productId.ToString("B") + "/Local/" + filename;
this.Items.Add(new MyViewModel() { Icon = storeFile });
Sadly it seems this is not possible after all. I am a bit shocked and a lot disappointed by this. Can't really understand how MS doesn't support this case.
This is the answer I got over at MSDN forums:
It Will Not Support XAML Binding Directly From Isolated Storage With
ISOStore URI Scheme.
Here is Detailed Answer For Your Answer.
http://mark.mymonster.nl/2013/05/24/yeah-windows-phone-supports-isolated-storage-access-through-an-uri-scheme-does-it
So that's it.

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;
}

Setting WPF image source in code

I'm trying to set a WPF image's source in code. The image is embedded as a resource in the project. By looking at examples I've come up with the below code. For some reason it doesn't work - the image does not show up.
By debugging I can see that the stream contains the image data. So what's wrong?
Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;
The icon is defined something like this: <Image x:Name="_icon" Width="16" Height="16" />
After having the same problem as you and doing some reading, I discovered the solution - Pack URIs.
I did the following in code:
Image finalImage = new Image();
finalImage.Width = 80;
...
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png");
logo.EndInit();
...
finalImage.Source = logo;
Or shorter, by using another BitmapImage constructor:
finalImage.Source = new BitmapImage(
new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png"));
The URI is broken out into parts:
Authority: application:///
Path: The name of a resource file that is compiled into a referenced assembly. The path must conform to the following format: AssemblyShortName[;Version][;PublicKey];component/Path
AssemblyShortName: the short name for the referenced assembly.
;Version [optional]: the version of the referenced assembly that contains the resource file. This is used when two or more referenced assemblies with the same short name are loaded.
;PublicKey [optional]: the public key that was used to sign the referenced assembly. This is used when two or more referenced assemblies with the same short name are loaded.
;component: specifies that the assembly being referred to is referenced from the local assembly.
/Path: the name of the resource file, including its path, relative to the root of the referenced assembly's project folder.
The three slashes after application: have to be replaced with commas:
Note: The authority component of a pack URI
is an embedded URI that points to a
package and must conform to RFC 2396.
Additionally, the "/" character must
be replaced with the "," character,
and reserved characters such as "%"
and "?" must be escaped. See the OPC
for details.
And of course, make sure you set the build action on your image to Resource.
var uriSource = new Uri(#"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);
This will load a image called "Untitled.png" in a folder called "Images" with its "Build Action" set to "Resource" in an assembly called "WpfApplication1".
This is a bit less code and can be done in a single line.
string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;
Very easy:
To set a menu item's image dynamically, only do the following:
MyMenuItem.ImageSource =
new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));
...whereas "icon.ico" can be located everywhere (currently it's located in the 'Resources' directory) and must be linked as Resource...
Simplest way:
var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);
This is my way:
internal static class ResourceAccessor
{
public static Uri Get(string resourcePath)
{
var uri = string.Format(
"pack://application:,,,/{0};component/{1}"
, Assembly.GetExecutingAssembly().GetName().Name
, resourcePath
);
return new Uri(uri);
}
}
Usage:
new BitmapImage(ResourceAccessor.Get("Images/1.png"))
You can also reduce this to one line. This is the code I used to set the Icon for my main window. It assumes the .ico file is marked as Content and is being copied to the output directory.
this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));
Have you tried:
Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;
If your image is stored in a ResourceDictionary, you can do it with only one line of code:
MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;
Here is an example that sets the image path dynamically (image located somewhere on disc rather than build as resource):
if (File.Exists(imagePath))
{
// Create image element to set as icon on the menu element
Image icon = new Image();
BitmapImage bmImage = new BitmapImage();
bmImage.BeginInit();
bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
bmImage.EndInit();
icon.Source = bmImage;
icon.MaxWidth = 25;
item.Icon = icon;
}
Reflections on Icons...
First thought, you would think that the Icon property can only contain an image. But it can actually contain anything! I discovered this by accident when I programmatically tried to set the Image property directly to a string with the path to an image. The result was that it did not show the image, but the actual text of the path!
This leads to an alternative to not have to make an image for the icon, but use text with a symbol font instead to display a simple "icon". The following example uses the Wingdings font which contains a "floppydisk" symbol. This symbol is really the character <, which has special meaning in XAML, so we have to use the encoded version < instead. This works like a dream! The following shows a floppydisk symbol as an icon on the menu item:
<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
<MenuItem.Icon>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings"><</Label>
</MenuItem.Icon>
</MenuItem>
There's also a simpler way. If the image is loaded as a resource in the XAML, and the code in question is the code-behind for that XAML content:
Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);
Put the frame in a VisualBrush:
VisualBrush brush = new VisualBrush { TileMode = TileMode.None };
brush.Visual = frame;
brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;
Put the VisualBrush in GeometryDrawing
GeometryDrawing drawing = new GeometryDrawing();
drawing.Brush = brush;
// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;
Now put the GeometryDrawing in a DrawingImage:
new DrawingImage(drawing);
Place this on your source of the image, and voilĂ !
You could do it a lot easier though:
<Image>
<Image.Source>
<BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
</Image.Source>
</Image>
And in code:
BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };
There's also a simpler way. If the image is loaded as a resource in the XAML, and the code in question is the codebehind for that XAML:
Here's the resource dictionary for a XAML file - the only line you care about is the ImageBrush with the key "PosterBrush" - the rest of the code is just to show context
<UserControl.Resources>
<ResourceDictionary>
<ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>
</ResourceDictionary>
</UserControl.Resources>
Now, in the code behind, you can just do this
ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];
How to load an image from embedded in resource icons and images (corrected version of Arcturus):
Suppose you want to add a button with an image. What should you do?
Add to project folder icons and put image ClickMe.png here
In properties of 'ClickMe.png', set 'BuildAction' to 'Resource'
Suppose your compiled assembly name is 'Company.ProductAssembly.dll'.
Now it's time to load our image in XAML
<Button Width="200" Height="70">
<Button.Content>
<StackPanel>
<Image Width="20" Height="20">
<Image.Source>
<BitmapImage UriSource="/Company.ProductAssembly;component/Icons/ClickMe.png"></BitmapImage>
</Image.Source>
</Image>
<TextBlock HorizontalAlignment="Center">Click me!</TextBlock>
</StackPanel>
</Button.Content>
</Button>
Done.
I am a new to WPF, but not in .NET.
I have spent five hours trying to add a PNG file to a "WPF Custom Control Library Project" in .NET 3.5 (Visual Studio 2010) and setting it as a background of an image-inherited control.
Nothing relative with URIs worked. I can not imagine why there is no method to get a URI from a resource file, through IntelliSense, maybe as:
Properties.Resources.ResourceManager.GetURI("my_image");
I've tried a lot of URIs and played with ResourceManager, and Assembly's GetManifest methods, but all there were exceptions or NULL values.
Here I pot the code that worked for me:
// Convert the image in resources to a Stream
Stream ms = new MemoryStream()
Properties.Resources.MyImage.Save(ms, ImageFormat.Png);
// Create a BitmapImage with the stream.
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();
// Set as source
Source = bitmap;
You just missed a little bit.
To get an embedded resource from any assembly, you have to mention the assembly name with your file name as I have mentioned here:
Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream(asm.GetName().Name + "." + "Desert.jpg");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
image1.Source = bitmap;
If you already have a stream and know the format, you can use something like this:
static ImageSource PngStreamToImageSource (Stream pngStream) {
var decoder = new PngBitmapDecoder(pngStream,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
return decoder.Frames[0];
}
Here is if you want to locate it next to your executable (relative from the executable)
img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + #"\Images\image.jpg", UriKind.Absolute));
Force chose UriKind will be correct:
Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));
UriKind options:
UriKind.Relative // relative path
UriKind.Absolute // exactly path

Categories