Click here to Skip to main content
11,709,844 members (69,405 online)
Click here to Skip to main content

Extracting Embedded Images From An Assembly

, 3 Apr 2006 CPOL 180.6K 11.4K 127
Rate this:
Please Sign up or sign in to vote.
A tool which allows you to view, save, and copy an image embedded in any assembly.

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)

Share

About the Author

Josh Smith
Software Developer (Senior) Cynergy Systems
United States United States
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[^].

You may also be interested in...

Comments and Discussions

 
QuestionThe specified file is not a .NET assembly. Pin
Member 843063116-Oct-14 4:19
memberMember 843063116-Oct-14 4:19 
AnswerRe: The specified file is not a .NET assembly. Pin
sartoris17-Apr-15 14:10
membersartoris17-Apr-15 14:10 
GeneralRe: The specified file is not a .NET assembly. Pin
heulendoch13-Jul-15 23:42
memberheulendoch13-Jul-15 23:42 
QuestionAdded All Requests From Everyone - New Version Uploaded Pin
LatencyXXX9-Apr-14 20:57
memberLatencyXXX9-Apr-14 20:57 
AnswerRe: Added All Requests From Everyone - New Version Uploaded Pin
Member 109202432-Jul-14 9:53
memberMember 109202432-Jul-14 9:53 
GeneralRe: Added All Requests From Everyone - New Version Uploaded Pin
LatencyXXX2-Jul-14 14:42
memberLatencyXXX2-Jul-14 14:42 
GeneralMy vote of 5 Pin
Eng. Mohammed El-Said20-Aug-10 5:41
memberEng. Mohammed El-Said20-Aug-10 5:41 
GeneralNew version : support for png, jpg,gif and Save All images Pin
sheyenrath7-Apr-10 10:36
membersheyenrath7-Apr-10 10:36 
AnswerRe: New version : support for png, jpg,gif and Save All images Pin
perilbrain14-Jul-12 9:52
memberperilbrain14-Jul-12 9:52 
GeneralVC.net 2003- how ro extract an image stored in the pic box Pin
minad_78611-Apr-07 3:22
memberminad_78611-Apr-07 3:22 
GeneralRe: VC.net 2003- how ro extract an image stored in the pic box Pin
Josh Smith11-Apr-07 4:46
mvpJosh Smith11-Apr-07 4:46 
GeneralExtract All Images in Single Click Pin
Nilesh Gambhava14-Feb-07 15:49
memberNilesh Gambhava14-Feb-07 15:49 
GeneralRe: Extract All Images in Single Click Pin
Josh Smith14-Feb-07 16:23
mvpJosh Smith14-Feb-07 16:23 
GeneralGreat Artical! Pin
erikkl200029-Dec-06 6:58
membererikkl200029-Dec-06 6:58 
GeneralExcellent! Pin
sam6nz3-Jul-06 11:50
membersam6nz3-Jul-06 11:50 
GeneralRe: Excellent! Pin
Josh Smith3-Jul-06 12:35
memberJosh Smith3-Jul-06 12:35 
QuestionWhat about other file types Pin
c-a-b-19-Apr-06 9:02
memberc-a-b-19-Apr-06 9:02 
AnswerRe: What about other file types Pin
Josh Smith19-Apr-06 10:28
memberJosh Smith19-Apr-06 10:28 
GeneralRe: What about other file types Pin
c-a-b-20-Apr-06 3:18
memberc-a-b-20-Apr-06 3:18 
GeneralEmbedding/Extracting executable Pin
zorro.tmh16-Apr-06 5:09
memberzorro.tmh16-Apr-06 5:09 
GeneralRe: Embedding/Extracting executable Pin
Josh Smith16-Apr-06 12:25
memberJosh Smith16-Apr-06 12:25 
GeneralRe: Embedding/Extracting executable Pin
Steve Hansen10-May-06 5:17
memberSteve Hansen10-May-06 5:17 
GeneralRe: Embedding/Extracting executable Pin
Josh Smith10-May-06 7:47
memberJosh Smith10-May-06 7:47 
NewsRe: Embedding/Extracting executable Pin
Steve Hansen10-May-06 12:07
memberSteve Hansen10-May-06 12:07 
GeneralRe: Embedding/Extracting executable Pin
Josh Smith10-May-06 13:03
memberJosh Smith10-May-06 13:03 
QuestionGif images? Pin
cmr_nz28-Mar-06 16:47
membercmr_nz28-Mar-06 16:47 
AnswerRe: Gif images? Pin
Josh Smith29-Mar-06 1:08
memberJosh Smith29-Mar-06 1:08 
GeneralMore suggestions Pin
Dario Marmieri27-Mar-06 20:51
memberDario Marmieri27-Mar-06 20:51 
GeneralRe: More suggestions Pin
Josh Smith28-Mar-06 1:30
memberJosh Smith28-Mar-06 1:30 
GeneralSuggestions Pin
Dario Marmieri27-Mar-06 20:31
memberDario Marmieri27-Mar-06 20:31 
GeneralRe: Suggestions Pin
Josh Smith28-Mar-06 1:27
memberJosh Smith28-Mar-06 1:27 
QuestionReplace images in an assembly? Pin
Bernhard Hofmann27-Mar-06 19:31
memberBernhard Hofmann27-Mar-06 19:31 
AnswerRe: Replace images in an assembly? Pin
Josh Smith28-Mar-06 1:25
memberJosh Smith28-Mar-06 1:25 
GeneralRe: Replace images in an assembly? Pin
tayspen4-Apr-06 14:56
membertayspen4-Apr-06 14:56 
GeneralRe: Replace images in an assembly? Pin
Boniolopez4-Apr-06 22:43
memberBoniolopez4-Apr-06 22:43 
AnswerRe: Replace images in an assembly? Pin
tayspen16-Apr-06 14:03
membertayspen16-Apr-06 14:03 
QuestionVery useful, but... Pin
Miss Litchi27-Mar-06 2:56
memberMiss Litchi27-Mar-06 2:56 
AnswerRe: Very useful, but... Pin
Josh Smith27-Mar-06 6:51
memberJosh Smith27-Mar-06 6:51 
GeneralRe: Very useful, but... Pin
Miss Litchi27-Mar-06 19:56
memberMiss Litchi27-Mar-06 19:56 
GeneralRe: Very useful, but... Pin
Josh Smith28-Mar-06 1:32
memberJosh Smith28-Mar-06 1:32 
Generalvery usefull Pin
Varindir Rajesh Mahdihar26-Mar-06 4:55
memberVarindir Rajesh Mahdihar26-Mar-06 4:55 
GeneralRe: very usefull Pin
Josh Smith26-Mar-06 5:09
memberJosh Smith26-Mar-06 5:09 
GeneralGood Job Pin
jinzhecheng25-Mar-06 17:24
memberjinzhecheng25-Mar-06 17:24 
GeneralRe: Good Job Pin
Josh Smith26-Mar-06 1:08
memberJosh Smith26-Mar-06 1:08 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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