/* * 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. * */ using System.Diagnostics; using System; using System.Drawing; namespace Tizen.NUI { using global::System; using global::System.ComponentModel; using global::System.Runtime.InteropServices; using Tizen.NUI.BaseComponents; /// /// Capture snapshots the current scene and save as a file. /// Applications should follow the example below to create capture : /// /// Capture capture = new Capture(); /// /// If required, you can also subscribe Finished event : /// /// capture.Finished += onCaptureFinished; /// /// At the subcribed event handler, user can know whether capture finish succeeded state. /// /// private void onCaptureFinished(object sender, CaptureFinishedEventArgs e) /// { /// if(e.Success) { //capture success, do something. } /// else { //capture failure, do something. } /// } /// /// suppose that we want to capture View 'A'. And, the View 'A' is overlapped by another View 'B' that is not a child of 'A'. /// in this case, if source is root of scene, the captured image includes a part of View 'B' on the 'A'. /// however, if source is just View 'A', the result includes only 'A'. /// [EditorBrowsable(EditorBrowsableState.Never)] public class Capture : BaseHandle { /// /// Create an Capture. /// [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) { } /// /// Dispose /// /// [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); } /// /// Start capture and save the image as a file. /// /// source View or Layer to be used for capture. /// This source must be added on the window in advance. /// top-left position of area to be captured. /// this position is defined in the window. /// captured size. /// image file path to be saved as a file. /// If path is empty string, the captured result is not be saved as a file. /// background color of captured scene. /// This exception can be due to the invalid size values, of when width or height is lower than zero. /// This exception is thrown when size or path or position or color is null. [EditorBrowsable(EditorBrowsableState.Never)] public void Start(Container source, Position position, Size size, string path, Color color) { if (null == size) { throw new ArgumentNullException(nameof(size)); } else 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"); } else if (null == position) { throw new ArgumentNullException(nameof(position)); } else if (null == color) { throw new ArgumentNullException(nameof(color)); } if (source is View || source is Layer) { Interop.Capture.Start4(swigCPtr, source.SwigCPtr, new Vector2(position.X, position.Y).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(); } } /// /// Start capture and save the image as a file. /// /// source View or Layer to be used for capture. /// This source must be added on the window in advance. /// captured size. /// image file path to be saved as a file. /// If path is empty string, the captured result is not be saved as a file. /// background color of captured scene. /// The value to control image quality for jpeg file format in the range [1, 100]. /// This exception can be due to the invalid size values, of when width or height is lower than zero. /// This exception is thrown when size or path or color is null. [EditorBrowsable(EditorBrowsableState.Never)] public void Start(Container source, Size size, string path, Color color, uint quality) { if (null == size) { throw new ArgumentNullException(nameof(size)); } else 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"); } else if (quality > 100) { throw new InvalidOperationException("quality should between 0 to 100"); } else if (null == color) { throw new ArgumentNullException(nameof(color)); } if (source is View || source is Layer) { Interop.Capture.Start3(swigCPtr, source.SwigCPtr, new Vector2(size.Width, size.Height).SwigCPtr, path, new Vector4(color.R, color.G, color.B, color.A).SwigCPtr, quality); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } } /// /// Start capture and save the image as a file. /// /// source View or Layer to be used for capture. /// This source must be added on the window in advance. /// captured size. /// image file path to be saved as a file. /// If path is empty string, the captured result is not be saved as a file. /// background color of captured scene. /// This exception can be due to the invalid size values, of when width or height is lower than zero. /// This exception is thrown when size or path or color is null. [EditorBrowsable(EditorBrowsableState.Never)] public void Start(Container source, Size size, string path, Color color) { if (null == size) { throw new ArgumentNullException(nameof(size)); } else 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"); } else if (null == color) { throw new ArgumentNullException(nameof(color)); } 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(); } } /// /// Start capture and save the image as a file. /// /// /// Background color of captured scene is transparent. /// /// source View or Layer to be used for capture. /// This source must be added on the window in advance. /// captured size. /// image file path to be saved as a file. /// If path is empty string, the captured result is not be saved as a file. /// This exception can be due to the invalid size values, of when width or height is lower than zero. /// This exception is thrown when size or path is null. [EditorBrowsable(EditorBrowsableState.Never)] public void Start(Container source, Size size, string path) { if (null == size) { throw new ArgumentNullException(nameof(size)); } else 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(); } } /// /// Set result image quality in case of jpeg. /// /// quality The value to control image quality for jpeg file format in the range [1, 100] /// This exception can be due to the invalid size values, of when quality is lower than zero or over than 100. [EditorBrowsable(EditorBrowsableState.Never)] public void SetImageQuality(uint quality) { if (quality < 0 || quality > 100) { throw new InvalidOperationException("quality should between zero to 100"); } Interop.Capture.SetImageQuality(swigCPtr, quality); } 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 finishedEventHandler; /// /// For subscribing Finished event sent by this class. /// [EditorBrowsable(EditorBrowsableState.Never)] public event EventHandler 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); } } } /// /// Get NativeImageSource that is saved captured image. /// /// NativeImageSource that is saved captured image. [EditorBrowsable(EditorBrowsableState.Never)] public NativeImageSource GetNativeImageSource() { Tizen.Log.Debug("NUI", $"GetNativeImageSource()"); return new NativeImageSource(Interop.Capture.GetNativeImageSourcePtr(swigCPtr), true); } /// /// Generate captured image's Url /// /// The Url string representing this captured image source [EditorBrowsable(EditorBrowsableState.Never)] public string GenerateUrl() { string url = ""; url = Interop.Capture.GenerateUrl(swigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return url; } } /// /// CaptureFinishedEventArgs /// [EditorBrowsable(EditorBrowsableState.Never)] public class CaptureFinishedEventArgs : EventArgs { /// /// Status of saving the result after capture. /// /// /// true when succeeded in saving the result after capture. /// false when failed to capture by time out or to save the result. /// 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(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(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(); } } }