Create a custom raster type
ThumbnailBuilder\ThumbnailBuilder.vb
' 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.
' 

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

Namespace CustomRasterBuilder
    Interface IThumbnailBuilder
        Inherits IRasterBuilder
#Region "ThumbnailBuilder Members"
        '''<summary>
        ''' Raster Builder to which the ThumbnailBuilder is attached.
        '''</summary>
        Property InnerRasterBuilder() As IRasterBuilder
#End Region
    End Interface

    ''' <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
        Implements IRasterTypeFactory
#Region "Private Members"
        Private myRasterTypeNames As IStringArray
        ' List of Raster Types that the factory can create.
        Private myUID As UID
        ' UID for the Thumbnail Raster type.
#End Region

#Region "IRasterTypeFactory Members"

        Public Sub New()
            ' 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}"
        End Sub

        ''' <summary>
        ''' The UID for the factory.
        ''' </summary>
        Public ReadOnly Property CLSID() As UID Implements IRasterTypeFactory.CLSID
            Get
                Return myUID
            End Get
        End Property

        ''' <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 Function CreateRasterType(ByVal RasterTypeName As String) As IRasterType Implements IRasterTypeFactory.CreateRasterType
            Try
                Select Case RasterTypeName
                    Case "Thumbnail Raster Dataset"
                        If True Then
                            ' Create a Raster Type Name object.
                            Dim theRasterTypeName As IRasterTypeName = 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.
                            Dim theRasterType As IRasterType = DirectCast(DirectCast(theRasterTypeName, IName).Open(), IRasterType)
                            If theRasterType Is Nothing Then
                                Console.WriteLine("Error:Raster Type not found " & theRasterTypeName.Name)
                                Return Nothing
                            End If

                            ' 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 
                            Dim thumbnailBuilder As IRasterBuilder = New ThumbnailBuilder()
                            '  Set the InnerRasterBuilder property with current Raster Type's Raster Builder
                            DirectCast(thumbnailBuilder, ThumbnailBuilder).InnerRasterBuilder = theRasterType.RasterBuilder
                            ' Set the Raster Builder of theRasterType to the above created thumbnail builder.
                            theRasterType.RasterBuilder = thumbnailBuilder
                            Dim theName As IName = theRasterType.FullName
                            DirectCast(theName, IRasterTypeName).Name = "Thumbnail Raster Dataset"
                            Return theRasterType
                        End If

                    Case "Thumbnail QuickBird"
                        If True Then
                            ' Create a Raster Type Name object.
                            Dim theRasterTypeName As IRasterTypeName = 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.
                            Dim theRasterType As IRasterType = DirectCast(DirectCast(theRasterTypeName, IName).Open(), IRasterType)
                            If theRasterType Is Nothing Then
                                Console.WriteLine("Error:Raster Type not found " & theRasterTypeName.Name)
                                Return Nothing
                            End If

                            ' 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 
                            Dim thumbnailBuilder As IRasterBuilder = New ThumbnailBuilder()
                            '  Set the InnerRasterBuilder property with current Raster Type's Raster Builder
                            DirectCast(thumbnailBuilder, ThumbnailBuilder).InnerRasterBuilder = theRasterType.RasterBuilder
                            ' Set the Raster Builder of theRasterType to the above created thumbnail builder.
                            theRasterType.RasterBuilder = thumbnailBuilder
                            Dim theName As IName = theRasterType.FullName
                            DirectCast(theName, IRasterTypeName).Name = "Thumbnail QuickBird"
                            Return theRasterType
                        End If
                    Case Else
                        Return Nothing
                End Select
            Catch ex As Exception
                Throw New Exception("Error: Failed to create " & RasterTypeName & ": " & ex.Message)
            End Try
        End Function

        ''' <summary>
        ''' Name of the Raster Type factory.
        ''' </summary>
        Public ReadOnly Property Name() As String Implements IRasterTypeFactory.Name
            Get
                Return "Thumbnail Raster Type Factory"
            End Get
        End Property

        ''' <summary>
        ''' List of Raster Types which the factory can create.
        ''' </summary>
        Public ReadOnly Property RasterTypeNames() As IStringArray Implements IRasterTypeFactory.RasterTypeNames
            Get
                Return myRasterTypeNames
            End Get
        End Property
#End Region

#Region "COM Registration Function(s)"
        <ComRegisterFunction()> _
        Private Shared Sub Reg(ByVal regKey As String)
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Register(regKey)
        End Sub

        <ComUnregisterFunction()> _
        Private Shared Sub Unreg(ByVal regKey As String)
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Unregister(regKey)
        End Sub
#End Region
    End Class

    '''<summary>
    ''' This class implements the interface IThumbnailBuilder, IPersistVariant.
    '''</summary>
    <Guid("CB37C3B0-5080-4bec-9065-AF036CEBA0F9")> _
    <ClassInterface(ClassInterfaceType.None)> _
    <ProgId("CustomRasterBuilder.ThumbnailBuilder")> _
    <ComVisible(True)> _
    Public Class ThumbnailBuilder
        Implements IThumbnailBuilder
        Implements IPersistVariant
        Implements IRasterBuilderInit
#Region "Private Members"
        Public m_innerRasterBuilder As IRasterBuilder
        ' Inner Raster Builder 
        Private myUID As UID
        ' 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 Shared Sub AddingNewField(ByVal myFields As IFields)
            Dim pField As IField = New FieldClass()
            ' Create a new field object
            Dim objectIDFieldEditor As IFieldEdit = DirectCast(pField, IFieldEdit)
            ' 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
            Dim fieldsEditor As IFieldsEdit = DirectCast(myFields, IFieldsEdit)
            ' Add the newly created field to list of existing fields
            fieldsEditor.AddField(pField)
            Return
        End Sub

        ''' <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 Sub Resampling(ByVal mybuilderItem As IBuilderItem)
            Try
                Dim pFuncRasterDataset As IFunctionRasterDataset = mybuilderItem.Dataset
                ' Get the FunctionRasterDataset from mybuilderItem
                Dim pRasterDataset As IRasterDataset
                pRasterDataset = DirectCast(pFuncRasterDataset, IRasterDataset)
                ' Cast the FunctionRasterDataset to Raster Dataset
                Dim thePropSet As IPropertySet = pFuncRasterDataset.Properties
                ' Get the properties of the raster Dataset
                Dim praster As IRaster = pRasterDataset.CreateDefaultRaster()
                ' Create default raster from the above raster dataset
                praster.ResampleMethod = rstResamplingTypes.RSP_NearestNeighbor
                ' The raster is resampled by RSP_NearestNeighbor
                Dim pRasterProps As IRasterProps = DirectCast(praster, IRasterProps)
                ' Raster properties are used to update the height, width of the raster
                pRasterProps.Height = 256
                pRasterProps.Width = 256

                Dim pConverter As IRasterExporter = New RasterExporterClass()
                ' IRasterExporter object is used to convert the raster to byte array.
                Dim pBytesArr As Byte()
                pBytesArr = pConverter.ExportToBytes(praster, "TIFF")
                ' Convert the resampled Raster to a Byte array 
                Dim memBlobStream As IMemoryBlobStream = New MemoryBlobStream()
                ' Create new IMemoryBlobStream
                Dim varBlobStream As IMemoryBlobStreamVariant = DirectCast(memBlobStream, IMemoryBlobStreamVariant)
                ' Assign to IMemoryBlobStreamVariant
                Dim anObject As Object = pBytesArr
                varBlobStream.ImportFromVariant(anObject)
                ' IMemoryBlobStreamVariant object is assigned the byte array
                ' and saved to the property "ThumbNail"
                thePropSet.SetProperty("ThumbNail", memBlobStream)
            Catch ex As Exception
                Dim myExc As New System.Exception("Error: Failed to Re-Sampled the raster.Thumbnails will not be created." & ex.Message, ex)
                Throw myExc
            End Try
            Return

        End Sub
#End Region

#Region "ThumbnailBuilder Members"
        ''' <summary>
        ''' This property gets and sets the raster type of the Thumbnail Builder.
        ''' </summary>
        Public Property InnerRasterBuilder() As IRasterBuilder Implements IThumbnailBuilder.InnerRasterBuilder
            Get
                Return m_innerRasterBuilder
            End Get
            Set(ByVal value As IRasterBuilder)
                m_innerRasterBuilder = value
            End Set
        End Property

        Public Sub New()
            m_innerRasterBuilder = Nothing

            myUID = New UIDClass()
            myUID.Value = "{" & "CB37C3B0-5080-4bec-9065-AF036CEBA0F9" & "}"
        End Sub
#End Region

#Region "IRasterBuilder Members"
        ''' <summary>
        ''' AuxiliaryFieldAlias property gets and sets the Auxiliary fields Alias
        ''' present in the raster builder
        ''' </summary>
        Public Property AuxiliaryFieldAlias() As ESRI.ArcGIS.esriSystem.IPropertySet Implements IRasterBuilder.AuxiliaryFieldAlias
            Get
                Return m_innerRasterBuilder.AuxiliaryFieldAlias
            End Get
            Set(ByVal value As ESRI.ArcGIS.esriSystem.IPropertySet)
                m_innerRasterBuilder.AuxiliaryFieldAlias = value
            End Set
        End Property

        ''' <summary>
        ''' Flag to specify whether the Raster Builder can build items in place.
        ''' </summary>
        Public ReadOnly Property CanBuildInPlace() As Boolean Implements IRasterBuilder.CanBuildInPlace
            Get
                Return m_innerRasterBuilder.CanBuildInPlace
            End Get
        End Property

        ''' <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 Property AuxiliaryFields() As IFields Implements IRasterBuilder.AuxiliaryFields
            Get
                Dim pRasterBuilder As ESRI.ArcGIS.DataSourcesRaster.IRasterBuilder = m_innerRasterBuilder
                Dim myFields As IFields = pRasterBuilder.AuxiliaryFields
                ' Existing Fields present in the Raster Builder. 
                Try
                    Dim count As Integer = myFields.FindField("ThumbNail")
                    ' Check if the Field "ThumbNail" already exists.
                    If count = -1 Then
                        AddingNewField(myFields)
                        ' If not add the new field "ThumbNail"
                        ' Assign the updated Fields back to the raster builder.
                        pRasterBuilder.AuxiliaryFields = myFields
                    End If
                Catch ex As Exception
                    Dim myExc As New System.Exception("Failed to add the field ThumbNail." & ex.Message, ex)
                    Throw myExc
                End Try
                ' Return the updated fields.
                Return m_innerRasterBuilder.AuxiliaryFields
            End Get
            Set(ByVal value As IFields)
                m_innerRasterBuilder.AuxiliaryFields = value
            End Set
        End Property

        ''' <summary>
        ''' Prepare the Raster Type for generating Crawler items
        ''' </summary>
        ''' <param name="pCrawler">Crawler to use to generate the crawler items</param>
        Public Sub BeginConstruction(ByVal pCrawler As IDataSourceCrawler) Implements IRasterBuilder.BeginConstruction
            m_innerRasterBuilder.BeginConstruction(pCrawler)
        End Sub

        ''' <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 Function Build(ByVal pItemURI As IItemURI) As IBuilderItem Implements IRasterBuilder.Build
            Dim pbuilderItem As IBuilderItem = m_innerRasterBuilder.Build(pItemURI)
            ' Generate the IBuilderItem
            Resampling(pbuilderItem)
            ' Generate the Thumbnail from the item.
            Return pbuilderItem
        End Function

        ''' <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 Sub ConstructURIs(ByVal crawlerItem As Object) Implements IRasterBuilder.ConstructURIs
            m_innerRasterBuilder.ConstructURIs(crawlerItem)
        End Sub

        ''' <summary>
        ''' Finish Construction of the URI's
        ''' </summary>
        ''' <returns></returns>
        Public Function EndConstruction() As IItemURIArray Implements IRasterBuilder.EndConstruction
            Return m_innerRasterBuilder.EndConstruction()
        End Function

        ''' <summary>
        ''' Generate the next URI.
        ''' </summary>
        ''' <returns>The URI generated.</returns>
        Public Function GetNextURI() As IItemURI Implements IRasterBuilder.GetNextURI
            Return m_innerRasterBuilder.GetNextURI()
        End Function

        ''' <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 Function GetRecommendedCrawler(ByVal pDataSourceProperties As IPropertySet) As IDataSourceCrawler Implements IRasterBuilder.GetRecommendedCrawler
            Return m_innerRasterBuilder.GetRecommendedCrawler(pDataSourceProperties)
        End Function

        ''' <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 Function IsStale(ByVal pItemURI As IItemURI) As Boolean Implements IRasterBuilder.IsStale
            Return m_innerRasterBuilder.IsStale(pItemURI)
        End Function

        ''' <summary>
        ''' Properties associated with the Raster Type
        ''' </summary>
        Public Property Properties() As IPropertySet Implements IRasterBuilder.Properties
            Get
                Return m_innerRasterBuilder.Properties
            End Get
            Set(ByVal value As IPropertySet)
                m_innerRasterBuilder.Properties = value
            End Set
        End Property


#End Region

#Region "IPersistVariant Members"
        ''' <summary>
        ''' UID for the object implementing the Persist Variant
        ''' </summary>
        Private ReadOnly Property IPersistVariant_ID() As UID Implements IPersistVariant.ID
            Get
                Return myUID
            End Get
        End Property

        ''' <summary>
        ''' Load the object from the stream provided
        ''' </summary>
        ''' <param name="Stream">Stream that represents the serialized Raster Type</param>
        Private Sub IPersistVariant_Load(ByVal Stream As IVariantStream) Implements IPersistVariant.Load
            Dim name As String = DirectCast(Stream.Read(), String)
            'if (innerRasterBuilder is IPersistVariant)
            '    ((IPersistVariant)innerRasterBuilder).Load(Stream);
            m_innerRasterBuilder = DirectCast(Stream.Read(), IRasterBuilder)
            ' Load the innerRasterBuilder from the stream.
        End Sub

        ''' <summary>
        ''' Same the Raster Type to the stream provided
        ''' </summary>
        ''' <param name="Stream">Stream to serialize the Raster Type into</param>
        Private Sub IPersistVariant_Save(ByVal Stream As IVariantStream) Implements IPersistVariant.Save
            Stream.Write("ThmbnailBuilder")
            'if (innerRasterBuilder is IPersistVariant)
            '    ((IPersistVariant)innerRasterBuilder).Save(Stream);
            Stream.Write(m_innerRasterBuilder)
            ' Save the innerRasterBuilder into the stream.
        End Sub
#End Region

#Region "IRasterBuilderInit Members"
        ''' <summary>
        ''' Default spatial reference for the MD.
        ''' </summary>
        Private Property IRasterBuilderInit_DefaultSpatialReference() As ISpatialReference Implements IRasterBuilderInit.DefaultSpatialReference
            Get
                Return DirectCast(m_innerRasterBuilder, IRasterBuilderInit).DefaultSpatialReference
            End Get
            Set(ByVal value As ISpatialReference)
                DirectCast(m_innerRasterBuilder, IRasterBuilderInit).DefaultSpatialReference = value
            End Set
        End Property

        ''' <summary>
        ''' Parent mosaic dataset for the Raster Builder.
        ''' </summary>
        Private Property IRasterBuilderInit_MosaicDataset() As IMosaicDataset Implements IRasterBuilderInit.MosaicDataset
            Get
                Return DirectCast(m_innerRasterBuilder, IRasterBuilderInit).MosaicDataset
            End Get
            Set(ByVal value As IMosaicDataset)
                DirectCast(m_innerRasterBuilder, IRasterBuilderInit).MosaicDataset = value
            End Set
        End Property

        ''' <summary>
        ''' The raster type operation helper object associated with this raster type.
        ''' </summary>
        Private Property IRasterBuilderInit_RasterTypeOperation() As IRasterTypeOperation Implements IRasterBuilderInit.RasterTypeOperation
            Get
                Return DirectCast(m_innerRasterBuilder, IRasterBuilderInit).RasterTypeOperation
            End Get
            Set(ByVal value As IRasterTypeOperation)
                DirectCast(m_innerRasterBuilder, IRasterBuilderInit).RasterTypeOperation = value
            End Set
        End Property

        ''' <summary>
        ''' Tracker for when cancel is pressed.
        ''' </summary>
        Private Property IRasterBuilderInit_TrackCancel() As ITrackCancel Implements IRasterBuilderInit.TrackCancel
            Get
                Return DirectCast(m_innerRasterBuilder, IRasterBuilderInit).TrackCancel
            End Get
            Set(ByVal value As ITrackCancel)
                DirectCast(m_innerRasterBuilder, IRasterBuilderInit).TrackCancel = value
            End Set
        End Property
#End Region
    End Class
End Namespace