229 lines
9.0 KiB
C#
229 lines
9.0 KiB
C#
|
#region PDFsharp - A .NET library for processing PDF
|
||
|
//
|
||
|
// Authors:
|
||
|
// Stefan Lange
|
||
|
//
|
||
|
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
|
||
|
//
|
||
|
// http://www.pdfsharp.com
|
||
|
// http://sourceforge.net/projects/pdfsharp
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
// copy of this software and associated documentation files (the "Software"),
|
||
|
// to deal in the Software without restriction, including without limitation
|
||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||
|
// Software is furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included
|
||
|
// in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
// DEALINGS IN THE SOFTWARE.
|
||
|
#endregion
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Globalization;
|
||
|
using PdfSharp.Drawing;
|
||
|
|
||
|
namespace PdfSharp.Pdf.Advanced
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Contains all external PDF files from which PdfFormXObjects are imported into the current document.
|
||
|
/// </summary>
|
||
|
internal sealed class PdfFormXObjectTable : PdfResourceTable
|
||
|
{
|
||
|
// The name PdfFormXObjectTable is technically not correct, because in contrast to PdfFontTable
|
||
|
// or PdfImageTable this class holds no PdfFormXObject objects. Actually it holds instances of
|
||
|
// the class ImportedObjectTable, one for each external document. The PdfFormXObject instances
|
||
|
// are not cached, because they hold a transformation matrix that make them unique. If the user
|
||
|
// wants to use a particual page of a PdfFormXObject more than once, he must reuse the object
|
||
|
// before he changes the PageNumber or the transformation matrix. In other words this class
|
||
|
// caches the indirect objects of an external form, not the form itself.
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of this class, which is a singleton for each document.
|
||
|
/// </summary>
|
||
|
public PdfFormXObjectTable(PdfDocument document)
|
||
|
: base(document)
|
||
|
{ }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a PdfFormXObject from an XPdfForm. Because the returned objects must be unique, always
|
||
|
/// a new instance of PdfFormXObject is created if none exists for the specified form.
|
||
|
/// </summary>
|
||
|
public PdfFormXObject GetForm(XForm form)
|
||
|
{
|
||
|
// If the form already has a PdfFormXObject, return it.
|
||
|
if (form._pdfForm != null)
|
||
|
{
|
||
|
Debug.Assert(form.IsTemplate, "An XPdfForm must not have a PdfFormXObject.");
|
||
|
if (ReferenceEquals(form._pdfForm.Owner, Owner))
|
||
|
return form._pdfForm;
|
||
|
//throw new InvalidOperationException("Because of a current limitation of PDFsharp an XPdfForm object can be used only within one single PdfDocument.");
|
||
|
|
||
|
// Dispose PdfFromXObject when document has changed
|
||
|
form._pdfForm = null;
|
||
|
}
|
||
|
|
||
|
XPdfForm pdfForm = form as XPdfForm;
|
||
|
if (pdfForm != null)
|
||
|
{
|
||
|
// Is the external PDF file from which is imported already known for the current document?
|
||
|
Selector selector = new Selector(form);
|
||
|
PdfImportedObjectTable importedObjectTable;
|
||
|
if (!_forms.TryGetValue(selector, out importedObjectTable))
|
||
|
{
|
||
|
// No: Get the external document from the form and create ImportedObjectTable.
|
||
|
PdfDocument doc = pdfForm.ExternalDocument;
|
||
|
importedObjectTable = new PdfImportedObjectTable(Owner, doc);
|
||
|
_forms[selector] = importedObjectTable;
|
||
|
}
|
||
|
|
||
|
PdfFormXObject xObject = importedObjectTable.GetXObject(pdfForm.PageNumber);
|
||
|
if (xObject == null)
|
||
|
{
|
||
|
xObject = new PdfFormXObject(Owner, importedObjectTable, pdfForm);
|
||
|
importedObjectTable.SetXObject(pdfForm.PageNumber, xObject);
|
||
|
}
|
||
|
return xObject;
|
||
|
}
|
||
|
Debug.Assert(form.GetType() == typeof(XForm));
|
||
|
form._pdfForm = new PdfFormXObject(Owner, form);
|
||
|
return form._pdfForm;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the imported object table.
|
||
|
/// </summary>
|
||
|
public PdfImportedObjectTable GetImportedObjectTable(PdfPage page)
|
||
|
{
|
||
|
// Is the external PDF file from which is imported already known for the current document?
|
||
|
Selector selector = new Selector(page);
|
||
|
PdfImportedObjectTable importedObjectTable;
|
||
|
if (!_forms.TryGetValue(selector, out importedObjectTable))
|
||
|
{
|
||
|
importedObjectTable = new PdfImportedObjectTable(Owner, page.Owner);
|
||
|
_forms[selector] = importedObjectTable;
|
||
|
}
|
||
|
return importedObjectTable;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the imported object table.
|
||
|
/// </summary>
|
||
|
public PdfImportedObjectTable GetImportedObjectTable(PdfDocument document)
|
||
|
{
|
||
|
if (document == null)
|
||
|
throw new ArgumentNullException("document");
|
||
|
|
||
|
// Is the external PDF file from which is imported already known for the current document?
|
||
|
Selector selector = new Selector(document);
|
||
|
PdfImportedObjectTable importedObjectTable;
|
||
|
if (!_forms.TryGetValue(selector, out importedObjectTable))
|
||
|
{
|
||
|
// Create new table for document.
|
||
|
importedObjectTable = new PdfImportedObjectTable(Owner, document);
|
||
|
_forms[selector] = importedObjectTable;
|
||
|
}
|
||
|
return importedObjectTable;
|
||
|
}
|
||
|
|
||
|
public void DetachDocument(PdfDocument.DocumentHandle handle)
|
||
|
{
|
||
|
if (handle.IsAlive)
|
||
|
{
|
||
|
foreach (Selector selector in _forms.Keys)
|
||
|
{
|
||
|
PdfImportedObjectTable table = _forms[selector];
|
||
|
if (table.ExternalDocument != null && table.ExternalDocument.Handle == handle)
|
||
|
{
|
||
|
_forms.Remove(selector);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clean table
|
||
|
bool itemRemoved = true;
|
||
|
while (itemRemoved)
|
||
|
{
|
||
|
itemRemoved = false;
|
||
|
foreach (Selector selector in _forms.Keys)
|
||
|
{
|
||
|
PdfImportedObjectTable table = _forms[selector];
|
||
|
if (table.ExternalDocument == null)
|
||
|
{
|
||
|
_forms.Remove(selector);
|
||
|
itemRemoved = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Map from Selector to PdfImportedObjectTable.
|
||
|
/// </summary>
|
||
|
readonly Dictionary<Selector, PdfImportedObjectTable> _forms = new Dictionary<Selector, PdfImportedObjectTable>();
|
||
|
|
||
|
/// <summary>
|
||
|
/// A collection of information that uniquely identifies a particular ImportedObjectTable.
|
||
|
/// </summary>
|
||
|
public class Selector
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of FormSelector from an XPdfForm.
|
||
|
/// </summary>
|
||
|
public Selector(XForm form)
|
||
|
{
|
||
|
// HACK: just use full path to identify
|
||
|
_path = form._path.ToLowerInvariant();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of FormSelector from a PdfPage.
|
||
|
/// </summary>
|
||
|
public Selector(PdfPage page)
|
||
|
{
|
||
|
PdfDocument owner = page.Owner;
|
||
|
_path = "*" + owner.Guid.ToString("B");
|
||
|
_path = _path.ToLowerInvariant();
|
||
|
}
|
||
|
|
||
|
public Selector(PdfDocument document)
|
||
|
{
|
||
|
_path = "*" + document.Guid.ToString("B");
|
||
|
_path = _path.ToLowerInvariant();
|
||
|
}
|
||
|
|
||
|
public string Path
|
||
|
{
|
||
|
get { return _path; }
|
||
|
set { _path = value; }
|
||
|
}
|
||
|
string _path;
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
Selector selector = obj as Selector;
|
||
|
if (selector == null)
|
||
|
return false;
|
||
|
return _path == selector._path;
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return _path.GetHashCode();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|