Click here to Skip to main content
Click here to Skip to main content

Extracting Embedded Images From An Assembly

By , 3 Apr 2006
 

Embedded Image Grabber tool

Introduction

This article examines a simple utility application, Embedded Image Grabber, which allows you to view, save, and copy images, icons, and cursors embedded in an assembly. The utility was compiled against v2.0 of the .NET framework, but the core functionality could easily be ported to v1.x, if necessary.

Background

Before looking at how Embedded Image Grabber works, let's take a moment to review what an embedded resource is. When an assembly is created, it is possible to store arbitrary files within it, such as BMPs, XML files, etc. Those files are called embedded resources. Embedding a resource within an assembly has several benefits, such as:

  • Simplifying deployment (less files to manage).
  • Simplifying resource consumption (there is no chance that the file will be missing at runtime).

You can easily embed an image into an assembly using Visual Studio .NET, by following these steps:

  1. Add an image file to a project.
  2. In Solution Explorer, right click on the image file and select Properties from the context menu.
  3. In the Properties window, select Embedded Resource for the Build Action property.
  4. Compile the project into an assembly.

As you might imagine, the .NET framework provides support for programmatic retrieval of embedded resources. We will be examining how that is implemented, later in the article.

Using the utility

There are four essential steps to using this tool:

  1. Run Embedded Image Grabber.exe.
  2. Click the Open button to locate the assembly which contains the image(s) you want to extract.
  3. Navigate to the image(s) you are interested in, via the BindingNavigator at the top of the window.
  4. Click either the Save or Copy button to persist an image to the disk or clipboard.

Tip - Steps 1 and 2 can be consolidated by simply drag-dropping the target assembly onto Embedded Image Grabber.exe.

Other features:

  • Save Options - when saving an embedded icon or cursor, you have the option of saving it either as the original type of file or as a bitmap. The Save As dialog will default to using the extension which corresponds to the original type of the embedded resource.
  • Open via Drag-Drop - In addition to being able to open the application with an assembly loaded by drag-dropping the assembly onto Embedded Image Grabber.exe, you can also load an assembly while the app is running, via drag-drop. Simply drop an assembly onto the form, and the embedded images it contains will be loaded.
  • 'All Images' tab - provides a grid view of every image in the assembly. It makes searching for an image faster.
  • Properties View - a PropertyGrid which displays detailed information about the current image. Click the rightmost button on the toolbar to show/hide this view.
  • Context Menu - provides quick access to save, copy, or show/hide properties of an image.
  • View Options - when the 'Individual Image' tab is selected, the toolbar will have a combobox which allows you to alter the way that the current image is rendered (such as zoomed, centered, etc.).

How it works

The primary method responsible for extracting images from an assembly and displaying them in the user interface is LoadImagesFromAssembly.

private void LoadImagesFromAssembly( string assemblyPath )
{
   // Try to load the assembly at the specified location.
   Assembly assembly = this.LoadAssembly( assemblyPath, true );
   if( assembly == null )
      return;

   this.currentAssembly = assembly;

   // Dispose of the images currently being displayed, if any.
   if( this.bindingSource.DataSource != null )
      foreach( ImageInfo imgInfo in this.bindingSource.DataSource 
                                      as List<ImageInfo> )
         imgInfo.Dispose();

   // Bind to a list of every image embedded in the assembly.
   this.bindingSource.DataSource = 
     this.ExtractImagesFromAssembly( this.currentAssembly );
}

As seen in the method above, the ImageGrabberForm uses a BindingSource component to orchestrate data binding. The BindingNavigator, DataGridView, PropertyGrid, and PictureBox all bind to the binding source, which makes the synchronized image navigation aspect of the GUI extremely easy to implement.

The real work of extracting images from an assembly is in the ExtractImagesFromAssembly method, as you might have guessed.

private List<ImageInfo> ExtractImagesFromAssembly( Assembly assembly )
{
   List<ImageInfo> imageInfos = new List<ImageInfo>();

   foreach( string name in assembly.GetManifestResourceNames() )
   {
      using( Stream stream = assembly.GetManifestResourceStream( name ) )
      {
         // Treat the resource as an icon.
         try
         {
            Icon icon = new Icon( stream );
            imageInfos.Add( new ImageInfo( icon, name ) );
            continue;
         }
         catch( ArgumentException )
         {
            stream.Position = 0;
         }


         // Treat the resource as a cursor.
         try
         {
            Cursor cursor = new Cursor( stream );
            imageInfos.Add( new ImageInfo( cursor, name ) );
            continue;
         }
         catch( ArgumentException )
         {
            stream.Position = 0;
         }


         // Treat the resource as an image.
         try
         {
            Image image = Image.FromStream( stream );

            // If the image is an animated GIF, do not add it to the 
            // collection because the Image class cannot handle them and
            // will throw an exception when the image is displayed.
            FrameDimension frameDim = 
               new FrameDimension( image.FrameDimensionsList[0] );
            bool isAnimatedGif = image.GetFrameCount( frameDim ) > 1;
            if( !isAnimatedGif )
               imageInfos.Add( new ImageInfo( image, name ) );
            else
               image.Dispose();

            continue;
         }
         catch( ArgumentException )
         {
            stream.Position = 0;
         }


         // Treat the resource as a resource file.
         try
         {
            // The embedded resource in the stream is not an image, so
            // read it into a ResourceReader and extract the values
            // from there.
            using( IResourceReader reader = new ResourceReader( stream ) )
            {
               foreach( DictionaryEntry entry in reader )
               {
                  if( entry.Value is Icon )
                  {
                     imageInfos.Add( new ImageInfo( entry.Value, name ) );
                  }
                  else if( entry.Value is Image )
                  {
                     imageInfos.Add( new ImageInfo( entry.Value, name ) );
                  }
                  else if( entry.Value is ImageListStreamer )
                  {
                     // Load an ImageList with the ImageListStreamer and
                     // store a reference to every image it contains.
                     using( ImageList imageList = new ImageList() )
                     {
                        imageList.ImageStream = 
                           entry.Value as ImageListStreamer;
                        foreach( Image image in imageList.Images )
                           imageInfos.Add( new ImageInfo( image, name ) );
                     }
                  }
               }
            }
         }
         catch( Exception )
         {
         }
      }            
   }

   return imageInfos;
}

The code seen above opens a stream for every named resource in the specified assembly, and then either creates an Icon from the stream or, if that fails, a Cursor, or an Image, or, if all else fails, it reads the contents of the embedded resource via a System.Resources.ResourceReader. The resource reader is necessary for extracting images, icons, and images stored in an ImageList from a resource file (.resx). The ImageInfo helper class is used to store the image and related information.

History

  • 3/25/2006 - Created article.
  • 3/26/2006 - Fixed the image saving code. It is necessary to copy the image being saved to a Bitmap before saving it, otherwise an exception can be thrown.
  • 3/27/2006 - Added code which extracts images from the ResourceReader. Also added code which extracts cursors.
  • 4/1/2006
    • Added section about other features in the utility.
    • Fixed bug where embedded animated GIFs caused the app to crash.
    • Updated the code snippets.
    • Provided new downloads for both the utility and the source code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Josh Smith
Software Developer (Senior) Cynergy Systems
United States United States
Member
Josh creates software, for iOS and Windows.
 
He works at Cynergy Systems as a Senior Experience Developer.
 
Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.
 
Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.
 
Check out his Advanced MVVM[^] book.
 
Visit his WPF blog[^] or stop by his iOS blog[^].

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberEng. Mohammed El-Said20 Aug '10 - 5:41 
Great
GeneralNew version : support for png, jpg,gif and Save All imagesmembersheyenrath7 Apr '10 - 10:36 
I've created a new version from Embedded Image Grabber which supports:
- png images
- jpg images
- gif images
- Save all images at once to a folder
 
Binary and SourceCode can be found here.
AnswerRe: New version : support for png, jpg,gif and Save All imagesmemberperilbrain14 Jul '12 - 9:52 
Please add this new version as an alternative edition to this article !!!
GeneralVC.net 2003- how ro extract an image stored in the pic boxmemberminad_78611 Apr '07 - 3:22 
Hi,
I have implemented a picture box on to which
an image can be dragged and dropped by the user.
After having done that the image has to be written to a pdf file so I need the image in the picture box.
How do I extract the image?
From what I have understood I need to use the assembly but
I dont know how.
Code samples would be very useful.
Thanks in advance for your help.
 

GeneralRe: VC.net 2003- how ro extract an image stored in the pic boxmvpJosh Smith11 Apr '07 - 4:46 
You don't need to use the technique outlined in this article for that task. That doesn't make any sense. The image in your PictureBox can be accessed via the PictureBox's Image property.
 
:josh:
My WPF Blog[^]
Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!

GeneralExtract All Images in Single ClickmemberNilesh Gambhava14 Feb '07 - 15:49 
Hi Josh,
Really Excellent Work,
 
I wanted to extract all images in a single click because Assembly contains more than 1000 Images. So I changed code little bit as below
 
private void PerformSave()
{
for (int i = 0; i < this.bindingSource.Count; i++)
{
ImageInfo imageInfo = this.bindingSource.Current as ImageInfo;
 
string filename = imageInfo.ResourceDetails.ResourceName.Replace("Microsoft.BusinessSolutions.SmallBusinessAccounting.UI.", "");
filename = filename.Replace(".resources", "");
filename += i.ToString();
if (imageInfo.ResourceDetails.ImageType == ImageType.Icon)
filename += ".ico";
else if (imageInfo.ResourceDetails.ImageType == ImageType.Cursor)
filename += ".cur";
else
filename += ".bmp";
this.SaveImage(imageInfo, "c:\\Icons\\" + filename);
this.bindingSource.MoveNext();
}
}
 
You can put it in some better way, like Save All.

 
Nilesh Gambhava,
Life is NP-Complete so don't use Algorithm but use Heuristics

GeneralRe: Extract All Images in Single ClickmvpJosh Smith14 Feb '07 - 16:23 
Thanks Nilesh. Having a 'Save All' button makes sense. I'll add it in sometime. Smile | :)
 
:josh:
My WPF Blog[^]

GeneralGreat Artical!membererikkl200029 Dec '06 - 6:58 
Thank you very much for your imageGrabber.
 
I made a little program that displays icons based on the registry extention.
 
I am having problems tring to save the icon; i keep getting errors..
 
Can you please give me suggestion on how to save an icon extracted from an assembly.
 
What i do is when ever an extention is selected from a listBox; that icon is displayed into a picture box and also displayed as the current forms icon. So i try to do a this.Icon.Save( fullPath+FileName ) and i am getting errors.
 
-------------------------------------------------------------
Here is the Error
 
Problem saving icon
Error HRESULT E_FAIL has been returned from a call to a COM component.
 

-------------------------------------------------------------
Here is a little snippet of the code.
 

if (this.sfdIcon.ShowDialog() == DialogResult.OK)
{
try
{
using (FileStream fs = new FileStream(this.sfdIcon.FileName, FileMode.Create, FileAccess.Write))
{
//Our current icon is the icon on the form.
 
this.Icon.Save(fs);
 
fs.Flush();
}
 
}
catch (Exception ex)
{
MessageBox.Show("Problem saving icon" +
Environment.NewLine +
ex.Message);
}
finally { /*img.Dispose(); img = null;*/ }
}
 

 
-------------------------------------------------------------
And here is the full program.. ( it is really small )
 
http://www.constructionsupercenter.com/SoftWare/Example/Registry/Get-Icons-By-Extentions/Get-Default-Icons[0].zip[^]
GeneralExcellent!membersam6nz3 Jul '06 - 11:50 
Have been battling to get some images out of an imagelist; finding this made it soooo easy.
 
Thankyou, I'll be keeping your app handy.
 
5!
GeneralRe: Excellent!memberJosh Smith3 Jul '06 - 12:35 
I'm glad to know that it helped! Big Grin | :-D
 
:josh:
My WPF Blog[^]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 3 Apr 2006
Article Copyright 2006 by Josh Smith
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid