--- /dev/null
+
+namespace Tizen.NUI
+{
+ using global::System;
+ using global::System.Runtime.InteropServices;
+
+ internal static partial class Interop
+ {
+ internal static partial class Capture
+ {
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Upcast")]
+ public static extern IntPtr Upcast(IntPtr jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_Capture")]
+ public static extern IntPtr NewEmpty();
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_New")]
+ public static extern IntPtr New();
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_DownCast")]
+ public static extern IntPtr Downcast(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Capture")]
+ public static extern void Delete(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Assign")]
+ public static extern IntPtr Assign(HandleRef jarg1, HandleRef jarg2);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Start_1")]
+ public static extern void Start1(HandleRef jarg0, HandleRef jarg1, HandleRef jarg2, string jarg3, HandleRef jarg4);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Start_2")]
+ public static extern void Start2(HandleRef capture, HandleRef source, HandleRef size, string path);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_Empty")]
+ public static extern bool SignalEmpty(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_GetConnectionCount")]
+ public static extern uint SignalGetConnectionCount(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_Connect")]
+ public static extern void SignalConnect(HandleRef jarg1, HandleRef jarg2);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_Disconnect")]
+ public static extern void SignalDisconnect(HandleRef jarg1, HandleRef jarg2);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_Emit")]
+ public static extern void SignalEmit(HandleRef jarg1, HandleRef jarg2, int jarg3);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_Capture_Signal")]
+ public static extern IntPtr NewSignal();
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_Capture_Signal")]
+ public static extern void DeleteSignal(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_Signal_Get")]
+ public static extern IntPtr Get(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_GetNativeImageSource")]
+ public static extern IntPtr GetNativeImageSourcePtr(HandleRef jarg1);
+
+ [DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Capture_GenerateUrl")]
+ public static extern string GenerageUrl(HandleRef capture);
+
+ }
+ }
+}
--- /dev/null
+using System.Diagnostics;
+using System;
+using System.Drawing;
+/*
+ * Copyright(c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.NUI
+{
+ using global::System;
+ using global::System.ComponentModel;
+ using global::System.Runtime.InteropServices;
+ using global::System.ComponentModel;
+ using Tizen.NUI.BaseComponents;
+
+ /// <summary>
+ /// Capture snapshots the current scene and save as a file.
+ /// Applications should follow the example below to create capture :
+ /// <code>
+ /// Capture capture = new Capture();
+ /// </code>
+ /// If required, you can also subscribe Finished event :
+ /// <code>
+ /// capture.Finished += onCaptureFinished;
+ /// </code>
+ /// At the subcribed event handler, user can know whether capture finish succeeded state.
+ /// <code>
+ /// private void onCaptureFinished(object sender, CaptureFinishedEventArgs e)
+ /// {
+ /// if(e.Success) { //capture success, do something. }
+ /// else { //capture failure, do something. }
+ /// }
+ /// </code>
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class Capture : BaseHandle
+ {
+ /// <summary>
+ /// Create an Capture.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Capture() : this(Interop.Capture.New(), true)
+ {
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+
+ internal Capture(IntPtr cPtr, bool cMemoryOwn) : base(Interop.Capture.Upcast(cPtr), cMemoryOwn)
+ {
+ }
+
+ /// <summary>
+ /// Dispose
+ /// </summary>
+ /// <param name="type"></param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ if (type == DisposeTypes.Explicit)
+ {
+ //Called by User
+ //Release your own managed resources here.
+ //You should release all of your own disposable objects here.
+ }
+
+ base.Dispose(type);
+ }
+
+ /// This will not be public opened.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void ReleaseSwigCPtr(HandleRef swigCPtr)
+ {
+ Interop.Capture.Delete(swigCPtr);
+ }
+
+ /// <summary>
+ /// Start capture and save the image as a file.
+ /// </summary>
+ /// <param name="source">source View or Layer to be used for capture.</param>
+ /// <param name="size">captured size.</param>
+ /// <param name="path">image file path to be saved as a file.
+ /// If path is empty string, the captured result is not be saved as a file.</param>
+ /// <param name="color">background color of captured scene.</param>
+ /// <exception cref="InvalidOperationException">This exception can be due to the invalid size values, of when width or height is lower than zero.</exception>
+ /// <exception cref="ArgumentNullException">This exception is due to the path is null.</exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Start(Container source, Size size, string path, Color color)
+ {
+ if (size.Width <= 0 || size.Height <=0)
+ {
+ throw new InvalidOperationException("size should larger than zero");
+ }
+ else if (null == path)
+ {
+ throw new ArgumentNullException("path should not be null");
+ }
+
+ if (source is View || source is Layer)
+ {
+ Interop.Capture.Start1(swigCPtr, source.SwigCPtr, new Vector2(size.Width, size.Height).SwigCPtr, path, new Vector4(color.R, color.G, color.B, color.A).SwigCPtr);
+
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+ }
+
+ /// <summary>
+ /// Start capture and save the image as a file.
+ /// </summary>
+ /// <remarks>
+ /// Background color of captured scene is transparent.
+ /// </remarks>
+ /// <param name="source">source View or Layer to be used for capture.</param>
+ /// <param name="size">captured size.</param>
+ /// <param name="path">image file path to be saved as a file.
+ /// If path is empty string, the captured result is not be saved as a file.</param>
+ /// <exception cref="InvalidOperationException">This exception can be due to the invalid size values, of when width or height is lower than zero.</exception>
+ /// <exception cref="ArgumentNullException">This exception is due to the path is null.</exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Start(Container source, Size size, string path)
+ {
+ if (size.Width <= 0 || size.Height <=0)
+ {
+ throw new InvalidOperationException("size should larger than zero");
+ }
+ else if (null == path)
+ {
+ throw new ArgumentNullException("path should not be null");
+ }
+
+ if (source is View || source is Layer)
+ {
+ Interop.Capture.Start2(swigCPtr, source.SwigCPtr, new Vector2(size.Width, size.Height).SwigCPtr, path);
+
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+ }
+
+ private void onFinished(IntPtr data, int state)
+ {
+ if (data != IntPtr.Zero)
+ {
+ var arg = new CaptureFinishedEventArgs();
+ // dali native definition :
+ // enum class FinishState
+ // {
+ // SUCCEEDED, ///< Succeeded in saving the result after capture
+ // FAILED ///< Failed to capture by time out or to save the result
+ // };
+ arg.Success = (state == 0) ? true : false;
+ finishedEventHandler?.Invoke(this, arg);
+ }
+ }
+
+ private CaptureSignal finishedSignal;
+ private delegate void finishedCallbackType(IntPtr data, int state);
+ private finishedCallbackType finishedCallback;
+ private EventHandler<CaptureFinishedEventArgs> finishedEventHandler;
+
+ /// <summary>
+ /// For subscribing Finished event sent by this class.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler<CaptureFinishedEventArgs> Finished
+ {
+ add
+ {
+ if (finishedEventHandler == null && disposed == false)
+ {
+ finishedSignal = new CaptureSignal(Interop.Capture.Get(swigCPtr), false);
+ finishedCallback = onFinished;
+ finishedSignal.Connect(finishedCallback);
+ }
+ finishedEventHandler += value;
+ }
+ remove
+ {
+ finishedEventHandler -= value;
+
+ if (finishedEventHandler == null && finishedSignal?.Empty() == false)
+ {
+ finishedCallback = onFinished;
+ finishedSignal.Disconnect(finishedCallback);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get NativeImageSource that is saved captured image.
+ /// </summary>
+ /// <returns>NativeImageSource that is saved captured image.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public NativeImageSource GetNativeImageSource()
+ {
+ Tizen.Log.Debug("NUI", $"GetNativeImageSource()");
+ return new NativeImageSource(Interop.Capture.GetNativeImageSourcePtr(swigCPtr), true);
+ }
+
+ /// <summary>
+ /// Generate captured image's Url
+ /// </summary>
+ /// <returns>The Url string representing this captured image source</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string GenerateUrl()
+ {
+ string url = "";
+ url = Interop.Capture.GenerageUrl(swigCPtr);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return url;
+ }
+
+ }
+
+ /// <summary>
+ /// CaptureFinishedEventArgs
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class CaptureFinishedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Status of saving the result after capture.
+ /// </summary>
+ /// <value>
+ /// true when succeeded in saving the result after capture.
+ /// false when failed to capture by time out or to save the result.
+ /// </value>
+ public bool Success { get; internal set; }
+ }
+
+ internal class CaptureSignal : Disposable
+ {
+ internal CaptureSignal(IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+ {
+ }
+
+ protected override void ReleaseSwigCPtr(HandleRef swigCPtr)
+ {
+ if (swigCMemOwn)
+ {
+ Interop.Capture.DeleteSignal(swigCPtr);
+ }
+ }
+
+ public bool Empty()
+ {
+ bool ret = Interop.Capture.SignalEmpty(swigCPtr);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ public uint GetConnectionCount()
+ {
+ uint ret = Interop.Capture.SignalGetConnectionCount(swigCPtr);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ public void Connect(Delegate func)
+ {
+ IntPtr ip = Marshal.GetFunctionPointerForDelegate<Delegate>(func);
+ {
+ Interop.Capture.SignalConnect(swigCPtr, new HandleRef(this, ip));
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+ }
+
+ public void Disconnect(Delegate func)
+ {
+ IntPtr ip = Marshal.GetFunctionPointerForDelegate<Delegate>(func);
+ {
+ Interop.Capture.SignalDisconnect(swigCPtr, new HandleRef(this, ip));
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+ }
+
+ public void Emit(Capture src, bool success)
+ {
+ Interop.Capture.SignalEmit(swigCPtr, src.SwigCPtr, (success ? 0 : 1));
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ }
+ }
+}
--- /dev/null
+
+using global::System;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using NUnit.Framework;
+
+namespace Tizen.NUI.Samples
+{
+ using log = Tizen.Log;
+ public class CaptureTest : IExample
+ {
+ public void Activate()
+ {
+ log.Debug(tag, $"Activate(): start \n");
+ resourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+
+ window = NUIApplication.GetDefaultWindow();
+ window.TouchEvent += Win_TouchEvent;
+
+ root = new View()
+ {
+ Name = "test_root",
+ Size = new Size(500, 500),
+ Position = new Position(10, 10),
+ BackgroundColor = Color.White,
+ };
+
+ window.Add(root);
+
+ log.Debug(tag, $"root view added \n");
+
+ capturedView0 = new ImageView(resourcePath + "/images/image1.jpg")
+ {
+ Name = "test_v0",
+ Size = new Size(100, 100),
+ BackgroundColor = Color.Red,
+ };
+ root.Add(capturedView0);
+
+ capturedView1 = new ImageView(resourcePath + "/images/image2.jpg")
+ {
+ Name = "test_v1",
+ Size = new Size(150, 150),
+ Position = new Position(150, 150),
+ BackgroundColor = Color.Yellow,
+ };
+ root.Add(capturedView1);
+
+ //TDD
+ //tddTest();
+ //checkCaptureNew();
+ }
+
+ private void onCaptureFinished(object sender, CaptureFinishStateEventArgs e)
+ {
+ log.Debug(tag, $"onCaptureFinished() statue={e.Success} \n");
+
+ if (sender is Capture)
+ {
+ log.Debug(tag, $"sender is Capture \n");
+ var url = capture.GenerateUrl();
+ capturedImage = new ImageView(url);
+ log.Debug(tag, $"url={url} \n");
+
+ capturedImage.Size = new Size(300, 300);
+ capturedImage.Position = new Position(10, 10);
+ root.Add(capturedImage);
+ done = false;
+ }
+ }
+
+ private void Win_TouchEvent(object sender, Window.TouchEventArgs e)
+ {
+ if (e.Touch.GetState(0) == PointStateType.Down)
+ {
+ if (!done)
+ {
+ done = true;
+ capture = new Capture();
+ capture.Start(root, new Size(345, 543), @"/opt/usr/nui_captured.jpg");
+ capture.Finished += onCaptureFinished;
+ log.Debug(tag, $"capture done \n");
+ }
+ }
+ }
+
+ private void tddTest()
+ {
+ log.Debug(tag, $"TDD test before Assert");
+
+ Assert.IsFalse(true, "TDD test, Exception throw");
+
+ Assert.IsFalse(false, "TDD test, Exception throw");
+
+ log.Debug(tag, $"TDD test after Assert");
+ }
+
+ private void checkCaptureNew()
+ {
+ var target = new Capture();
+ Assert.IsNotNull(target, "target should not be null");
+ Assert.IsTrue(target is Capture, "target should be Capture class");
+ }
+
+ public void Deactivate()
+ {
+ }
+
+ const string tag = "NUITEST";
+ private Window window;
+ private View root, capturedView0, capturedView1;
+ private Capture capture;
+ private ImageView capturedImage;
+ private bool done = false;
+ private string resourcePath;
+ }
+}