/// <summary> /// Raises the <see cref="PrintDocument.PrintPage"/> event. It is called before a page prints. /// </summary> /// <remarks> /// This method is overridden to print an Excel document. /// After doing its own work, it will call <see cref="PrintDocument.PrintPage"/> so you can draw your own thing over it. /// </remarks> /// <param name="e">A <see cref="PrintPageEventArgs"/> that contains the event data.</param> protected override void OnPrintPage(PrintPageEventArgs e) { // There is a bug in Vs2005 (but not in 2003) where the VisibleClipBounds property does not change with the PageUnit, and it remains the same as when the graphics was created. // See http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=230594 (VisibleClipBounds does not produce correct results for different PageUnit) // So, we are going to store the VisibleClipBounds here. It looks like if we do not call e.Graphics.Save, things work fine. // Other bug in the framework (and this is also in .NET 1.1) //This code alone in an OnPrintPage event: /* * e.Graphics.PageUnit=GraphicsUnit.Inch; * RectangleF r = e.Graphics.VisibleClipBounds; * e.Graphics.PageUnit=GraphicsUnit.Point; * * Font fnt = new Font("arial", 12, FontStyle.Underline); * e.Graphics.DrawString("hello", fnt, Brushes.Tomato, 100, 100); * * will not print the underline, even if printing to a virtual printer. * (preview will work fine). If instead of GraphicsUnit.Inch we use GraphicsUnit.Display, * Underline gets drawn in the wrong place! * * Using GraphicsUnit.Point in both places seems to fix it. */ RectangleF VisibleClipInches100; GraphicsUnit SaveUnits = e.Graphics.PageUnit; try { e.Graphics.PageUnit = GraphicsUnit.Point; //NEEDS TO BE Point, since this is what we will use later. Other unit will confuse GDI+. VisibleClipInches100 = e.Graphics.VisibleClipBounds; VisibleClipInches100 = new RectangleF(VisibleClipInches100.X / 72F * 100, VisibleClipInches100.Y / 72F * 100, VisibleClipInches100.Width / 72F * 100, VisibleClipInches100.Height / 72F * 100); } finally { e.Graphics.PageUnit = SaveUnits; } if (FRenderer == null || FRenderer.Workbook == null) { return; } System.Drawing.Drawing2D.GraphicsState InitialState = e.Graphics.Save(); try { IFlxGraphics aCanvas = new GdiPlusGraphics(e.Graphics); //We could change the interpolation mode for images here. //e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; //e.Graphics.SmoothingMode = SmoothingMode.HighQuality; //e.Graphics.PageUnit=GraphicsUnit.Display; //Display is not reliable as unit as it might change depending on the device. We will be using Point. e.Graphics.PageUnit = GraphicsUnit.Point; if (AntiAliasedText) { e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; } if (CurrentSheetPage == 1) { FRenderer.SetCanvas(aCanvas); MyPrintRange = FRenderer.InternalCalcPrintArea(FPrintRange); if (CurrentWorkbookPage == 1 && AllVisibleSheets) { TotalWorkbookPages = GetPagesToPrint(e, aCanvas, VisibleClipInches100); } FRenderer.InitializePrint(aCanvas, ConvertToUnits(e.PageBounds, false), ConvertToMargins(e.Graphics, e.PageBounds, VisibleClipInches100, false), MyPrintRange, out PaintClipRect, out TotalSheetPages, out PagePrintRange); if (!AllVisibleSheets) { TotalWorkbookPages = TotalSheetPages; } PagesToPrint = TotalWorkbookPages; if (CurrentWorkbookPage == 1) //skip the first non printing pages. { if (PrinterSettings.FromPage > 0 && PrinterSettings.ToPage >= PrinterSettings.FromPage) { PagesToPrint = Math.Min(PrinterSettings.ToPage, TotalWorkbookPages); for (int i = 1; i < PrinterSettings.FromPage; i++) { if (CurrentWorkbookPage > TotalWorkbookPages) { return; } OnBeforePrintPage(e); FRenderer.GenericPrint(aCanvas, ConvertToUnits(e.PageBounds, false), MyPrintRange, 0, PaintClipRect, 0, false, PagePrintRange, ref CurrentPrintArea); IncCurrentPage(); } } } } if (CurrentWorkbookPage <= PagesToPrint) { int CurrentPage = ResetPageNumberOnEachSheet ? CurrentSheetPage : CurrentWorkbookPage; int TotalPages = ResetPageNumberOnEachSheet ? TotalSheetPages : TotalWorkbookPages; OnBeforePrintPage(e); FRenderer.GenericPrint(aCanvas, ConvertToUnits(e.PageBounds, false), MyPrintRange, CurrentPage, PaintClipRect, TotalPages, true, PagePrintRange, ref CurrentPrintArea); IncCurrentPage(); } e.HasMorePages = CurrentWorkbookPage <= PagesToPrint; } finally { e.Graphics.Restore(InitialState); } base.OnPrintPage(e); }
/// <summary> /// Exports the associated xls workbook to a graphics stream. You need to provide a /// Graphics object with the correct dimensions. (To get the needed dimensions, use <see cref="GetRealPageSize()"/> /// </summary> /// <param name="imgData">Graphics where the image will be stored. Set it to null to skip the page.</param> /// <param name="exportInfo"> Information needed to export, cached for speed. The first time you call this method (or when you change xls.ActiveSheet), make exportInfo=null</param> public bool ExportNext(Graphics imgData, ref TImgExportInfo exportInfo) { FRenderer.CreateFontCache(); try { Bitmap bmp = null; try { if (imgData == null) { bmp = BitmapConstructor.CreateBitmap(1, 1); imgData = Graphics.FromImage(bmp); imgData.PageUnit = GraphicsUnit.Point; } IFlxGraphics aCanvas = new GdiPlusGraphics(imgData); GraphicsUnit OriginalUnits = imgData.PageUnit; try { imgData.PageUnit = GraphicsUnit.Point; FRenderer.SetCanvas(aCanvas); try { if (exportInfo == null) { exportInfo = GetExportInfo(aCanvas); } exportInfo.IncCurrentPage(); if (exportInfo.CurrentPage > exportInfo.TotalPages) { return(false); } int SaveActiveSheet = Workbook.ActiveSheet; try { Workbook.ActiveSheet = exportInfo.CurrentSheet; int CurrentLogicalPage = -1; if (ResetPageNumberOnEachSheet) { CurrentLogicalPage = exportInfo.ActiveSheet.FCurrentPage; } else { CurrentLogicalPage = exportInfo.CurrentPage; } TOneImgExportInfo OneResult = exportInfo.ActiveSheet; if (LastInitSheet != exportInfo.CurrentSheet) { TXlsCellRange ra; int p; RectangleF[] r; FRenderer.InitializePrint(aCanvas, OneResult.PageBounds, OneResult.PageBounds, OneResult.PrintRanges, out r, out p, out ra); LastInitSheet = exportInfo.CurrentSheet; } if (bmp == null) { OnBeforePaint(new ImgPaintEventArgs(imgData, CalcPageBounds(exportInfo.ActiveSheet.PageBounds), exportInfo.CurrentPage, exportInfo.ActiveSheet.CurrentPage, exportInfo.TotalPages)); } FRenderer.GenericPrint(aCanvas, OneResult.PageBounds, OneResult.PrintRanges, CurrentLogicalPage, OneResult.PaintClipRect, exportInfo.TotalLogicalPages(ResetPageNumberOnEachSheet), bmp == null, OneResult.PagePrintRange, ref OneResult.FCurrentPrintArea); aCanvas.ResetClip(); if (bmp == null) { OnAfterPaint(new ImgPaintEventArgs(imgData, CalcPageBounds(exportInfo.ActiveSheet.PageBounds), exportInfo.CurrentPage, exportInfo.ActiveSheet.CurrentPage, exportInfo.TotalPages)); } } finally { Workbook.ActiveSheet = SaveActiveSheet; } } finally { FRenderer.SetCanvas(null); } } finally { imgData.PageUnit = OriginalUnits; } } finally { if (bmp != null) { bmp.Dispose(); imgData.Dispose(); } } } finally { FRenderer.DisposeFontCache(); } return(true); }
/// <summary> /// Exports the active sheet on the current XlsFile. You can define which is the first page to print and the global count of pages, so the /// page numbers on headers and footers of the excel file correspond with the actual pages on the pdf. /// </summary> /// <param name="startPage">Fist page that the headers and footers on the xls file will show. If you are exporting only one sheet to the pdf file, /// this can be 1. If you are exporting more than one sheet to the same pdf file, you will want to set StartPage to the actual page on the pdf.</param> /// <param name="totalPages">The total number of pages to display on Excel headers and footers. If you are exporting only one sheet to the pdf file, set it to -1, and it will be calculated automatically. If not, please suply here the total number of pages the file will have so FlexCel can show footers like "page 1 of 50"</param> public void ExportSheet(int startPage, int totalPages) { if (PdfCanvas == null) { FlxMessages.ThrowException(FlxErr.ErrBeginExportNotCalled); } Workbook.Recalc(false); FirstPageInSheet = startPage - 1; PdfGraphics RealCanvas = new PdfGraphics(PdfCanvas); LoadPageSize(); if (FirstPage) { OnBeforeNewPage(new PageEventArgs(PdfCanvas, CurrentTotalPage, CurrentTotalPage - FirstPageInSheet)); PrepareCanvas(); PdfCanvas.BeginDoc(FPdfStream); PdfCanvas.PageLayout = FPageLayout; FPdfStream = null; } IFlxGraphics aCanvas = RealCanvas; FRenderer.SetCanvas(aCanvas); try { RectangleF[] PaintClipRect; TXlsCellRange[] MyPrintRange = FRenderer.InternalCalcPrintArea(FPrintRange); TXlsCellRange PagePrintRange; int PagesInSheet; FRenderer.InitializePrint(aCanvas, PdfGraphics.ConvertToUnits(PdfCanvas.PageSize), PdfGraphics.ConvertToUnits(PdfCanvas.PageSize), MyPrintRange, out PaintClipRect, out PagesInSheet, out PagePrintRange); if (totalPages < 0) { totalPages = PagesInSheet; } FProgress.SetTotalPages(totalPages); int PrintArea = 0; for (int i = 0; i < PagesInSheet; i++) { if (Canceled) { return; } LoadPageSize(); if (!FirstPage) { CurrentTotalPage++; OnBeforeNewPage(new PageEventArgs(PdfCanvas, CurrentTotalPage, CurrentTotalPage - FirstPageInSheet)); PrepareCanvas(); PdfCanvas.NewPage(); } OnBeforeGeneratePage(new PageEventArgs(PdfCanvas, CurrentTotalPage, CurrentTotalPage - FirstPageInSheet)); PrepareCanvas(); PdfCanvas.SaveState(); FirstPage = false; if (Canceled) { return; } FProgress.SetPage(startPage + i); FRenderer.GenericPrint(aCanvas, PdfGraphics.ConvertToUnits(PdfCanvas.PageSize), MyPrintRange, startPage + i, PaintClipRect, totalPages, true, PagePrintRange, ref PrintArea); if (Canceled) { return; } PdfCanvas.RestoreState(); OnAfterGeneratePage(new PageEventArgs(PdfCanvas, CurrentTotalPage, CurrentTotalPage - FirstPageInSheet)); PrepareCanvas(); } } finally { FRenderer.SetCanvas(null); } }