File: Common\Utilities\ImageLoader.cs
Project: ndp\fx\src\DataVisualization\System.Windows.Forms.DataVisualization.csproj (System.Windows.Forms.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		ImageLoader.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting.Utilities
//
//	Classes:	ImageLoader
//
//  Purpose:	ImageLoader utility class loads specified image and 
//              caches it in the memory for the future use.
//          
//              Images can be loaded from different places including 
//              Files, URIs, WebRequests and Control Resources.
//
//	Reviewed:	AG - August 7, 2002
//              AG - Microsoft 5, 2007
//
//===================================================================
 
 
#region Used Namespaces
 
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Reflection;
using System.Net;
using System.IO;
using System.Security;
using System.Resources;
 
#if Microsoft_CONTROL
	using System.Windows.Forms.DataVisualization.Charting;
#else
	using System.Web;
    using System.Web.UI.DataVisualization.Charting;
#endif
 
#endregion
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting.Utilities
#else
	namespace System.Web.UI.DataVisualization.Charting.Utilities
#endif
{
	/// <summary>
    /// ImageLoader utility class loads and returns specified image 
    /// form the File, URI, Web Request or Chart Resources. 
    /// Loaded images are stored in the internal hashtable which 
    /// allows to improve performance if image need to be used 
    /// several times.
	/// </summary>
	internal class ImageLoader : IDisposable, IServiceProvider
	{
		#region Fields
 
		// Image storage
		private Hashtable			_imageData = null;
 
		// Reference to the service container
		private IServiceContainer	_serviceContainer = null;
 
		#endregion
 
		#region Constructors and Initialization
 
		/// <summary>
		/// Default constructor is not accessible.
		/// </summary>
		private ImageLoader()
		{
		}
 
		/// <summary>
		/// Default public constructor.
		/// </summary>
		/// <param name="container">Service container.</param>
		public ImageLoader(IServiceContainer container)
		{
			if(container == null)
			{
				throw(new ArgumentNullException(SR.ExceptionImageLoaderInvalidServiceContainer));
			}
            _serviceContainer = container;
		}
 
		/// <summary>
		/// Returns Image Loader service object
		/// </summary>
		/// <param name="serviceType">Requested service type.</param>
		/// <returns>Image Loader service object.</returns>
		[EditorBrowsableAttribute(EditorBrowsableState.Never)]
		object IServiceProvider.GetService(Type serviceType)
		{
			if(serviceType == typeof(ImageLoader))
			{
				return this;
			}
			throw (new ArgumentException( SR.ExceptionImageLoaderUnsupportedType( serviceType.ToString())));
		}
 
		/// <summary>
		/// Dispose images in the hashtable
		/// </summary>
		public void Dispose()
		{
            if (_imageData != null)
			{
                foreach (DictionaryEntry entry in _imageData)
				{
                    if (entry.Value is IDisposable)
                    {
                        ((IDisposable)entry.Value).Dispose();
                    }
				}
                _imageData = null;
				GC.SuppressFinalize(this);  
			}
		}
 
		#endregion
 
		#region Methods
 
		/// <summary>
		/// Loads image from URL. Checks if image already loaded (cached).
		/// </summary>
        /// <param name="imageURL">Image name (FileName, URL, Resource).</param>
		/// <returns>Image object.</returns>
		public System.Drawing.Image LoadImage(string imageURL)
		{
			return LoadImage(imageURL, true);
		}
			
		/// <summary>
		/// Loads image from URL. Checks if image already loaded (cached).
		/// </summary>
		/// <param name="imageURL">Image name (FileName, URL, Resource).</param>
		/// <param name="saveImage">True if loaded image should be saved in cache.</param>
		/// <returns>Image object</returns>
        public System.Drawing.Image LoadImage(string imageURL, bool saveImage)
		{
            System.Drawing.Image image = null;
 
			// Check if image is defined in the chart image collection
            if (_serviceContainer != null)
			{
                Chart chart = (Chart)_serviceContainer.GetService(typeof(Chart));
				if(chart != null)
				{
					foreach(NamedImage namedImage in chart.Images)
					{
						if(namedImage.Name == imageURL)
						{
							return namedImage.Image;
						}
					}
				}
			}
 
			// Create new hashtable
            if (_imageData == null)
			{
                _imageData = new Hashtable(StringComparer.OrdinalIgnoreCase);
			}
 
			// First check if image with this name already loaded
            if (_imageData.Contains(imageURL))
			{
				image = (System.Drawing.Image)_imageData[imageURL];
			}
 
#if ! Microsoft_CONTROL
 
			// Try to load as relative URL using the Control object
			if(image == null)
			{
                Chart control = (Chart)_serviceContainer.GetService(typeof(Chart));
                if (control != null && control.Page != null)
                {
                    if (!control.IsDesignMode())
                    {
                        image = LoadFromFile(control.Page.MapPath(imageURL));
                    }
                    else if (control.IsDesignMode() && !String.IsNullOrEmpty(control.webFormDocumentURL))
                    {   
                        // Find current web page path and fileName
                        Uri pageUri = new Uri(control.webFormDocumentURL);
                        string path = pageUri.LocalPath;
                        string pageFile = pageUri.Segments[pageUri.Segments.Length-1];
 
                        // Find full image fileName
                        string imageFileRelative = control.ResolveClientUrl(imageURL);
                        string imageFile = path.Replace(pageFile, imageFileRelative);
                        
                        // Load image
                        image = LoadFromFile(imageFile);
                    }
                }
 
                else if ( HttpContext.Current != null )
                {
                    image = LoadFromFile(HttpContext.Current.Request.MapPath(imageURL));
                }
			}
#endif
 
			// Try to load image from resource
			if(image == null)
			{
                try
                {
 
                    // Check if resource class type was specified
                    int columnIndex = imageURL.IndexOf("::", StringComparison.Ordinal);
                    if (columnIndex > 0)
                    {
                        string resourceRootName = imageURL.Substring(0, columnIndex);
                        string resourceName = imageURL.Substring(columnIndex + 2);
                        System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager(resourceRootName, Assembly.GetExecutingAssembly());
                        image = (System.Drawing.Image)(resourceManager.GetObject(resourceName));
                    }
#if Microsoft_CONTROL
                    else if (Assembly.GetEntryAssembly() != null)
                    {
                        // Check if resource class type was specified
                        columnIndex = imageURL.IndexOf(':');
                        if (columnIndex > 0)
                        {
                            string resourceRootName = imageURL.Substring(0, columnIndex);
                            string resourceName = imageURL.Substring(columnIndex + 1);
                            System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager(resourceRootName, Assembly.GetEntryAssembly());
                            image = (Image)(resourceManager.GetObject(resourceName));
                        }
                        else
                        {
                            // Try to load resource from every type defined in entry assembly
                            Assembly entryAssembly = Assembly.GetEntryAssembly();
                            if (entryAssembly != null)
                            {
                                foreach (Type type in entryAssembly.GetTypes())
                                {
                                    System.Resources.ResourceManager resourceManager = new System.Resources.ResourceManager(type);
                                    try
                                    {
                                        image = (Image)(resourceManager.GetObject(imageURL));
                                    }
                                    catch (ArgumentNullException)
                                    {
                                    }
                                    catch (MissingManifestResourceException)
                                    {
                                    }
 
                                    // Check if image was loaded
                                    if (image != null)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
#endif
                }
                catch (MissingManifestResourceException)
                {
                }
			}
		
 
			// Try to load image using the Web Request
			if(image == null)
			{
				Uri	imageUri = null;
				try 
				{
					// Try to create URI directly from image URL (will work in case of absolute URL)
					imageUri = new Uri(imageURL);
				}
				catch(UriFormatException)
				{}
 
 
				// Load image from file or web resource
				if(imageUri != null)
				{
                    try
                    {
                        WebRequest request = WebRequest.Create(imageUri);
                        image = System.Drawing.Image.FromStream(request.GetResponse().GetResponseStream());
                    }
                    catch (ArgumentException)
                    {
                    }
                    catch (NotSupportedException)
                    {
                    }
                    catch (SecurityException)
                    {
                    }
				}
            }
#if Microsoft_CONTROL
            // absolute uri(without Server.MapPath)in web is not allowed. Loading from replative uri Server[Page].MapPath is done above.
            // Try to load as file
			if(image == null)
			{
 
                image = LoadFromFile(imageURL);
            }
#endif
 
            // Error loading image
			if(image == null)
			{
#if ! Microsoft_CONTROL
				throw(new ArgumentException( SR.ExceptionImageLoaderIncorrectImageUrl( imageURL ) ) );
#else
				throw(new ArgumentException( SR.ExceptionImageLoaderIncorrectImageLocation( imageURL ) ) );
#endif
            }
 
			// Save new image in cache
			if(saveImage)
			{
                _imageData[imageURL] = image;
			}
 
			return image;
		}
 
		/// <summary>
		/// Helper function which loads image from file.
		/// </summary>
		/// <param name="fileName">File name.</param>
		/// <returns>Loaded image or null.</returns>
        private System.Drawing.Image LoadFromFile(string fileName)
		{
			// Try to load image from file
			try
			{
				return System.Drawing.Image.FromFile(fileName);
			}
			catch(FileNotFoundException)
			{
				return null;
			}
		}
 
        /// <summary>
        /// Returns the image size taking the image DPI into consideration.
        /// </summary>
        /// <param name="name">Image name (FileName, URL, Resource).</param>
        /// <param name="graphics">Graphics used to calculate the image size.</param>
        /// <param name="size">Calculated size.</param>
        /// <returns>false if it fails to calculate the size, otherwise true.</returns>
        internal bool GetAdjustedImageSize(string name, Graphics graphics, ref SizeF size)
        {
            Image image = LoadImage(name);
 
            if (image == null)
                return false;
 
            GetAdjustedImageSize(image, graphics, ref size);
 
            return true;
        }
 
        /// <summary>
        /// Returns the image size taking the image DPI into consideration.
        /// </summary>
        /// <param name="image">Image for whcih to calculate the size.</param>
        /// <param name="graphics">Graphics used to calculate the image size.</param>
        /// <param name="size">Calculated size.</param>
        internal static void GetAdjustedImageSize(Image image, Graphics graphics, ref SizeF size)
        {
            if (graphics != null)
            {
                //this will work in case the image DPI is specified, otherwise the image DPI will be assumed to be same as the screen DPI
                size.Width = image.Width * graphics.DpiX / image.HorizontalResolution;
                size.Height = image.Height * graphics.DpiY / image.VerticalResolution;
            }
            else
            {
                size.Width = image.Width;
                size.Height = image.Height;
            }
        }
 
        /// <summary>
        /// Checks if the image has the same DPI as the graphics object.
        /// </summary>
        /// <param name="image">Image to be checked.</param>
        /// <param name="graphics">Graphics object to be used.</param>
        /// <returns>true if they match, otherwise false.</returns>
        internal static bool DoDpisMatch(Image image, Graphics graphics)
        {
            return graphics.DpiX == image.HorizontalResolution && graphics.DpiY == image.VerticalResolution;
        }
 
        internal static Image GetScaledImage(Image image, Graphics graphics)
        {
            Bitmap scaledImage = new Bitmap(image, new Size((int)(image.Width * graphics.DpiX / image.HorizontalResolution),
                (int)(image.Height * graphics.DpiY / image.VerticalResolution)));
 
            return scaledImage;
        }
 
 
		#endregion
	}
}