Skip to content

Commit

Permalink
[ImageUtil] Remove deprecated API and change native pinvoke APIs (#5950)
Browse files Browse the repository at this point in the history
  • Loading branch information
hsgwon authored and hinohie committed Feb 20, 2024
1 parent f68aa0a commit 9034213
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 86 deletions.
87 changes: 62 additions & 25 deletions src/Tizen.Multimedia.Util/ImageUtil/ImageEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using System.Threading.Tasks;
using static Interop;
using NativeEncoder = Interop.ImageUtil.Encode;
using NativeUtil = Interop.ImageUtil;

namespace Tizen.Multimedia.Util
{
Expand All @@ -34,8 +35,11 @@ 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)
{
Expand Down Expand Up @@ -88,16 +92,14 @@ public void SetResolution(Size resolution)
"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)"/>
Expand All @@ -111,19 +113,18 @@ public void SetColorSpace(ColorSpace colorSpace)
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);
Expand All @@ -132,6 +133,7 @@ private void RunEncoding(object outStream)
finally
{
Marshal.FreeHGlobal(outBuffer);
NativeUtil.Destroy(_imageUtilHandle).ThrowIfFailed("Failed to destroy ImageUtil handle");
}
}

Expand Down Expand Up @@ -195,21 +197,25 @@ public Task EncodeAsync(byte[] inputBuffer, Stream outStream)
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);
}

internal void Initialize()
{
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);
Expand Down Expand Up @@ -413,6 +419,8 @@ internal override 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>
Expand Down Expand Up @@ -453,26 +461,55 @@ public Task EncodeAsync(IEnumerable<GifFrame> frames, Stream outStream)
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");
}
}
}
}

Expand Down
37 changes: 0 additions & 37 deletions src/Tizen.Multimedia.Util/ImageUtil/ImageUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,43 +47,6 @@ public static IEnumerable<ColorSpace> GetSupportedColorSpaces(ImageFormat format
return colorspaces;
}

/// <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>
Expand Down
12 changes: 12 additions & 0 deletions src/Tizen.Multimedia.Util/ImageUtil/ImageUtilEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ public enum PngCompression
Level9,
}

internal enum AnimationType
{
/// <summary>
/// GIF
/// </summary>
Gif,
/// <summary>
/// WebP
/// </summary>
WebP
}

/// <summary>
/// Specifies how an image is rotated or flipped.
/// </summary>
Expand Down
64 changes: 46 additions & 18 deletions src/Tizen.Multimedia.Util/Interop/Interop.ImageUtil.Encode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,41 @@ internal static extern ImageUtilError EncodeRunAsync(ImageEncoderHandle handle,
[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);
}
}

Expand All @@ -79,6 +85,28 @@ protected ImageEncoderHandle() : 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;
}
}

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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ internal static extern ImageUtilError Run(TransformHandle handle, IntPtr srcPack
[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);

Expand Down
6 changes: 3 additions & 3 deletions src/Tizen.Multimedia.Util/Interop/Interop.ImageUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ internal static partial class ImageUtil
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);

Expand All @@ -42,5 +39,8 @@ internal static extern ImageUtilError GetImage(IntPtr handle, out int width, out

[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);
}
}

0 comments on commit 9034213

Please sign in to comment.