using System.Threading.Tasks;
using static Interop;
using NativeEncoder = Interop.ImageUtil.Encode;
+using NativeUtil = Interop.ImageUtil;
namespace Tizen.Multimedia.Util
{
public abstract class ImageEncoder : IDisposable
{
private ImageEncoderHandle _handle;
+ internal IntPtr _imageUtilHandle;
+ internal IntPtr _animationHandle;
- private bool _hasResolution;
+ internal Size? _resolution;
+ internal ColorSpace? _colorSpace;
internal ImageEncoder(ImageFormat format)
{
"The height of resolution can't be less than or equal to zero.");
}
- NativeEncoder.SetResolution(Handle, (uint)resolution.Width, (uint)resolution.Height).
- ThrowIfFailed("Failed to set the resolution");
-
- _hasResolution = true;
+ _resolution = resolution;
}
/// <summary>
/// Sets the color-space of the output image.
/// </summary>
/// <param name="colorSpace">The target color-space.</param>
+ /// <value>The default color space is <see cref="ColorSpace.Rgba8888"/>
/// <exception cref="ArgumentException"><paramref name="colorSpace"/> is invalid.</exception>
/// <exception cref="NotSupportedException"><paramref name="colorSpace"/> is not supported by the encoder.</exception>
/// <seealso cref="ImageUtil.GetSupportedColorSpaces(ImageFormat)"/>
throw new NotSupportedException($"{colorSpace.ToString()} is not supported for {OutputFormat}.");
}
- NativeEncoder.SetColorspace(Handle, colorSpace.ToImageColorSpace()).
- ThrowIfFailed("Failed to set the color space");
+ _colorSpace = colorSpace;
}
- private void RunEncoding(object outStream)
+ internal virtual void RunEncoding(object outStream)
{
IntPtr outBuffer = IntPtr.Zero;
+ int size = 0;
try
{
- NativeEncoder.SetOutputBuffer(Handle, out outBuffer).ThrowIfFailed("Failed to initialize encoder");
-
- NativeEncoder.Run(Handle, out var size).ThrowIfFailed("Failed to encode given image");
+ NativeEncoder.RunToBuffer(Handle, _imageUtilHandle, out outBuffer, out size).
+ ThrowIfFailed("Failed to encode given image");
byte[] buf = new byte[size];
Marshal.Copy(outBuffer, buf, 0, (int)size);
finally
{
Marshal.FreeHGlobal(outBuffer);
+ NativeUtil.Destroy(_imageUtilHandle).ThrowIfFailed("Failed to destroy ImageUtil handle");
}
}
throw new ArgumentException("buffer is empty.", nameof(inputBuffer));
}
- return EncodeAsync(handle =>
- {
- NativeEncoder.SetInputBuffer(handle, inputBuffer).
- ThrowIfFailed("Failed to configure encoder; InputBuffer");
+ return EncodeAsync(handle => {
+ NativeUtil.Create((uint)_resolution.Value.Width, (uint)_resolution.Value.Height, _colorSpace.Value.ToImageColorSpace(),
+ inputBuffer, inputBuffer.Length, out _imageUtilHandle).ThrowIfFailed("Failed to create ImageUtil handle");
}, outStream);
}
{
Configure(Handle);
- if (_hasResolution == false)
+ if (!_resolution.HasValue)
{
throw new InvalidOperationException("Resolution is not set.");
}
+ if (!_colorSpace.HasValue)
+ {
+ _colorSpace = ColorSpace.Rgba8888;
+ Log.Info("Tizen.Multimedia.Util", "ColorSpace was set to default value(Rgba8888).");
+ }
}
internal abstract void Configure(ImageEncoderHandle handle);
/// <since_tizen> 4 </since_tizen>
public class GifEncoder : ImageEncoder
{
+ private IEnumerable<GifFrame> _frames;
+
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoder"/> class.
/// </summary>
throw new ArgumentNullException(nameof(frames));
}
- if (frames.Count() == 0)
+ if (!frames.Any())
{
throw new ArgumentException("frames is a empty collection", nameof(frames));
}
- return EncodeAsync(handle =>
+ _frames = frames;
+
+ return EncodeAsync(handle => {}, outStream);
+ }
+
+ internal override void RunEncoding(object outStream)
+ {
+ IntPtr outBuffer = IntPtr.Zero;
+
+ NativeEncoder.AnimationCreate(AnimationType.Gif, out _animationHandle).
+ ThrowIfFailed("Failed to create animation handle");
+
+ try
{
- foreach (GifFrame frame in frames)
+ foreach (GifFrame frame in _frames)
{
if (frame == null)
{
- throw new ArgumentNullException(nameof(frames));
+ throw new ArgumentNullException(nameof(frame));
}
- NativeEncoder.SetInputBuffer(handle, frame.Buffer).
- ThrowIfFailed("Failed to configure encoder; Buffer");
- NativeEncoder.SetGifFrameDelayTime(handle, (ulong)frame.Delay).
- ThrowIfFailed("Failed to configure encoder; Delay");
+ NativeUtil.Create((uint)_resolution.Value.Width, (uint)_resolution.Value.Height, _colorSpace.Value.ToImageColorSpace(),
+ frame.Buffer, frame.Buffer.Length, out _imageUtilHandle).ThrowIfFailed("Failed to create ImageUtil handle");
+ NativeEncoder.AnimationAddFrame(_animationHandle, _imageUtilHandle, frame.Delay).
+ ThrowIfFailed("Failed to add frame");
+
+ NativeUtil.Destroy(_imageUtilHandle).ThrowIfFailed("Failed to destroy ImageUtil handle");
}
- }, outStream);
+
+ NativeEncoder.AnimationSaveToBuffer(_animationHandle, out outBuffer, out ulong size).
+ ThrowIfFailed("Failed to encode given image");
+
+ byte[] buf = new byte[size];
+ Marshal.Copy(outBuffer, buf, 0, (int)size);
+ (outStream as Stream).Write(buf, 0, (int)size);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(outBuffer);
+ if (_animationHandle != IntPtr.Zero)
+ {
+ NativeEncoder.AnimationDestroy(_animationHandle).ThrowIfFailed("Failed to destroy animation handle");
+ }
+ }
}
}
}
/// <summary>
- /// Calculates the size of the image buffer for the specified resolution and color-space.
- /// </summary>
- /// <param name="resolution">The resolution of the image.</param>
- /// <param name="colorSpace"><see cref="ColorSpace"/> of the image.</param>
- /// <returns>The buffer size.</returns>
- /// <exception cref="ArgumentOutOfRangeException">
- /// width of <paramref name="resolution"/> is less than or equal to zero.<br/>
- /// -or-<br/>
- /// height of <paramref name="resolution"/> is less than or equal to zero.
- /// </exception>
- /// <exception cref="ArgumentException"><paramref name="colorSpace"/> is invalid.</exception>
- /// <since_tizen> 4 </since_tizen>
- [Obsolete("Please do not use! This will be deprecated in level 6.")]
- public static int CalculateBufferSize(Size resolution, ColorSpace colorSpace)
- {
- if (resolution.Width <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(resolution), resolution.Width,
- "width can't be less than or equal to zero.");
- }
- if (resolution.Height <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(resolution), resolution.Height,
- "height can't be less than or equal to zero.");
- }
-
- ValidationUtil.ValidateEnum(typeof(ColorSpace), colorSpace, nameof(colorSpace));
-
- uint bufferSize;
- global::Interop.ImageUtil.CalculateBufferSize(resolution.Width, resolution.Height,
- colorSpace.ToImageColorSpace(), out bufferSize)
- .ThrowIfFailed("Failed to calculate buffer size for given parameter");
-
- return (int)bufferSize;
- }
-
- /// <summary>
/// Extracts representative color from an image buffer.
/// </summary>
/// <param name="buffer">Raw image buffer.</param>
Level9,
}
+ internal enum AnimationType
+ {
+ /// <summary>
+ /// GIF
+ /// </summary>
+ Gif,
+ /// <summary>
+ /// WebP
+ /// </summary>
+ WebP
+ }
+
/// <summary>
/// Specifies how an image is rotated or flipped.
/// </summary>
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_destroy")]
internal static extern ImageUtilError Destroy(IntPtr handle);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_resolution")]
- internal static extern ImageUtilError SetResolution(ImageEncoderHandle handle, uint width, uint height);
-
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_colorspace")]
- internal static extern ImageUtilError SetColorspace(ImageEncoderHandle handle, ImageColorSpace colorspace);
-
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_quality")]
internal static extern ImageUtilError SetQuality(ImageEncoderHandle handle, int quality);
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_png_compression")]
internal static extern ImageUtilError SetPngCompression(ImageEncoderHandle handle, PngCompression compression);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_gif_frame_delay_time")]
- internal static extern ImageUtilError SetGifFrameDelayTime(ImageEncoderHandle handle, ulong delayTime);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_run_to_buffer")]
+ internal static extern ImageUtilError RunToBuffer(ImageEncoderHandle handle, IntPtr imageUtilHandle, out IntPtr buffer, out int size);
+
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_lossless")]
+ internal static extern ImageUtilError SetLossless(ImageEncoderHandle handle, bool lossless);
+
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_create")]
+ internal static extern ImageUtilError AnimationCreate(AnimationType type, out IntPtr animHandle);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_output_path")]
- internal static extern ImageUtilError SetOutputPath(ImageEncoderHandle handle, string path);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_set_loop_count")]
+ internal static extern ImageUtilError AnimationSetLoopCount(IntPtr animHandle, uint count);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_input_buffer")]
- internal static extern ImageUtilError SetInputBuffer(ImageEncoderHandle handle, byte[] srcBuffer);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_set_background_color")]
+ internal static extern ImageUtilError AnimationSetBackgroundColor(IntPtr animHandle, byte r, byte g, byte b, byte a);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_output_buffer")]
- internal static extern ImageUtilError SetOutputBuffer(ImageEncoderHandle handle, out IntPtr dstBuffer);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_set_lossless")]
+ internal static extern ImageUtilError AnimationSetLossless(IntPtr animHandle, bool isLossless);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_run")]
- internal static extern ImageUtilError Run(ImageEncoderHandle handle, out ulong size);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_add_frame")]
+ internal static extern ImageUtilError AnimationAddFrame(IntPtr animHandle, IntPtr utilHandle, uint delayTime);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_encode_set_lossless")]
- internal static extern ImageUtilError SetLossless(ImageEncoderHandle handle, bool lossless);
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_save_to_file")]
+ internal static extern ImageUtilError AnimationSaveToFile(IntPtr animHandle, string path);
+
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_save_to_buffer")]
+ internal static extern ImageUtilError AnimationSaveToBuffer(IntPtr animHandle, out IntPtr dstBuffer, out ulong size);
+
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_anim_encode_destroy")]
+ internal static extern ImageUtilError AnimationDestroy(IntPtr animHandle);
}
}
return true;
}
}
+
+ internal class AgifImageEncoderHandle : SafeHandle
+ {
+ protected AgifImageEncoderHandle() : base(IntPtr.Zero, true)
+ {
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero;
+
+
+ protected override bool ReleaseHandle()
+ {
+ var ret = ImageUtil.Encode.Destroy(handle);
+ if (ret != ImageUtilError.None)
+ {
+ Log.Debug(GetType().FullName, $"Failed to release native {GetType().Name}");
+ return false;
+ }
+
+ return true;
+ }
+ }
}
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_transform_set_colorspace")]
internal static extern ImageUtilError SetColorspace(TransformHandle handle, ImageColorSpace colorspace);
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_transform_set_hardware_acceleration")]
- internal static extern ImageUtilError SetHardwareAcceleration(TransformHandle handle, bool mode);
-
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_transform_set_rotation")]
internal static extern ImageUtilError SetRotation(TransformHandle handle, ImageRotation rotation);
internal static extern ImageUtilError ForeachSupportedColorspace(ImageFormat type, SupportedColorspaceCallback callback,
IntPtr userData = default(IntPtr));
- [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_calculate_buffer_size")]
- internal static extern ImageUtilError CalculateBufferSize(int width, int height, ImageColorSpace colorspace, out uint size);
-
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_extract_color_from_memory")]
internal static extern ImageUtilError ExtractColorFromMemory(byte[] buffer, int width, int height, out byte rgbR, out byte rgbG, out byte rgbB);
[DllImport(Libraries.ImageUtil, EntryPoint = "image_util_destroy_image")]
internal static extern ImageUtilError Destroy(IntPtr handle);
+
+ [DllImport(Libraries.ImageUtil, EntryPoint = "image_util_create_image")]
+ internal static extern ImageUtilError Create(uint width, uint height, ImageColorSpace colorSpace, byte[] srcBuffer, int size, out IntPtr handle);
}
}