Create a custom raster type
ThumbnailBuilder\ThumbnailBuilder.cs
// Copyright 2012 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.ADF.CATIDs;
using System.Runtime.InteropServices;

namespace CustomRasterBuilder
{
    interface IThumbnailBuilder : IRasterBuilder
    {
        #region ThumbnailBuilder Members
        ///<summary>
        /// Raster Builder to which the ThumbnailBuilder is attached.
        ///</summary>
        IRasterBuilder InnerRasterBuilder
        {
            get;
            set;
        }
        #endregion
    };

    /// <summary>
    /// The Raster Type Factory class that is used to create the Custom 
    /// Raster Type.
    /// </summary>
    [Guid("C6629CC4-B301-451a-9481-4D7751E9701C")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("CustomRasterBuilder.ThumbnailFactory")]
    [ComVisible(true)]
    public class ThumbnailFactory : IRasterTypeFactory
    {
        #region Private Members
        IStringArray myRasterTypeNames; // List of Raster Types that the factory can create.
        UID myUID; // UID for the Thumbnail Raster type.
        #endregion

        #region IRasterTypeFactory Members

        public ThumbnailFactory()
        {
            // The Raster Type name should follow the pattern 
            // 'Thumbnail ' follwed by the name of the built-in 
            // Raster Type to attach the Thumbnail Builder to.            
            myRasterTypeNames = new StrArrayClass();
            myRasterTypeNames.Add("Thumbnail Raster Dataset");
            myRasterTypeNames.Add("Thumbnail QuickBird");

            myUID = new UIDClass();
            myUID.Value = "{C6629CC4-B301-451a-9481-4D7751E9701C}";
        }

        /// <summary>
        /// The UID for the factory.
        /// </summary>
        public UID CLSID
        {
            get { return myUID; }
        }

        /// <summary>
        /// The main function which creates the Raster Type object.
        /// </summary>
        /// <param name="RasterTypeName">Name of the Raster Type to create.</param>
        /// <returns></returns>
        public IRasterType CreateRasterType(string RasterTypeName)
        {
            try
            {
                switch (RasterTypeName)
                {
                    case "Thumbnail Raster Dataset":
                        {
                            // Create a Raster Type Name object.
                            IRasterTypeName theRasterTypeName = new RasterTypeNameClass();
                            // Assign the name of the built-in Raster Type to the name object.
                            // The Name field accepts a path to an .art file as well 
                            // the name for a built-in Raster Type.
                            theRasterTypeName.Name = RasterTypeName.Replace("Thumbnail ", "");
                            // Use the Open function from the IName interface to get the Raster Type object.
                            IRasterType theRasterType = (IRasterType)(((IName)theRasterTypeName).Open());
                            if (theRasterType == null)
                            {
                                Console.WriteLine("Error:Raster Type not found " + theRasterTypeName.Name);
                                return null;
                            }

                            // Create a new ThumbnailBuilder object and set it's InnerRasterBuilder property to 
                            // the RasterBuilder from the RasterType object. Then set the thumbnail builder to 
                            // be the RasterBuilder for the RasterType object. This inserts the thumbnail builder in 
                            // between the RasterType and it's RasterBuilder.

                            // Create the Thumbnail Builder 
                            IRasterBuilder thumbnailBuilder = new ThumbnailBuilder();
                            //  Set the InnerRasterBuilder property with current Raster Type's Raster Builder
                            ((ThumbnailBuilder)thumbnailBuilder).InnerRasterBuilder = theRasterType.RasterBuilder;
                            // Set the Raster Builder of theRasterType to the above created thumbnail builder.
                            theRasterType.RasterBuilder = thumbnailBuilder;
                            IName theName = theRasterType.FullName;
                            ((IRasterTypeName)theName).Name = "Thumbnail Raster Dataset";
                            return theRasterType;
                        }

                    case "Thumbnail QuickBird":
                        {
                            // Create a Raster Type Name object.
                            IRasterTypeName theRasterTypeName = new RasterTypeNameClass();
                            // Assign the name of the built-in Raster Type to the name object.
                            // The Name field accepts a path to an .art file as well 
                            // the name for a built-in Raster Type.
                            theRasterTypeName.Name = RasterTypeName.Replace("Thumbnail ", "");
                            // Use the Open function from the IName interface to get the Raster Type object.
                            IRasterType theRasterType = (IRasterType)(((IName)theRasterTypeName).Open());
                            if (theRasterType == null)
                            {
                                Console.WriteLine("Error:Raster Type not found " + theRasterTypeName.Name);
                                return null;
                            }

                            // Create a new TumbnailBuilder object and set it's InnerRasterBuilder property to 
                            // the RasterBuilder from the RasterType object. Then set the thumbnail builder to 
                            // be the RasterBuilder for the RasterType object. This inserts the thumbnail builder in 
                            // between the RasterType and it's RasterBuilder.

                            // Create the Thumbnail Builder 
                            IRasterBuilder thumbnailBuilder = new ThumbnailBuilder();
                            //  Set the InnerRasterBuilder property with current Raster Type's Raster Builder
                            ((ThumbnailBuilder)thumbnailBuilder).InnerRasterBuilder = theRasterType.RasterBuilder;
                            // Set the Raster Builder of theRasterType to the above created thumbnail builder.
                            theRasterType.RasterBuilder = thumbnailBuilder;
                            IName theName = theRasterType.FullName;
                            ((IRasterTypeName)theName).Name = "Thumbnail QuickBird";
                            return theRasterType;
                        }

                    default:
                        return null;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error: Failed to create " + RasterTypeName + ": " + ex.Message);
            }
        }

        /// <summary>
        /// Name of the Raster Type factory.
        /// </summary>
        public string Name
        {
            get { return "Thumbnail Raster Type Factory"; }
        }

        /// <summary>
        /// List of Raster Types which the factory can create.
        /// </summary>
        public IStringArray RasterTypeNames
        {
            get { return myRasterTypeNames; }
        }
        #endregion

        #region COM Registration Function(s)
        [ComRegisterFunction()]
        static void Reg(string regKey)
        {
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Register(regKey);
        }

        [ComUnregisterFunction()]
        static void Unreg(string regKey)
        {
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Unregister(regKey);
        }
        #endregion
    }

    ///<summary>
    /// This class implements the interface IThumbnailBuilder, IPersistVariant.
    ///</summary>
    [Guid("5CACFBA7-F865-4873-B57C-BE2A46E1C5E3")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("CustomRasterBuilder.ThumbnailBuilder")]
    [ComVisible(true)]
    public class ThumbnailBuilder : IThumbnailBuilder, IPersistVariant, IRasterBuilderInit
    {
        #region Private Members
        public IRasterBuilder innerRasterBuilder; // Inner Raster Builder 
        UID myUID; // UID for the Thumbnail Builder.

        /// <summary>
        /// The following function creates a field called "ThumbNail" and adds it to the existing
        /// fields in the mosaic dataset catalog as a blob.
        /// </summary>
        /// <param name="myFields">List of fields added to the Mosaic Catalog</param>
        private static void AddingNewField(IFields myFields)
        {
            IField pField = new FieldClass(); // Create a new field object
            IFieldEdit objectIDFieldEditor = (IFieldEdit)pField; // Set the field editor for this field
            objectIDFieldEditor.Name_2 = "ThumbNail"; // Set the name of the field
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeBlob; // Set the type of the field as Blob
            IFieldsEdit fieldsEditor = (IFieldsEdit)myFields; // Add the newly created field to list of existing fields
            fieldsEditor.AddField(pField);
            return;
        }

        /// <summary>
        /// Each BuilderItem contains a Function Raster Dataset which is used to create the thumbnail.
        /// The thumbnail is created by Nearest Neighbor resampling of the Function Raster Dataset. 
        /// The resampled raster is exported as a byte array and saved Into the IMemoryBlobStreamVariant. 
        /// The blob is then inserted into the Thumbnail field.
        /// </summary>
        /// <param name="mybuilderItem">Item containing the Function Dataset to be added to the Mosaic Dataset</param>
        private void Resampling(IBuilderItem mybuilderItem)
        {
            try
            {
                IFunctionRasterDataset pFuncRasterDataset = mybuilderItem.Dataset; // Get the FunctionRasterDataset from mybuilderItem
                IRasterDataset pRasterDataset;
                pRasterDataset = (IRasterDataset)pFuncRasterDataset; // Cast the FunctionRasterDataset to Raster Dataset
                IPropertySet thePropSet = pFuncRasterDataset.Properties; // Get the properties of the raster Dataset
                IRaster praster = pRasterDataset.CreateDefaultRaster(); // Create default raster from the above raster dataset
                praster.ResampleMethod = rstResamplingTypes.RSP_NearestNeighbor; // The raster is resampled by RSP_NearestNeighbor
                IRasterProps pRasterProps = (IRasterProps)praster; // Raster properties are used to update the height, width of the raster
                pRasterProps.Height = 256;
                pRasterProps.Width = 256;

                IRasterExporter pConverter = new RasterExporterClass(); // IRasterExporter object is used to convert the raster to byte array.
                byte[] pBytesArr;
                pBytesArr = pConverter.ExportToBytes(praster, "TIFF"); // Convert the resampled Raster to a Byte array 
                IMemoryBlobStream memBlobStream = new MemoryBlobStream(); // Create new IMemoryBlobStream
                IMemoryBlobStreamVariant varBlobStream = (IMemoryBlobStreamVariant)memBlobStream; // Assign to IMemoryBlobStreamVariant
                object anObject = pBytesArr;
                varBlobStream.ImportFromVariant(anObject); // IMemoryBlobStreamVariant object is assigned the byte array
                thePropSet.SetProperty("ThumbNail", memBlobStream); // and saved to the property "ThumbNail"
            }
            catch (Exception ex)
            {
                System.Exception myExc = new System.Exception(
                    "Error: Failed to Re-Sampled the raster.Thumbnails will not be created." + ex.Message, ex);
                throw myExc;
            }
            return;

        }
        #endregion

        #region ThumbnailBuilder Members
        /// <summary>
        /// This property gets and sets the raster type of the Thumbnail Builder.
        /// </summary>
        public IRasterBuilder InnerRasterBuilder
        {
            get
            {
                return innerRasterBuilder;
            }
            set
            {
                innerRasterBuilder = value;
            }
        }

        public ThumbnailBuilder()
        {
            innerRasterBuilder = null;

            myUID = new UIDClass();
            myUID.Value = "{" + "5CACFBA7-F865-4873-B57C-BE2A46E1C5E3" + "}";
        }
        #endregion

        #region IRasterBuilder Members
        /// <summary>
        /// AuxiliaryFieldAlias property gets and sets the Auxiliary fields Alias
        /// present in the raster builder
        /// </summary>
        public ESRI.ArcGIS.esriSystem.IPropertySet AuxiliaryFieldAlias
        {
            get
            {
                return innerRasterBuilder.AuxiliaryFieldAlias;
            }
            set
            {
                innerRasterBuilder.AuxiliaryFieldAlias = value;
            }
        }

        /// <summary>
        /// Flag to specify whether the Raster Builder can build items in place.
        /// </summary>
        public bool CanBuildInPlace
        {
            get { return innerRasterBuilder.CanBuildInPlace; }
        }

        /// <summary>
        /// For adding Thumbnails, a new field called "Thumbnail" of type blob is created
        /// and added to the Auxiliary Fields in raster builder.
        /// </summary>
        public IFields AuxiliaryFields
        {
            get
            {
                ESRI.ArcGIS.DataSourcesRaster.IRasterBuilder pRasterBuilder = innerRasterBuilder;
                IFields myFields = pRasterBuilder.AuxiliaryFields; // Existing Fields present in the Raster Builder. 
                try
                {
                    int count = myFields.FindField("ThumbNail"); // Check if the Field "ThumbNail" already exists.
                    if (count == -1)
                    {
                        AddingNewField(myFields); // If not add the new field "ThumbNail"
                        pRasterBuilder.AuxiliaryFields = myFields; // Assign the updated Fields back to the raster builder.
                    }
                }
                catch (Exception ex)
                {
                    System.Exception myExc = new System.Exception("Failed to add the field ThumbNail." + ex.Message, ex);
                    throw myExc;
                }
                return innerRasterBuilder.AuxiliaryFields; // Return the updated fields.
            }
            set
            {
                innerRasterBuilder.AuxiliaryFields = value;
            }
        }

        /// <summary>
        /// Prepare the Raster Type for generating Crawler items
        /// </summary>
        /// <param name="pCrawler">Crawler to use to generate the crawler items</param>
        public void BeginConstruction(IDataSourceCrawler pCrawler)
        {
            innerRasterBuilder.BeginConstruction(pCrawler);
        }

        /// <summary>
        /// Call the build function of the inner Raster Type and generate a thumbnail from the Builder Item created.
        /// </summary>
        /// <param name="pItemURI">URI of the Item to be built</param>
        /// <returns></returns>
        public IBuilderItem Build(IItemURI pItemURI)
        {
            IBuilderItem pbuilderItem = innerRasterBuilder.Build(pItemURI); // Generate the IBuilderItem
            Resampling(pbuilderItem); // Generate the Thumbnail from the item.
            return pbuilderItem;
        }

        /// <summary>
        /// Construct a Unique Resource Identifier (URI)
        /// for each crawler item
        /// </summary>
        /// <param name="crawlerItem">Crawled Item from which the URI is generated</param>
        public void ConstructURIs(object crawlerItem)
        {
            innerRasterBuilder.ConstructURIs(crawlerItem);
        }

        /// <summary>
        /// Finish Construction of the URI's
        /// </summary>
        /// <returns></returns>
        public IItemURIArray EndConstruction()
        {
            return innerRasterBuilder.EndConstruction();
        }

        /// <summary>
        /// Generate the next URI.
        /// </summary>
        /// <returns>The URI generated.</returns>
        public IItemURI GetNextURI()
        {
            return innerRasterBuilder.GetNextURI();
        }

        /// <summary>
        /// Get the recommended data crawler for the Raster Type based on 
        /// properties provided by the user.
        /// </summary>
        /// <param name="pDataSourceProperties">List of properties provided by the user</param>
        /// <returns></returns>
        public IDataSourceCrawler GetRecommendedCrawler(IPropertySet pDataSourceProperties)
        {
            return innerRasterBuilder.GetRecommendedCrawler(pDataSourceProperties);
        }

        /// <summary>
        /// Check if the item provided is "stale" or not valid
        /// </summary>
        /// <param name="pItemURI">URI for the item to be checked</param>
        /// <returns></returns>
        public bool IsStale(IItemURI pItemURI)
        {
            return innerRasterBuilder.IsStale(pItemURI);
        }

        /// <summary>
        /// Properties associated with the Raster Type
        /// </summary>
        public IPropertySet Properties
        {
            get
            {
                return innerRasterBuilder.Properties;
            }
            set
            {
                innerRasterBuilder.Properties = value;
            }
        }


        #endregion

        #region IPersistVariant Members
        /// <summary>
        /// UID for the object implementing the Persist Variant
        /// </summary>
        UID IPersistVariant.ID
        {
            get { return myUID; }
        }

        /// <summary>
        /// Load the object from the stream provided
        /// </summary>
        /// <param name="Stream">Stream that represents the serialized Raster Type</param>
        void IPersistVariant.Load(IVariantStream Stream)
        {
            string name = (string)Stream.Read();
            //if (innerRasterBuilder is IPersistVariant)
            //    ((IPersistVariant)innerRasterBuilder).Load(Stream);
            innerRasterBuilder = (IRasterBuilder)Stream.Read(); // Load the innerRasterBuilder from the stream.
        }

        /// <summary>
        /// Same the Raster Type to the stream provided
        /// </summary>
        /// <param name="Stream">Stream to serialize the Raster Type into</param>
        void IPersistVariant.Save(IVariantStream Stream)
        {
            Stream.Write("ThmbnailBuilder");
            //if (innerRasterBuilder is IPersistVariant)
            //    ((IPersistVariant)innerRasterBuilder).Save(Stream);
            Stream.Write(innerRasterBuilder); // Save the innerRasterBuilder into the stream.
        }
        #endregion

        #region IRasterBuilderInit Members
        /// <summary>
        /// Default spatial reference for the MD.
        /// </summary>
        ISpatialReference IRasterBuilderInit.DefaultSpatialReference
        {
            get
            {
                return ((IRasterBuilderInit)innerRasterBuilder).DefaultSpatialReference;
            }
            set
            {
                ((IRasterBuilderInit)innerRasterBuilder).DefaultSpatialReference = value;
            }
        }

        /// <summary>
        /// Parent mosaic dataset for the Raster Builder.
        /// </summary>
        IMosaicDataset IRasterBuilderInit.MosaicDataset
        {
            get
            {
                return ((IRasterBuilderInit)innerRasterBuilder).MosaicDataset;
            }
            set
            {
                ((IRasterBuilderInit)innerRasterBuilder).MosaicDataset = value;
            }
        }

        /// <summary>
        /// The raster type operation helper object associated with this raster type.
        /// </summary>
        IRasterTypeOperation IRasterBuilderInit.RasterTypeOperation
        {
            get
            {
                return ((IRasterBuilderInit)innerRasterBuilder).RasterTypeOperation;
            }
            set
            {
                ((IRasterBuilderInit)innerRasterBuilder).RasterTypeOperation = value;
            }
        }

        /// <summary>
        /// Tracker for when cancel is pressed.
        /// </summary>
        ITrackCancel IRasterBuilderInit.TrackCancel
        {
            get
            {
                return ((IRasterBuilderInit)innerRasterBuilder).TrackCancel;
            }
            set
            {
                ((IRasterBuilderInit)innerRasterBuilder).TrackCancel = value;
            }
        }
        #endregion
    }
}