/// <summary> /// Disposes of all the resources that have been allocated by the <see cref="Camera" />. /// </summary> public void Dispose() { // Checks if the IPC wrapper for gPhoto2 has already been disposed of, if not then it is disposed of if (this.gPhoto2IpcWrapper != null) { this.gPhoto2IpcWrapper.Dispose(); this.gPhoto2IpcWrapper = null; } }
/// <summary> /// Iterates all configurations of the specified camera and initializes them. /// </summary> /// <param name="gPhoto2IpcWrapper"> /// The IPC wrapper, which is to be used to interface with gPhoto2. The IPC wrapper must be injected, because the configurations should /// use the exact same IPC wrapper used by the camera (the IPC wrapper ensures that only one operation at a time is executed, /// which is important when interfacing with the camera). If two operations, e.g. configuration a value and capturing an image, would /// be performed at the same time, the program would crash, because gPhoto2 can only do one thing at a time). /// </param> /// <exception cref="CameraConfiguration"> /// If anything goes wrong during the retrieval of the camera configurations, then a <see cref="CameraConfiguration" /> exception is thrown. /// </exception> /// <returns>Returns a read-only list containing all configurations of the specified camera.</returns> internal static async Task <IEnumerable <CameraConfiguration> > GetCameraConfigurationsAsync(GPhoto2IpcWrapper gPhoto2IpcWrapper) { // Gets all the configurations of the specified camera and returns them return(await gPhoto2IpcWrapper.ExecuteInteractiveAsync("list-config", output => { // Creates a new result list for the camera configurations List <CameraConfiguration> CameraConfigurations = new List <CameraConfiguration>(); // Creates a string reader, so that the output of gPhoto2 can be read line by line using (StringReader stringReader = new StringReader(output)) { // Cycles over the each line of the output and creates a new configuration (each line contains the name of the configuration) string line; while (!string.IsNullOrWhiteSpace(line = stringReader.ReadLine())) { CameraConfigurations.Add(new CameraConfiguration(line.Trim(), gPhoto2IpcWrapper)); } } // Returns all configurations that have been found by gPhoto2 for the specified camera return Task.FromResult(CameraConfigurations); })); }
/// <summary> /// Intializes a new <see cref="CameraConfiguration" /> instance. The constructor is made internal, so that the factory pattern, /// which is used to instantiate new instances of <see cref="CameraConfiguration" />, can be enforced. /// </summary> /// <param name="configurationName">The name of the configuration.</param> /// <param name="gPhoto2IpcWrapper"> /// The IPC wrapper, which is to be used to interface with gPhoto2. The IPC wrapper must be injected, because the configuration /// should use the exact same IPC wrapper used by the camera (the IPC wrapper ensures that only one operation at a time is executed, /// which is important when interfacing with the camera). If two operations, e.g. setting a value and capturing an image, would /// be performed at the same time, the program would crash, because gPhoto2 can only do one thing at a time). /// </param> internal CameraConfiguration(string configurationName, GPhoto2IpcWrapper gPhoto2IpcWrapper) { // Stores the all information about the configuration for later use this.Name = configurationName; this.gPhoto2IpcWrapper = gPhoto2IpcWrapper; }
/// <summary> /// Iterates all cameras attached to the system and initializes them. /// </summary> /// <returns>Returns a read-only list of all cameras attached to the system.</returns> public static async Task <IEnumerable <Camera> > GetCamerasAsync() { // Creates a new IPC wrapper, which can be used to interface with gPhoto2 GPhoto2IpcWrapper gPhoto2IpcWrapper = new GPhoto2IpcWrapper { StandardCommandLineParameters = "--quiet" }; // Gets all the cameras attached to the computer List <Camera> createdCameras = await gPhoto2IpcWrapper.ExecuteAsync("--auto-detect", output => { // Creates a new result list for the cameras List <Camera> cameras = new List <Camera>(); // Creates a string reader, so that the output of gPhoto2 can be read line by line using (StringReader stringReader = new StringReader(output)) { // Dismisses the first two lines because they only contain the header of the table containing the cameras stringReader.ReadLine(); stringReader.ReadLine(); // The line contains the name of the camera and its port separated by multiple whitespaces, this regular //expression is used to split them Regex cameraAndPortRegex = new Regex("^(?<Name>((\\S\\s\\S)|\\S)+)\\s\\s+(?<Port>((\\S\\s\\S)|\\S)+)$"); // Cycles over the rest of the lines (each line represents a row in the table containing the cameras) string line; while (!string.IsNullOrWhiteSpace(line = stringReader.ReadLine())) { // Trims the line, because it might have leading or trailing whitespaces (the regular expression would be // more complex with them) line = line.Trim(); // Reads the name and the port of the camera Match match = cameraAndPortRegex.Match(line); string cameraName = match.Groups["Name"].Value; string cameraPort = match.Groups["Port"].Value; // If either the camera name or the port is null or whitespace, then the camera could not be matched if (string.IsNullOrWhiteSpace(cameraName) || string.IsNullOrWhiteSpace(cameraPort)) { continue; } // Creates the new camera and adds it to the result set Camera camera = new Camera(cameraName, cameraPort); cameras.Add(camera); } } // Returns all cameras that have been found by gPhoto2 return(Task.FromResult(cameras)); }); // Initializes the cameras that have been created (since all camera commands are executed in an action block, they must not // be nested, because otherwise they would end up in a dead lock, therefore the initialization is done outside of the // camera command) await Task.WhenAll(createdCameras.Select(createdCamera => createdCamera.InitializeAsync())); // Returns the initialized cameras return(createdCameras); }