#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.Collections.Generic;
namespace PdfSharp.Pdf.Advanced
{
///
/// Represents a PDF resource object.
///
public sealed class PdfResources : PdfDictionary
{
// Resource management works roughly like this:
// When the user creates an XFont and uses it in the XGraphics of a PdfPage, then at the first time
// a PdfFont is created and cached in the document global font table. If the user creates a new
// XFont object for an exisisting PdfFont, the PdfFont object is reused. When the PdfFont is added
// to the resources of a PdfPage for the first time, it is added to the page local PdfResourceMap for
// fonts and automatically associated with a local resource name.
///
/// Initializes a new instance of the class.
///
/// The document.
public PdfResources(PdfDocument document)
: base(document)
{
Elements[Keys.ProcSet] = new PdfLiteral("[/PDF/Text/ImageB/ImageC/ImageI]");
}
internal PdfResources(PdfDictionary dict)
: base(dict)
{ }
///
/// Adds the specified font to this resource dictionary and returns its local resource name.
///
public string AddFont(PdfFont font)
{
string name;
if (!_resources.TryGetValue(font, out name))
{
name = NextFontName;
_resources[font] = name;
if (font.Reference == null)
Owner._irefTable.Add(font);
Fonts.Elements[name] = font.Reference;
}
return name;
}
///
/// Adds the specified image to this resource dictionary
/// and returns its local resource name.
///
public string AddImage(PdfImage image)
{
string name;
if (!_resources.TryGetValue(image, out name))
{
name = NextImageName;
_resources[image] = name;
if (image.Reference == null)
Owner._irefTable.Add(image);
XObjects.Elements[name] = image.Reference;
}
return name;
}
///
/// Adds the specified form object to this resource dictionary
/// and returns its local resource name.
///
public string AddForm(PdfFormXObject form)
{
string name;
if (!_resources.TryGetValue(form, out name))
{
name = NextFormName;
_resources[form] = name;
if (form.Reference == null)
Owner._irefTable.Add(form);
XObjects.Elements[name] = form.Reference;
}
return name;
}
///
/// Adds the specified graphics state to this resource dictionary
/// and returns its local resource name.
///
public string AddExtGState(PdfExtGState extGState)
{
string name;
if (!_resources.TryGetValue(extGState, out name))
{
name = NextExtGStateName;
_resources[extGState] = name;
if (extGState.Reference == null)
Owner._irefTable.Add(extGState);
ExtGStates.Elements[name] = extGState.Reference;
}
return name;
}
///
/// Adds the specified pattern to this resource dictionary
/// and returns its local resource name.
///
public string AddPattern(PdfShadingPattern pattern)
{
string name;
if (!_resources.TryGetValue(pattern, out name))
{
name = NextPatternName;
_resources[pattern] = name;
if (pattern.Reference == null)
Owner._irefTable.Add(pattern);
Patterns.Elements[name] = pattern.Reference;
}
return name;
}
///
/// Adds the specified pattern to this resource dictionary
/// and returns its local resource name.
///
public string AddPattern(PdfTilingPattern pattern)
{
string name;
if (!_resources.TryGetValue(pattern, out name))
{
name = NextPatternName;
_resources[pattern] = name;
if (pattern.Reference == null)
Owner._irefTable.Add(pattern);
Patterns.Elements[name] = pattern.Reference;
}
return name;
}
///
/// Adds the specified shading to this resource dictionary
/// and returns its local resource name.
///
public string AddShading(PdfShading shading)
{
string name;
if (!_resources.TryGetValue(shading, out name))
{
name = NextShadingName;
_resources[shading] = name;
if (shading.Reference == null)
Owner._irefTable.Add(shading);
Shadings.Elements[name] = shading.Reference;
}
return name;
}
///
/// Gets the fonts map.
///
internal PdfResourceMap Fonts
{
get { return _fonts ?? (_fonts = (PdfResourceMap)Elements.GetValue(Keys.Font, VCF.Create)); }
}
PdfResourceMap _fonts;
///
/// Gets the external objects map.
///
internal PdfResourceMap XObjects
{
get { return _xObjects ?? (_xObjects = (PdfResourceMap)Elements.GetValue(Keys.XObject, VCF.Create)); }
}
PdfResourceMap _xObjects;
// TODO: make own class
internal PdfResourceMap ExtGStates
{
get
{
return _extGStates ?? (_extGStates = (PdfResourceMap)Elements.GetValue(Keys.ExtGState, VCF.Create));
}
}
PdfResourceMap _extGStates;
// TODO: make own class
internal PdfResourceMap ColorSpaces
{
get { return _colorSpaces ?? (_colorSpaces = (PdfResourceMap)Elements.GetValue(Keys.ColorSpace, VCF.Create)); }
}
PdfResourceMap _colorSpaces;
// TODO: make own class
internal PdfResourceMap Patterns
{
get { return _patterns ?? (_patterns = (PdfResourceMap) Elements.GetValue(Keys.Pattern, VCF.Create)); }
}
PdfResourceMap _patterns;
// TODO: make own class
internal PdfResourceMap Shadings
{
get { return _shadings ?? (_shadings = (PdfResourceMap) Elements.GetValue(Keys.Shading, VCF.Create)); }
}
PdfResourceMap _shadings;
// TODO: make own class
internal PdfResourceMap Properties
{
get {return _properties ?? (_properties = (PdfResourceMap) Elements.GetValue(Keys.Properties, VCF.Create));}
}
PdfResourceMap _properties;
///
/// Gets a new local name for this resource.
///
string NextFontName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/F{0}", _fontNumber++))) { }
return name;
}
}
int _fontNumber;
///
/// Gets a new local name for this resource.
///
string NextImageName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/I{0}", _imageNumber++))) { }
return name;
}
}
int _imageNumber;
///
/// Gets a new local name for this resource.
///
string NextFormName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/Fm{0}", _formNumber++))) { }
return name;
}
}
int _formNumber;
///
/// Gets a new local name for this resource.
///
string NextExtGStateName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/GS{0}", _extGStateNumber++))) { }
return name;
}
}
int _extGStateNumber;
///
/// Gets a new local name for this resource.
///
string NextPatternName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/Pa{0}", _patternNumber++))) ;
return name;
}
}
int _patternNumber;
///
/// Gets a new local name for this resource.
///
string NextShadingName
{
get
{
string name;
while (ExistsResourceNames(name = string.Format("/Sh{0}", _shadingNumber++))) ;
return name;
}
}
int _shadingNumber;
///
/// Check whether a resource name is already used in the context of this resource dictionary.
/// PDF4NET uses GUIDs as resource names, but I think this weapon is to heavy.
///
internal bool ExistsResourceNames(string name)
{
// TODO: more precise: is this page imported and is PageOptions != Replace
// BUG:
//if (!Owner.IsImported)
// return false;
// Collect all resouce names of all imported resources.
if (_importedResourceNames == null)
{
_importedResourceNames = new Dictionary();
if (Elements[Keys.Font] != null)
Fonts.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.XObject] != null)
XObjects.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.ExtGState] != null)
ExtGStates.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.ColorSpace] != null)
ColorSpaces.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.Pattern] != null)
Patterns.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.Shading] != null)
Shadings.CollectResourceNames(_importedResourceNames);
if (Elements[Keys.Properties] != null)
Properties.CollectResourceNames(_importedResourceNames);
}
return _importedResourceNames.ContainsKey(name);
// This is superfluous because PDFsharp resource names cannot be double.
// importedResourceNames.Add(name, null);
}
///
/// All the names of imported resources.
///
Dictionary _importedResourceNames;
///
/// Maps all PDFsharp resources to their local resource names.
///
readonly Dictionary _resources = new Dictionary();
///
/// Predefined keys of this dictionary.
///
public sealed class Keys : KeysBase
{
///
/// (Optional) A dictionary that maps resource names to graphics state
/// parameter dictionaries.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string ExtGState = "/ExtGState";
///
/// (Optional) A dictionary that maps each resource name to either the name of a
/// device-dependent color space or an array describing a color space.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string ColorSpace = "/ColorSpace";
///
/// (Optional) A dictionary that maps each resource name to either the name of a
/// device-dependent color space or an array describing a color space.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string Pattern = "/Pattern";
///
/// (Optional; PDF 1.3) A dictionary that maps resource names to shading dictionaries.
///
[KeyInfo("1.3", KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string Shading = "/Shading";
///
/// (Optional) A dictionary that maps resource names to external objects.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string XObject = "/XObject";
///
/// (Optional) A dictionary that maps resource names to font dictionaries.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string Font = "/Font";
///
/// (Optional) An array of predefined procedure set names.
///
[KeyInfo(KeyType.Array | KeyType.Optional)]
public const string ProcSet = "/ProcSet";
///
/// (Optional; PDF 1.2) A dictionary that maps resource names to property list
/// dictionaries for marked content.
///
[KeyInfo(KeyType.Dictionary | KeyType.Optional, typeof(PdfResourceMap))]
public const string Properties = "/Properties";
///
/// Gets the KeysMeta for these keys.
///
internal static DictionaryMeta Meta
{
get { return _meta ?? (_meta = CreateMeta(typeof(Keys))); }
}
static DictionaryMeta _meta;
}
///
/// Gets the KeysMeta of this dictionary type.
///
internal override DictionaryMeta Meta
{
get { return Keys.Meta; }
}
}
}