/// <summary>
/// Provides the image decoder for IRasterGridDecoder example.
/// </summary>
public class RasterGridDecoderExample : Vintasoft.Imaging.Codecs.Decoders.DecoderBase, Vintasoft.Imaging.Codecs.Decoders.IRasterGridDecoder
{
#region Constants
/// <summary>
/// The rect decoding time, in milliseconds (emulate image decoding).
/// </summary>
private const int RectDecodingTimeMs = 1;
#endregion
#region Fields
/// <summary>
/// The list with information about pages.
/// </summary>
List<RasterGridPageMetadata> _pageInfos = new List<RasterGridPageMetadata>();
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RasterGridDecoderExample"/> class.
/// </summary>
/// <remarks>
/// This constructor is used in <see cref="T:Vintasoft.Imaging.Codecs.Decoders.AvailableDecoders" /> and
/// should not be used in real applications.
/// </remarks>
public RasterGridDecoderExample()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RasterGridDecoderExample"/> class.
/// </summary>
/// <param name="stream">The stream, which stores raw data of image/document source.</param>
public RasterGridDecoderExample(Stream stream)
: base(stream)
{
if (!IsValidFormat(stream))
throw new NotSupportedException();
StreamReader reader = new StreamReader(stream);
while (!reader.EndOfStream)
{
_pageInfos.Add(RasterGridPageMetadata.Parse(reader));
}
}
#endregion
#region Properties
/// <summary>
/// Gets the name of the decoder.
/// </summary>
public override string Name
{
get
{
return RasterGridCodecExample.CodecName;
}
}
#endregion
#region Methods
#region PUBLIC
/// <summary>
/// Determines that decoder can read a region of the image.
/// </summary>
/// <param name="scale">The rect scale.</param>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <returns>
/// <b>True</b> if decoder can read a region of the image;<br /><b>false</b> if decoder can read only rectangle of the image.
/// </returns>
/// <remarks>
/// <i>Region</i> represents a rectangular region on the image and
/// composed from a sequence of rectangles.
/// </remarks>
public bool CanReadImageRegion(int pageIndex, int scale, Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings)
{
return _pageInfos[pageIndex].CanReadImageRegion;
}
/// <summary>
/// Determines that decoder can progressively read the image.
/// </summary>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <returns>
/// <b>True</b> if decoder can progressively read the image;<br /><b>false</b> if decoder cannot progressively read the image.
/// </returns>
public bool CanUseProgressiveDecoding(int pageIndex, Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings)
{
return false;
}
/// <summary>
/// Returns an image, which is associated with the specified page of image/document source.
/// </summary>
/// <param name="pageIndex">The zero-based page index in image/document source.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <param name="renderingSettings">Rendering settings used for rendering the image of page.
/// This parameter has effect only if <see cref="P:Vintasoft.Imaging.Codecs.Decoders.DecoderBase.IsVectorDecoder" /> property is equal to <b>True</b>.</param>
/// <param name="progressDelegate">Progress delegate.</param>
/// <returns>
/// Rendered image, which is associated with the specified page of image/document source, if decoder supports rendering;
/// otherwise, image associated with the specified page of the image source.
/// </returns>
public override Vintasoft.Imaging.VintasoftImage GetImage(int pageIndex,
Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings,
Vintasoft.Imaging.Codecs.Decoders.RenderingSettings renderingSettings,
EventHandler<Vintasoft.Imaging.ProgressEventArgs> progressDelegate)
{
throw new NotSupportedException();
}
/// <summary>
/// Returns information about image without loading the image data into memory.
/// </summary>
/// <param name="pageIndex">The zero-based page index in image/document source.</param>
/// <param name="renderingSettings">Rendering settings used for getting info about the image of page.
/// This parameter has effect only if <see cref="P:Vintasoft.Imaging.Codecs.Decoders.DecoderBase.IsVectorDecoder" /> property is equal to <b>True</b>.</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)
{
RasterGridPageMetadata pageInfo = _pageInfos[pageIndex];
return new Vintasoft.Imaging.Codecs.Decoders.ImageInfo(
pageInfo.ImageWidth, pageInfo.ImageHeight, pageInfo.BitsPerPixel, new Vintasoft.Imaging.Palette(), pageInfo.Resolution);
}
/// <summary>
/// Returns a scaled rectangle of raster image.
/// </summary>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="rectIndex">The zero based the rectangle index.</param>
/// <param name="scale">Scale factor. Possible values: 1 - original image rect should
/// be get; N - reduced image rect should be get.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <param name="imageLoadingProgress">Delegate of the image loading progress.
/// Can be set to <b>null</b> (<b>Nothing</b> in Visual Basic).</param>
/// <param name="intermediateImageRequest">Delegate for requesting intermediate image.
/// Can be set to <b>null</b> (<b>Nothing</b> in Visual Basic)</param>
/// <returns>
/// Scaled rectangle of image.
/// </returns>
public Vintasoft.Imaging.VintasoftImage GetImageRect(int pageIndex, int rectIndex, int scale,
Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings,
EventHandler<Vintasoft.Imaging.ProgressEventArgs> imageLoadingProgress,
EventHandler<Vintasoft.Imaging.ImageRendering.IntermediateImageRequestEventArgs> intermediateImageRequest)
{
RasterGridPageMetadata pageInfo = _pageInfos[pageIndex];
Rectangle[] grid = GetImageRectGrid(pageIndex, decodingSettings);
Rectangle rect = grid[rectIndex];
Vintasoft.Imaging.VintasoftImage image = CreateImage(rect.Width, rect.Height, scale, pageInfo);
DrawTileInfo(image, $"{rectIndex}\n1/{scale}", scale);
// emulate image decoding
if (RectDecodingTimeMs > 0)
System.Threading.Thread.Sleep(RectDecodingTimeMs);
return image;
}
/// <summary>
/// Returns a scaled region of raster image.
/// </summary>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="leftTopRectIndex">The zero based index of left-top rectangle.</param>
/// <param name="rightBottomRectIndex">The zero based index of right-bottom rectangle.</param>
/// <param name="scale">Scale factor. Possible values: 1 - original image rect should
/// be get; N - reduced image rect should be get.</param>
/// <param name="decodingSettings">Decoding settings.</param>
/// <param name="imageLoadingProgress">Delegate of the image loading progress.
/// Can be set to <b>null</b> (<b>Nothing</b> in Visual Basic).</param>
/// <param name="intermediateImageRequest">Delegate for requesting intermediate image.
/// Can be set to <b>null</b> (<b>Nothing</b> in Visual Basic)</param>
/// <returns>
/// Scaled region of image.
/// </returns>
public Vintasoft.Imaging.VintasoftImage GetImageRegion(int pageIndex, int leftTopRectIndex, int rightBottomRectIndex, int scale,
Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings, EventHandler<Vintasoft.Imaging.ProgressEventArgs> imageLoadingProgress,
EventHandler<Vintasoft.Imaging.ImageRendering.IntermediateImageRequestEventArgs> intermediateImageRequest)
{
RasterGridPageMetadata pageInfo = _pageInfos[pageIndex];
Rectangle[] grid = GetImageRectGrid(pageIndex, decodingSettings);
Rectangle leftTopRect = grid[leftTopRectIndex];
Rectangle rightBottomRect = grid[rightBottomRectIndex];
Rectangle rect = new Rectangle(
leftTopRect.X,
leftTopRect.Y,
rightBottomRect.X + rightBottomRect.Width - leftTopRect.X,
rightBottomRect.Y + rightBottomRect.Height - leftTopRect.Y);
Vintasoft.Imaging.VintasoftImage image = CreateImage(rect.Width, rect.Height, scale, pageInfo);
DrawTileInfo(image, $"{leftTopRectIndex}:{rightBottomRectIndex}\n1/{scale}", scale);
// emulate image decoding
if (RectDecodingTimeMs > 0)
System.Threading.Thread.Sleep(RectDecodingTimeMs);
return image;
}
/// <summary>
/// Returns an image grid as array of rectangles.
/// </summary>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <returns>
/// An image grid as array of rectangles.
/// </returns>
/// <remarks>
/// Method must return an array with one rectangle which size is equal to the size
/// of image if decoder cannot get image by parts.
/// </remarks>
public Rectangle[] GetImageRectGrid(int pageIndex, Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings)
{
RasterGridPageMetadata pageInfo = _pageInfos[pageIndex];
return SplitIntoTileRectangles(new Size(pageInfo.ImageWidth, pageInfo.ImageHeight), new Size(pageInfo.TileWidth, pageInfo.TileHeight));
}
/// <summary>
/// Returns an array of scale factors for rectangles of image grid.
/// </summary>
/// <param name="pageIndex">The zero based page index.</param>
/// <param name="decodingSettings">The decoding settings that should be used for decoding of page image.</param>
/// <returns>
/// An array of scale factors for rectangles of image grid.
/// </returns>
/// <remarks>
/// Possible values of scale factor:
/// <ul><li>1 - decoder can return image rectangle without scaling</li><li>N - decoder can return an image rectangle reduced N times</li></ul>
/// </remarks>
public int[] GetImageRectScales(int pageIndex, Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings)
{
return _pageInfos[pageIndex].TileScales;
}
/// <summary>
/// Returns a metadata of specified page of image/document source.
/// </summary>
/// <param name="pageIndex">The zero-based page index in image/document source.</param>
/// <returns>
/// A metadata of specified page of image/document source.
/// </returns>
public override Vintasoft.Imaging.Metadata.PageMetadata GetPageMetadata(int pageIndex)
{
return _pageInfos[pageIndex];
}
/// <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(Stream stream)
{
string name = Name;
int index = 0;
while (stream.ReadByte() != (byte)name[0])
{
if (index++ > 5)
return false;
}
stream.Position--;
byte[] bytes = new byte[name.Length];
stream.Read(bytes, 0, bytes.Length);
for (int i = 0; i < bytes.Length; i++)
{
if (bytes[i] != (byte)name[i])
return false;
}
return true;
}
#endregion
#region PROTECTED
/// <summary>
/// Returns the number of pages in the source file stream.
/// </summary>
/// <returns>
/// The number of pages in the source file stream.
/// </returns>
protected override int GetPageCount()
{
return _pageInfos.Count;
}
#endregion
#region PRIVATE
/// <summary>
/// Splits an image area into tile rectangles.
/// </summary>
/// <param name="imageSize">Size of the image.</param>
/// <param name="tileSize">Size of the tile.</param>
/// <returns>
/// An image grid as array of rectangles.
/// </returns>
private static Rectangle[] SplitIntoTileRectangles(Size imageSize, Size tileSize)
{
List<Rectangle> rectangles = new List<Rectangle>();
int rows = (int)Math.Ceiling((double)imageSize.Height / tileSize.Height);
int cols = (int)Math.Ceiling((double)imageSize.Width / tileSize.Width);
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
int width = tileSize.Width;
int height = tileSize.Height;
if (col == cols - 1)
width = imageSize.Width - col * tileSize.Width;
if (row == rows - 1)
height = imageSize.Height - row * tileSize.Height;
rectangles.Add(new Rectangle(col * tileSize.Width, row * tileSize.Height, width, height));
}
}
return rectangles.ToArray();
}
/// <summary>
/// Draws the tile information.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="tileInfo">The tile information.</param>
/// <param name="scale">The scale.</param>
private void DrawTileInfo(Vintasoft.Imaging.VintasoftImage image, string tileInfo, int scale)
{
using (Vintasoft.Imaging.Drawing.DrawingEngine graphics = image.CreateDrawingEngine())
{
graphics.Clear(Color.White);
using (Vintasoft.Imaging.Drawing.IDrawingFont font = graphics.DrawingFactory.CreateDefaultFont(Math.Max(10, 180f / scale)))
using (Vintasoft.Imaging.Drawing.IDrawingBrush brush = graphics.DrawingFactory.CreateSolidBrush(Color.Black))
{
graphics.DrawText(tileInfo, font, brush, new RectangleF(0, 0, image.Width, image.Height),
new Vintasoft.Imaging.Drawing.TextLayoutProperties(Vintasoft.Imaging.AnchorType.Center, true));
}
using (Vintasoft.Imaging.Drawing.IDrawingPen pen = graphics.DrawingFactory.CreatePen(Color.Blue, 20.0f / scale))
{
graphics.DrawRectangle(pen, new RectangleF(0, 0, image.Width, image.Height));
}
}
}
/// <summary>
/// Creates the image.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pageInfo">The page information.</param>
/// <returns>A new instace of <see cref="VintasoftImage"/> class.</returns>
private Vintasoft.Imaging.VintasoftImage CreateImage(int width, int height, int scale, RasterGridPageMetadata pageInfo)
{
Vintasoft.Imaging.PixelFormat pixelFormat;
if (pageInfo.BitsPerPixel == 24)
pixelFormat = Vintasoft.Imaging.PixelFormat.Bgr24;
else if (pageInfo.BitsPerPixel == 32)
pixelFormat = Vintasoft.Imaging.PixelFormat.Bgra32;
else
throw new NotImplementedException();
return new Vintasoft.Imaging.VintasoftImage((int)Math.Round(width / (float)scale), (int)Math.Round(height / (float)scale), pixelFormat);
}
#endregion
#endregion
}
/// <summary>
/// Provides information about ratser page metadata and raster grid.
/// </summary>
public class RasterGridPageMetadata : Vintasoft.Imaging.Metadata.PageMetadata
{
#region Constructors
/// <summary>
/// Prevents a default instance of the <see cref="RasterGridPageMetadata"/> class from being created.
/// </summary>
private RasterGridPageMetadata()
: base("RasterGridPageExample")
{
}
#endregion
#region Properties
string _pageName = null;
/// <summary>
/// Gets the name of the page.
/// </summary>
public string PageName
{
get
{
return _pageName;
}
}
int _imageWidth = 0;
/// <summary>
/// Gets the width of the image, in pixels.
/// </summary>
public override int ImageWidth
{
get
{
return _imageWidth;
}
}
int _imageHeight = 0;
/// <summary>
/// Gets the height of the image, in pixels.
/// </summary>
public override int ImageHeight
{
get
{
return _imageHeight;
}
}
/// <summary>
/// Gets the bits per-pixel of the image.
/// </summary>
/// <value>
/// The bits per pixel.
/// </value>
public override int BitsPerPixel
{
get
{
return 24;
}
}
int _tileWidth = 0;
/// <summary>
/// Gets the width of the tile, in pixels, without scale.
/// </summary>
public int TileWidth
{
get
{
return _tileWidth;
}
}
int _tileHeight = 0;
/// <summary>
/// Gets the height of the tile, in pixels, without scale.
/// </summary>
public int TileHeight
{
get
{
return _tileHeight;
}
}
int[] _tileScales;
/// <summary>
/// Gets the supported tile scales.
/// </summary>
public int[] TileScales
{
get
{
return _tileScales;
}
}
/// <summary>
/// Gets a value indicating whether the information about image resolution is stored
/// in an image page.
/// </summary>
public override bool HasResolution
{
get
{
return true;
}
}
bool _canReadImageRegion = false;
/// <summary>
/// Gets a value that indicates that decoder can read a region of the image.
/// </summary>
public bool CanReadImageRegion
{
get
{
return _canReadImageRegion;
}
}
#endregion
#region Methods
/// <summary>
/// Parses page info uses specified reader.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>A new instance of <see cref="RasterGridPageMetadata"/> class.</returns>
internal static RasterGridPageMetadata Parse(TextReader reader)
{
RasterGridPageMetadata result = new RasterGridPageMetadata();
result._pageName = ReadLine(reader);
result._imageWidth = ReadInt(reader);
result._imageHeight = ReadInt(reader);
result.Resolution = new Vintasoft.Imaging.Resolution(ReadInt(reader), ReadInt(reader));
result._tileWidth = ReadInt(reader);
result._tileHeight = ReadInt(reader);
string[] scaleStrings = ReadLine(reader).Split(',');
int[] scales = new int[scaleStrings.Length];
for (int i = 0; i < scales.Length; i++)
{
scales[i] = int.Parse(scaleStrings[i].Trim());
}
result._tileScales = scales;
result._canReadImageRegion = ReadLine(reader).ToLowerInvariant() == "true";
return result;
}
/// <summary>
/// Reads the string value from text reader.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>The line.</returns>
private static string ReadLine(TextReader reader)
{
string result = reader.ReadLine();
while (result == "" || result.StartsWith("'"))
result = reader.ReadLine();
return result;
}
/// <summary>
/// Reads the int value from text reader.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>The int value.</returns>
private static int ReadInt(TextReader reader)
{
return int.Parse(ReadLine(reader));
}
#endregion
}