using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading;
using System.Threading.Tasks;
using static Interop;
using static Interop.Decode;
/// <summary>
/// This is a base class for image decoders.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public abstract class ImageDecoder : IDisposable
{
private ImageDecoderHandle _handle;
/// <summary>
/// Gets the image format of this decoder.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public ImageFormat InputFormat { get; }
private ImageDecoderHandle Handle
/// <exception cref="ArgumentException"><paramref name="colorSpace"/> is invalid.</exception>
/// <exception cref="NotSupportedException"><paramref name="colorSpace"/> is not supported by the decoder.</exception>
/// <seealso cref="ImageUtil.GetSupportedColorSpaces(ImageFormat)"/>
+ /// <since_tizen> 4 </since_tizen>
public void SetColorSpace(ColorSpace colorSpace)
{
ValidationUtil.ValidateEnum(typeof(ColorSpace), colorSpace, nameof(ColorSpace));
/// <summary>
/// Decodes an image from the specified file.
/// </summary>
- /// <param name="inputFilePath">Input file path from which to decode.</param>
+ /// <param name="inputFilePath">The input file path from which to decode.</param>
/// <returns>A task that represents the asynchronous decoding operation.</returns>
/// <remarks>
- /// Only Graphics Interchange Format(GIF) codec returns more than one frame.\n
- /// \n
- /// http://tizen.org/privilege/mediastorage is needed if <paramref name="inputFilePath"/> is relevant to media storage.\n
- /// http://tizen.org/privilege/externalstorage is needed if <paramref name="inputFilePath"/> is relevant to external storage.
+ /// Only Graphics Interchange Format(GIF) codec returns more than one frame.<br/>
+ /// <br/>
+ /// http://tizen.org/privilege/mediastorage is needed if <paramref name="inputFilePath"/> is relevant to the media storage.<br/>
+ /// http://tizen.org/privilege/externalstorage is needed if <paramref name="inputFilePath"/> is relevant to the external storage.
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="inputFilePath"/> is null.</exception>
/// <exception cref="ArgumentException">
- /// <paramref name="inputFilePath"/> is an empty string.\n
- /// - or -\n
- /// <paramref name="inputFilePath"/> is not a image file.\n
- /// - or -\n
- /// The format of <paramref name="inputFilePath"/> is not <see cref="InputFormat"/>.
+ /// <paramref name="inputFilePath"/> is an empty string.<br/>
+ /// -or-<br/>
+ /// <paramref name="inputFilePath"/> is not a image file.
/// </exception>
/// <exception cref="FileNotFoundException"><paramref name="inputFilePath"/> does not exists.</exception>
- /// <exception cref="UnauthorizedAccessException">Caller does not have required permission to access the path.</exception>
+ /// <exception cref="UnauthorizedAccessException">The caller does not have required permission to access the path.</exception>
/// <exception cref="FileFormatException">The format of <paramref name="inputFilePath"/> is not <see cref="InputFormat"/>.</exception>
/// <exception cref="ObjectDisposedException">The <see cref="ImageDecoder"/> has already been disposed of.</exception>
+ /// <since_tizen> 4 </since_tizen>
public async Task<IEnumerable<BitmapFrame>> DecodeAsync(string inputFilePath)
{
if (inputFilePath == null)
var pathPtr = Marshal.StringToHGlobalAnsi(inputFilePath);
try
{
-
SetInputPath(Handle, pathPtr).ThrowIfFailed("Failed to set input file path for decoding");
return await DecodeAsync();
}
/// </summary>
/// <param name="inputBuffer">The image buffer from which to decode.</param>
/// <returns>A task that represents the asynchronous decoding operation.</returns>
- /// <remarks>
- /// Only Graphics Interchange Format(GIF) codec returns more than one frame.\n
- /// </remarks>
+ /// <remarks>Only Graphics Interchange Format(GIF) codec returns more than one frame.</remarks>
/// <exception cref="ArgumentNullException"><paramref name="inputBuffer"/> is null.</exception>
- /// <exception cref="ArgumentException">
- /// <paramref name="inputBuffer"/> is an empty array.\n
- /// - or -\n
- /// The format of <paramref name="inputBuffer"/> is not <see cref="InputFormat"/>.
- /// </exception>
+ /// <exception cref="ArgumentException"><paramref name="inputBuffer"/> is an empty array.</exception>
/// <exception cref="FileFormatException">The format of <paramref name="inputBuffer"/> is not <see cref="InputFormat"/>.</exception>
/// <exception cref="ObjectDisposedException">The <see cref="ImageDecoder"/> has already been disposed of.</exception>
+ /// <since_tizen> 4 </since_tizen>
public Task<IEnumerable<BitmapFrame>> DecodeAsync(byte[] inputBuffer)
{
if (inputBuffer == null)
}
}
- internal Task<IEnumerable<BitmapFrame>> DecodeAsync()
+ private IEnumerable<BitmapFrame> RunDecoding()
{
- Initialize(Handle);
+ IntPtr outBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
+ Marshal.WriteIntPtr(outBuffer, IntPtr.Zero);
- IntPtr outBuffer = IntPtr.Zero;
- SetOutputBuffer(Handle, out outBuffer).ThrowIfFailed("Failed to decode given image");
+ try
+ {
+ SetOutputBuffer(Handle, outBuffer).ThrowIfFailed("Failed to decode given image");
- var tcs = new TaskCompletionSource<IEnumerable<BitmapFrame>>();
+ DecodeRun(Handle, out var width, out var height, out var size).
+ ThrowIfFailed("Failed to decode");
- Task.Run(() =>
+ yield return new BitmapFrame(Marshal.ReadIntPtr(outBuffer), width, height, (int)size);
+ }
+ finally
{
- try
+ if (Marshal.ReadIntPtr(outBuffer) != IntPtr.Zero)
{
- int width, height;
- ulong size;
+ LibcSupport.Free(Marshal.ReadIntPtr(outBuffer));
+ }
- DecodeRun(Handle, out width, out height, out size).ThrowIfFailed("Failed to decode");
+ Marshal.FreeHGlobal(outBuffer);
+ }
+ }
- tcs.SetResult(new[] { new BitmapFrame(outBuffer, width, height, (int)size) });
- }
- catch (Exception e)
- {
- tcs.TrySetException(e);
- }
- finally
- {
- LibcSupport.Free(outBuffer);
- }
- });
+ internal Task<IEnumerable<BitmapFrame>> DecodeAsync()
+ {
+ Initialize(Handle);
- return tcs.Task;
+ return Task.Factory.StartNew(RunDecoding, CancellationToken.None,
+ TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
+ TaskScheduler.Default);
}
internal virtual void Initialize(ImageDecoderHandle handle)
/// Releases the unmanaged resources used by the ImageDecoder.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
+ /// <since_tizen> 4 </since_tizen>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
/// <summary>
/// Releases all resources used by the ImageDecoder.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public void Dispose()
{
Dispose(true);
/// <summary>
/// Provides the ability to decode Bitmap (BMP) encoded images.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public class BmpDecoder : ImageDecoder
{
private static readonly byte[] _header = { (byte)'B', (byte)'M' };
/// <summary>
- /// Initialize a new instance of the <see cref="BmpDecoder"/> class.
+ /// Initializes a new instance of the <see cref="BmpDecoder"/> class.
/// </summary>
/// <remarks><see cref="ImageDecoder.InputFormat"/> will be the <see cref="ImageFormat.Bmp"/>.</remarks>
+ /// <since_tizen> 4 </since_tizen>
public BmpDecoder() : base(ImageFormat.Bmp)
{
}
}
/// <summary>
- /// Provides the ability to decode Portable Network Graphics (PNG) encoded images.
+ /// Provides the ability to decode the Portable Network Graphics (PNG) encoded images.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public class PngDecoder : ImageDecoder
{
private static readonly byte[] _header = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
/// <summary>
- /// Initialize a new instance of the <see cref="PngDecoder"/> class.
+ /// Initializes a new instance of the <see cref="PngDecoder"/> class.
/// </summary>
/// <remarks><see cref="ImageDecoder.InputFormat"/> will be the <see cref="ImageFormat.Png"/>.</remarks>
+ /// <since_tizen> 4 </since_tizen>
public PngDecoder() : base(ImageFormat.Png)
{
}
}
/// <summary>
- /// Provides the ability to decode Joint Photographic Experts Group (JPEG) encoded images.
+ /// Provides the ability to decode the Joint Photographic Experts Group (JPEG) encoded images.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public class JpegDecoder : ImageDecoder
{
private static readonly byte[] _header = { 0xFF, 0xD8 };
/// <summary>
/// A read-only field that represents the default value of <see cref="Downscale"/>.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public static readonly JpegDownscale DefaultJpegDownscale = JpegDownscale.None;
private JpegDownscale _jpegDownscale = DefaultJpegDownscale;
/// <summary>
- /// Initialize a new instance of the <see cref="JpegDecoder"/> class.
+ /// Initializes a new instance of the <see cref="JpegDecoder"/> class.
/// </summary>
/// <remarks><see cref="ImageDecoder.InputFormat"/> will be the <see cref="ImageFormat.Jpeg"/>.</remarks>
+ /// <since_tizen> 4 </since_tizen>
public JpegDecoder() : base(ImageFormat.Jpeg)
{
}
/// Gets or sets the downscale at which the jpeg image should be decoded.
/// </summary>
/// <exception cref="ArgumentException"><paramref name="value"/> is invalid.</exception>
+ /// <since_tizen> 4 </since_tizen>
public JpegDownscale Downscale
{
get
}
/// <summary>
- /// Provides the ability to decode Graphics Interchange Format (GIF) encoded images.
+ /// Provides the ability to decode the Graphics Interchange Format (GIF) encoded images.
/// </summary>
+ /// <since_tizen> 4 </since_tizen>
public class GifDecoder : ImageDecoder
{
private static readonly byte[] _header = { (byte)'G', (byte)'I', (byte)'F' };
/// <summary>
- /// Initialize a new instance of the <see cref="GifDecoder"/> class.
+ /// Initializes a new instance of the <see cref="GifDecoder"/> class.
/// </summary>
/// <remarks><see cref="ImageDecoder.InputFormat"/> will be the <see cref="ImageFormat.Gif"/>.</remarks>
+ /// <since_tizen> 4 </since_tizen>
public GifDecoder() : base(ImageFormat.Gif)
{
}