VintaSoft Imaging .NET SDK v8.7
In This Topic
    Custom processing command
    In This Topic

    You need to do the following steps if you want to create custom processing command:

    1. Create new class inherited from Vintasoft.Imaging.ImageProcessing.ProcessingCommandBase or any other existing processing command from Vintasoft.Imaging.ImageProcessing namespace
    2. Override the ProcessImageInPlace() method in your class
    3. Override the SupportedPixelFormats property if your command does not support all pixel formats
    4. Call the RaiseProgress method during execution of your command if your command supports progress


    Example: Here is an example of the command that inverts colors of an image:
    ' The project, which uses this code, must have references to the following assemblies:
    ' - Vintasoft.Imaging
    
    ''' <summary>
    ''' Inverts colors of an image.
    ''' </summary>
    Public Class CustomInvertCommand
        Inherits Vintasoft.Imaging.ImageProcessing.ProcessingCommandWithRegion
    
        #Region "Constructors"
    
        ''' <summary>
        ''' Initializes a new instance of the  class.
        ''' </summary>
        Public Sub New()
            MyBase.New()
        End Sub
    
        #End Region
    
    
    
        #Region "Properties"
    
        ''' <summary>
        ''' Gets the name of the command.
        ''' </summary>
        Public Overrides ReadOnly Property Name() As String
            Get
                Return "Invert"
            End Get
        End Property
    
        ''' <summary>
        ''' Gets a list of supported native pixel formats for this processing command.
        ''' </summary>
        Public Overrides ReadOnly Property SupportedNativePixelFormats() As System.Collections.ObjectModel.ReadOnlyCollection(Of Vintasoft.Imaging.PixelFormat)
            Get
                Dim supportedNativePixelFormats__1 As New System.Collections.Generic.List(Of Vintasoft.Imaging.PixelFormat)()
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.BlackWhite)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Indexed1)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Indexed4)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Indexed8)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Gray8)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Gray16)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Bgr24)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Bgr32)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Bgr48)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Bgra32)
                supportedNativePixelFormats__1.Add(Vintasoft.Imaging.PixelFormat.Bgra64)
                Return supportedNativePixelFormats__1.AsReadOnly()
            End Get
        End Property
    
        #End Region
    
    
    
        #Region "Methods"
    
        ''' <summary>
        ''' Returns the pixel format of output image (image after processing)
        ''' for input image with specified pixel format.
        ''' </summary>
        ''' <param name="inputPixelFormat">Pixel format of input image.</param>
        ''' <returns>Pixel format of output image.</returns>
        Public Overrides Function GetOutputPixelFormat(inputPixelFormat As Vintasoft.Imaging.PixelFormat) As Vintasoft.Imaging.PixelFormat
            If IsPixelFormatSupported(inputPixelFormat) Then
                Return inputPixelFormat
            End If
            Return Vintasoft.Imaging.PixelFormat.Undefined
        End Function
    
        ''' <summary>
        ''' Creates a new <see cref="CustomInvertCommand"/> that is a copy of the current
        ''' instance.
        ''' </summary>
        ''' <returns>A new <see cref="CustomInvertCommand"/> that is a copy of this
        ''' instance.</returns>
        Public Overrides Function Clone() As Object
            Return New CustomInvertCommand()
        End Function
    
        ''' <summary>
        ''' Processes the image in-place.
        ''' </summary>
        ''' <param name="image">Image to process.</param>
        ''' <returns>
        ''' <b>true</b> if image is processed;
        ''' <b>false</b> if processing is canceled or not necessary.
        ''' </returns>
        ''' <remarks>
        ''' This method changes the <i>image</i>.
        ''' </remarks>
        Protected Overrides Function ProcessImageInPlace(image As Vintasoft.Imaging.VintasoftImage) As Boolean
            Dim rect As System.Drawing.Rectangle = Me.GetSafeRegionOfInterest(image)
    
            Dim cancel As Boolean = False
    
            Dim height As Integer = rect.Height
    
            Dim pixelManipulator As Vintasoft.Imaging.PixelManipulator
            Dim rowData As Byte()
            Dim rowLength As Integer
    
            Dim progress As Single = 0
            Dim progressDelta As Single = 100F / height
    
            Select Case image.PixelFormat
                Case Vintasoft.Imaging.PixelFormat.BlackWhite, Vintasoft.Imaging.PixelFormat.Indexed1, Vintasoft.Imaging.PixelFormat.Indexed4, Vintasoft.Imaging.PixelFormat.Indexed8, Vintasoft.Imaging.PixelFormat.Gray8
                    If Not RegionOfInterest.IsEmpty Then
                        Throw New Vintasoft.Imaging.ImageProcessing.ImageProcessingException(String.Format("{0}: this processing command does not support RegionOfInterest for palette images.", Name))
                    End If
    
                    image.Palette.Invert()
                    Exit Select
    
                Case Vintasoft.Imaging.PixelFormat.Gray16
                    pixelManipulator = image.OpenPixelManipulator()
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite)
                    rowLength = rect.Width * 2
                    rowData = New Byte(rowLength - 1) {}
                    For y As Integer = 0 To height - 1
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength)
                        For x As Integer = 0 To rowLength - 1 Step 2
                            rowData(x) = rowData(x) Xor &Hff
                            rowData(x + 1) = rowData(x + 1) Xor &H3f
                        Next
                        pixelManipulator.WriteRowData(y, rowData, 0, rowLength)
    
                        ' change the progress
                        progress += progressDelta
                        ' raise the progress event
                        If Not RaiseProgress(progress, True) Then
                            cancel = True
                            Exit For
                        End If
                    Next
                    pixelManipulator.UnlockPixels()
                    ' close the pixel manipulator
                    image.ClosePixelManipulator(True)
                    Exit Select
    
                Case Vintasoft.Imaging.PixelFormat.Bgr24, Vintasoft.Imaging.PixelFormat.Bgr48
                    pixelManipulator = image.OpenPixelManipulator()
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite)
                    rowLength = rect.Width * 3
                    rowData = New Byte(rowLength - 1) {}
                    For y As Integer = 0 To height - 1
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength)
                        For x As Integer = 0 To rowLength - 1
                            rowData(x) = rowData(x) Xor &Hff
                        Next
                        pixelManipulator.WriteRowDataUnsafe(y, rowData, 0, rowLength)
    
                        ' change the progress
                        progress += progressDelta
                        ' raise the progress event
                        If Not RaiseProgress(progress, True) Then
                            cancel = True
                            Exit For
                        End If
                    Next
                    pixelManipulator.UnlockPixels()
                    ' close the pixel manipulator
                    image.ClosePixelManipulator(True)
                    Exit Select
    
                Case Vintasoft.Imaging.PixelFormat.Bgr32, Vintasoft.Imaging.PixelFormat.Bgra32, Vintasoft.Imaging.PixelFormat.Bgra64
                    pixelManipulator = image.OpenPixelManipulator()
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite)
                    rowLength = rect.Width * 4
                    rowData = New Byte(rowLength - 1) {}
                    For y As Integer = 0 To height - 1
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength)
                        For x As Integer = 0 To rowLength - 1 Step 4
                            rowData(x) = rowData(x) Xor &Hff
                            rowData(x + 1) = rowData(x + 1) Xor &Hff
                            rowData(x + 2) = rowData(x + 2) Xor &Hff
                        Next
                        pixelManipulator.WriteRowDataUnsafe(y, rowData, 0, rowLength)
    
                        ' change the progress
                        progress += progressDelta
                        ' raise the progress event
                        If Not RaiseProgress(progress, True) Then
                            cancel = True
                            Exit For
                        End If
                    Next
                    pixelManipulator.UnlockPixels()
                    ' close the pixel manipulator
                    image.ClosePixelManipulator(True)
                    Exit Select
            End Select
    
            Return Not cancel
        End Function
    
        #End Region
    
    End Class
                  
    
    // The project, which uses this code, must have references to the following assemblies:
    // - Vintasoft.Imaging
    
    /// <summary>
    /// Inverts colors of an image.
    /// </summary>
    public class CustomInvertCommand : Vintasoft.Imaging.ImageProcessing.ProcessingCommandWithRegion
    {
    
        #region Constructors
    
        /// <summary>
        /// Initializes a new instance of the  class.
        /// </summary>
        public CustomInvertCommand()
            : base()
        {
        }
    
        #endregion
    
    
    
        #region Properties
    
        /// <summary>
        /// Gets the name of the command.
        /// </summary>
        public override string Name
        {
            get
            {
                return "Invert";
            }
        }
    
        /// <summary>
        /// Gets a list of supported native pixel formats for this processing command.
        /// </summary>
        public override System.Collections.ObjectModel.ReadOnlyCollection<Vintasoft.Imaging.PixelFormat> SupportedNativePixelFormats
        {
            get
            {
                System.Collections.Generic.List<Vintasoft.Imaging.PixelFormat> supportedNativePixelFormats =
                    new System.Collections.Generic.List<Vintasoft.Imaging.PixelFormat>();
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.BlackWhite);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Indexed1);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Indexed4);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Indexed8);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Gray8);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Gray16);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgr24);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgr32);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgr48);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgra32);
                supportedNativePixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgra64);
                return supportedNativePixelFormats.AsReadOnly();
            }
        }
    
        #endregion
    
    
    
        #region Methods
    
        /// <summary>
        /// Returns the pixel format of output image (image after processing)
        /// for input image with specified pixel format.
        /// </summary>
        /// <param name="inputPixelFormat">Pixel format of input image.</param>
        /// <returns>Pixel format of output image.</returns>
        public override Vintasoft.Imaging.PixelFormat GetOutputPixelFormat(
            Vintasoft.Imaging.PixelFormat inputPixelFormat)
        {
            if (IsPixelFormatSupported(inputPixelFormat))
                return inputPixelFormat;
            return Vintasoft.Imaging.PixelFormat.Undefined;
        }
    
        /// <summary>
        /// Creates a new <see cref="CustomInvertCommand"/> that is a copy of the current
        /// instance.
        /// </summary>
        /// <returns>A new <see cref="CustomInvertCommand"/> that is a copy of this
        /// instance.</returns>
        public override object Clone()
        {
            return new CustomInvertCommand();
        }
    
        /// <summary>
        /// Processes the image in-place.
        /// </summary>
        /// <param name="image">Image to process.</param>
        /// <returns>
        /// <b>true</b> if image is processed;
        /// <b>false</b> if processing is canceled or not necessary.
        /// </returns>
        /// <remarks>
        /// This method changes the <i>image</i>.
        /// </remarks>
        protected override bool ProcessImageInPlace(Vintasoft.Imaging.VintasoftImage image)
        {
            System.Drawing.Rectangle rect = this.GetSafeRegionOfInterest(image);
    
            bool cancel = false;
    
            int height = rect.Height;
    
            Vintasoft.Imaging.PixelManipulator pixelManipulator;
            byte[] rowData;
            int rowLength;
    
            float progress = 0;
            float progressDelta = 100f / height;
    
            switch (image.PixelFormat)
            {
                case Vintasoft.Imaging.PixelFormat.BlackWhite:
                case Vintasoft.Imaging.PixelFormat.Indexed1:
                case Vintasoft.Imaging.PixelFormat.Indexed4:
                case Vintasoft.Imaging.PixelFormat.Indexed8:
                case Vintasoft.Imaging.PixelFormat.Gray8:
                    if (!RegionOfInterest.IsEmpty)
                        throw new Vintasoft.Imaging.ImageProcessing.ImageProcessingException(
                            string.Format("{0}: this processing command does not support RegionOfInterest for palette images.", Name));
    
                    image.Palette.Invert();
                    break;
    
                case Vintasoft.Imaging.PixelFormat.Gray16:
                    pixelManipulator = image.OpenPixelManipulator();
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite);
                    rowLength = rect.Width * 2;
                    rowData = new byte[rowLength];
                    for (int y = 0; y < height; y++)
                    {
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength);
                        for (int x = 0; x < rowLength; x += 2)
                        {
                            rowData[x] ^= 0xFF;
                            rowData[x + 1] ^= 0x3F;
                        }
                        pixelManipulator.WriteRowData(y, rowData, 0, rowLength);
    
                        // change the progress
                        progress += progressDelta;
                        // raise the progress event
                        if (!RaiseProgress(progress, true))
                        {
                            cancel = true;
                            break;
                        }
                    }
                    pixelManipulator.UnlockPixels();
                    // close the pixel manipulator
                    image.ClosePixelManipulator(true);
                    break;
    
                case Vintasoft.Imaging.PixelFormat.Bgr24:
                case Vintasoft.Imaging.PixelFormat.Bgr48:
                    pixelManipulator = image.OpenPixelManipulator();
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite);
                    rowLength = rect.Width * 3;
                    rowData = new byte[rowLength];
                    for (int y = 0; y < height; y++)
                    {
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength);
                        for (int x = 0; x < rowLength; x++)
                        {
                            rowData[x] ^= 0xFF;
                        }
                        pixelManipulator.WriteRowDataUnsafe(y, rowData, 0, rowLength);
    
                        // change the progress
                        progress += progressDelta;
                        // raise the progress event
                        if (!RaiseProgress(progress, true))
                        {
                            cancel = true;
                            break;
                        }
                    }
                    pixelManipulator.UnlockPixels();
                    // close the pixel manipulator
                    image.ClosePixelManipulator(true);
                    break;
    
                case Vintasoft.Imaging.PixelFormat.Bgr32:
                case Vintasoft.Imaging.PixelFormat.Bgra32:
                case Vintasoft.Imaging.PixelFormat.Bgra64:
                    pixelManipulator = image.OpenPixelManipulator();
                    pixelManipulator.LockPixels(rect, Vintasoft.Imaging.BitmapLockMode.ReadWrite);
                    rowLength = rect.Width * 4;
                    rowData = new byte[rowLength];
                    for (int y = 0; y < height; y++)
                    {
                        pixelManipulator.ReadRowDataUnsafe(y, rowData, 0, rowLength);
                        for (int x = 0; x < rowLength; x += 4)
                        {
                            rowData[x] ^= 0xFF;
                            rowData[x + 1] ^= 0xFF;
                            rowData[x + 2] ^= 0xFF;
                        }
                        pixelManipulator.WriteRowDataUnsafe(y, rowData, 0, rowLength);
    
                        // change the progress
                        progress += progressDelta;
                        // raise the progress event
                        if (!RaiseProgress(progress, true))
                        {
                            cancel = true;
                            break;
                        }
                    }
                    pixelManipulator.UnlockPixels();
                    // close the pixel manipulator
                    image.ClosePixelManipulator(true);
                    break;
            }
    
            return !cancel;
        }
    
        #endregion
    
    }