private PageBacking LoadBackground(TemplateProject project, int sourcePageIndex, TemplatePage pageDef) { var backing = new PageBacking(); if (_basePdf is null && !string.IsNullOrWhiteSpace(project.BasePdfFile !)) { using var fileStream = _files.Load(project.BasePdfFile); _basePdf = PdfReader.Open(fileStream, PdfDocumentOpenMode.Import); // Must use import mode to copy pages across } if (_basePdf != null) { backing.ExistingPage = _basePdf.Pages[sourcePageIndex]; } if (!string.IsNullOrWhiteSpace(pageDef.BackgroundImage !)) { using var fileStream = _files.Load(project.BasePdfFile); backing.BackgroundImage = XImage.FromStream(fileStream); } return(backing); }
/// <summary> /// Render a prepared page into a PDF document /// </summary> private Result <Nothing> OutputPage(PdfDocument document, DocumentPage pageToRender, XFont font, PageBacking background, int pageIndex, int pageTotal) { var pageDef = pageToRender.Definition; // If we have a source PDF, and we aren't trying to render a blank page, then import the page var shouldCopyPdfPage = background.ExistingPage != null && pageDef.RenderBackground; var page = shouldCopyPdfPage ? document.AddPage(background.ExistingPage !) : document.AddPage(/*blank*/); // If dimensions are silly, reset to A4 if (pageDef.WidthMillimetres < 10 || pageDef.WidthMillimetres > 1000) { pageDef.WidthMillimetres = 210; } if (pageDef.HeightMillimetres < 10 || pageDef.HeightMillimetres > 1000) { pageDef.HeightMillimetres = 297; } // Set the PDF page size (in points under the hood) page.Width = XUnit.FromMillimeter(pageDef.WidthMillimetres); page.Height = XUnit.FromMillimeter(pageDef.HeightMillimetres); using var gfx = XGraphics.FromPdfPage(page); gfx.Save(); if (shouldCopyPdfPage && background.ExistingPage !.Rotate != 0) { // Match visual-rotations on page var centre = new XPoint(0, 0); var visualRotate = background.ExistingPage !.Rotate % 360; // degrees, spec says it should be a multiple of 90. var angle = 360.0 - visualRotate; gfx.RotateAtTransform(angle, centre); switch (visualRotate) { case 90: gfx.TranslateTransform(-page.Height.Point, 0); break; case 180: gfx.TranslateTransform(-page.Width.Point, -page.Height.Point); break; case 270: gfx.TranslateTransform(-page.Height.Point / 2.0, -page.Height.Point); // this one is a guess, as I don't have an example break; default: throw new Exception("Unhandled visual rotation case"); } if (background.ExistingPage.Orientation == PageOrientation.Landscape) { (page.Width, page.Height) = (page.Height, page.Width); } } // Draw background at full page size _loadingTimer.Start(); if (pageDef.RenderBackground && background.BackgroundImage != null) { var destRect = new XRect(0, 0, (float)page.Width.Point, (float)page.Height.Point); gfx.DrawImage(background.BackgroundImage, destRect); } _loadingTimer.Stop(); // Do default scaling var fx = page.Width.Point / page.Width.Millimeter; var fy = page.Height.Point / page.Height.Millimeter; // If using an image, work out the bitmap -> page adjustment if (background.BackgroundImage != null) { fx = page.Width.Point / background.BackgroundImage.PixelWidth; fy = page.Height.Point / background.BackgroundImage.PixelHeight; } // Draw each box. foreach (var boxDef in pageToRender.DocumentBoxes) { var result = RenderBox(font, boxDef, fx, fy, gfx, pageToRender, pageIndex, pageTotal); if (result.IsFailure) { return(result); } } gfx.Restore(); return(Result.Success()); }