Save Icon File To Hard Drive - c#

I know that this must be incredibly easy - It's unbelievable how long I have searched for an answer to this question based on how simple it is in VB6. I simply want to extract an Icon from an EXE File using Icon.ExtractAssociatedIcon, and then save this icon file to my hard drive.
So, here is what I have, and I will also show you what I have tried so you don't think I'm being lazy.
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog();
string s = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\IconData.ico";
Icon ico = Icon.ExtractAssociatedIcon(ofd.FileName);
Bitmap bmp = ico.ToBitmap();
bmp.Save(s, System.Drawing.Imaging.ImageFormat.Icon);
The above code just makes a file called "IconData.ico" on my desktop which is 0 bytes in length. Again, I am sure this must be incredibly easy to do, but for the life of my I can't figure it out.
Thank you!

You will get better results if you save the icon without first converting to a bitmap. This is because an "Icon" can contain multiple sizes whereas a bitmap is a single size chosen during the conversion.
The Icon class does not have a save to file method, but it does have a save to FileStream method, so you can save it like this:
string s = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\IconData.ico";
using (FileStream fs = new FileStream(s, FileMode.Create))
ico.Save(fs);

Related

c#/WinForms - Take file from resources and place it in directory on C: drive

I'm sure this has been done before and is probably quite simple to achieve but I can't seem to find anything on the internet when I've searched.
I'm looking for a way to pickup/copy a file from my applications resources and place it into a folder on my the C: drive. Can this be done? Or should I read in the contents of the file and then create a new one in the desired directory?Any pointers/advice would be appreciated! Thanks.
You can take the contents of the embedded file and write them out to your desired location as follows:
using (var fs = new FileStream(#"C:\Temp\Foo.txt", FileMode.Create))
using (var sw = new StreamWriter(fs))
{
var data = Stuff.Foo;
sw.Write(data);
}
I did this for a text file embedded in Stuff.resx in my project. There's a Write overload for various types so you can use what you need. For instance, an image will come back as a bitmap.
I achieved this by using File.WriteAllBytes()
Example:
File.WriteAllBytes("C:\\MyApp\\TextExample.json", MyApp.Properties.Resources.TextExample);

System.drawing.Image PathTooLong

I need to handle Images with really long paths (no way to save to shorter paths because files already exist in company). For the System.IO.path I had the same problem and found AlphaFS (can handle long paths way over 260 chars), which works perfectly. Is there any way to do the same thing for the System.drawing.Image class?
Id need that in general, but as an example I get the PathTooLong-Exception when calling Image.FromFile(path);
No, there is not. You could load the file yourself, and then read the image from a stream:
using (MemoryStream ms = new MemoryStream(yourOwnReadBytes))
{
Image i = Image.FromStream(ms);
}

while deleting image from path getting error in vb.net

I am working on windowes form application..in show button event i wrote code like this:
Me.PictureBox1.Load("C:/Signature.tif")
PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
Me.PictureBox1.BorderStyle = BorderStyle.Fixed3D
then save button click i wrote code like this:
Dim exittime As String = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")
Dim ms As New MemoryStream
Dim byt() As Byte
PictureBox1.Image.Save(ms, PictureBox1.Image.RawFormat)
byt = ms.GetBuffer
Dim sqlstr As String = "Update Visitorlogo_tbl set signimage=#pic,exittime='" & exittime & "',status=2 where PassNo='" & txtvisitorid.Text & "'"
Dim cmd1 As New SqlCommand(sqlstr, con.connect)
cmd1.Parameters.Add("#pic", SqlDbType.Image)
cmd1.Parameters("#pic").Value = byt
cmd1.ExecuteNonQuery()
con.disconnect()
PictureBox1.Image = Nothing
If System.IO.File.Exists("C:/Signature.tif") Then
System.IO.File.Delete("C:/Signature.tif")
End If
while saving image image got saving,,but after that i want to delete image from that path.. while coming to this line : System.IO.File.Delete("C:/Signature.tif") am getting error: The process cannot access the file 'C:\Signature.tif' because it is being used by another process
Possible the problem is here.
Me.PictureBox1.Load("C:/Signature.tif")
try this
Me.PictureBox1.Image = new Bitmap("C:\Signature.tif");
UPDATED:
PictureBox1.Load() method will load the file from given location and stores the file path in PictureBox.ImageLocation property. with this method, application will open that image and lock so, other user cannot modify or read it.
PictureBox1.Image = new Bitmap("filePath"); will create the another image object from given file path and it will not lock down the original one. This method will not load the original image from given file location. So, the PictureBox1.ImageLocation property will not be set here. How you can access that image and modify it.
The PictureBox will keep the file open. Therefore you can use the fix suggested by #Shell to release the file after reading the contents. This behavior is by design of the PictureBox.
http://support.microsoft.com/kb/309482
Here is a workaround adapted from the knowledge base article
Using fs as New System.IO.FileStream("C:\Signature.tif", IO.FileMode.Open, IO.FileAccess.Read)
PictureBox1.Image = System.Drawing.Image.FromStream(fs)
End Using
As the error message suggests the image is open by another process. Have you got the image open in a graphics program for example?
Do you have another instance of your application running in the background that has locked the image for reading?
If so close the other programs.

The dispose of an OpenFileDialog in C#?

I have searched throughout entire Stack Overflow, but I couldn't find an answer to the following:
When I'm using my OpenFileDialog, the files I open get blocked for use out of my program until I close my program. So if I open an image, I am not allowed to replace that image in my Windows Explorer anymore.
I think this is a problem with disposing my OpenFileDialog, but I'm not sure how to solve it...
My code:
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Title = "Open Image";
ofd.Filter = "PNG Image(*.png|*.png" +
"|GIF Image(*.gif|*.gif" +
"|Bitmap Image(*.bmp|*.bmp" +
"|JPEG Compressed Image (*.jpg|*.jpg";
if (ofd.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(ofd.FileName);
}
}
I thought that the using block would solve this problem, but nope... It still gets used by the program. I want to load the image in the picturebox and then I want the image to be available again (so I can rename it, replace it, etc...).
This is not related to the OpenFileDialog. It couldn't possibly be, because the dialog doesn't actually open the file. It just allows the user to select a file to open, and then returns that path to you so that you can write code that opens the file. Besides, you're correctly disposing of the OpenFileDialog through your use of the using statement.
The problem here comes from your actually opening the file—ofd.FileName—as a Bitmap. When you use the Bitmap constructor overload that accepts a path string, the file on disk that contains the image remains locked until the Bitmap object is disposed. So says the documentation:
The file remains locked until the Bitmap is disposed.
Because you're assigning the bitmap to pictureBox1.Image, the Bitmap object will not be disposed until pictureBox1 is disposed. And therefore your image file on disk will remain locked.
If you want to unlock the file, you will either need to make a copy of the bitmap and dispose the original, or clear out the PictureBox and dispose its previous image when you are finished with it.
As I understand your question, it sounds like you want to be able to make changes to the image file on disk while continuing to display the image in the picture box. If that's the case, you will need to make a copy. Do that using the constructor overload that takes an Image, like this:
if (ofd.ShowDialog() == DialogResult.OK)
{
// Load the image the user selected
using (Image img = Image.FromFile(ofd.FileName))
{
// Create a copy of it
Bitmap bmpCopy = new Bitmap(img);
// Clear out the bitmap currently in the picture box,
// if there is one.
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
// Assign the copy of the bitmap to the picture box.
pictureBox1.Image = bmpCopy;
}
}
As written by Chris, try something like:
pictureBox1.Image = Image.FromStream(new MemoryStream(File.ReadAllBytes(old.FileName)));
It reads all the file with File.ReadAllBytes, put it in a MemoryStream and pass the MemoryStream to the Image static initializer.
Equivalent to:
byte[] bytes = File.ReadAllBytes(old.FileName);
MemoryStream ms = new MemoryStream(bytes);
pictureBox1.Image = Image.FromStream(ms);
You mustn't dispose the MemoryStream! If/when the Image will be disposed, the finalizer of MemoryStream will kick in (if you don't have other references to ms) and the MemoryStream will be disposed (note that this isn't something that will happen immediately... It's something that will happen when the GC will run)
The technique I've found to be best is to read the file into a byte array with File.ReadAllBytes() (that opens and closes the file), and then use ImageConverter to convert the byte array into an Image. See here for example: https://stackoverflow.com/a/16576471/253938
Edit:
Quote from that previous post of mine: "Some of the other techniques I've tried have been non-optimal because they changed the bit depth of the pixels (24-bit vs. 32-bit) or ignored the image's resolution (dpi)."

C# Argument 'picture' must be a picture that can be used as an Icon

I am having trouble importing an icon into my application. I have a main form and I am trying to import to it a new icon via the Icon field in Properties.
The image is already in .ico format: this is the link to the icon I'm trying to use.
Does anyone know why Microsoft Visual Studio would be displaying this error?
Any help would be great.
I had this error recently. Some recommendations:
make sure the icon is square (16x16, 32x32)
try saving it to a PNG and using this free service for conversion : http://www.convertico.com/
We have an application that works fine on 99% of our computers, but in one laptop it pops out this error.
It looks like our issue is that the laptop user set the screen text/image size to 150%. This could cause otherwise working images no longer working. We will see whether this works.
UPDATE
A commenter seems to have the same problem. And yes, we resolved this problem by setting the screen text size to less than 150%.
After a second restart and then opening and re-saving the .ico myself in Gimp, then I was able to import it without any errors. Not too sure what caused this problem but it was just a freak error.
Credits to Xiaohuan ZHOU for the answer in this question. This function losslessly converts PNG (including transparency) to .ICO file format.
public void ConvertToIco(Image img, string file, int size)
{
Icon icon;
using (var msImg = new MemoryStream())
using (var msIco = new MemoryStream())
{
img.Save(msImg, ImageFormat.Png);
using (var bw = new BinaryWriter(msIco))
{
bw.Write((short)0); //0-1 reserved
bw.Write((short)1); //2-3 image type, 1 = icon, 2 = cursor
bw.Write((short)1); //4-5 number of images
bw.Write((byte)size); //6 image width
bw.Write((byte)size); //7 image height
bw.Write((byte)0); //8 number of colors
bw.Write((byte)0); //9 reserved
bw.Write((short)0); //10-11 color planes
bw.Write((short)32); //12-13 bits per pixel
bw.Write((int)msImg.Length); //14-17 size of image data
bw.Write(22); //18-21 offset of image data
bw.Write(msImg.ToArray()); // write image data
bw.Flush();
bw.Seek(0, SeekOrigin.Begin);
icon = new Icon(msIco);
}
}
using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write))
{
icon.Save(fs);
}
}
In my situation the error was because I used a stream and didn't ensure that the stream pointer is at the beginning.
Adding the following line before new Icon(stream) solved the problem:
stream.Seek(0, SeekOrigin.Begin);

Categories