public void ImageExtractor_ProcessAsync() { // Arrange var loggerFactory = base.GetService <ILoggerFactory>(); var fileSystemStrategy = base.GetService <IFileSystemStrategy>(); var factory = base.GetService <IItkImageReaderFactory>(); var command = new ProcessPathCommand() { SourcePath = GetDataPath("SMIR.Brain.XX.O.CT.339203.nii"), DestinationPath = GetTempPath(), AmountPerAxis = 10, AxisTypes = new HashSet <AxisType> { AxisType.X, AxisType.Y, AxisType.Z } }; IImageExtractor extractor = new ItkImageExtractor(loggerFactory, fileSystemStrategy, factory); var ct = new CancellationToken(); try { // Act var result = extractor.ProcessAsync(command, ct).Result; // Assert Assert.AreEqual(28, result.Images.Count); } finally { DeleteDirectory(command.DestinationPath); } }
public void ImageService_ProcessAsync_2(string filename) { // Arrange var service = GetService <IImageService>(); var ct = new CancellationToken(); var command = new ProcessPathCommand() { AmountPerAxis = 4, OutputSize = 50, SourcePath = GetDataPath(filename), DestinationPath = GetTempPath() }; command.AxisTypes.Add(AxisType.Z); try { // Act var result = service.ProcessAsync(command, ct).Result; var json = File.ReadAllText(Path.Combine(command.DestinationPath, result.JsonFilename)); // Assert Assert.AreEqual(command.AmountPerAxis, result.Images.Count); } finally { DeleteDirectory(command.DestinationPath); } }
private async Task ExecuteCommandAsync(ProcessPathCommand command, CancellationToken ct, bool openCombinedGif = false) { var watch = Stopwatch.StartNew(); Logger.LogInformation($"{this.GetMethodName()} started"); var result = await Mediator.Send(command, ct); if (openCombinedGif) { var p = new Process { StartInfo = new ProcessStartInfo(Path.Combine(command.DestinationPath, result.CombinedGif)) { UseShellExecute = true } }; p.Start(); } watch.Stop(); TimeSpan t = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds); Logger.LogInformation($"{this.GetMethodName()} ended after {t.ToReadableTime()}"); }
public async Task ExecuteAsync(string[] args, CancellationToken ct) { var command = new ProcessPathCommand(); bool openCombinedGif = false; Parser.Default.ParseArguments <Options>(args) .WithParsed(o => { command.OutputSize = o.OutputSize; command.AmountPerAxis = o.AmountPerAxis; command.SourcePath = o.SourcePath; command.DestinationPath = o.DestinationPath; command.Grayscale = Convert.ToBoolean(o.Grayscale); openCombinedGif = Convert.ToBoolean(o.OpenCombinedGif); }); if (args.Contains("--help") || args.Contains("--version")) { await Task.CompletedTask; } else { await ExecuteCommandAsync(command, ct, openCombinedGif); } }
public void ProcessPathCommand_Validation_Failures() { // Arrange var mediator = GetService <IMediator>(); var ct = new CancellationToken(); var command = new ProcessPathCommand(); // Act & Assert var ex = Assert.ThrowsAsync <ValidationException>(() => mediator.Send(command, ct)); Assert.AreEqual("One or more validation failures have occurred.", ex.Message); Assert.IsNotNull(ex.Failures); Assert.AreEqual(3, ex.Failures.Count); var firstEntry = ex.Failures[nameof(command.AmountPerAxis)]; Assert.AreEqual(1, firstEntry.Length); Assert.AreEqual("'Amount Per Axis' must be greater than '0'.", firstEntry[0]); var secondEntry = ex.Failures[nameof(command.SourcePath)]; Assert.AreEqual(1, secondEntry.Length); Assert.AreEqual("'Source Path' must not be empty.", secondEntry[0]); var thirdEntry = ex.Failures[nameof(command.DestinationPath)]; Assert.AreEqual(1, thirdEntry.Length); Assert.AreEqual("'Destination Path' must not be empty.", thirdEntry[0]); }
public void ImageExtractor_ProcessAsync() { // Arrange var extractor = GetService <IImageExtractor>(); var ct = new CancellationToken(); var command = new ProcessPathCommand() { SourcePath = GetDataPath("SMIR.Brain_3more.XX.XX.OT.6560.mha"), DestinationPath = GetTempPath(), AmountPerAxis = 6 }; try { // Act var result = extractor.ProcessAsync(command, ct).Result; // Assert // 6 (per axis) * 3 (x, y, z) = 18 Assert.AreEqual(18, result.Images.Count); Assert.AreEqual(5, (int)result.LabelCount); } finally { DeleteDirectory(command.DestinationPath); } }
private async Task ExecuteTestAsync(string[] args, CancellationToken ct) { var command = new ProcessPathCommand() { AmountPerAxis = 10, DesiredSize = 250, SourcePath = Path.Combine(FileSystemHelper.BuildCurrentPath(), "data", "SMIR.Brain.XX.O.MR_Flair.36620.mha"), DestinationPath = Path.Combine(FileSystemHelper.BuildCurrentPath(), "temp", Guid.NewGuid().ToString("N")) }; command.AxisTypes.Add(AxisType.Z); await ExecuteCommandAsync(command, ct, true); }
/// <inheritdoc/> public async Task <ProcessResultModel> ProcessAsync(ProcessPathCommand command, CancellationToken ct) { if (string.IsNullOrWhiteSpace(command.SourcePath)) { throw new UnexpectedNullException("Empty source path."); } if (string.IsNullOrWhiteSpace(command.DestinationPath)) { throw new UnexpectedNullException("Empty destination path."); } var sourceFs = fileSystemStrategy.Create(command.SourcePath); var destFs = fileSystemStrategy.Create(command.DestinationPath); var watermarkFs = fileSystemStrategy.Create(command.WatermarkSourcePath); var commandClone = command.DeepClone(); commandClone.SourcePath = sourceFs.BuildAbsolutePath(command.SourcePath); commandClone.DestinationPath = destFs.BuildAbsolutePath(command.DestinationPath); commandClone.WatermarkSourcePath = watermarkFs.BuildAbsolutePath(command.WatermarkSourcePath); // Creates all directories and subdirectories in the specified path unless they already exist. destFs.Directory.CreateDirectory(commandClone.DestinationPath); // TODO: support zip files var result = await imageExtractor.ProcessAsync(commandClone, ct); // Set GIFs result.Gifs = await gifImageWriter.WriteAsync( command.DestinationPath, result.Images, command.BezierEasingTypePerAxis, ct); result.CombinedGif = await gifImageWriter.WriteAsync( command.DestinationPath, result.Images, "combined", command.BezierEasingTypeCombined, ct); // Set application version var appInfo = appInfoFactory.Create(); result.Version = appInfo.AppVersion; // Write JSON and set filename await jsonWriter.WriteAsync(commandClone.DestinationPath, "output", result, (filename) => { result.JsonFilename = filename; }); return(result); }
/// <summary> /// Executes the specified arguments asynchronous. /// </summary> /// <param name="args">The arguments.</param> /// <param name="ct">The cancellation token.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <exception cref="ArgumentNullException"> /// SourcePath /// or /// DestinationPath /// </exception> public async Task ExecuteAsync(string[] args, CancellationToken ct) { var command = new ProcessPathCommand(); bool openCombinedGif = false; Parser.Default.ParseArguments <Options>(args) .WithParsed(o => { command.DesiredSize = o.DesiredSize; command.AmountPerAxis = o.AmountPerAxis; command.SourcePath = o.SourcePath; command.DestinationPath = o.DestinationPath; command.Grayscale = Convert.ToBoolean(o.Grayscale); openCombinedGif = Convert.ToBoolean(o.OpenCombinedGif); }); await ExecuteCommandAsync(command, ct, openCombinedGif); }
private PositionAxisContainerModel <string> WriteImage( int position, IFileSystem fs, ProcessPathCommand command, T1 reader, AxisType axisType, ImageFormat imageFormat, string filename, BitmapWrapper watermark = null) { var bitmap = reader.ExtractPosition(axisType, position, command.OutputSize); if (bitmap != null) { if (command.Grayscale) { bitmap = bitmap.To8bppIndexedGrayscale(); } bitmap = bitmap.ToCenter(command.OutputSize, Color.Black); if (bitmap == null) { throw new UnexpectedNullException("Bitmap could not be centered."); } if (watermark != null) { bitmap = bitmap.AppendWatermark(watermark); } fs.File.WriteAllBytes(fs.Path.Combine(command.DestinationPath, filename), bitmap.ToByteArray(imageFormat)); bitmap.Dispose(); return(new PositionAxisContainerModel <string>(position, axisType, filename)); } return(null); }
/// <summary> /// Returns "Crop to custom selection" composite command. /// </summary> /// <param name="path">Custom selection path.</param> /// <param name="pathBounds">Selection path bounds.</param> /// <param name="crop">Crop command.</param> /// <returns>Crop command for custom selection.</returns> ProcessingCommandBase GetCropToPathCommand( GraphicsPath path, RectangleF pathBounds, CropCommand crop) { Rectangle viewerImageRect = new Rectangle(0, 0, _viewer.Image.Width, _viewer.Image.Height); crop.RegionOfInterest = new RegionOfInterest(GetBoundingRect(RectangleF.Intersect(pathBounds, viewerImageRect))); // overlay command _overlayImage = crop.Execute(_viewer.Image); OverlayCommand overlay = new OverlayCommand(_overlayImage); // overlay with path command ProcessPathCommand overlayWithPath = new ProcessPathCommand(overlay, path); // clear image command ClearImageCommand clearImage = new ClearImageCommand(Color.Transparent); // create composite command: clear, overlay with path, crop return(new CompositeCommand(clearImage, overlayWithPath, crop)); }
public void ProcessPathCommand() { // Arrange var mediator = GetService <IMediator>(); var ct = new CancellationToken(); var command = new ProcessPathCommand() { SourcePath = GetDataPath("SMIR.Brain_3more.XX.XX.OT.6560.mha"), DestinationPath = GetTempPath(), AmountPerAxis = 6, AxisTypes = new HashSet <AxisType> { AxisType.X, AxisType.Y, AxisType.Z } }; try { // Act var result = mediator.Send(command, ct).Result; // Assert // 6 (per axis) * 3 (x, y, z) = 18 Assert.AreEqual(18, result.Images.Count); Assert.AreEqual(5, result.LabelCount); Assert.AreEqual(160, result.Size[0]); Assert.AreEqual(216, result.Size[1]); Assert.AreEqual(176, result.Size[2]); } finally { DeleteDirectory(command.DestinationPath); } }
/// <inheritdoc/> protected override async Task <ProcessResultModel> ProtectedHandleAsync(ProcessObjectCommand request, CancellationToken cancellationToken) { context.BeginTransaction(); var objectEntity = await context.ObjectRepository.GetFirstOrDefaultAsync(e => e.Id == Guid.Parse(request.Id), cancellationToken); if (objectEntity == null) { throw new UnexpectedNullException($"{nameof(ObjectEntity)} not found."); } // Create temporary directory and use it as destination path var tempDestPath = fileSystem.Path.Combine(configuration.WorkingDirectory, "Temp", Guid.NewGuid().ToString()); fileSystem.Directory.CreateDirectory(tempDestPath); // TODO: extract if needed, update the ObjectEntity.UncompressedPath // and use the extracted directory as source path var pathRequest = new ProcessPathCommand() { SourcePath = fileSystem.Path.Combine(configuration.WorkingDirectory, objectEntity.SourcePath), DestinationPath = tempDestPath, DesiredSize = request.DesiredSize, AmountPerAxis = request.AmountPerAxis, AxisTypes = request.AxisTypes, ImageFormat = request.ImageFormat, BezierEasingTypePerAxis = request.BezierEasingTypePerAxis, BezierEasingTypeCombined = request.BezierEasingTypeCombined, Grayscale = request.Grayscale }; // Start the processing var result = await mediator.Send(pathRequest, cancellationToken); if (result == null) { throw new UnexpectedNullException($"The processing result of object {request.Id} was null."); } // Move content of temporary directory and delete it var resultsDirectoryName = "Results"; var resultsPath = fileSystem.Path.Combine(configuration.WorkingDirectory, resultsDirectoryName); var baseDestPath = fileSystem.Path.Combine(resultsDirectoryName, result.Id); var destPath = fileSystem.Path.Combine(configuration.WorkingDirectory, baseDestPath); fileSystem.Directory.CreateDirectory(resultsPath); fileSystem.Directory.Move(tempDestPath, destPath); var resultEntity = await context.ResultRepository.GetFirstOrDefaultAsync(e => e.Id == Guid.Parse(result.Id), cancellationToken); if (resultEntity == null) { throw new UnexpectedNullException($"{nameof(ResultEntity)} not found."); } // Update BaseFsPath of ResultEntity resultEntity.BasePath = baseDestPath; resultEntity.ModifiedDate = DateTime.UtcNow; context.ResultRepository.Update(resultEntity); await context.SaveChangesAsync(cancellationToken); context.CommitTransaction(); return(result); }
/// <summary> /// Executes image processing command synchronously or asynchronously. /// </summary> /// <param name="command">Command to execute.</param> /// <param name="async">A value indicating whether to execute command asynchronously.</param> public bool ExecuteProcessingCommand(ProcessingCommandBase command, bool async) { RectangularSelectionToolWithCopyPaste rectSelectionTool = CompositeVisualTool.FindVisualTool <RectangularSelectionToolWithCopyPaste>(_viewer.VisualTool); CustomSelectionTool customSelectionTool = CompositeVisualTool.FindVisualTool <CustomSelectionTool>(_viewer.VisualTool); if (rectSelectionTool != null) { // set the region of interest Rectangle selectionRectangle = ViewerSelectionRectangle; ProcessingCommandWithRegion commandWorkWithRegion = command as ProcessingCommandWithRegion; if (commandWorkWithRegion != null) { commandWorkWithRegion.RegionOfInterest = new RegionOfInterest(selectionRectangle.Left, selectionRectangle.Top, selectionRectangle.Width, selectionRectangle.Height); } else if (command is DrawImageCommand) { ((DrawImageCommand)command).DestRect = selectionRectangle; } else if (!selectionRectangle.IsEmpty) { MessageBox.Show("Selected image processing command cannot work with regions. Entire image will be processed.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information); } } else if (customSelectionTool != null) { RectangleF selectionBBox = RectangleF.Empty; if (customSelectionTool.Selection != null) { selectionBBox = customSelectionTool.Selection.GetBoundingBox(); } if (selectionBBox.Width >= 1 && selectionBBox.Height >= 1) { if (command is ChangePixelFormatCommand || command is ChangePixelFormatToBgrCommand || command is ChangePixelFormatToBlackWhiteCommand || command is ChangePixelFormatToGrayscaleCommand || command is ChangePixelFormatToPaletteCommand || command is RotateCommand || command is ResampleCommand || command is ResizeCommand || !command.CanModifyImage) { MessageBox.Show("Selected image processing command cannot work with custom selection. Entire image will be processed.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { GraphicsPath path = customSelectionTool.Selection.GetAsGraphicsPath(); RectangleF pathBounds = path.GetBounds(); if (pathBounds.Width > 0 && pathBounds.Height > 0) { if (command is CropCommand) { // crop to custom selection command = GetCropToPathCommand(path, pathBounds, (CropCommand)command); // clear selection customSelectionTool.Selection = null; } else { // process path command = new ProcessPathCommand(command, path); } } else { MessageBox.Show("Selected path is empty.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); return(false); } } } } // get a reference to the image for processing VintasoftImage imageToProcess = _viewer.Image; ProcessingCommandBase executeCommand = command; if (_executeMultithread) { ParallelizingProcessingCommand parallelizingCommand = new ParallelizingProcessingCommand(command); if (command is ProcessingCommandWithRegion) { parallelizingCommand.RegionOfInterest = ((ProcessingCommandWithRegion)command).RegionOfInterest; } executeCommand = parallelizingCommand; } if (UndoManager != null) { _imageProcessingUndoMonitor = new ImageProcessingUndoMonitor(UndoManager, executeCommand); } // subscribe to the events of the image processing command executeCommand.Started += new EventHandler <ImageProcessingEventArgs>(command_Started); executeCommand.Progress += new EventHandler <ImageProcessingProgressEventArgs>(command_Progress); executeCommand.Finished += new EventHandler <ImageProcessedEventArgs>(command_Finished); executeCommand.ExpandSupportedPixelFormats = ExpandSupportedPixelFormats; executeCommand.RestoreSourcePixelFormat = false; // specify that image processing command is working (several commands cannot work together) _isImageProcessingWorking = true; // get the start time of the image processing command _processingCommandStartTime = DateTime.Now; // if image processing command should be executed asynchronously if (async) { // start the image processing command asynchronously ProcessingCommandTask executor = new ProcessingCommandTask(executeCommand, imageToProcess); executor.ImageProcessingExceptionOccurs += new EventHandler(executor_ImageProcessingExceptionOccurs); Thread thread = new Thread(executor.Execute); thread.IsBackground = true; thread.Start(); } // if image processing command should be executed synchronously else { try { // execute the image processing command synchronously executeCommand.ExecuteInPlace(imageToProcess); } catch (Exception ex) { executor_ImageProcessingExceptionOccurs(this, EventArgs.Empty); DemosTools.ShowErrorMessage(ex); return(false); } } return(true); }
public void ImageService_ProcessAsync() { // Arrange var service = GetService <IImageService>(); var ct = new CancellationToken(); var command = new ProcessPathCommand() { AmountPerAxis = 10, DesiredSize = 250, SourcePath = GetDataPath("SMIR.Brain_3more.XX.XX.OT.6560.mha"), DestinationPath = GetTempPath() }; command.AxisTypes.Add(AxisType.Z); var expected = @"{ ""resultType"": 1, ""labelCount"": 5, ""images"": [ { ""position"": 0, ""axisType"": 2, ""entity"": ""Z_0.png"" }, { ""position"": 1, ""axisType"": 2, ""entity"": ""Z_1.png"" }, { ""position"": 2, ""axisType"": 2, ""entity"": ""Z_2.png"" }, { ""position"": 3, ""axisType"": 2, ""entity"": ""Z_3.png"" }, { ""position"": 4, ""axisType"": 2, ""entity"": ""Z_4.png"" }, { ""position"": 5, ""axisType"": 2, ""entity"": ""Z_5.png"" }, { ""position"": 6, ""axisType"": 2, ""entity"": ""Z_6.png"" }, { ""position"": 7, ""axisType"": 2, ""entity"": ""Z_7.png"" }, { ""position"": 8, ""axisType"": 2, ""entity"": ""Z_8.png"" }, { ""position"": 9, ""axisType"": 2, ""entity"": ""Z_9.png"" } ], ""gifs"": [ { ""axisType"": 2, ""entity"": ""Z.gif"" } ], ""combinedGif"": ""combined.gif"", ""id"": null, ""createdDate"": ""0001-01-01T00:00:00"", ""modifiedDate"": ""0001-01-01T00:00:00"", ""version"": ""0.0.3"", ""jsonFilename"": ""output.json"", ""discriminator"": ""ProcessResultModel"" }"; try { // Act var result = service.ProcessAsync(command, ct).Result; var json = File.ReadAllText(Path.Combine(command.DestinationPath, result.JsonFilename)); // Assert Assert.AreEqual(command.AmountPerAxis, result.Images.Count); Assert.AreEqual(5, result.LabelCount); Assert.AreEqual(expected, json); } finally { DeleteDirectory(command.DestinationPath); } }
/// <inheritdoc/> protected override async Task <ProcessResultModel> ProtectedHandleAsync(ProcessObjectCommand request, CancellationToken cancellationToken) { var objectEntity = await Context.ObjectRepository.GetFirstOrDefaultAsync(e => e.Id == Guid.Parse(request.Id), cancellationToken); if (objectEntity == null) { throw new UnexpectedNullException($"{nameof(ObjectEntity)} not found."); } var directoryName = fileSystem.Path.GetDirectoryName(objectEntity.SourcePath); if (!directoryName.EndsWith(objectEntity.Id.ToString())) { throw new AmiException(string.Format( "The directory name of object {0} ends with an unexpected name: {1}", objectEntity.Id, directoryName)); } // Create temporary directory and use it as destination path var tempDestPath = fileSystem.Path.Combine(configuration.Options.WorkingDirectory, "Temp", Guid.NewGuid().ToString()); fileSystem.Directory.CreateDirectory(tempDestPath); var fullSourcePath = fileSystem.Path.Combine(configuration.Options.WorkingDirectory, objectEntity.SourcePath); var pathRequest = new ProcessPathCommand() { SourcePath = fullSourcePath, DestinationPath = tempDestPath, OutputSize = request.OutputSize, AmountPerAxis = request.AmountPerAxis, Delay = request.Delay, AxisTypes = request.AxisTypes, ImageFormat = request.ImageFormat, BezierEasingTypePerAxis = request.BezierEasingTypePerAxis, BezierEasingTypeCombined = request.BezierEasingTypeCombined, Grayscale = request.Grayscale }; // Extract archive if needed if (archiveReader.IsArchive(fullSourcePath)) { var extractedPath = fileSystem.Path.Combine(directoryName, "Extracted"); var fullExtractedPath = fileSystem.Path.Combine(configuration.Options.WorkingDirectory, extractedPath); // Use the extracted directory as source path pathRequest.SourcePath = fullExtractedPath; if (string.IsNullOrWhiteSpace(objectEntity.ExtractedPath)) { fileSystem.Directory.CreateDirectory(fullExtractedPath); await archiveExtractor.ExtractAsync(fullSourcePath, fullExtractedPath, cancellationToken); objectEntity.ModifiedDate = DateTime.UtcNow; objectEntity.ExtractedPath = extractedPath; Context.ObjectRepository.Update(objectEntity); } } // Start the processing var result = await mediator.Send(pathRequest, cancellationToken); if (result == null) { throw new UnexpectedNullException($"The processing result of object {request.Id} was null."); } // Ensure "Results" directory exists var resultsDirectoryName = "Results"; var resultsPath = fileSystem.Path.Combine(configuration.Options.WorkingDirectory, resultsDirectoryName); fileSystem.Directory.CreateDirectory(resultsPath); // Move content of temporary directory and delete it var baseDestPath = fileSystem.Path.Combine(resultsDirectoryName, result.Id); var destPath = fileSystem.Path.Combine(configuration.Options.WorkingDirectory, baseDestPath); fileSystem.Directory.Move(tempDestPath, destPath); var resultEntity = await Context.ResultRepository.GetFirstOrDefaultAsync(e => e.Id == Guid.Parse(result.Id), cancellationToken); if (resultEntity == null) { throw new UnexpectedNullException($"{nameof(ResultEntity)} not found."); } // Update BaseFsPath of ResultEntity resultEntity.BasePath = baseDestPath; resultEntity.ModifiedDate = DateTime.UtcNow; Context.ResultRepository.Update(resultEntity); await Context.SaveChangesAsync(cancellationToken); return(result); }
/// <inheritdoc/> public async Task <ProcessResultModel> ProcessAsync(ProcessPathCommand command, CancellationToken ct) { Ensure.ArgumentNotNull(command, nameof(command)); Ensure.ArgumentNotNull(ct, nameof(ct)); ImageFormat imageFormat = GetImageFormat(command.ImageFormat); string imageExtension = imageFormat.FileExtensionFromEncoder(); if (string.IsNullOrWhiteSpace(imageExtension)) { throw new UnexpectedNullException("Image file extension could not be determined."); } var fs = fileSystemStrategy.Create(command.DestinationPath); if (fs == null) { throw new UnexpectedNullException("Filesystem could not be created based on the destination path."); } var reader = readerFactory.Create(); if (reader == null) { throw new UnexpectedNullException("Image reader could not be created."); } await reader.InitAsync(command.SourcePath, ct); reader.Mapper = new AxisPositionMapper(command.AmountPerAxis, reader.Width, reader.Height, reader.Depth); PreProcess(reader, imageFormat, command.AmountPerAxis, command.OutputSize); var result = new ProcessResultModel { LabelCount = Convert.ToInt32(reader.GetLabelCount()), Size = new int[] { reader.Width, reader.Height, reader.Depth } }; ISet <AxisType> axisTypes = new HashSet <AxisType>(command.AxisTypes); if (axisTypes.Count == 0) { axisTypes = new HashSet <AxisType> { AxisType.Z }; } BitmapWrapper watermark = null; if (!string.IsNullOrWhiteSpace(command.WatermarkSourcePath)) { BitmapReader bitmapReader = new BitmapReader(); var watermarkBitmap = await bitmapReader.ReadAsync(command.WatermarkSourcePath, command.OutputSize, ct); if (watermarkBitmap == null) { throw new UnexpectedNullException("Watermark could not be read."); } watermark = new BitmapWrapper(watermarkBitmap); } var images = new List <PositionAxisContainerModel <string> >(); foreach (AxisType axisType in axisTypes) { for (int i = 0; i < reader.Mapper.GetLength(axisType); i++) { ct.ThrowIfCancellationRequested(); string filename = $"{axisType}_{i}{imageExtension}"; var image = WriteImage(i, fs, command, reader, axisType, imageFormat, filename, watermark); if (image != null) { images.Add(image); } } } reader.Dispose(); result.Images = images.OrderBy(e => e.Position).ToList(); return(result); }
/// <inheritdoc/> public async Task <ProcessResultModel> ProcessAsync(ProcessPathCommand command, CancellationToken ct) { Ensure.ArgumentNotNull(command, nameof(command)); Ensure.ArgumentNotNull(ct, nameof(ct)); if (string.IsNullOrWhiteSpace(command.SourcePath)) { throw new UnexpectedNullException("Empty source path."); } if (string.IsNullOrWhiteSpace(command.DestinationPath)) { throw new UnexpectedNullException("Empty destination path."); } var sourceFs = fileSystemStrategy.Create(command.SourcePath); var destFs = fileSystemStrategy.Create(command.DestinationPath); var watermarkFs = fileSystemStrategy.Create(command.WatermarkSourcePath); var commandClone = command.DeepClone(); commandClone.SourcePath = sourceFs.BuildAbsolutePath(command.SourcePath); commandClone.DestinationPath = destFs.BuildAbsolutePath(command.DestinationPath); commandClone.WatermarkSourcePath = watermarkFs.BuildAbsolutePath(command.WatermarkSourcePath); // Creates all directories and subdirectories in the specified path unless they already exist. destFs.Directory.CreateDirectory(commandClone.DestinationPath); // SourcePath can be a directory, archive or file if (archiveReader.IsArchive(commandClone.SourcePath)) { var extractedPath = destFs.Path.Combine(commandClone.DestinationPath, "Extracted"); destFs.Directory.CreateDirectory(extractedPath); await archiveExtractor.ExtractAsync(commandClone.SourcePath, extractedPath, ct); // Use the extracted directory as source path commandClone.SourcePath = extractedPath; } var result = await imageExtractor.ProcessAsync(commandClone, ct); if (result == null) { throw new UnexpectedNullException("The images could not be processed."); } // Set GIFs result.Gifs = await gifImageWriter.WriteAsync( commandClone.DestinationPath, result.Images, commandClone.Delay, commandClone.BezierEasingTypePerAxis, ct); result.CombinedGif = await gifImageWriter.WriteAsync( commandClone.DestinationPath, result.Images, "combined", commandClone.Delay, commandClone.BezierEasingTypeCombined, ct); // Set application version var appInfo = appInfoFactory.Create(); result.Version = appInfo.AppVersion; // Write JSON and set filename await jsonWriter.WriteAsync(commandClone.DestinationPath, "output", result, (filename) => { result.JsonFilename = filename; }); return(result); }
/// <summary> /// Processes the images asynchronous. /// </summary> /// <param name="command">The command information.</param> /// <param name="ct">The cancellation token.</param> /// <returns> /// The result of the image processing. /// </returns> /// <exception cref="ArgumentNullException"> /// command /// or /// ct /// </exception> /// <exception cref="UnexpectedNullException"> /// Image file extension could not be determined. /// or /// Filesystem could not be created based on the destination path. /// or /// Image reader could not be created. /// or /// Watermark could not be read. /// or /// Bitmap could not be centered. /// </exception> public async Task <ProcessResultModel> ProcessAsync(ProcessPathCommand command, CancellationToken ct) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (ct == null) { throw new ArgumentNullException(nameof(ct)); } var result = new ProcessResultModel(); var imageFormat = GetImageFormat(command.ImageFormat); var imageExtension = imageFormat.FileExtensionFromEncoder(); if (string.IsNullOrWhiteSpace(imageExtension)) { throw new UnexpectedNullException("Image file extension could not be determined."); } var fs = fileSystemStrategy.Create(command.DestinationPath); if (fs == null) { throw new UnexpectedNullException("Filesystem could not be created based on the destination path."); } var reader = readerFactory.Create(); if (reader == null) { throw new UnexpectedNullException("Image reader could not be created."); } await reader.InitAsync(command.SourcePath, ct); reader.Mapper = new AxisPositionMapper(Convert.ToUInt32(command.AmountPerAxis), reader.Width, reader.Height, reader.Depth); PreProcess(reader, imageFormat, Convert.ToUInt32(command.AmountPerAxis), Convert.ToUInt32(command.DesiredSize)); result.LabelCount = Convert.ToInt32(reader.GetLabelCount()); ISet <AxisType> axisTypes = new HashSet <AxisType>(command.AxisTypes); if (axisTypes.Count == 0) { axisTypes = reader.GetRecommendedAxisTypes(); } BitmapWrapper watermark = null; if (!string.IsNullOrWhiteSpace(command.WatermarkSourcePath)) { BitmapReader bitmapReader = new BitmapReader(); var watermarkBitmap = await bitmapReader.ReadAsync(command.WatermarkSourcePath, Convert.ToUInt32(command.DesiredSize), ct); if (watermarkBitmap == null) { throw new UnexpectedNullException("Watermark could not be read."); } watermark = new BitmapWrapper(watermarkBitmap); } var images = new List <PositionAxisContainerModel <string> >(); foreach (AxisType axisType in axisTypes) { for (int i = 0; i < command.AmountPerAxis; i++) { ct.ThrowIfCancellationRequested(); string filename = $"{axisType}_{i}{imageExtension}"; var bitmap = reader.ExtractPosition(axisType, Convert.ToUInt32(i), Convert.ToUInt32(command.DesiredSize)); if (bitmap != null) { if (command.Grayscale) { bitmap = bitmap.To8bppIndexedGrayscale(); } bitmap = bitmap.ToCenter(Convert.ToUInt32(command.DesiredSize), Color.Black); if (bitmap == null) { throw new UnexpectedNullException("Bitmap could not be centered."); } if (watermark != null) { bitmap = bitmap.AppendWatermark(watermark); } fs.File.WriteAllBytes(fs.Path.Combine(command.DestinationPath, filename), bitmap.ToByteArray(imageFormat)); images.Add(new PositionAxisContainerModel <string>(Convert.ToUInt32(i), axisType, filename)); } } } result.Images = images.OrderBy(e => e.Position).ToList(); return(result); }