VintaSoft Imaging .NET SDK 15.1: Documentation for .NET developer
In This Topic
Custom processing command
In This Topic
The following steps must be made if the custom image processing command must be created:
  1. Create new class, which is inherited from ProcessingCommandBase or any other existing image processing command from Vintasoft.Imaging.ImageProcessing namespace
  2. Override the ProcessingCommandBase.ProcessImageInPlace method in your class
  3. Override the ProcessingCommandBase.SupportedPixelFormats property if your command does not support all pixel formats
  4. Call the ProcessingCommandBase.RaiseProgress method during execution of your command if your command supports progress


Here is C#/VB.NET code that shows how to create the image processing command that inverts image colors:
/// <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

}
''' <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