Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public enum OperationType
- {
- Create,
- Undo,
- Redo,
- Delete,
- Add,
- Move
- }
- public enum SlideType : byte
- {
- Introduction = 1,
- Content = 2,
- FinancialInstrument = 3
- }
- public class SlideDeckSession
- {
- public Guid Id { get; set; }
- public int LanguageId { get; set; }
- public List<SlideDeckStep> Steps { get; set; } = new();
- public List<SlideDeckSlide> Slides { get; set; } = new();
- }
- public class SlideDeckSlide
- {
- public SlideType Type { get; set; }
- public string? Name { get; set; }
- public string Path { get; set; } = default!;
- public int LanguageId { get; set; }
- public int? ContentId { get; set; }
- public int? ContentTypeId { get; set; }
- public int? FinancialInstrumentId { get; set; }
- public int? FinancialInstrumentTypeId { get; set; }
- }
- public class SlideDeckStep
- {
- public OperationType Type { get; set; }
- public List<int>? SlideIds { get; set; }
- public bool Undone { get; set; }
- }
- public class AddContentHandler : BaseAddHandler<AddContentRequest, AddContentInfo>
- {
- public AddContentHandler(
- IOptions<StorageOptions> storageOptions
- , IMediator mediator
- , IDbContextFactory<ApplicationDbContext> dbContextFactory
- ) : base(storageOptions, mediator, dbContextFactory)
- {
- }
- protected override Task<int> GetItemLanguageIdAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedContent>()
- .Where(x => x.Id == id && !x.IsDeleted)
- .OrderByDescending(x => x.LanguageId == languageId)
- .ThenByDescending(x => x.Language.IsDefault)
- .ThenBy(x => x.Language.Priority)
- .Select(x => x.LanguageId)
- .FirstOrDefaultAsync(cancellationToken);
- protected override SlideDeckSlide GetSlideInfo(AddContentInfo item, int itemLanguageId, string slideName, int stepIndex, int pictureIndex)
- => new()
- {
- ContentId = item.Id,
- ContentTypeId = item.GetItemTypeId(),
- LanguageId = itemLanguageId,
- Type = SlideType.Content,
- Name = slideName,
- Path = GetScreenShotUrlPath(stepIndex, pictureIndex)
- };
- protected override Task SendTransformRequestAsync(int id, int typeId, int languageId, CancellationToken cancellationToken)
- => _mediator.Send(new TransformRequest
- {
- Id = id,
- LanguageId = languageId,
- ContentTypeId = typeId
- }, cancellationToken);
- protected override Task<Asset?> GetPresentationContentAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedContent>()
- .Where(x => x.Id == id && x.LanguageId == languageId)
- .Select(x => x.SlideManagerContent)
- .FirstOrDefaultAsync(cancellationToken);
- protected override Task<string?> GetSlideNameAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedContent>()
- .Where(x => x.Id == id && x.LanguageId == languageId)
- .Select(x => x.Title)
- .FirstOrDefaultAsync(cancellationToken);
- }
- public class AddFinancialInstrumentHandler : BaseAddHandler<AddFinancialInstrumentRequest, AddFinancialInstrumentInfo>
- {
- public AddFinancialInstrumentHandler(
- IOptions<StorageOptions> storageOptions
- , IMediator mediator
- , IDbContextFactory<ApplicationDbContext> dbContextFactory
- ) : base(storageOptions, mediator, dbContextFactory)
- {
- }
- protected override Task<int> GetItemLanguageIdAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedFinancialInstrument>()
- .Where(x => x.Id == id)
- .OrderByDescending(x => x.LanguageId == languageId)
- .ThenByDescending(x => x.Language.IsDefault)
- .ThenBy(x => x.Language.Priority)
- .Select(x => x.LanguageId)
- .FirstOrDefaultAsync(cancellationToken);
- protected override SlideDeckSlide GetSlideInfo(AddFinancialInstrumentInfo item, int itemLanguageId, string slideName, int stepIndex, int pictureIndex)
- => new()
- {
- FinancialInstrumentId = item.Id,
- FinancialInstrumentTypeId = item.GetItemTypeId(),
- LanguageId = itemLanguageId,
- Type = SlideType.FinancialInstrument,
- Name = slideName,
- Path = GetScreenShotUrlPath(stepIndex, pictureIndex)
- };
- protected override Task SendTransformRequestAsync(int id, int typeId, int languageId, CancellationToken cancellationToken)
- => _mediator.Send(new TransformRequest
- {
- Id = id,
- LanguageId = languageId,
- FinancialInstrumentTypeId = typeId
- }, cancellationToken);
- protected override Task<Asset?> GetPresentationContentAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedFinancialInstrument>()
- .Where(x => x.Id == id && x.LanguageId == languageId)
- .Select(x => x.SlideManagerContent)
- .FirstOrDefaultAsync(cancellationToken);
- protected override Task<string?> GetSlideNameAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken)
- => db.Set<LocalizedFinancialInstrument>()
- .Where(x => x.Id == id && x.LanguageId == languageId)
- .Select(x => x.Name)
- .FirstOrDefaultAsync(cancellationToken);
- }
- public abstract class BaseHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
- where TRequest : IRequest<TResponse>
- {
- private const string PresentationName = "result.pptx";
- protected SlideDeckSession CurrentSession { get; set; } = default!;
- private string BaseFolder => Path.Combine(_storageOptions.DocumentsFolder, _storageOptions.TempFolder);
- private LanguageInfo Language { get; set; } = default!;
- protected string CurrentPresentationPath => Path.Combine(GetCurrentPresentationFolder(), PresentationName);
- protected int NextStepIndex => CurrentSession.Steps.Count;
- protected string NextStepFolder => Path.Combine(GetCurrentPresentationFolder(), NextStepIndex.ToString());
- protected string NextStepPresentationPath => Path.Combine(NextStepFolder, PresentationName);
- // ReSharper disable once StaticMemberInGenericType
- private static readonly JsonSerializerOptions JsonSerializerOptions = new()
- {
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
- Converters = { new JsonStringEnumConverter() },
- #if DEBUG
- WriteIndented = true
- #endif
- };
- protected readonly StorageOptions _storageOptions;
- protected readonly IMediator _mediator;
- protected BaseHandler(
- IOptions<StorageOptions> storageOptions
- , IMediator mediator
- )
- {
- _storageOptions = storageOptions.Value;
- _mediator = mediator;
- }
- public abstract Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
- private Task<LanguageInfo> GetLanguageAsync(int languageId, CancellationToken cancellationToken)
- => GetLanguage(languageId, _mediator, cancellationToken);
- private string GetCurrentPresentationFolder()
- => Path.Combine(BaseFolder, CurrentSession.Id.ToString(), Language.Code);
- protected string GetCurrentPresentationPath()
- => Path.Combine(GetCurrentPresentationFolder(), PresentationName);
- protected string GetPresentationWithDisclaimersPath()
- => Path.Combine(GetCurrentPresentationFolder(), $"{CurrentSession.Id}.pptx");
- private string GetPresentationFolderByStep(int stepIndex)
- => Path.Combine(GetCurrentPresentationFolder(), stepIndex.ToString());
- protected string GetPresentationPathByStep(int stepIndex)
- => Path.Combine(GetPresentationFolderByStep(stepIndex), PresentationName);
- protected Task SendScreenShotRequestAsync(string presentationPath, List<(int, string)> slides, CancellationToken cancellationToken)
- => _mediator.Send(new TakePresentationScreenShotsRequest
- {
- PresentationPath = presentationPath,
- Slides = slides
- }, cancellationToken);
- protected string GetScreenShotLocalPath(int stepIndex, int slideIndex)
- => Path.Combine(GetCurrentPresentationFolder(), stepIndex.ToString(), $"{slideIndex}.png");
- protected string GetScreenShotUrlPath(int stepIndex, int slideIndex)
- => $"docs/{_storageOptions.TempFolder}/{CurrentSession.Id}/{Language.Code}/{stepIndex}/{slideIndex}.png";
- protected async Task OpenSessionAsync(Guid sessionId, CancellationToken cancellationToken)
- {
- await using var stream = new FileStream(GetCurrentStatePath(sessionId), FileMode.Open);
- CurrentSession = await JsonSerializer.DeserializeAsync<SlideDeckSession>(stream, JsonSerializerOptions, cancellationToken) ?? throw new Exception($"Can not deserialize current state of slide deck session: {sessionId}");
- Language = await GetLanguageAsync(CurrentSession.LanguageId, cancellationToken);
- }
- protected Task SaveSessionAsync(CancellationToken cancellationToken)
- => File.WriteAllTextAsync(
- GetCurrentStatePath(CurrentSession.Id),
- JsonSerializer.Serialize(CurrentSession, JsonSerializerOptions),
- cancellationToken);
- private string GetCurrentStatePath(Guid sessionId)
- => Path.Combine(BaseFolder, sessionId.ToString(), "currentState.json");
- protected static IPresentation MergePresentations(IPresentation firstPresentation, IPresentation secondPresentation)
- {
- var resultPresentation = new Presentation();
- resultPresentation.SlideSize.SetSize(firstPresentation.SlideSize.Size.Width, firstPresentation.SlideSize.Size.Height, SlideSizeScaleType.EnsureFit);
- MergeInternal(firstPresentation);
- MergeInternal(secondPresentation);
- resultPresentation.Slides.RemoveAt(0);
- return resultPresentation;
- void MergeInternal(IPresentation toMerge)
- {
- foreach (var slide in toMerge.Slides)
- resultPresentation.Slides.AddClone(slide);
- }
- }
- }
- public abstract class BaseAddHandler<TRequest, TItem> : BaseHandler<TRequest, SlideDeckSession>
- where TItem : BaseAddInfo
- where TRequest : BaseAddRequest<TItem>
- {
- private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
- protected BaseAddHandler(
- IOptions<StorageOptions> storageOptions
- , IMediator mediator
- , IDbContextFactory<ApplicationDbContext> dbContextFactory
- ) : base(storageOptions, mediator)
- {
- _dbContextFactory = dbContextFactory;
- }
- public override async Task<SlideDeckSession> Handle(TRequest request, CancellationToken cancellationToken)
- {
- await OpenSessionAsync(request.SessionId, cancellationToken);
- var slideIndexes = new List<int>();
- var currentStepSlideIndex = 0;
- Directory.CreateDirectory(NextStepFolder);
- await using var db = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
- foreach (var item in request.Items)
- {
- var itemLanguageId = await GetItemLanguageIdAsync(item.Id, CurrentSession.LanguageId, db, cancellationToken);
- var presentationContent = await GetPresentationContentAsync(item.Id, itemLanguageId, db, cancellationToken);
- if (presentationContent == null)
- {
- await SendTransformRequestAsync(item.Id, item.GetItemTypeId(), itemLanguageId, cancellationToken);
- presentationContent = await GetPresentationContentAsync(item.Id, itemLanguageId, db, cancellationToken);
- if (presentationContent == null) continue; // todo: temp solution. wait till all types of template will be created
- }
- var slideName = await GetSlideNameAsync(item.Id, itemLanguageId, db, cancellationToken);
- var itemSlideIndexes = await ProcessItemAsync(
- Path.Combine(_storageOptions.DocumentsFolder, presentationContent.Link),
- NextStepIndex,
- currentStepSlideIndex,
- cancellationToken);
- foreach (var itemSlideIndex in itemSlideIndexes)
- {
- CurrentSession.Slides.Add(GetSlideInfo(item, itemLanguageId, slideName!, NextStepIndex, currentStepSlideIndex));
- slideIndexes.Add(itemSlideIndex);
- currentStepSlideIndex++;
- }
- File.Copy(NextStepPresentationPath, CurrentPresentationPath, true);
- }
- if (!slideIndexes.Any()) return CurrentSession;
- CurrentSession.Steps.Add(new SlideDeckStep
- {
- Type = OperationType.Add,
- SlideIds = slideIndexes
- });
- await SaveSessionAsync(cancellationToken);
- return CurrentSession;
- }
- private async Task<List<int>> ProcessItemAsync(
- string itemPresentationPath
- , int stepIndex
- , int slideIndexCounter
- , CancellationToken cancellationToken
- )
- {
- var stepPresentationPath = GetPresentationPathByStep(stepIndex);
- using var currentPresentation = new Presentation(CurrentPresentationPath);
- using var itemPresentation = new Presentation(itemPresentationPath);
- using var mergedPresentations = MergePresentations(currentPresentation, itemPresentation);
- mergedPresentations.Save(stepPresentationPath, SaveFormat.Pptx);
- var slidesToScreenShot = Enumerable.Range(mergedPresentations.Slides.Count - itemPresentation.Slides.Count, itemPresentation.Slides.Count)
- .Select(slideIndex => (slideIndex, GetScreenShotLocalPath(stepIndex, slideIndexCounter++))).ToList();
- await SendScreenShotRequestAsync(stepPresentationPath, slidesToScreenShot, cancellationToken);
- return slidesToScreenShot.Select(x => x.slideIndex).ToList();
- }
- protected abstract SlideDeckSlide GetSlideInfo(TItem item, int itemLanguageId, string slideName, int stepIndex, int pictureIndex);
- protected abstract Task<int> GetItemLanguageIdAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken);
- protected abstract Task SendTransformRequestAsync(int id, int typeId, int languageId, CancellationToken cancellationToken);
- protected abstract Task<Asset?> GetPresentationContentAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken);
- protected abstract Task<string?> GetSlideNameAsync(int id, int languageId, ApplicationDbContext db, CancellationToken cancellationToken);
- }
- public class CreateHandler : BaseHandler<CreateRequest, SlideDeckSession>
- {
- public CreateHandler(
- IMediator mediator
- , IOptions<StorageOptions> storageOptions
- ) : base(storageOptions, mediator)
- {
- }
- public override async Task<SlideDeckSession> Handle(CreateRequest request, CancellationToken cancellationToken)
- {
- CurrentSession = new SlideDeckSession
- {
- Id = Guid.NewGuid(),
- LanguageId = request.LanguageId
- };
- var (presentationPath, slidesCount) = await _mediator.Send(new TransformRequest { Id = CurrentSession.Id, LanguageId = request.LanguageId }, cancellationToken);
- await SaveSessionAsync(cancellationToken);
- await OpenSessionAsync(CurrentSession.Id, cancellationToken);
- File.Copy(presentationPath, GetCurrentPresentationPath());
- var titleSlideScreenShots = Enumerable.Range(0, slidesCount)
- .Select(slideId => (slideId, GetScreenShotLocalPath(0, slideId)))
- .ToList();
- CurrentSession.Slides.AddRange(titleSlideScreenShots.Select(x => new SlideDeckSlide
- {
- Path = GetScreenShotUrlPath(0, x.slideId),
- LanguageId = request.LanguageId,
- Type = SlideType.Introduction
- }));
- CurrentSession.Steps.Add(new()
- {
- Type = OperationType.Create,
- SlideIds = titleSlideScreenShots.Select(x => x.slideId).ToList()
- });
- await SendScreenShotRequestAsync(presentationPath, titleSlideScreenShots, cancellationToken);
- await SaveSessionAsync(cancellationToken);
- return CurrentSession;
- }
- }
- public class DownloadHandler : BaseHandler<DownloadRequest, FileStream>
- {
- private readonly IMapper _mapper;
- private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
- public DownloadHandler(
- IOptions<StorageOptions> storageOptions
- , IMediator mediator
- , IMapper mapper
- , IDbContextFactory<ApplicationDbContext> dbContextFactory
- ) : base(storageOptions, mediator)
- {
- _mapper = mapper;
- _dbContextFactory = dbContextFactory;
- }
- public override async Task<FileStream> Handle(DownloadRequest request, CancellationToken cancellationToken)
- {
- await OpenSessionAsync(request.SessionId, cancellationToken);
- var resultFilePath = GetPresentationWithDisclaimersPath();
- await using var db = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
- var disclaimerTypes = new HashSet<int>(2);
- var disclaimerContents = new List<AssetInfo>(2);
- foreach (var slide in CurrentSession.Slides.Where(x => x.Type is SlideType.FinancialInstrument or SlideType.Content))
- disclaimerTypes.Add(slide.Type switch
- {
- SlideType.Content when slide.ContentTypeId is
- (int)ContentType.AllAssetsRatingComment or
- (int)ContentType.AssetRatingComment or
- (int)ContentType.SubAssetRatingComment or
- (int)ContentType.WorldRatingComment or
- (int)ContentType.RegionRatingComment or
- (int)ContentType.CountryRatingComment or
- (int)ContentType.AllSectorsRatingComment or
- (int)ContentType.SectorTypeRatingComment or
- (int)ContentType.SectorRatingComment => (int)ContentType.DisclaimerWithoutPerformance,
- _ => (int)ContentType.DisclaimerWithPerformance
- });
- foreach (var contentTypeId in disclaimerTypes)
- {
- var content = await GetDisclaimerContentAsync(db, CurrentSession.LanguageId, contentTypeId, cancellationToken);
- if (content != null)
- disclaimerContents.Add(content);
- }
- File.Copy(CurrentPresentationPath, resultFilePath, true);
- foreach (var disclaimerAsset in disclaimerContents)
- {
- using var currentPresentation = new Presentation(resultFilePath);
- using var disclaimerPresentation = new Presentation(Path.Combine(_storageOptions.DocumentsFolder, disclaimerAsset.Link));
- using var mergedPresentations = MergePresentations(currentPresentation, disclaimerPresentation);
- mergedPresentations.Save(resultFilePath, SaveFormat.Pptx);
- }
- return new FileStream(resultFilePath, FileMode.Open, FileAccess.Read);
- }
- private async Task<AssetInfo?> GetDisclaimerContentAsync(ApplicationDbContext db, int languageId, int contentTypeId, CancellationToken cancellationToken)
- {
- var disclaimerInfo =
- await (contentTypeId == (int)ContentType.DisclaimerWithPerformance
- ? db.Set<DisclaimerWithPerformance>()
- .ApplyQuery(new Application.Features.ContentManagement.Content.DisclaimerWithPerformance.GetLatestQuery())
- .SelectMany(x => x.Localizations)
- : db.Set<DisclaimerWithoutPerformance>()
- .ApplyQuery(new Application.Features.ContentManagement.Content.DisclaimerWithoutPerformance.GetLatestQuery())
- .SelectMany(x => x.Localizations))
- .OrderByDescending(x => x.LanguageId == languageId)
- .ThenByDescending(x => x.Language.IsDefault)
- .ThenBy(x => x.Language.Priority)
- .Select(x => new { x.Id, x.LanguageId, x.SlideManagerContent })
- .FirstOrDefaultAsync(cancellationToken);
- if (disclaimerInfo == null) return null;
- if (disclaimerInfo.SlideManagerContent != null)
- return _mapper.Map<AssetInfo>(disclaimerInfo.SlideManagerContent);
- await _mediator.Send(new Transformation.Features.Content.TransformRequest
- {
- Id = disclaimerInfo.Id,
- LanguageId = disclaimerInfo.LanguageId,
- ContentTypeId = contentTypeId
- }, cancellationToken);
- return await db.Set<LocalizedContent>()
- .Where(x => x.Id == disclaimerInfo.Id && x.LanguageId == disclaimerInfo.LanguageId)
- .Select(x => x.SlideManagerContent)
- .ProjectTo<AssetInfo>(_mapper.ConfigurationProvider)
- .FirstOrDefaultAsync(cancellationToken);
- }
- }
- public class RemoveHandler : BaseHandler<RemoveRequest, SlideDeckSession>
- {
- public RemoveHandler(IOptions<StorageOptions> storageOptions, IMediator mediator) : base(storageOptions, mediator)
- {
- }
- public override async Task<SlideDeckSession> Handle(RemoveRequest request, CancellationToken cancellationToken)
- {
- await OpenSessionAsync(request.SessionId, cancellationToken);
- Directory.CreateDirectory(NextStepFolder);
- using var presentation = new Presentation(CurrentPresentationPath);
- if (presentation.Slides.Count <= request.SlideIndex)
- throw new BadRequestException("Slide index was outside of valid values");
- presentation.Slides.RemoveAt(request.SlideIndex);
- presentation.Save(NextStepPresentationPath, SaveFormat.Pptx);
- presentation.Save(CurrentPresentationPath, SaveFormat.Pptx);
- CurrentSession.Slides.RemoveAt(request.SlideIndex);
- CurrentSession.Steps.Add(new()
- {
- Type = OperationType.Delete,
- SlideIds = new()
- {
- request.SlideIndex
- }
- });
- await SaveSessionAsync(cancellationToken);
- return CurrentSession;
- }
- }
- public class UndoHandler : BaseHandler<UndoRequest, SlideDeckSession>
- {
- public UndoHandler(IOptions<StorageOptions> storageOptions, IMediator mediator) : base(storageOptions, mediator)
- {
- }
- public override async Task<SlideDeckSession> Handle(UndoRequest request, CancellationToken cancellationToken)
- {
- await OpenSessionAsync(request.SessionId, cancellationToken);
- var lastStepToUndo = GetLastUndoableStep() ?? throw new BadRequestException("Can't undo last step");
- Directory.CreateDirectory(NextStepFolder);
- switch (lastStepToUndo.Step.Type)
- {
- case OperationType.Add:
- {
- foreach (var stepSlideId in lastStepToUndo.Step.SlideIds!.OrderByDescending(x => x))
- CurrentSession.Slides.RemoveAt(stepSlideId);
- break;
- }
- case OperationType.Move:
- (CurrentSession.Slides[lastStepToUndo.Step.SlideIds![0]], CurrentSession.Slides[lastStepToUndo.Step.SlideIds![1]]) =
- (CurrentSession.Slides[lastStepToUndo.Step.SlideIds![1]], CurrentSession.Slides[lastStepToUndo.Step.SlideIds![0]]);
- break;
- case OperationType.Delete:
- {
- var previousSessionState = await OpenSessionByStepAsync(lastStepToUndo.PreviousStepIndex, cancellationToken);
- CurrentSession.Slides.Insert(lastStepToUndo.Step.SlideIds![0], previousSessionState.Slides[lastStepToUndo.Step.SlideIds![0]]);
- break;
- }
- }
- File.Copy(GetPresentationPathByStep(lastStepToUndo.PreviousStepIndex), NextStepPresentationPath);
- File.Copy(NextStepPresentationPath, CurrentPresentationPath, true);
- lastStepToUndo.Step.Undone = true;
- CurrentSession.Steps.Add(new()
- {
- SlideIds = lastStepToUndo.Step.SlideIds,
- Type = OperationType.Undo
- });
- await SaveSessionAsync(cancellationToken);
- return CurrentSession;
- }
- private (SlideDeckStep Step, int StepIndex, int PreviousStepIndex)? GetLastUndoableStep()
- {
- for (var i = CurrentSession.Steps.Count - 1; i >= 1; i--)
- if (CurrentSession.Steps[i].Type is OperationType.Add or OperationType.Delete or OperationType.Move && !CurrentSession.Steps[i].Undone)
- return (CurrentSession.Steps[i], i, i - 1);
- return null;
- }
- }
- public class TakePresentationScreenShotsHandler : IRequestHandler<TakePresentationScreenShotsRequest, Unit>
- {
- private const int DesiredX = 1280;
- private const int DesiredY = 720;
- public Task<Unit> Handle(TakePresentationScreenShotsRequest request, CancellationToken cancellationToken)
- {
- if (!File.Exists(request.PresentationPath)) throw new FileNotFoundException("Not found presentation", request.PresentationPath);
- using var presentation = new Presentation(request.PresentationPath);
- var scaleX = (float)(1.0 / presentation.SlideSize.Size.Width) * DesiredX;
- var scaleY = (float)(1.0 / presentation.SlideSize.Size.Height) * DesiredY;
- foreach (var (slideId, screenShotPath) in request.Slides)
- {
- var bmp = presentation.Slides[slideId].GetThumbnail(scaleX, scaleY);
- Directory.CreateDirectory(Directory.GetParent(screenShotPath)!.FullName);
- bmp.Save(screenShotPath, System.Drawing.Imaging.ImageFormat.Png);
- }
- return Unit.Task;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement