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