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
/// <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
/// <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
/// <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
/// <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
/// <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