VintaSoft Imaging .NET SDK 15.1: Documentation for .NET developer
In This Topic
An example of custom codec
In This Topic
The given below series of examples demonstrates how to:

Example of SimpleBmpCodec class derived from Codec class

Here is C#/VB.NET code that demonstrates how to create SimpleBmpCodec class derived from Codec class:
public class SimpleBmpCodec : Vintasoft.Imaging.Codecs.Codec
{

    #region Constructor

    /// <summary>
    /// Initializes a new instance of the SimpleBmpCodec class.
    /// </summary>
    public SimpleBmpCodec()
        : base("Simple Bmp", ".bmp")
    {
    }

    #endregion



    #region Properties

    /// <summary>
    /// Gets a value indicating whether codec can create decoder.
    /// </summary>
    /// <value>
    /// Always returns <b>true</b>.
    /// </value>
    public override bool CanCreateDecoder
    {
        get { return true; }
    }

    /// <summary>
    /// Gets a value indicating whether codec can create encoder.
    /// </summary>
    /// <value>
    /// Always returns <b>true</b>.
    /// </value>
    public override bool CanCreateEncoder
    {
        get { return true; }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Creates a new decoder instance for decoding specified stream.
    /// </summary>
    /// <param name="stream">A stream which should be opened using decoder.</param>
    /// <param name="layoutSettings">A document layout settings.</param>
    /// <returns>New decoder instance for specified stream.</returns>
    public override Vintasoft.Imaging.Codecs.Decoders.DecoderBase CreateDecoder(System.IO.Stream stream,
        Vintasoft.Imaging.Codecs.Decoders.DocumentLayoutSettings layoutSettings)
    {
        return new SimpleBmpDecoder(stream);
    }

    /// <summary>
    /// Creates a new decoder instance of the codec.
    /// </summary>
    /// <returns>New decoder instance.</returns>
    public override Vintasoft.Imaging.Codecs.Decoders.DecoderBase CreateDecoder()
    {
        return new SimpleBmpDecoder();
    }

    /// <summary>
    /// Creates a new encoder instance of the codec.
    /// </summary>
    /// <returns>New encoder instance.</returns>
    public override Vintasoft.Imaging.Codecs.Encoders.EncoderBase CreateEncoder()
    {
        return new SimpleBmpEncoder();
    }

    #endregion

}
Public Class SimpleBmpCodec
    Inherits Vintasoft.Imaging.Codecs.Codec

    #Region "Constructor"

    ''' <summary>
    ''' Initializes a new instance of the SimpleBmpCodec class.
    ''' </summary>
    Public Sub New()
        MyBase.New("Simple Bmp", ".bmp")
    End Sub

    #End Region



    #Region "Properties"

    ''' <summary>
    ''' Gets a value indicating whether codec can create decoder.
    ''' </summary>
    ''' <value>
    ''' Always returns <b>true</b>.
    ''' </value>
    Public Overrides ReadOnly Property CanCreateDecoder() As Boolean
        Get
            Return True
        End Get
    End Property

    ''' <summary>
    ''' Gets a value indicating whether codec can create encoder.
    ''' </summary>
    ''' <value>
    ''' Always returns <b>true</b>.
    ''' </value>
    Public Overrides ReadOnly Property CanCreateEncoder() As Boolean
        Get
            Return True
        End Get
    End Property

    #End Region



    #Region "Methods"

    ''' <summary>
    ''' Creates a new decoder instance for decoding specified stream.
    ''' </summary>
    ''' <param name="stream">A stream which should be opened using decoder.</param>
    ''' <param name="layoutSettings">A document layout settings.</param>
    ''' <returns>New decoder instance for specified stream.</returns>
    Public Overrides Function CreateDecoder(stream As System.IO.Stream, layoutSettings As Vintasoft.Imaging.Codecs.Decoders.DocumentLayoutSettings) As Vintasoft.Imaging.Codecs.Decoders.DecoderBase
        Return New SimpleBmpDecoder(stream)
    End Function

    ''' <summary>
    ''' Creates a new decoder instance of the codec.
    ''' </summary>
    ''' <returns>New decoder instance.</returns>
    Public Overrides Function CreateDecoder() As Vintasoft.Imaging.Codecs.Decoders.DecoderBase
        Return New SimpleBmpDecoder()
    End Function

    ''' <summary>
    ''' Creates a new encoder instance of the codec.
    ''' </summary>
    ''' <returns>New encoder instance.</returns>
    Public Overrides Function CreateEncoder() As Vintasoft.Imaging.Codecs.Encoders.EncoderBase
        Return New SimpleBmpEncoder()
    End Function

    #End Region

End Class



Example of method which shows how to use SimpleBmpCodec instead of standard BMP codec

Here is C#/VB.NET code that demonstrates how to use SimpleBmpCodec instead of standard BMP codec:
/// <summary>
/// Replaces the standard BMP codec to the simple BMP codec.
/// </summary>
public static void ReplaceStandardBmpCodecToSimpleBmpCodec()
{
    Vintasoft.Imaging.Codecs.Codec standardBmpCodec = null;
    // search a reference to the standard BMP codec
    for (int i = 0; i < Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs.Count; i++)
    {
        if (Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs[i].Name.ToUpperInvariant() == "BMP")
        {
            standardBmpCodec = Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs[i];
            break;
        }
    }
    // remove standard BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.RemoveCodec(standardBmpCodec);
    // add simple BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.AddCodec(new SimpleBmpCodec());
}

/// <summary>
/// Replaces the simple BMP codec to the standard BMP codec.
/// </summary>
public static void ReplaceSimpleBmpCodecToStandardBmpCodec()
{
    Vintasoft.Imaging.Codecs.Codec simpleBmpCodec = null;
    // search a reference to the simple BMP codec
    for (int i = 0; i < Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs.Count; i++)
    {
        if (Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs[i].Name.ToUpperInvariant() == "SIMPLE BMP")
        {
            simpleBmpCodec = Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs[i];
            break;
        }
    }
    // remove simple BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.RemoveCodec(simpleBmpCodec);
    // add standard BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.AddCodec(Vintasoft.Imaging.Codecs.Codec.CreateStandardCodec("Bmp"));
}
''' <summary>
''' Replaces the standard BMP codec to the simple BMP codec.
''' </summary>
Public Shared Sub ReplaceStandardBmpCodecToSimpleBmpCodec()
    Dim standardBmpCodec As Vintasoft.Imaging.Codecs.Codec = Nothing
    ' search a reference to the standard BMP codec
    For i As Integer = 0 To Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs.Count - 1
        If Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs(i).Name.ToUpperInvariant() = "BMP" Then
            standardBmpCodec = Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs(i)
            Exit For
        End If
    Next
    ' remove standard BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.RemoveCodec(standardBmpCodec)
    ' add simple BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.AddCodec(New SimpleBmpCodec())
End Sub

''' <summary>
''' Replaces the simple BMP codec to the standard BMP codec.
''' </summary>
Public Shared Sub ReplaceSimpleBmpCodecToStandardBmpCodec()
    Dim simpleBmpCodec As Vintasoft.Imaging.Codecs.Codec = Nothing
    ' search a reference to the simple BMP codec
    For i As Integer = 0 To Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs.Count - 1
        If Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs(i).Name.ToUpperInvariant() = "SIMPLE BMP" Then
            simpleBmpCodec = Vintasoft.Imaging.Codecs.AvailableCodecs.Codecs(i)
            Exit For
        End If
    Next
    ' remove simple BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.RemoveCodec(simpleBmpCodec)
    ' add standard BMP codec
    Vintasoft.Imaging.Codecs.AvailableCodecs.AddCodec(Vintasoft.Imaging.Codecs.Codec.CreateStandardCodec("Bmp"))
End Sub



Example of SimpleBmp codec's decoder

Here is C#/VB.NET code that demonstrates how to create SimpleBmp codec's decoder:
/// <summary>
/// Defines a decoder for BMP images.
/// </summary>
public class SimpleBmpDecoder : Vintasoft.Imaging.Codecs.Decoders.DecoderBase
{

    #region Fields

    /// <summary>
    /// BMP file.
    /// </summary>
    SimpleBmpFile _file = null;

    #endregion



    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpDecoder"/> class.
    /// </summary>
    public SimpleBmpDecoder()
        : base()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpDecoder"/> class.
    /// </summary>
    /// <param name="stream">Stream with the image.</param>
    public SimpleBmpDecoder(System.IO.Stream stream)
        : base(stream)
    {
        _file = new SimpleBmpFile(stream);
    }

    #endregion



    #region Properties

    /// <summary>
    /// Gets the name of the decoder.
    /// </summary>
    public override string Name
    {
        get
        {
            return "Simple Bmp";
        }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Determines that stream contains image file in format of this decoder.
    /// </summary>
    /// <param name="stream">Stream with binary data of the image file.</param>
    /// <returns>
    /// <b>true</b> if stream contains image file in format of this decoder;
    /// otherwise, <b>false</b>.
    /// </returns>
    public override bool IsValidFormat(System.IO.Stream stream)
    {
        lock (stream)
            return SimpleBmpFile.IsValidFormat(stream);
    }

    /// <summary>
    /// Returns information about BMP image without loading the image data into memory.
    /// </summary>
    /// <param name="pageIndex">The zero based page index.</param>
    /// <param name="renderingSettings">Rendering settings used for getting info about
    /// the image of page.</param>
    /// <param name="decodingSettings">decoding settings used for getting info about
    /// the image of page.</param>
    /// <returns>Information about the image associated with the
    /// page of the source image.</returns>
    public override Vintasoft.Imaging.Codecs.Decoders.ImageInfo GetImageInfo(
        int pageIndex, 
        Vintasoft.Imaging.Codecs.Decoders.RenderingSettings renderingSettings, 
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings)
    {
        CheckPageIndexValue(pageIndex);
        CheckRenderingSettingsValue(renderingSettings);

        SimpleBmpPage page = _file.Page;
        Vintasoft.Imaging.Palette palette = page.Palette;
        if (palette == null)
            palette = new Vintasoft.Imaging.Palette();

        return new Vintasoft.Imaging.Codecs.Decoders.ImageInfo(
            page.Width, page.Height, page.PixelFormat, palette, page.Resolution);
    }

    /// <summary>
    /// Returns an image of BMP file.
    /// </summary>
    /// <param name="pageIndex">The zero based page index (is not used).</param>
    /// <param name="decodingSettings">Decoding settings used for decode the image of page.</param>
    /// <param name="renderingSettings">Rendering settings used for rendering the image
    /// of page (is not used).</param>
    /// <param name="progressDelegate">Progress delegate.</param>
    /// <returns>Image of BMP file.</returns>
    public override Vintasoft.Imaging.VintasoftImage GetImage(int pageIndex,
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings,
        Vintasoft.Imaging.Codecs.Decoders.RenderingSettings renderingSettings,
        System.EventHandler<Vintasoft.Imaging.ProgressEventArgs> progressDelegate)
    {
        CheckPageIndexValue(pageIndex);
        CheckRenderingSettingsValue(renderingSettings);

        lock (_file)
        {
            // get image
            Vintasoft.Imaging.VintasoftImage image = _file.Page.GetImage(progressDelegate);

            // perform the color correction if necessary
            PerformColorCorrection(pageIndex, image, decodingSettings);

            // return the image
            return image;
        }
    }

    /// <summary>
    /// Returns a metadata of BMP file.
    /// </summary>
    /// <param name="pageIndex">The zero based page index (not used).</param>
    /// <returns>Metadata of BMP file.</returns>
    public override Vintasoft.Imaging.Metadata.PageMetadata GetPageMetadata(int pageIndex)
    {
        return new Vintasoft.Imaging.Metadata.PageMetadata("Bmp");
    }

    /// <summary>
    /// Closes the source of the decoder.
    /// </summary>
    public override void Close()
    {
        if (_file != null)
        {
            _file.Dispose();
            _file = null;
        }
        base.Close();
    }

    #endregion

}
''' <summary>
''' Defines a decoder for BMP images.
''' </summary>
Public Class SimpleBmpDecoder
    Inherits Vintasoft.Imaging.Codecs.Decoders.DecoderBase

    #Region "Fields"

    ''' <summary>
    ''' BMP file.
    ''' </summary>
    Private _file As SimpleBmpFile = Nothing

    #End Region



    #Region "Constructor"

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpDecoder"/> class.
    ''' </summary>
    Public Sub New()
        MyBase.New()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpDecoder"/> class.
    ''' </summary>
    ''' <param name="stream">Stream with the image.</param>
    Public Sub New(stream As System.IO.Stream)
        MyBase.New(stream)
        _file = New SimpleBmpFile(stream)
    End Sub

    #End Region



    #Region "Properties"

    ''' <summary>
    ''' Gets the name of the decoder.
    ''' </summary>
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "Simple Bmp"
        End Get
    End Property

    #End Region



    #Region "Methods"

    ''' <summary>
    ''' Determines that stream contains image file in format of this decoder.
    ''' </summary>
    ''' <param name="stream">Stream with binary data of the image file.</param>
    ''' <returns>
    ''' <b>true</b> if stream contains image file in format of this decoder;
    ''' otherwise, <b>false</b>.
    ''' </returns>
    Public Overrides Function IsValidFormat(stream As System.IO.Stream) As Boolean
        SyncLock stream
            Return SimpleBmpFile.IsValidFormat(stream)
        End SyncLock
    End Function

    ''' <summary>
    ''' Returns information about BMP image without loading the image data into memory.
    ''' </summary>
    ''' <param name="pageIndex">The zero based page index.</param>
    ''' <param name="renderingSettings">Rendering settings used for getting info about
    ''' the image of page.</param>
    ''' <param name="decodingSettings">decoding settings used for getting info about
    ''' the image of page.</param>
    ''' <returns>Information about the image associated with the
    ''' page of the source image.</returns>
    Public Overrides Function GetImageInfo(pageIndex As Integer, renderingSettings As Vintasoft.Imaging.Codecs.Decoders.RenderingSettings, decodingSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings) As Vintasoft.Imaging.Codecs.Decoders.ImageInfo
        CheckPageIndexValue(pageIndex)
        CheckRenderingSettingsValue(renderingSettings)

        Dim page As SimpleBmpPage = _file.Page
        Dim palette As Vintasoft.Imaging.Palette = page.Palette
        If palette Is Nothing Then
            palette = New Vintasoft.Imaging.Palette()
        End If

        Return New Vintasoft.Imaging.Codecs.Decoders.ImageInfo(page.Width, page.Height, page.PixelFormat, palette, page.Resolution)
    End Function

    ''' <summary>
    ''' Returns an image of BMP file.
    ''' </summary>
    ''' <param name="pageIndex">The zero based page index (is not used).</param>
    ''' <param name="decodingSettings">Decoding settings used for decode the image of page.</param>
    ''' <param name="renderingSettings">Rendering settings used for rendering the image
    ''' of page (is not used).</param>
    ''' <param name="progressDelegate">Progress delegate.</param>
    ''' <returns>Image of BMP file.</returns>
    Public Overrides Function GetImage(pageIndex As Integer, decodingSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings, renderingSettings As Vintasoft.Imaging.Codecs.Decoders.RenderingSettings, progressDelegate As System.EventHandler(Of Vintasoft.Imaging.ProgressEventArgs)) As Vintasoft.Imaging.VintasoftImage
        CheckPageIndexValue(pageIndex)
        CheckRenderingSettingsValue(renderingSettings)

        SyncLock _file
            ' get image
            Dim image As Vintasoft.Imaging.VintasoftImage = _file.Page.GetImage(progressDelegate)

            ' perform the color correction if necessary
            PerformColorCorrection(pageIndex, image, decodingSettings)

            ' return the image
            Return image
        End SyncLock
    End Function

    ''' <summary>
    ''' Returns a metadata of BMP file.
    ''' </summary>
    ''' <param name="pageIndex">The zero based page index (not used).</param>
    ''' <returns>Metadata of BMP file.</returns>
    Public Overrides Function GetPageMetadata(pageIndex As Integer) As Vintasoft.Imaging.Metadata.PageMetadata
        Return New Vintasoft.Imaging.Metadata.PageMetadata("Bmp")
    End Function

    ''' <summary>
    ''' Closes the source of the decoder.
    ''' </summary>
    Public Overrides Sub Close()
        If _file IsNot Nothing Then
            _file.Dispose()
            _file = Nothing
        End If
        MyBase.Close()
    End Sub

    #End Region

End Class



Example of SimpleBmp codec's encoder

Here is C#/VB.NET code that demonstrates how to create SimpleBmp codec's encoder:
/// <summary>
/// Defines an encoder for BMP images.
/// </summary>
public class SimpleBmpEncoder : Vintasoft.Imaging.Codecs.Encoders.EncoderBase
{
            
    #region Constructor

    /// <summary>
    /// Initializes a new instance of the SimpleBmpEncoder class.
    /// </summary>
    public SimpleBmpEncoder() 
        : base()
    {
    }

    #endregion



    #region Properties
  
    /// <summary>
    /// Gets the name of the encoder.
    /// </summary>
    public override string Name
    {
        get 
        {
            return "Simple Bmp";
        }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Sets the encoder settings.
    /// </summary>
    /// <param name="encoderSettings">The encoder settings.</param>
    public override void SetSettings(Vintasoft.Imaging.Codecs.Encoders.EncoderSettings encoderSettings)
    {
        throw new System.NotSupportedException();
    }

    /// <summary>
    /// Saves single image to the stream.
    /// </summary>
    /// <param name="image"><b>VintasoftImage</b> object to save.</param>
    /// <param name="metadataTree">Virtual metadata tree which contains information
    /// about cached image metadata.</param>
    /// <param name="stream">Stream where the image should be saved.</param>
    /// <param name="progressController">Progress controller.</param>
    protected override void SaveImageWithMetadataToStream(
        Vintasoft.Imaging.VintasoftImage image, 
        Vintasoft.Imaging.Metadata.MetadataNode metadataTree, 
        System.IO.Stream stream, 
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        stream.SetLength(0);

        using (SimpleBmpFile bmpFile = new SimpleBmpFile(image))
        {
            bmpFile.Save(stream, progressController);
        }
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    /// <returns>
    /// A new object that is a copy of this instance.
    /// </returns>
    public override object Clone()
    {
        SimpleBmpEncoder encoder = new SimpleBmpEncoder();
        CopyTo(encoder);
        return encoder;
    }

    #endregion

}
''' <summary>
''' Defines an encoder for BMP images.
''' </summary>
Public Class SimpleBmpEncoder
    Inherits Vintasoft.Imaging.Codecs.Encoders.EncoderBase

    #Region "Constructor"

    ''' <summary>
    ''' Initializes a new instance of the SimpleBmpEncoder class.
    ''' </summary>
    Public Sub New()
        MyBase.New()
    End Sub

    #End Region



    #Region "Properties"

    ''' <summary>
    ''' Gets the name of the encoder.
    ''' </summary>
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "Simple Bmp"
        End Get
    End Property

    #End Region



    #Region "Methods"

    ''' <summary>
    ''' Sets the encoder settings.
    ''' </summary>
    ''' <param name="encoderSettings">The encoder settings.</param>
    Public Overrides Sub SetSettings(encoderSettings As Vintasoft.Imaging.Codecs.Encoders.EncoderSettings)
        Throw New System.NotSupportedException()
    End Sub

    ''' <summary>
    ''' Saves single image to the stream.
    ''' </summary>
    ''' <param name="image"><b>VintasoftImage</b> object to save.</param>
    ''' <param name="metadataTree">Virtual metadata tree which contains information
    ''' about cached image metadata.</param>
    ''' <param name="stream">Stream where the image should be saved.</param>
    ''' <param name="progressController">Progress controller.</param>
    Protected Overrides Sub SaveImageWithMetadataToStream(image As Vintasoft.Imaging.VintasoftImage, metadataTree As Vintasoft.Imaging.Metadata.MetadataNode, stream As System.IO.Stream, progressController As Vintasoft.Imaging.Utils.IProgressController)
        stream.SetLength(0)

        Using bmpFile As New SimpleBmpFile(image)
            bmpFile.Save(stream, progressController)
        End Using
    End Sub

    ''' <summary>
    ''' Creates a new object that is a copy of the current instance.
    ''' </summary>
    ''' <returns>
    ''' A new object that is a copy of this instance.
    ''' </returns>
    Public Overrides Function Clone() As Object
        Dim encoder As New SimpleBmpEncoder()
        CopyTo(encoder)
        Return encoder
    End Function

    #End Region

End Class



Example of SimpleBmp codec's image file

Here is C#/VB.NET code that demonstrates how to create SimpleBmp codec's image file:
/// <summary>
/// Class that allows to manipulate BMP file.
/// </summary>
public class SimpleBmpFile : 
    Vintasoft.Imaging.Codecs.ImageFiles.SinglePageImageFile<SimpleBmpPage>
{

    #region Fields

    /// <summary>
    /// Bitmap file header length.
    /// </summary>
    const uint BITMAPFILEHEADER_LENGTH = 14;

    /// <summary>
    /// Image data offset.
    /// </summary>
    uint _offsetToImageData;

    /// <summary>
    /// BMP file size.
    /// </summary>
    uint _fileSize;

    #endregion



    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    /// </summary>
    /// <param name="stream">Stream which contains the image file.</param>
    public SimpleBmpFile(System.IO.Stream stream)
        : base(stream)
    {
        _source = new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream);
        try
        {
            Parse();
        }
        catch
        {
            _source.Dispose();
            throw;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    /// </summary>
    /// <param name="fileName">The name of the image file.</param>
    /// <param name="mode">A FileMode constant that determines how to open or create the image file.</param>
    /// <param name="access">A FileAccess constant that determines how the image file can be accessed.</param>
    public SimpleBmpFile(string fileName, System.IO.FileMode mode, System.IO.FileAccess access)
        : base(fileName, mode, access)
    {
        _source = new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(fileName, mode, access);
        try
        {
            Parse();
        }
        catch
        {
            _source.Dispose();
            throw;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    /// </summary>
    /// <param name="image">A first page image.</param>
    public SimpleBmpFile(Vintasoft.Imaging.VintasoftImage image)
    {
        if (image.PixelFormat != Vintasoft.Imaging.PixelFormat.Bgr24 &&
            image.PixelFormat != Vintasoft.Imaging.PixelFormat.Bgr32)
            throw new System.NotImplementedException();

        // create memory stream
        System.IO.MemoryStream stream = new System.IO.MemoryStream();
        // create image file source
        _source = new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream);
        // create new Bmp page
        base.Page = new SimpleBmpPage(_source, image);
    }

    #endregion



    #region Properties

    Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource _source;
    /// <summary>
    /// Source of the image file.
    /// </summary>
    /// <remarks>
    /// This object provides access to the binary data of the image file.
    /// </remarks>
    protected override Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource Source
    {
        get
        {
            return _source;
        }
    }

    /// <summary>
    /// Gets the page of this BMP file.
    /// </summary>
    /// <exception cref="System.InvalidOperationException">Thrown if page is sets.</exception>
    public override SimpleBmpPage Page
    {
        get
        {
            return base.Page;
        }
        set
        {
            throw new System.InvalidOperationException();
        }
    }

    #endregion



    #region Methods

    #region PUBLIC

    /// <summary>
    /// Saves this BMP file to specified stream.
    /// </summary>
    /// <param name="stream">Stream to save the image file.</param>
    /// <param name="progressController">Progress controller.</param>
    /// <exception cref="System.ArgumentNullException">Thrown if <i>stream</i> is null.</exception>
    /// <remarks>
    /// This method saves changes to specified stream. Current source of the image
    /// file is not changed.
    /// </remarks>
    public override void Save(System.IO.Stream stream, 
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // create image file source
        using (Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source = 
            new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream))
        {
            SaveToSource(source, progressController);
        }
    }

    /// <summary>
    /// Saves this BMP file to specified file.
    /// </summary>
    /// <param name="filename">The name of the image file.</param>
    /// <param name="progressController">Progress controller.</param>
    /// <exception cref="System.ArgumentNullException">Thrown if <i>filename</i> is null.</exception>
    /// <remarks>
    /// This method saves changes to specified file. Current source of the image
    /// file is not changed.
    /// </remarks>
    public override void Save(string filename, 
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // create image file source
        using (Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source = 
            new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(
            filename, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
        {
            SaveToSource(source, progressController);
        }
    }

    /// <summary>
    /// Saves changes of the image file to specified stream.
    /// </summary>
    /// <param name="stream">Stream to save the image file.</param>
    /// <param name="progressController">Progress controller.</param>
    /// <remarks>
    /// This method saves changes to specified stream and makes this stream
    /// as current source of the image file. Previous source of the image
    /// file is closed without save changes.
    /// </remarks>
    public override void SaveChanges(System.IO.Stream stream, 
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // create image file source
        using (Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source =
            new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream))
        {
            source.SwitchToThisSource = true;
            SaveToSource(source, progressController);
        }
    }

    /// <summary>
    /// Saves changes of the image file to specified file.
    /// </summary>
    /// <param name="filename">The filename to save the image file.</param>
    /// <param name="progressController">Progress controller.</param>
    /// <remarks>
    /// This method saves changes to specified file and makes this file
    /// as current source of the image file. Previous source of the image
    /// file is closed without save changes.
    /// </remarks>
    public override void SaveChanges(string filename, 
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // create image file source
        using (Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source = 
            new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(
            filename, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
        {
            source.SwitchToThisSource = true;
            SaveToSource(source, progressController);
        }
    }

    /// <summary>
    /// Saves changes of the image file to the current source of the image file.
    /// </summary>
    /// <param name="progressController">Progress controller.</param>
    /// <exception cref="System.InvalidOperationException">
    /// Thrown if source is open in read-only mode and cannot be changed.
    /// </exception>
    public override void SaveChanges(
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // if can't be write to source
        if (!Source.Stream.CanWrite)
            throw new System.InvalidOperationException();

        Source.Position = BITMAPFILEHEADER_LENGTH;
        // update page header
        Page.WriteHeader(Source);
    }

    /// <summary>
    /// Determines that stream contains BMP file.
    /// </summary>
    /// <param name="stream">Stream with binary data of the BMP file.</param>
    /// <returns>
    /// <b>true</b> if stream contains BMP file;
    /// otherwise, <b>false</b>.
    /// </returns>
    public static bool IsValidFormat(System.IO.Stream stream)
    {
        long position = stream.Position;
        try
        {
            return (stream.ReadByte() == 0x42) && (stream.ReadByte() == 0x4D);
        }
        finally
        {
            stream.Position = position;
        }            
    }

    #endregion


    #region PROTECTED

    /// <summary>
    /// Parses the BMP file.
    /// </summary>
    /// <remarks>
    /// This method reads structure of the image file and must called from the
    /// constructor of the class.
    /// </remarks>
    protected override void Parse()
    {
        lock (Source.Stream)
        {
            // WORD bfType
            if (Source.ReadByte() != 0x42 || Source.ReadByte() != 0x4D)
                throw new System.ArgumentException("ImageFileSource is not BMP file.", "Source");

            // DWORD bfSize
            _fileSize = Source.ReadUInt32();

            // WORD bfReserved1
            // WORD bfReserved2
            Source.Position += 4;

            // DWORD bfOffBits
            _offsetToImageData = Source.ReadUInt32();

            // parse page
            base.Page = new SimpleBmpPage(Source, _offsetToImageData);
        }
    }

    #endregion


    #region PRIVATE

    /// <summary>
    /// Saves BMP file to a source.
    /// </summary>
    /// <param name="source">Source of the image file.</param>
    /// <param name="progressController">Progress controller.</param>
    private void SaveToSource(
        Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source,
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // if specified source equals source of this file
        if (source.Stream == this.Source.Stream)
        {
            // save changes to a file
            SaveChanges(progressController);
            return;
        }

        // write header
        WriteHeader(source);

        // write page
        Page.Save(source, progressController);

        // if it is necessary to switch the source
        if (source.SwitchToThisSource)
        {
            // if this file has the source
            if (this.Source != null)
                // close current source of this file
                this.Source.Dispose();

            // set a new source for this file
            _source = source;
        }
    }

    /// <summary>
    /// Writes the BMP file header to a source.
    /// </summary>
    /// <param name="source">Source of the image file.</param>
    private void WriteHeader(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source)
    {
        lock (source.Stream)
        {
            // WORD bfType
            source.WriteByte(0x42);
            source.WriteByte(0x4D);
            // DWORD bfSize
            source.WriteUInt32(_fileSize);
            // WORD bfReserved1
            source.WriteUInt16(0);
            // WORD bfReserved2
            source.WriteUInt16(0);
            // DWORD bfOffBits - write BMP file header length + BMP page header length
            source.WriteUInt32(BITMAPFILEHEADER_LENGTH + SimpleBmpPage.BITMAPINFOHEADER_LENGTH);
        }
    }

    #endregion

    #endregion

}
''' <summary>
''' Class that allows to manipulate BMP file.
''' </summary>
Public Class SimpleBmpFile
    Inherits Vintasoft.Imaging.Codecs.ImageFiles.SinglePageImageFile(Of SimpleBmpPage)

    #Region "Fields"

    ''' <summary>
    ''' Bitmap file header length.
    ''' </summary>
    Const BITMAPFILEHEADER_LENGTH As UInteger = 14

    ''' <summary>
    ''' Image data offset.
    ''' </summary>
    Private _offsetToImageData As UInteger

    ''' <summary>
    ''' BMP file size.
    ''' </summary>
    Private _fileSize As UInteger

    #End Region



    #Region "Constructor"

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    ''' </summary>
    ''' <param name="stream">Stream which contains the image file.</param>
    Public Sub New(stream As System.IO.Stream)
        MyBase.New(stream)
        _source = New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream)
        Try
            Parse()
        Catch
            _source.Dispose()
            Throw
        End Try
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    ''' </summary>
    ''' <param name="fileName">The name of the image file.</param>
    ''' <param name="mode">A FileMode constant that determines how to open or create the image file.</param>
    ''' <param name="access">A FileAccess constant that determines how the image file can be accessed.</param>
    Public Sub New(fileName As String, mode As System.IO.FileMode, access As System.IO.FileAccess)
        MyBase.New(fileName, mode, access)
        _source = New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(fileName, mode, access)
        Try
            Parse()
        Catch
            _source.Dispose()
            Throw
        End Try
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpFile"/> class.
    ''' </summary>
    ''' <param name="image">A first page image.</param>
    Public Sub New(image As Vintasoft.Imaging.VintasoftImage)
        If image.PixelFormat <> Vintasoft.Imaging.PixelFormat.Bgr24 AndAlso image.PixelFormat <> Vintasoft.Imaging.PixelFormat.Bgr32 Then
            Throw New System.NotImplementedException()
        End If

        ' create memory stream
        Dim stream As New System.IO.MemoryStream()
        ' create image file source
        _source = New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream)
        ' create new Bmp page
        MyBase.Page = New SimpleBmpPage(_source, image)
    End Sub

    #End Region



    #Region "Properties"

    Private _source As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource
    ''' <summary>
    ''' Source of the image file.
    ''' </summary>
    ''' <remarks>
    ''' This object provides access to the binary data of the image file.
    ''' </remarks>
    Protected Overrides ReadOnly Property Source() As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource
        Get
            Return _source
        End Get
    End Property

    ''' <summary>
    ''' Gets the page of this BMP file.
    ''' </summary>
    ''' <exception cref="System.InvalidOperationException">Thrown if page is sets.</exception>
    Public Overrides Property Page() As SimpleBmpPage
        Get
            Return MyBase.Page
        End Get
        Set
            Throw New System.InvalidOperationException()
        End Set
    End Property

    #End Region



    #Region "Methods"

    #Region "PUBLIC"

    ''' <summary>
    ''' Saves this BMP file to specified stream.
    ''' </summary>
    ''' <param name="stream">Stream to save the image file.</param>
    ''' <param name="progressController">Progress controller.</param>
    ''' <exception cref="System.ArgumentNullException">Thrown if <i>stream</i> is null.</exception>
    ''' <remarks>
    ''' This method saves changes to specified stream. Current source of the image
    ''' file is not changed.
    ''' </remarks>
    Public Overrides Sub Save(stream As System.IO.Stream, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' create image file source
        Using source As New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream)
            SaveToSource(source, progressController)
        End Using
    End Sub

    ''' <summary>
    ''' Saves this BMP file to specified file.
    ''' </summary>
    ''' <param name="filename">The name of the image file.</param>
    ''' <param name="progressController">Progress controller.</param>
    ''' <exception cref="System.ArgumentNullException">Thrown if <i>filename</i> is null.</exception>
    ''' <remarks>
    ''' This method saves changes to specified file. Current source of the image
    ''' file is not changed.
    ''' </remarks>
    Public Overrides Sub Save(filename As String, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' create image file source
        Using source As New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(filename, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite)
            SaveToSource(source, progressController)
        End Using
    End Sub

    ''' <summary>
    ''' Saves changes of the image file to specified stream.
    ''' </summary>
    ''' <param name="stream">Stream to save the image file.</param>
    ''' <param name="progressController">Progress controller.</param>
    ''' <remarks>
    ''' This method saves changes to specified stream and makes this stream
    ''' as current source of the image file. Previous source of the image
    ''' file is closed without save changes.
    ''' </remarks>
    Public Overrides Sub SaveChanges(stream As System.IO.Stream, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' create image file source
        Using source As New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(stream)
            source.SwitchToThisSource = True
            SaveToSource(source, progressController)
        End Using
    End Sub

    ''' <summary>
    ''' Saves changes of the image file to specified file.
    ''' </summary>
    ''' <param name="filename">The filename to save the image file.</param>
    ''' <param name="progressController">Progress controller.</param>
    ''' <remarks>
    ''' This method saves changes to specified file and makes this file
    ''' as current source of the image file. Previous source of the image
    ''' file is closed without save changes.
    ''' </remarks>
    Public Overrides Sub SaveChanges(filename As String, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' create image file source
        Using source As New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource(filename, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite)
            source.SwitchToThisSource = True
            SaveToSource(source, progressController)
        End Using
    End Sub

    ''' <summary>
    ''' Saves changes of the image file to the current source of the image file.
    ''' </summary>
    ''' <param name="progressController">Progress controller.</param>
    ''' <exception cref="System.InvalidOperationException">
    ''' Thrown if source is open in read-only mode and cannot be changed.
    ''' </exception>
    Public Overrides Sub SaveChanges(progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' if can't be write to source
        If Not Source.Stream.CanWrite Then
            Throw New System.InvalidOperationException()
        End If

        Source.Position = BITMAPFILEHEADER_LENGTH
        ' update page header
        Page.WriteHeader(Source)
    End Sub

    ''' <summary>
    ''' Determines that stream contains BMP file.
    ''' </summary>
    ''' <param name="stream">Stream with binary data of the BMP file.</param>
    ''' <returns>
    ''' <b>true</b> if stream contains BMP file;
    ''' otherwise, <b>false</b>.
    ''' </returns>
    Public Shared Function IsValidFormat(stream As System.IO.Stream) As Boolean
        Dim position As Long = stream.Position
        Try
            Return (stream.ReadByte() = &H42) AndAlso (stream.ReadByte() = &H4d)
        Finally
            stream.Position = position
        End Try
    End Function

    #End Region


    #Region "PROTECTED"

    ''' <summary>
    ''' Parses the BMP file.
    ''' </summary>
    ''' <remarks>
    ''' This method reads structure of the image file and must called from the
    ''' constructor of the class.
    ''' </remarks>
    Protected Overrides Sub Parse()
        SyncLock Source.Stream
            ' WORD bfType
            If Source.ReadByte() <> &H42 OrElse Source.ReadByte() <> &H4d Then
                Throw New System.ArgumentException("ImageFileSource is not BMP file.", "Source")
            End If

            ' DWORD bfSize
            _fileSize = Source.ReadUInt32()

            ' WORD bfReserved1
            ' WORD bfReserved2
            Source.Position += 4

            ' DWORD bfOffBits
            _offsetToImageData = Source.ReadUInt32()

            ' parse page
            MyBase.Page = New SimpleBmpPage(Source, _offsetToImageData)
        End SyncLock
    End Sub

    #End Region


    #Region "PRIVATE"

    ''' <summary>
    ''' Saves BMP file to a source.
    ''' </summary>
    ''' <param name="source">Source of the image file.</param>
    ''' <param name="progressController">Progress controller.</param>
    Private Sub SaveToSource(source As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' if specified source equals source of this file
        If source.Stream Is Me.Source.Stream Then
            ' save changes to a file
            SaveChanges(progressController)
            Return
        End If

        ' write header
        WriteHeader(source)

        ' write page
        Page.Save(source, progressController)

        ' if it is necessary to switch the source
        If source.SwitchToThisSource Then
            ' if this file has the source
            If Me.Source IsNot Nothing Then
                ' close current source of this file
                Me.Source.Dispose()
            End If

            ' set a new source for this file
            _source = source
        End If
    End Sub

    ''' <summary>
    ''' Writes the BMP file header to a source.
    ''' </summary>
    ''' <param name="source">Source of the image file.</param>
    Private Sub WriteHeader(source As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource)
        SyncLock source.Stream
            ' WORD bfType
            source.WriteByte(&H42)
            source.WriteByte(&H4d)
            ' DWORD bfSize
            source.WriteUInt32(_fileSize)
            ' WORD bfReserved1
            source.WriteUInt16(0)
            ' WORD bfReserved2
            source.WriteUInt16(0)
            ' DWORD bfOffBits - write BMP file header length + BMP page header length
            source.WriteUInt32(BITMAPFILEHEADER_LENGTH + SimpleBmpPage.BITMAPINFOHEADER_LENGTH)
        End SyncLock
    End Sub

    #End Region

    #End Region

End Class



Example of SimpleBmp codec's image file page

Here is C#/VB.NET code that demonstrates how to create SimpleBmp codec's image file page:
/// <summary>
/// Class that allows to get information about BMP page.
/// </summary>
public class SimpleBmpPage : Vintasoft.Imaging.Codecs.ImageFiles.ImagePage
{

    #region Fields

    /// <summary>
    /// BMP page info header length.
    /// </summary>
    internal const uint BITMAPINFOHEADER_LENGTH = 40;

    /// <summary>
    /// Image stride (row width in bytes).
    /// </summary>
    int _stride;

    /// <summary>
    /// Indicates that image raw data is reversed.
    /// </summary>
    bool _reverseReadWrite;

    /// <summary>
    /// Image raw data offset, in bytes.
    /// </summary>
    long _offsetToImageData;

    /// <summary>
    /// Image length, in bytes.
    /// </summary>
    uint _imageSize;

    #endregion



    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpPage"/> class.
    /// </summary>
    /// <param name="source">Source of the image page.</param>
    /// <param name="offset">Offset of the image page in the source.</param>
    public SimpleBmpPage(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source, long offset)
        : base(source, offset)
    {
        _offsetToImageData = offset;
        Parse();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SimpleBmpPage"/> class.
    /// </summary>
    /// <param name="source">Source of the image page.</param>
    /// <param name="image">New image.</param>
    public SimpleBmpPage(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source, 
        Vintasoft.Imaging.VintasoftImage image)
        : base(source, 0)
    {        
        // sets the image settings
        _offsetToImageData = 0;
        _imagePixelFormat = image.PixelFormat;
        _width = image.Width;
        _height = image.Height;
        _resolution = image.Resolution;
        _hasResolution = true;
        _bitsPerPixel = image.BitsPerPixel;

        // calculate stride of image
        _stride = Vintasoft.Imaging.VintasoftBitmap.GetStride(_imagePixelFormat, Width);
        // image is reverse
        _reverseReadWrite = true;

        // encode image data
        EncodeImageData(Source, image);

        // set the image length
        _imageSize = (uint)Source.Length;
        // set bmp page length
        SetLength(BITMAPINFOHEADER_LENGTH + _imageSize);
    }

    #endregion



    #region Properties

    int _width;
    /// <summary>
    /// Gets the width, in pixels, of the image page.
    /// </summary>
    public override int Width
    {
        get
        {
            return _width;
        }
    }

    int _height;
    /// <summary>
    /// Gets the height, in pixels, of the image page.
    /// </summary>
    public override int Height
    {
        get
        {
            return System.Math.Abs(_height);
        }
    }

    int _bitsPerPixel;
    /// <summary>
    /// Gets the bit depth of the image page.
    /// </summary>
    public override int BitsPerPixel
    {
        get
        {
            return _bitsPerPixel;
        }
    }

    Vintasoft.Imaging.Palette _palette = null;
    /// <summary>
    /// Gets the palette of the image page.
    /// </summary>
    public override Vintasoft.Imaging.Palette Palette
    {
        get
        {
            return _palette;
        }
    }

    Vintasoft.Imaging.Resolution _resolution = Vintasoft.Imaging.Resolution.Empty;
    /// <summary>
    /// Gets or sets the resolution, in pixels per inch, of the image page.
    /// </summary>
    /// <value>
    /// The resolution loaded from an image metadata if <see cref="HasResolution"/> returns <b>true</b>;
    /// otherwise, the default (screen) resolution.
    /// </value>
    /// <seealso cref="HasResolution"/>
    public override Vintasoft.Imaging.Resolution Resolution
    {
        get
        {
            if (_resolution == Vintasoft.Imaging.Resolution.Empty)
                return Vintasoft.Imaging.ImagingEnvironment.ScreenResolution;
            return _resolution;
        }
        set
        {
            throw new System.NotImplementedException();
        }
    }

    bool _hasResolution = false;
    /// <summary>
    /// Gets a value indicating whether the information about image resolution is stored
    /// in a BMP page.
    /// </summary>
    /// <value>
    /// <b>True</b> - the <see cref="Resolution"/> property returns resolution loaded from image file;<br />
    /// <b>false</b> - the <see cref="Resolution"/> property returns the default (screen) resolution.
    /// </value>
    /// <seealso cref="Resolution"/>
    public override bool HasResolution
    {
        get 
        {
            return _hasResolution;
        }
    }

    Vintasoft.Imaging.PixelFormat _imagePixelFormat = Vintasoft.Imaging.PixelFormat.Undefined;
    /// <summary>
    /// Gets the pixel format of this page.
    /// </summary>
    public Vintasoft.Imaging.PixelFormat PixelFormat
    {
        get
        {
            return _imagePixelFormat;
        }
    }

    #endregion



    #region Methods

    #region PUBLIC

    /// <summary>
    /// Gets the image associated with this image page.
    /// </summary>
    /// <param name="decodingSettings">Decoding settings used for decode the image of page.</param>
    /// <param name="progressDelegate">Progress delegate.
    /// Can be set to null (Nothing in Visual Basic).</param>
    /// <returns>The image associated with this BMP page if image was loaded successfully;
    /// otherwise, null.</returns>
    public override Vintasoft.Imaging.VintasoftImage GetImage(
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings,
        System.EventHandler<Vintasoft.Imaging.ProgressEventArgs> progressDelegate)
    {
        // create image
        Vintasoft.Imaging.VintasoftImage image = new Vintasoft.Imaging.VintasoftImage(Width, Height, _imagePixelFormat);

        // if resolution is empty
        if (_resolution.IsEmpty())
            image.Resolution = Vintasoft.Imaging.ImagingEnvironment.ScreenResolution;
        else
        {
            _hasResolution = true;
            image.Resolution = _resolution;
        }

        // open pixel manipulator
        Vintasoft.Imaging.PixelManipulator pixelManipulator = image.OpenPixelManipulator();
        System.Drawing.Rectangle lockPixelsRectangle = new System.Drawing.Rectangle(0, 0, Width, Height);
        // lock pixels
        pixelManipulator.LockPixelsForSerialAccess(lockPixelsRectangle, Vintasoft.Imaging.BitmapLockMode.Write,
             _imagePixelFormat, new byte[_stride], _reverseReadWrite);
        try
        {
            // lock the original image source (image source from which BMP page must be read)
            lock (Source.Stream)
            {
                // go to the start of image data in original image source
                Source.Position = _offsetToImageData;
                // get serial buffer of pixel manipulator
                byte[] buffer = pixelManipulator.SerialBuffer;
                int yStart = Height - 1;

                int previousProgress = -1;
                double progressStep = 100.0 / yStart;
                double currentProgress = -progressStep;

                // for each image row
                for (int y = yStart; y >= 0; y--)
                {
                    // if progress must be generated
                    if (progressDelegate != null)
                    {
                        // calculate current progress
                        currentProgress += progressStep;
                        // if previous and current progress are different
                        if (previousProgress != (int)System.Math.Round(currentProgress))
                        {
                            // get the progress integer value
                            previousProgress = (int)System.Math.Round(currentProgress);
                            // raise the progress event
                            progressDelegate(this, new Vintasoft.Imaging.ProgressEventArgs(previousProgress));
                        }
                    }

                    // read row data from image source
                    Source.ReadBytes(buffer);
                    // write row data to the pixel manipulator
                    pixelManipulator.WriteRowAndMoveToNext();
                }
            }
        }
        finally
        {
            // unlock pixels
            pixelManipulator.UnlockPixels();
            // close pixel manipulator
            image.ClosePixelManipulator(true);
        }

        return image;
    }

    /// <summary>
    /// Saves the page to the image source.
    /// </summary>
    /// <param name="source">Image source.</param>
    /// <param name="progressController">Progress controller.</param>
    public override void Save(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source,
        Vintasoft.Imaging.Utils.IProgressController progressController)
    {
        // raise the Saving event
        OnSaving(System.EventArgs.Empty);

        // if progress controller is specified
        if (progressController != null)
        {
            // specify that there is only one progress stage
            progressController.Start(1);
            // start the progress stage
            progressController.NextStage(this, false);
        }

        // lock the destination image source (image source where BMP page must be written)
        lock (source.Stream)
        {
            // write header to the destination image source
            WriteHeader(source);

            // lock the original image source (image source from which BMP page must be read)
            lock (Source.Stream)
            {
                // go to the start of image data in original image source
                Source.Position = _offsetToImageData;
                // create buffer for row data
                byte[] buffer = new byte[_stride];

                // if progress controller is specified
                if (progressController != null)
                    // specify the count of progress steps
                    progressController.StartSteps((int)System.Math.Ceiling((double)_imageSize / buffer.Length));

                uint writeBytesCount = 0;

                // while the count of written bytes less than image size
                while (writeBytesCount != _imageSize)
                {
                    // if progress controller is specified
                    if (progressController != null)
                    {
                        // raise progress and check if saving process must be canceled
                        if (!progressController.NextStep(this, true))
                            // cancel saving process
                            break;
                    }

                    // get count of bytes to read
                    int bytesToRead = (int)System.Math.Min(_imageSize - writeBytesCount, buffer.Length);

                    // read image row data from original image source
                    this.Source.ReadBytes(buffer, 0, bytesToRead);
                    // write image row data to the destination image source
                    source.WriteBytes(buffer, 0, bytesToRead);

                    // update the count of written bytes
                    writeBytesCount += (uint)bytesToRead;
                }

                // if progress controller is specified
                if (progressController != null)
                    // finish a sequence of progress steps
                    progressController.FinishSteps(this);
            }
        }

        // if progress controller is specified
        if (progressController != null)
            // finish the progress stage
            progressController.Finish(this);

        // raise the Saved event
        OnSaved(new Vintasoft.Imaging.Codecs.ImageFiles.ImageFileBlockSourceInfoChangedEventArgs());
    }

    #endregion


    #region PROTECTED

    /// <summary>
    /// Parse the BMP page.
    /// </summary>
    protected override void Parse()
    {
        // lock the original image source (image source from which BMP page must be read)
        lock (Source.Stream)
        {
            // read info block length
            uint infoBlockLength = Source.ReadUInt32();

            // if info block is not standard
            if (infoBlockLength != BITMAPINFOHEADER_LENGTH)
                throw new System.NotSupportedException("Unsupported bitmap info block.");

            // LONG biWidth
            _width = Source.ReadInt32();

            // LONG biHeight
            _height = Source.ReadInt32();
            _reverseReadWrite = _height > 0;

            // WORD biPlanes
            Source.Position += 2;

            // WORD biBitCount
            System.UInt16 bitCount = Source.ReadUInt16();
            _bitsPerPixel = bitCount;

            switch (bitCount)
            {
                case 24:
                    _imagePixelFormat = Vintasoft.Imaging.PixelFormat.Bgr24;
                    break;

                case 32:
                    _imagePixelFormat = Vintasoft.Imaging.PixelFormat.Bgr32;
                    break;

                default:
                    throw new System.NotSupportedException("Unsupported pixel format.");
            }

            // calculate stride
            _stride = Vintasoft.Imaging.VintasoftBitmap.GetStride(_imagePixelFormat, Width);

            // DWORD biCompression;
            System.UInt32 compression = Source.ReadUInt32();

            // if image is compressed
            if (compression != 0)
                throw new System.NotSupportedException("Compressed data is not supported.");

            // DWORD biSizeImage;
            _imageSize = Source.ReadUInt32();

            if (_imageSize == 0)
                _imageSize = (uint)(_stride * Height);

            // LONG biXPelsPerMeter;
            float dpiX = Source.ReadInt32() / (100f * (1f / 2.54f));

            // LONG biYPelsPerMeter;
            float dpiY = Source.ReadInt32() / (100f * (1f / 2.54f));

            // set resolution
            _resolution = new Vintasoft.Imaging.Resolution(dpiX, dpiY);
            _hasResolution = true;

            // set page block
            SetLength(BITMAPINFOHEADER_LENGTH + _imageSize);
        }
    }

    #endregion


    #region INTERNAL

    /// <summary>
    /// Writes BMP page header.
    /// </summary>
    /// <param name="source">Image source where BMP page must be written.</param>
    internal void WriteHeader(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source)
    {
        // lock the destination image source (image source where BMP page must be written)
        lock (source.Stream)
        {
            // DWORD biSize
            source.WriteUInt32(BITMAPINFOHEADER_LENGTH);

            // LONG biWidth
            source.WriteInt32(_width);

            // LONG biHeight
            source.WriteInt32(_height);

            // WORD biPlanes
            source.WriteUInt16(1);

            // WORD biBitCount
            source.WriteUInt16((System.UInt16)_bitsPerPixel);

            // DWORD biCompression
            source.WriteUInt32(0);

            // DWORD biSizeImage
            source.WriteUInt32(_imageSize);

            int dpiX = 0;
            int dpiY = 0;
            // if resolution is not empty
            if (!_resolution.IsEmpty())
            {
                dpiX = (int)System.Math.Round(_resolution.Horizontal * (100.0f * (1.0f / 2.54f)));
                dpiY = (int)System.Math.Round(_resolution.Vertical * (100.0f * (1.0f / 2.54f)));
            }

            // LONG biXPelsPerMeter
            source.WriteInt32(dpiX);

            // LONG biYPelsPerMeter
            source.WriteInt32(dpiY);

            // DWORD biClrUsed
            source.WriteUInt32(0);

            // DWORD biClrImportant
            source.WriteUInt32(0);
        }
    }

    #endregion


    #region PRIVATE

    /// <summary>
    /// Encodes an image data.
    /// </summary>
    /// <param name="source">Image source.</param>
    /// <param name="image">Image.</param>
    private void EncodeImageData(Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource source, 
        Vintasoft.Imaging.VintasoftImage image)
    {
        // open the pixel manipulator
        Vintasoft.Imaging.PixelManipulator pixelManipulator = image.OpenPixelManipulator();

        // lock pixels
        System.Drawing.Rectangle lockPixelsRectangle = new System.Drawing.Rectangle(0, 0, Width, Height);
        pixelManipulator.LockPixelsForSerialAccess(lockPixelsRectangle, Vintasoft.Imaging.BitmapLockMode.Write,
            _imagePixelFormat, new byte[_stride], _reverseReadWrite);

        try
        {
            // lock the original image source (image source from which BMP page must be read)
            lock (Source.Stream)
            {
                // go to the start of image data in original image source
                Source.Position = _offsetToImageData;

                // get serial buffer of pixel manipulator
                byte[] buffer = pixelManipulator.SerialBuffer;

                // for each image row
                int yStart = Height - 1;
                for (int y = yStart; y >= 0; y--)
                {
                    // read row data from pixel manipulator
                    pixelManipulator.ReadRowAndMoveToNext();
                    // write row data to the image source
                    Source.WriteBytes(buffer);
                }
            }
        }
        finally
        {
            // unlock pixels
            pixelManipulator.UnlockPixels();
            // close the pixel manipulator
            image.ClosePixelManipulator(false);
        }
    }

    #endregion

    #endregion

}
''' <summary>
''' Class that allows to get information about BMP page.
''' </summary>
Public Class SimpleBmpPage
    Inherits Vintasoft.Imaging.Codecs.ImageFiles.ImagePage

    #Region "Fields"

    ''' <summary>
    ''' BMP page info header length.
    ''' </summary>
    Friend Const BITMAPINFOHEADER_LENGTH As UInteger = 40

    ''' <summary>
    ''' Image stride (row width in bytes).
    ''' </summary>
    Private _stride As Integer

    ''' <summary>
    ''' Indicates that image raw data is reversed.
    ''' </summary>
    Private _reverseReadWrite As Boolean

    ''' <summary>
    ''' Image raw data offset, in bytes.
    ''' </summary>
    Private _offsetToImageData As Long

    ''' <summary>
    ''' Image length, in bytes.
    ''' </summary>
    Private _imageSize As UInteger

    #End Region



    #Region "Constructors"

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpPage"/> class.
    ''' </summary>
    ''' <param name="source">Source of the image page.</param>
    ''' <param name="offset">Offset of the image page in the source.</param>
    Public Sub New(source As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource, offset As Long)
        MyBase.New(source, offset)
        _offsetToImageData = offset
        Parse()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="SimpleBmpPage"/> class.
    ''' </summary>
    ''' <param name="source">Source of the image page.</param>
    ''' <param name="image">New image.</param>
    Public Sub New(source__1 As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource, image As Vintasoft.Imaging.VintasoftImage)
        MyBase.New(source__1, 0)
        ' sets the image settings
        _offsetToImageData = 0
        _imagePixelFormat = image.PixelFormat
        _width = image.Width
        _height = image.Height
        _resolution = image.Resolution
        _hasResolution = True
        _bitsPerPixel = image.BitsPerPixel

        ' calculate stride of image
        _stride = Vintasoft.Imaging.VintasoftBitmap.GetStride(_imagePixelFormat, Width)
        ' image is reverse
        _reverseReadWrite = True

        ' encode image data
        EncodeImageData(Source, image)

        ' set the image length
        _imageSize = CUInt(Source.Length)
        ' set bmp page length
        SetLength(BITMAPINFOHEADER_LENGTH + _imageSize)
    End Sub

    #End Region



    #Region "Properties"

    Private _width As Integer
    ''' <summary>
    ''' Gets the width, in pixels, of the image page.
    ''' </summary>
    Public Overrides ReadOnly Property Width() As Integer
        Get
            Return _width
        End Get
    End Property

    Private _height As Integer
    ''' <summary>
    ''' Gets the height, in pixels, of the image page.
    ''' </summary>
    Public Overrides ReadOnly Property Height() As Integer
        Get
            Return System.Math.Abs(_height)
        End Get
    End Property

    Private _bitsPerPixel As Integer
    ''' <summary>
    ''' Gets the bit depth of the image page.
    ''' </summary>
    Public Overrides ReadOnly Property BitsPerPixel() As Integer
        Get
            Return _bitsPerPixel
        End Get
    End Property

    Private _palette As Vintasoft.Imaging.Palette = Nothing
    ''' <summary>
    ''' Gets the palette of the image page.
    ''' </summary>
    Public Overrides ReadOnly Property Palette() As Vintasoft.Imaging.Palette
        Get
            Return _palette
        End Get
    End Property

    Private _resolution As Vintasoft.Imaging.Resolution = Vintasoft.Imaging.Resolution.Empty
    ''' <summary>
    ''' Gets or sets the resolution, in pixels per inch, of the image page.
    ''' </summary>
    ''' <value>
    ''' The resolution loaded from an image metadata if <see cref="HasResolution"/> returns <b>true</b>;
    ''' otherwise, the default (screen) resolution.
    ''' </value>
    ''' <seealso cref="HasResolution"/>
    Public Overrides Property Resolution() As Vintasoft.Imaging.Resolution
        Get
            If _resolution = Vintasoft.Imaging.Resolution.Empty Then
                Return Vintasoft.Imaging.ImagingEnvironment.ScreenResolution
            End If
            Return _resolution
        End Get
        Set
            Throw New System.NotImplementedException()
        End Set
    End Property

    Private _hasResolution As Boolean = False
    ''' <summary>
    ''' Gets a value indicating whether the information about image resolution is stored
    ''' in a BMP page.
    ''' </summary>
    ''' <value>
    ''' <b>True</b> - the <see cref="Resolution"/> property returns resolution loaded from image file;<br />
    ''' <b>false</b> - the <see cref="Resolution"/> property returns the default (screen) resolution.
    ''' </value>
    ''' <seealso cref="Resolution"/>
    Public Overrides ReadOnly Property HasResolution() As Boolean
        Get
            Return _hasResolution
        End Get
    End Property

    Private _imagePixelFormat As Vintasoft.Imaging.PixelFormat = Vintasoft.Imaging.PixelFormat.Undefined
    ''' <summary>
    ''' Gets the pixel format of this page.
    ''' </summary>
    Public ReadOnly Property PixelFormat() As Vintasoft.Imaging.PixelFormat
        Get
            Return _imagePixelFormat
        End Get
    End Property

    #End Region



    #Region "Methods"

    #Region "PUBLIC"

    ''' <summary>
    ''' Gets the image associated with this image page.
    ''' </summary>
    ''' <param name="decodingSettings">Decoding settings used for decode the image of page.</param>
    ''' <param name="progressDelegate">Progress delegate.
    ''' Can be set to null (Nothing in Visual Basic).</param>
    ''' <returns>The image associated with this BMP page if image was loaded successfully;
    ''' otherwise, null.</returns>
    Public Overrides Function GetImage(decodingSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings, progressDelegate As System.EventHandler(Of Vintasoft.Imaging.ProgressEventArgs)) As Vintasoft.Imaging.VintasoftImage
        ' create image
        Dim image As New Vintasoft.Imaging.VintasoftImage(Width, Height, _imagePixelFormat)

        ' if resolution is empty
        If _resolution.IsEmpty() Then
            image.Resolution = Vintasoft.Imaging.ImagingEnvironment.ScreenResolution
        Else
            _hasResolution = True
            image.Resolution = _resolution
        End If

        ' open pixel manipulator
        Dim pixelManipulator As Vintasoft.Imaging.PixelManipulator = image.OpenPixelManipulator()
        Dim lockPixelsRectangle As New System.Drawing.Rectangle(0, 0, Width, Height)
        ' lock pixels
        pixelManipulator.LockPixelsForSerialAccess(lockPixelsRectangle, Vintasoft.Imaging.BitmapLockMode.Write, _imagePixelFormat, New Byte(_stride - 1) {}, _reverseReadWrite)
        Try
            ' lock the original image source (image source from which BMP page must be read)
            SyncLock Source.Stream
                ' go to the start of image data in original image source
                Source.Position = _offsetToImageData
                ' get serial buffer of pixel manipulator
                Dim buffer As Byte() = pixelManipulator.SerialBuffer
                Dim yStart As Integer = Height - 1

                Dim previousProgress As Integer = -1
                Dim progressStep As Double = 100.0 / yStart
                Dim currentProgress As Double = -progressStep

                ' for each image row
                For y As Integer = yStart To 0 Step -1
                    ' if progress must be generated
                    If progressDelegate IsNot Nothing Then
                        ' calculate current progress
                        currentProgress += progressStep
                        ' if previous and current progress are different
                        If previousProgress <> CInt(Math.Truncate(System.Math.Round(currentProgress))) Then
                            ' get the progress integer value
                            previousProgress = CInt(Math.Truncate(System.Math.Round(currentProgress)))
                            ' raise the progress event
                            progressDelegate(Me, New Vintasoft.Imaging.ProgressEventArgs(previousProgress))
                        End If
                    End If

                    ' read row data from image source
                    Source.ReadBytes(buffer)
                    ' write row data to the pixel manipulator
                    pixelManipulator.WriteRowAndMoveToNext()
                Next
            End SyncLock
        Finally
            ' unlock pixels
            pixelManipulator.UnlockPixels()
            ' close pixel manipulator
            image.ClosePixelManipulator(True)
        End Try

        Return image
    End Function

    ''' <summary>
    ''' Saves the page to the image source.
    ''' </summary>
    ''' <param name="source">Image source.</param>
    ''' <param name="progressController">Progress controller.</param>
    Public Overrides Sub Save(source__1 As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource, progressController As Vintasoft.Imaging.Utils.IProgressController)
        ' raise the Saving event
        OnSaving(System.EventArgs.Empty)

        ' if progress controller is specified
        If progressController IsNot Nothing Then
            ' specify that there is only one progress stage
            progressController.Start(1)
            ' start the progress stage
            progressController.NextStage(Me, False)
        End If

        ' lock the destination image source (image source where BMP page must be written)
        SyncLock source__1.Stream
            ' write header to the destination image source
            WriteHeader(source__1)

            ' lock the original image source (image source from which BMP page must be read)
            SyncLock Source.Stream
                ' go to the start of image data in original image source
                Source.Position = _offsetToImageData
                ' create buffer for row data
                Dim buffer As Byte() = New Byte(_stride - 1) {}

                ' if progress controller is specified
                If progressController IsNot Nothing Then
                    ' specify the count of progress steps
                    progressController.StartSteps(CInt(Math.Truncate(System.Math.Ceiling(CDbl(_imageSize) / buffer.Length))))
                End If

                Dim writeBytesCount As UInteger = 0

                ' while the count of written bytes less than image size
                While writeBytesCount <> _imageSize
                    ' if progress controller is specified
                    If progressController IsNot Nothing Then
                        ' raise progress and check if saving process must be canceled
                        If Not progressController.NextStep(Me, True) Then
                            ' cancel saving process
                            Exit While
                        End If
                    End If

                    ' get count of bytes to read
                    Dim bytesToRead As Integer = CInt(System.Math.Min(_imageSize - writeBytesCount, buffer.Length))

                    ' read image row data from original image source
                    Me.Source.ReadBytes(buffer, 0, bytesToRead)
                    ' write image row data to the destination image source
                    source__1.WriteBytes(buffer, 0, bytesToRead)

                    ' update the count of written bytes
                    writeBytesCount += CUInt(bytesToRead)
                End While

                ' if progress controller is specified
                If progressController IsNot Nothing Then
                    ' finish a sequence of progress steps
                    progressController.FinishSteps(Me)
                End If
            End SyncLock
        End SyncLock

        ' if progress controller is specified
        If progressController IsNot Nothing Then
            ' finish the progress stage
            progressController.Finish(Me)
        End If

        ' raise the Saved event
        OnSaved(New Vintasoft.Imaging.Codecs.ImageFiles.ImageFileBlockSourceInfoChangedEventArgs())
    End Sub

    #End Region


    #Region "PROTECTED"

    ''' <summary>
    ''' Parse the BMP page.
    ''' </summary>
    Protected Overrides Sub Parse()
        ' lock the original image source (image source from which BMP page must be read)
        SyncLock Source.Stream
            ' read info block length
            Dim infoBlockLength As UInteger = Source.ReadUInt32()

            ' if info block is not standard
            If infoBlockLength <> BITMAPINFOHEADER_LENGTH Then
                Throw New System.NotSupportedException("Unsupported bitmap info block.")
            End If

            ' LONG biWidth
            _width = Source.ReadInt32()

            ' LONG biHeight
            _height = Source.ReadInt32()
            _reverseReadWrite = _height > 0

            ' WORD biPlanes
            Source.Position += 2

            ' WORD biBitCount
            Dim bitCount As System.UInt16 = Source.ReadUInt16()
            _bitsPerPixel = bitCount

            Select Case bitCount
                Case 24
                    _imagePixelFormat = Vintasoft.Imaging.PixelFormat.Bgr24
                    Exit Select

                Case 32
                    _imagePixelFormat = Vintasoft.Imaging.PixelFormat.Bgr32
                    Exit Select
                Case Else

                    Throw New System.NotSupportedException("Unsupported pixel format.")
            End Select

            ' calculate stride
            _stride = Vintasoft.Imaging.VintasoftBitmap.GetStride(_imagePixelFormat, Width)

            ' DWORD biCompression;
            Dim compression As System.UInt32 = Source.ReadUInt32()

            ' if image is compressed
            If compression <> 0 Then
                Throw New System.NotSupportedException("Compressed data is not supported.")
            End If

            ' DWORD biSizeImage;
            _imageSize = Source.ReadUInt32()

            If _imageSize = 0 Then
                _imageSize = CUInt(_stride * Height)
            End If

            ' LONG biXPelsPerMeter;
            Dim dpiX As Single = Source.ReadInt32() / (100F * (1F / 2.54F))

            ' LONG biYPelsPerMeter;
            Dim dpiY As Single = Source.ReadInt32() / (100F * (1F / 2.54F))

            ' set resolution
            _resolution = New Vintasoft.Imaging.Resolution(dpiX, dpiY)
            _hasResolution = True

            ' set page block
            SetLength(BITMAPINFOHEADER_LENGTH + _imageSize)
        End SyncLock
    End Sub

    #End Region


    #Region "INTERNAL"

    ''' <summary>
    ''' Writes BMP page header.
    ''' </summary>
    ''' <param name="source">Image source where BMP page must be written.</param>
    Friend Sub WriteHeader(source As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource)
        ' lock the destination image source (image source where BMP page must be written)
        SyncLock source.Stream
            ' DWORD biSize
            source.WriteUInt32(BITMAPINFOHEADER_LENGTH)

            ' LONG biWidth
            source.WriteInt32(_width)

            ' LONG biHeight
            source.WriteInt32(_height)

            ' WORD biPlanes
            source.WriteUInt16(1)

            ' WORD biBitCount
            source.WriteUInt16(CUShort(_bitsPerPixel))

            ' DWORD biCompression
            source.WriteUInt32(0)

            ' DWORD biSizeImage
            source.WriteUInt32(_imageSize)

            Dim dpiX As Integer = 0
            Dim dpiY As Integer = 0
            ' if resolution is not empty
            If Not _resolution.IsEmpty() Then
                dpiX = CInt(Math.Truncate(System.Math.Round(_resolution.Horizontal * (100F * (1F / 2.54F)))))
                dpiY = CInt(Math.Truncate(System.Math.Round(_resolution.Vertical * (100F * (1F / 2.54F)))))
            End If

            ' LONG biXPelsPerMeter
            source.WriteInt32(dpiX)

            ' LONG biYPelsPerMeter
            source.WriteInt32(dpiY)

            ' DWORD biClrUsed
            source.WriteUInt32(0)

            ' DWORD biClrImportant
            source.WriteUInt32(0)
        End SyncLock
    End Sub

    #End Region


    #Region "PRIVATE"

    ''' <summary>
    ''' Encodes an image data.
    ''' </summary>
    ''' <param name="source">Image source.</param>
    ''' <param name="image">Image.</param>
    Private Sub EncodeImageData(source__1 As Vintasoft.Imaging.Codecs.ImageFiles.ImageFileSource, image As Vintasoft.Imaging.VintasoftImage)
        ' open the pixel manipulator
        Dim pixelManipulator As Vintasoft.Imaging.PixelManipulator = image.OpenPixelManipulator()

        ' lock pixels
        Dim lockPixelsRectangle As New System.Drawing.Rectangle(0, 0, Width, Height)
        pixelManipulator.LockPixelsForSerialAccess(lockPixelsRectangle, Vintasoft.Imaging.BitmapLockMode.Write, _imagePixelFormat, New Byte(_stride - 1) {}, _reverseReadWrite)

        Try
            ' lock the original image source (image source from which BMP page must be read)
            SyncLock Source.Stream
                ' go to the start of image data in original image source
                Source.Position = _offsetToImageData

                ' get serial buffer of pixel manipulator
                Dim buffer As Byte() = pixelManipulator.SerialBuffer

                ' for each image row
                Dim yStart As Integer = Height - 1
                For y As Integer = yStart To 0 Step -1
                    ' read row data from pixel manipulator
                    pixelManipulator.ReadRowAndMoveToNext()
                    ' write row data to the image source
                    Source.WriteBytes(buffer)
                Next
            End SyncLock
        Finally
            ' unlock pixels
            pixelManipulator.UnlockPixels()
            ' close the pixel manipulator
            image.ClosePixelManipulator(False)
        End Try
    End Sub

    #End Region

    #End Region

End Class