/// <summary> /// This is the main process of rendering a project to a pdf /// </summary> private RenderResultInfo RenderToDocument(object data, TemplateProject project, out PdfDocument document) { _loadingTimer.Reset(); _totalTimer.Restart(); _loadingTimer.Start(); _baseFontFamily = project.FontName; var result = new RenderResultInfo { Success = false }; _loadingTimer.Stop(); var mapper = new DataMapper(project, data); document = new PdfDocument(); document.Info.Author = "Generated from data by Form8sn"; document.Info.Title = project.Name; document.Info.CreationDate = DateTime.UtcNow; // Go through the project file and data, generate all the pages, and the // template boxes with appropriately formatted data var pageList = PrepareAllPages(project, mapper, result); if (pageList is null) { result.Success = false; return(result); } // Next, go through the prepared page and render them to PDF var ok = RenderPagesToPdfDocument(project, document, pageList, result); if (!ok) { result.Success = false; return(result); } _totalTimer.Stop(); result.Success = true; result.OverallTime = _totalTimer.Elapsed; result.LoadingTime = _loadingTimer.Elapsed; return(result); }
/// <summary> /// Follow all data paths and page repeaters in the project. Results in either a set of pages that /// can be rendered to PDF, or null if the document can't be rendered /// </summary> /// <param name="project">Project file to generate a document for</param> /// <param name="mapper">Data mapper holding the final data for a single document</param> /// <param name="result">Rendering result, including any error messages</param> /// <returns>List of pages to render, or null</returns> public static List <DocumentPage>?PrepareAllPages(TemplateProject project, DataMapper mapper, RenderResultInfo result) { var runningTotals = new Dictionary <string, decimal>(); // path -> total // First, we run through the definitions, gathering data // This lets us count pages, and defers fitting content into boxes until // we've decided to show it (e.g. if it's dependent on an empty box) var pageList = new List <DocumentPage>(); for (var pageIndex = 0; pageIndex < project.Pages.Count; pageIndex++) { var pageDef = project.Pages[pageIndex] !; if (pageDef.RepeatMode.Repeats) { var dataSets = mapper.GetRepeatData(pageDef.RepeatMode.DataPath); for (var repeatIndex = 0; repeatIndex < dataSets.Count; repeatIndex++) { var repeatData = dataSets[repeatIndex]; mapper.SetRepeater(repeatData, pageDef.RepeatMode.DataPath); var pageResult = PreparePage(pageDef, mapper, runningTotals, pageIndex); mapper.ClearRepeater(); ClearPageTotals(runningTotals); if (pageResult.IsFailure) { result.ErrorMessage = pageResult.FailureMessage; return(null); } pageResult.ResultData.RepeatIndex = repeatIndex; pageResult.ResultData.RepeatCount = dataSets.Count; pageList.Add(pageResult.ResultData); } } else { var pageResult = PreparePage(pageDef, mapper, runningTotals, pageIndex); ClearPageTotals(runningTotals); if (pageResult.IsFailure) { result.ErrorMessage = pageResult.FailureMessage; return(null); } pageList.Add(pageResult.ResultData); } } // remove boxes that have null/empty dependencies PruneBoxes(pageList); return(pageList); }
/// <summary> /// Render prepared pages into a PDF document /// </summary> /// <param name="project">Project file to generate a document for</param> /// <param name="document">Open and writable PDF file to add pages to</param> /// <param name="pageList">A set of pages from PrepareAllPages()</param> /// <param name="result">Rendering result, including any error messages</param> /// <returns>True for success, false for failure</returns> public bool RenderPagesToPdfDocument(TemplateProject project, PdfDocument document, List <DocumentPage> pageList, RenderResultInfo result) { for (var pageIndex = 0; pageIndex < pageList.Count; pageIndex++) { _loadingTimer.Start(); var page = pageList[pageIndex] !; var pageDef = page.Definition; using var background = LoadBackground(project, page.SourcePageIndex, pageDef); var font = GetFont(pageDef.PageFontSize ?? project.BaseFontSize ?? 16); _loadingTimer.Stop(); var pageResult = OutputPage(document, page, font, background, pageIndex, pageList.Count); if (pageResult.IsFailure) { result.ErrorMessage = pageResult.FailureMessage; return(false); } } return(true); }