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;
}
}
}
}