using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Printing; using System.IO; using System.Text; using System.Windows.Forms; namespace PdfiumViewer { /// /// Provides functionality to render a PDF document. /// public class PdfDocument : IPdfDocument { private bool _disposed; private PdfFile _file; private readonly List _pageSizes; /// /// Initializes a new instance of the PdfDocument class with the provided path. /// /// Path to the PDF document. public static PdfDocument Load(string path) { return Load(path, null); } /// /// Initializes a new instance of the PdfDocument class with the provided path. /// /// Path to the PDF document. /// Password for the PDF document. public static PdfDocument Load(string path, string password) { if (path == null) throw new ArgumentNullException(nameof(path)); return Load(File.OpenRead(path), password); } /// /// Initializes a new instance of the PdfDocument class with the provided path. /// /// Window to show any UI for. /// Path to the PDF document. public static PdfDocument Load(IWin32Window owner, string path) { if (owner == null) throw new ArgumentNullException(nameof(owner)); if (path == null) throw new ArgumentNullException(nameof(path)); return Load(owner, File.OpenRead(path), null); } /// /// Initializes a new instance of the PdfDocument class with the provided path. /// /// Window to show any UI for. /// Stream for the PDF document. public static PdfDocument Load(IWin32Window owner, Stream stream) { if (owner == null) throw new ArgumentNullException(nameof(owner)); if (stream == null) throw new ArgumentNullException(nameof(stream)); return Load(owner, stream, null); } private static PdfDocument Load(IWin32Window owner, Stream stream, string password) { try { while (true) { try { return new PdfDocument(stream, password); } catch (PdfException ex) { if (owner != null && ex.Error == PdfError.PasswordProtected) { using (var form = new PasswordForm()) { if (form.ShowDialog(owner) == DialogResult.OK) { password = form.Password; continue; } } } throw; } } } catch { stream.Dispose(); throw; } } /// /// Initializes a new instance of the PdfDocument class with the provided stream. /// /// Stream for the PDF document. public static PdfDocument Load(Stream stream) { return Load(stream, null); } /// /// Initializes a new instance of the PdfDocument class with the provided stream. /// /// Stream for the PDF document. /// Password for the PDF document. public static PdfDocument Load(Stream stream, string password) { if (stream == null) throw new ArgumentNullException(nameof(stream)); return new PdfDocument(stream, password); } /// /// Number of pages in the PDF document. /// public int PageCount { get { return PageSizes.Count; } } /// /// Bookmarks stored in this PdfFile /// public PdfBookmarkCollection Bookmarks { get { return _file.Bookmarks; } } /// /// Size of each page in the PDF document. /// public IList PageSizes { get; private set; } private PdfDocument(Stream stream, string password) { _file = new PdfFile(stream, password); _pageSizes = _file.GetPDFDocInfo(); if (_pageSizes == null) throw new Win32Exception(); PageSizes = new ReadOnlyCollection(_pageSizes); } /// /// Renders a page of the PDF document to the provided graphics instance. /// /// Number of the page to render. /// Graphics instance to render the page on. /// Horizontal DPI. /// Vertical DPI. /// Bounds to render the page in. /// Render the page for printing. public void Render(int page, Graphics graphics, float dpiX, float dpiY, Rectangle bounds, bool forPrinting) { Render(page, graphics, dpiX, dpiY, bounds, forPrinting ? PdfRenderFlags.ForPrinting : PdfRenderFlags.None); } /// /// Renders a page of the PDF document to the provided graphics instance. /// /// Number of the page to render. /// Graphics instance to render the page on. /// Horizontal DPI. /// Vertical DPI. /// Bounds to render the page in. /// Flags used to influence the rendering. public void Render(int page, Graphics graphics, float dpiX, float dpiY, Rectangle bounds, PdfRenderFlags flags) { if (graphics == null) throw new ArgumentNullException("graphics"); if (_disposed) throw new ObjectDisposedException(GetType().Name); float graphicsDpiX = graphics.DpiX; float graphicsDpiY = graphics.DpiY; var dc = graphics.GetHdc(); try { if ((int)graphicsDpiX != (int)dpiX || (int)graphicsDpiY != (int)dpiY) { var transform = new NativeMethods.XFORM { eM11 = graphicsDpiX / dpiX, eM22 = graphicsDpiY / dpiY }; NativeMethods.SetGraphicsMode(dc, NativeMethods.GM_ADVANCED); NativeMethods.ModifyWorldTransform(dc, ref transform, NativeMethods.MWT_LEFTMULTIPLY); } var point = new NativeMethods.POINT(); NativeMethods.SetViewportOrgEx(dc, bounds.X, bounds.Y, out point); bool success = _file.RenderPDFPageToDC( page, dc, (int)dpiX, (int)dpiY, 0, 0, bounds.Width, bounds.Height, FlagsToFPDFFlags(flags) ); NativeMethods.SetViewportOrgEx(dc, point.X, point.Y, out point); if (!success) throw new Win32Exception(); } finally { graphics.ReleaseHdc(dc); } } /// /// Renders a page of the PDF document to an image. /// /// Number of the page to render. /// Horizontal DPI. /// Vertical DPI. /// Render the page for printing. /// The rendered image. public Image Render(int page, float dpiX, float dpiY, bool forPrinting) { var size = PageSizes[page]; return Render(page, (int)size.Width, (int)size.Height, dpiX, dpiY, forPrinting); } /// /// Renders a page of the PDF document to an image. /// /// Number of the page to render. /// Horizontal DPI. /// Vertical DPI. /// Flags used to influence the rendering. /// The rendered image. public Image Render(int page, float dpiX, float dpiY, PdfRenderFlags flags) { // for Hishi--> _pageSizes[page] = _file.GetPDFDocInfo(page); // <-- var size = PageSizes[page]; return Render(page, (int)size.Width, (int)size.Height, dpiX, dpiY, flags); } /// /// Renders a page of the PDF document to an image. /// /// Number of the page to render. /// Width of the rendered image. /// Height of the rendered image. /// Horizontal DPI. /// Vertical DPI. /// Render the page for printing. /// The rendered image. public Image Render(int page, int width, int height, float dpiX, float dpiY, bool forPrinting) { return Render(page, width, height, dpiX, dpiY, forPrinting ? PdfRenderFlags.ForPrinting : PdfRenderFlags.None); } /// /// Renders a page of the PDF document to an image. /// /// Number of the page to render. /// Width of the rendered image. /// Height of the rendered image. /// Horizontal DPI. /// Vertical DPI. /// Flags used to influence the rendering. /// The rendered image. public Image Render(int page, int width, int height, float dpiX, float dpiY, PdfRenderFlags flags) { return Render(page, width, height, dpiX, dpiY, 0, flags); } /// /// Renders a page of the PDF document to an image. /// /// Number of the page to render. /// Width of the rendered image. /// Height of the rendered image. /// Horizontal DPI. /// Vertical DPI. /// Rotation. /// Flags used to influence the rendering. /// The rendered image. public Image Render(int page, int width, int height, float dpiX, float dpiY, PdfRotation rotate, PdfRenderFlags flags) { if (_disposed) throw new ObjectDisposedException(GetType().Name); if ((flags & PdfRenderFlags.CorrectFromDpi) != 0) { width = width * (int)dpiX / 72; height = height * (int)dpiY / 72; } var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); bitmap.SetResolution(dpiX, dpiY); var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bitmap.PixelFormat); try { var handle = NativeMethods.FPDFBitmap_CreateEx(width, height, 4, data.Scan0, width * 4); try { uint background = (flags & PdfRenderFlags.Transparent) == 0 ? 0xFFFFFFFF : 0x00FFFFFF; NativeMethods.FPDFBitmap_FillRect(handle, 0, 0, width, height, background); bool success = _file.RenderPDFPageToBitmap( page, handle, (int)dpiX, (int)dpiY, 0, 0, width, height, (int)rotate, FlagsToFPDFFlags(flags), (flags & PdfRenderFlags.Annotations) != 0 ); if (!success) throw new Win32Exception(); } finally { NativeMethods.FPDFBitmap_Destroy(handle); } } finally { bitmap.UnlockBits(data); } return bitmap; } private NativeMethods.FPDF FlagsToFPDFFlags(PdfRenderFlags flags) { return (NativeMethods.FPDF)(flags & ~(PdfRenderFlags.Transparent | PdfRenderFlags.CorrectFromDpi)); } /// /// Save the PDF document to the specified location. /// /// Path to save the PDF document to. public void Save(string path) { if (path == null) throw new ArgumentNullException("path"); using (var stream = File.Create(path)) { Save(stream); } } /// /// Save the PDF document to the specified location. /// /// Stream to save the PDF document to. public void Save(Stream stream) { if (stream == null) throw new ArgumentNullException("stream"); _file.Save(stream); } /// /// Finds all occurences of text. /// /// The text to search for. /// Whether to match case. /// Whether to match whole words only. /// All matches. public PdfMatches Search(string text, bool matchCase, bool wholeWord) { return Search(text, matchCase, wholeWord, 0, PageCount - 1); } /// /// Finds all occurences of text. /// /// The text to search for. /// Whether to match case. /// Whether to match whole words only. /// The page to search on. /// All matches. public PdfMatches Search(string text, bool matchCase, bool wholeWord, int page) { return Search(text, matchCase, wholeWord, page, page); } /// /// Finds all occurences of text. /// /// The text to search for. /// Whether to match case. /// Whether to match whole words only. /// The page to start searching. /// The page to end searching. /// All matches. public PdfMatches Search(string text, bool matchCase, bool wholeWord, int startPage, int endPage) { return _file.Search(text, matchCase, wholeWord, startPage, endPage); } /// /// Get all text on the page. /// /// The page to get the text for. /// The text on the page. public string GetPdfText(int page) { return _file.GetPdfText(page); } /// /// Get all text matching the text span. /// /// The span to get the text for. /// The text matching the span. public string GetPdfText(PdfTextSpan textSpan) { return _file.GetPdfText(textSpan); } /// /// Get all bounding rectangles for the text span. /// /// /// The algorithm used to get the bounding rectangles tries to join /// adjacent character bounds into larger rectangles. /// /// The span to get the bounding rectangles for. /// The bounding rectangles. public IList GetTextBounds(PdfTextSpan textSpan) { return _file.GetTextBounds(textSpan); } /// /// Convert a point from device coordinates to page coordinates. /// /// The page number where the point is from. /// The point to convert. /// The converted point. public PointF PointToPdf(int page, Point point) { return _file.PointToPdf(page, point); } /// /// Convert a point from page coordinates to device coordinates. /// /// The page number where the point is from. /// The point to convert. /// The converted point. public Point PointFromPdf(int page, PointF point) { return _file.PointFromPdf(page, point); } /// /// Convert a rectangle from device coordinates to page coordinates. /// /// The page where the rectangle is from. /// The rectangle to convert. /// The converted rectangle. public RectangleF RectangleToPdf(int page, Rectangle rect) { return _file.RectangleToPdf(page, rect); } /// /// Convert a rectangle from page coordinates to device coordinates. /// /// The page where the rectangle is from. /// The rectangle to convert. /// The converted rectangle. public Rectangle RectangleFromPdf(int page, RectangleF rect) { return _file.RectangleFromPdf(page, rect); } /// /// Creates a for the PDF document. /// /// public PrintDocument CreatePrintDocument() { return CreatePrintDocument(PdfPrintMode.CutMargin); } /// /// Creates a for the PDF document. /// /// Specifies the mode for printing. The default /// value for this parameter is CutMargin. /// public PrintDocument CreatePrintDocument(PdfPrintMode printMode) { return CreatePrintDocument(new PdfPrintSettings(printMode, null)); } /// /// Creates a for the PDF document. /// /// The settings used to configure the print document. /// public PrintDocument CreatePrintDocument(PdfPrintSettings settings) { return new PdfPrintDocument(this, settings); } /// /// Returns all links on the PDF page. /// /// The page to get the links for. /// The size of the page. /// A collection with the links on the page. public PdfPageLinks GetPageLinks(int page, Size size) { return _file.GetPageLinks(page, size); } /// /// Delete the page from the PDF document. /// /// The page to delete. public void DeletePage(int page) { _file.DeletePage(page); _pageSizes.RemoveAt(page); } /// /// Rotate the page. /// /// The page to rotate. /// How to rotate the page. public void RotatePage(int page, PdfRotation rotation) { _file.RotatePage(page, rotation); _pageSizes[page] = _file.GetPDFDocInfo(page); } /// /// Get metadata information from the PDF document. /// /// The PDF metadata. public PdfInformation GetInformation() { return _file.GetInformation(); } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// 2 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// Whether this method is called from Dispose. protected void Dispose(bool disposing) { if (!_disposed && disposing) { if (_file != null) { _file.Dispose(); _file = null; } _disposed = true; } } } }