Пример пользовательского кодека
В этом разделе
Приведенная ниже серия примеров демонстрирует, как:
- создайте простой пользовательский BMP кодек, поддерживающий кодирование и декодирование изображений в форматах Bgr24, Bgr32
- используйте класс SimpleBmpCodec вместо стандартного BMP кодека для декодирования/кодирования BMP файлов в SDK
Пример класса SimpleBmpCodec, производного от класса кодека
Вот C#/VB.NET код, который демонстрирует, как создать класс SimpleBmpCodec, производный от класса
Codec:
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
Пример метода, который демонстрирует, как использовать класс SimpleBmpCodec вместо стандартного BMP кодека
Вот C#/VB.NET код, который демонстрирует, как использовать класс SimpleBmpCodec вместо стандартного BMP кодека:
/// <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
Пример декодера для кодека SimpleBmp
Вот C#/VB.NET код, который демонстрирует, как создать декодер для кодека SimpleBmp:
/// <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
Пример энкодера для кодека SimpleBmp
Вот C#/VB.NET код, который демонстрирует, как создать энкодер для кодека SimpleBmp:
/// <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
Пример файла изображения для кодека SimpleBmp
Вот C#/VB.NET код, который демонстрирует, как создать файл изображения для кодека SimpleBmp:
/// <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
Пример страницы файла изображения для кодека SimpleBmp
Вот C#/VB.NET код, который демонстрирует, как создать страницу файла изображения для кодека SimpleBmp:
/// <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