I have file animaha135.gif in /Images folder, set "Build Action" as "Embedded Resource" or "Resources", I want to get this image to bitmap:
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri("pack://application:,,,/Images/animaha135.gif");
image.EndInit();
but it does not work:
Cannot locate resource 'images/animaha135.gif'.
what I do incorrectly?
solved this problem. Name of assembly was another than name of project. I set the same and my first code works
Don t build as "Embedded Resource". Build as "Resource". -> worked for me
EDIT:
use this to create your uri:
protected static Uri GetUri(string filename, Type type)
{
Assembly assembly = type.Assembly;
string assemblyName = assembly.ToString().Split(',')[0];
string uriString = String.Format("pack://application:,,,/{0};component/{1}",
assemblyName, filename);
return new Uri(uriString);
}
I used this for custom shadereffects
If you use embeed resources, you need read assembly maniffest
private void LoadImg()
{
//x is name of <Image name="x"/>
x.Source = GetResourceTextFile(GetResourcePath("Images/animaha135.gif"));
}
private string GetResourcePath(string path)
{
return path.Replace("/", ".");
}
public BitmapFrame GetResourceTextFile(string filename)
{
string result = string.Empty;
using (Stream stream = this.GetType().Assembly.GetManifestResourceStream(String.Format("{0}.{1}",this.GetType().Assembly.GetName().Name,filename)))
{
BitmapFrame bmp = BitmapFrame.Create(stream);
return bmp;
}
}
Other solution (return Bitmap):
//Use BitmapImage bitmap = GetResourceTextFile(GetResourcePath("Images/animaha135.gif"));
public BitmapImage GetResourceTextFile(string filename)
{
string result = string.Empty;
using (Stream stream = this.GetType().Assembly.GetManifestResourceStream(String.Format("{0}.{1}",this.GetType().Assembly.GetName().Name,filename)))
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = stream;
bi.EndInit();
return bi;
}
}
Note: Embed resources replace path => / by .
Related
I am attempting to copy a selected image to a folder and then want to display it with an Image object. The copying works fine, but when I want to display it it seems like the program cannot find it. Displaying the image only works if I manually use "add existing Item". Is there a way to add it automatically?
Here is my code:
string name = "image1";
OpenFileDialog dialog = new OpenFileDialog();
Nullable<bool> dialogOK = dialog.ShowDialog();
if(dialogOK == true)
{
File.Copy(dialog.FileName, #"..\..\Images\" + name + ".png", true);
image.Source = new BitmapImage(new Uri(#"Images\" + name + ".png", UriKind.Relative));
}
("image" is defined in xaml)
It seems safer to use an absolute path for loading the BitmapImage:
var dialog = new OpenFileDialog();
if (dialog.ShowDialog() == true)
{
var targetFile = #"..\..\Images\" + name + ".png";
var currentDir = Environment.CurrentDirectory;
var targetPath = Path.Combine(currentDir, targetFile);
var targetDir = Path.GetDirectoryName(targetPath);
Directory.CreateDirectory(targetDir);
File.Copy(dialog.FileName, targetPath, true);
image.Source = new BitmapImage(new Uri(targetPath));
}
In order to release the file directly after loading the BitmapImage, load it from a FileStream:
BitmapImage bitmap = new BitmapImage();
using (var stream = File.OpenRead(targetPath))
{
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
image.Source = bitmap;
I'm developing a small application which will get RAW image files, convert them to low quality JPEG's then load those JPEG's as thumbnails into a Grid.
My problem: I am having issues with the UI getting blocked while the images are being converted. I am dynamically adding controls to host those images in the grid just after the conversion is taking place for each image. Also I am binding those images to my Image control's Source with my ControlProperties ViewModel in code-behind.
My coding:
Here I am creating a new instance of my ControlProperties view model and inside I am doing the image conversion at the ImageSource.
cp = new ControlProperties()
{
ImageId = controlCount += 1, ImageSource = ThumbnailCreator.CreateThumbnail(imagePath)
};
My question:
Seeing as the images take a while to load, I am in need to get full control of my UI while they are being converted and added into my grid, but I am not getting it right at all. Can someone please help me with some advice or coding snippets to get me going please?
My ThumbnailCreator class
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace SomeProjName
{
public class ThumbnailCreator
{
private static string imageLocation;
private static int currentImage;
public static BitmapImage CreateThumbnail(string oldImagePath)
{
ConvertHighQualityRAWImage(oldImagePath);
if (imageLocation != string.Empty && imageLocation != null)
return OpenImage(imageLocation);
else return null;
}
//Creates low quality JPG image from RAW image
private static void ConvertHighQualityRAWImage(string oldImagePath)
{
BitmapImage image = new BitmapImage(new Uri(oldImagePath));
var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
encoder.Frames.Add(BitmapFrame.Create(image));
using (var filestream = new FileStream(GetImageLocation(), FileMode.Create))
encoder.Save(filestream);
image.UriSource = null;
image.StreamSource = null;
image = null;
GC.WaitForPendingFinalizers();
GC.Collect();
}
//Returns low quality JPG thumbnail to calling method
private static BitmapImage OpenImage(string imagePath)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.DecodePixelWidth = 283;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(imagePath, UriKind.Relative);
image.EndInit();
DeleteImage();
return image;
}
private static string GetImageLocation()
{
imageLocation = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "thumbnails")).FullName + GetCurrentImage();
return imageLocation;
}
private static string GetCurrentImage()
{
return "\\" + (currentImage += 1).ToString() + ".jpg";
}
private static void DeleteImage()
{
if (File.Exists(imageLocation))
File.Delete(imageLocation);
}
}
}
You don't need to save your thumbnails to file. Use a MemoryStream instead:
public class ThumbnailCreator
{
public static BitmapImage CreateThumbnail(string imagePath)
{
BitmapFrame source;
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
source = BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
var encoder = new JpegBitmapEncoder() { QualityLevel = 17 };
encoder.Frames.Add(BitmapFrame.Create(source));
var bitmap = new BitmapImage();
using (var stream = new MemoryStream())
{
encoder.Save(stream);
stream.Position = 0;
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
return bitmap;
}
The intermediate encoding and decoding pass doesn't even seem to be necessary, so you could simply write this:
public class ThumbnailCreator
{
public static BitmapImage CreateThumbnail(string imagePath)
{
var bitmap = new BitmapImage();
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
return bitmap;
}
}
If you want to call the CreateThumbnail method asynchronously, use Task.Run():
cp.ImageSource = await Task.Run(() => ThumbnailCreator.CreateThumbnail(fileName));
Final Solution:
I just want to add this comment to Clemens solution. I also use the Garbage Collector to stop massive memory usage build-up when loading a lot of images. Here is the final method that I use to create the thumbnails.
public static BitmapImage CreateThumbnail(string imagePath)
{
var bitmap = new BitmapImage();
using (var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
bitmap.BeginInit();
bitmap.DecodePixelWidth = 283;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
}
bitmap.Freeze();
GC.WaitForPendingFinalizers();
GC.Collect();
return bitmap;
}
My goal is to draw image "someImage.png", which is embedded resource, on WPF window, in overridden OnRender method:
protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);
drawingContext.DrawImage(ImageSource, Rect);
}
I found code to get my image from resources to Stream:
public BitmapSource GetSourceForOnRender()
{
System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
Stream myStream = myAssembly.GetManifestResourceStream("KisserConsole.someImage.png");
// What to do now?
return //BitmapSource
}
But how can i get or create BitmapSource now?
You can create a BitmapImage from the stream by setting its StreamSource property:
public BitmapSource GetSourceForOnRender()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var bitmap = new BitmapImage();
using (var stream =
assembly.GetManifestResourceStream("KisserConsole.someImage.png"))
{
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
}
return bitmap;
}
That said, you would usually create a BitmapImage from a Resource File Pack URI, like e.g.
new BitmapImage(new Uri(
"pack://application:,,,/KisserConsole.someImage.png"));
You can try to use this:
Uri uri = new Uri( $"pack://application:,,,/YourAssemblyName;component/Resources/images/photo.png", UriKind.Absolute );
BitmapImage bitmap = new BitmapImage( uri );
Make sure the Build Action of the image file is set to Resource.
How can I get ImageSource from MemoryStream in WPF using c# ? or convert MemoryStream to ImageSource to display it as image in wpf ?
using (MemoryStream memoryStream = ...)
{
var imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = memoryStream;
imageSource.EndInit();
// Assign the Source property of your image
image.Source = imageSource;
}
Additional to #Darin Dimitrov answer if you disposed the stream before assigning to Image.Source nothing will show, so be careful
For example, the Next method will not work, From one of my projects using LiteDB
public async Task<BitmapImage> DownloadImage(string id)
{
using (var stream = new MemoryStream())
{
var f = _appDbManager.DataStorage.FindById(id);
f.CopyTo(stream);
var imageSource = new BitmapImage {CacheOption = BitmapCacheOption.OnLoad};
imageSource.BeginInit();
imageSource.StreamSource = stream;
imageSource.EndInit();
return imageSource;
}
}
you can not use returned imageSource from the last function
But this implementation will work
public async Task<BitmapImage> DownloadImage(string id)
{
// TODO: [Note] Bug due to memory leaks, if we used Using( var stream = new MemoryStream()), we will lost the stream, and nothing will shown
var stream = new MemoryStream();
var f = _appDbManager.DataStorage.FindById(id);
f.CopyTo(stream);
var imageSource = new BitmapImage {CacheOption = BitmapCacheOption.OnLoad};
imageSource.BeginInit();
imageSource.StreamSource = stream;
imageSource.EndInit();
return imageSource;
}
I am using visual studio 2010, (desktop application) and using LINQ to SQL to save image/video or audio files to database in dataType VarBinary (MAX). This I can do... Problem is, I can't get them and display them in xaml because I can't get the converting part correct. Here is what I have so far (though its not working);
private void bt_Click (object sender, RoutedEventArgs e)
{
databaseDataContext context = new databaseDataContext();
var imageValue = from s in context.Images
where s.imageID == 2
select s.imageFile;
value = imageValue.Single().ToString();
//convert to string and taking down to next method to get converted in image
}
public string value { get; set; }
public object ImageSource //taking from http://stackoverflow.com/
{
get
{
BitmapImage image = new BitmapImage();
try
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.UriSource = new Uri(value, UriKind.Absolute);
image.EndInit();
Grid.Children.Add(image);
}
catch { return DependencyProperty.UnsetValue; } return image;
}
}
I not even sure if I am on the correct track? And I am assuming that video or audio is quite similar methods?
Since your image is stored in binary format in the database, you want to "stream" this into an image object by leveraging the MemoryStream object.
Looking at your code, your solution will look something like this:
BitmapImage bmpImage = new BitmapImage();
MemoryStream msImageStream = new MemoryStream();
msImageStream.Write(value, 0, value.Length);
bmpCardImage.BeginInit();
bmpCardImage.StreamSource = new MemoryStream(msImageStream.ToArray());
bmpCardImage.EndInit();
image.Source = bmpCardImage;
It's very easy, if you have a binary data and want to create an Image object, use this code:
public Image BinaryToImage(byte[] binaryData)
{
MemoryStream ms = new MemoryStream(binaryData);
Image img = Image.FromStream(ms);
return img;
}
If you already have the bytes, to verify that what you saved is correct you can save the bytes to a file and open it....
string tempFile = Path.GetTempFileName();
MemoryStream ms = new MemoryStream(bytes); //bytes that was read from the db
//Here I assume that you're reading a png image, you can put any extension you like is a file name
FileStream stream = new FileStream(tempFile + ".png", FileMode.Create);
ms.WriteTo(stream);
ms.Close();
stream.Close();
//And here we open the file with the default program
Process.Start(tempFile + ".png");
And later you can use the answer of Dillie-O and stream....
Dillie-O's code makes for a very nice extension method:
// from http://stackoverflow.com/questions/5623264/how-to-convert-varbinary-into-image-or-video-when-retrieved-from-database-in-c:
public static BitmapImage ToImage(this Binary b)
{
if (b == null)
return null;
var binary = b.ToArray();
var image = new BitmapImage();
var ms = new MemoryStream();
ms.Write(binary, 0, binary.Length);
image.BeginInit();
image.StreamSource = new MemoryStream(ms.ToArray());
image.EndInit();
return image;
}