ASCU_ALL/PrintPDF/PdfSharp/Pdf/PdfDictionary.cs
2021-05-25 17:00:45 +05:00

1913 lines
75 KiB
C#
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
using PdfSharp.Drawing;
using PdfSharp.Pdf.IO;
using PdfSharp.Pdf.Filters;
using PdfSharp.Pdf.Advanced;
using PdfSharp.Pdf.Internal;
namespace PdfSharp.Pdf
{
/// <summary>
/// Value creation flags. Specifies whether and how a value that does not exist is created.
/// </summary>
// ReSharper disable InconsistentNaming
public enum VCF
// ReSharper restore InconsistentNaming
{
/// <summary>
/// Don't create the value.
/// </summary>
None,
/// <summary>
/// Create the value as direct object.
/// </summary>
Create,
/// <summary>
/// Create the value as indirect object.
/// </summary>
CreateIndirect,
}
/// <summary>
/// Represents a PDF dictionary object.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay}")]
public class PdfDictionary : PdfObject, IEnumerable<KeyValuePair<string, PdfItem>>
{
// Reference: 3.2.6  Dictionary Objects / Page 59
/// <summary>
/// Initializes a new instance of the <see cref="PdfDictionary"/> class.
/// </summary>
public PdfDictionary()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="PdfDictionary"/> class.
/// </summary>
/// <param name="document">The document.</param>
public PdfDictionary(PdfDocument document)
: base(document)
{ }
/// <summary>
/// Initializes a new instance from an existing dictionary. Used for object type transformation.
/// </summary>
protected PdfDictionary(PdfDictionary dict)
: base(dict)
{
if (dict._elements != null)
dict._elements.ChangeOwner(this);
if (dict._stream != null)
dict._stream.ChangeOwner(this);
}
/// <summary>
/// Creates a copy of this dictionary. Direct values are deep copied. Indirect references are not
/// modified.
/// </summary>
public new PdfDictionary Clone()
{
return (PdfDictionary)Copy();
}
/// <summary>
/// This function is useful for importing objects from external documents. The returned object is not
/// yet complete. irefs refer to external objects and directed objects are cloned but their document
/// property is null. A cloned dictionary or array needs a 'fix-up' to be a valid object.
/// </summary>
protected override object Copy()
{
PdfDictionary dict = (PdfDictionary)base.Copy();
if (dict._elements != null)
{
dict._elements = dict._elements.Clone();
dict._elements.ChangeOwner(dict);
PdfName[] names = dict._elements.KeyNames;
foreach (PdfName name in names)
{
PdfObject obj = dict._elements[name] as PdfObject;
if (obj != null)
{
obj = obj.Clone();
// Recall that obj.Document is now null.
dict._elements[name] = obj;
}
}
}
if (dict._stream != null)
{
dict._stream = dict._stream.Clone();
dict._stream.ChangeOwner(dict);
}
return dict;
}
/// <summary>
/// Gets the dictionary containing the elements of this dictionary.
/// </summary>
public DictionaryElements Elements
{
get { return _elements ?? (_elements = new DictionaryElements(this)); }
}
/// <summary>
/// The elements of the dictionary.
/// </summary>
internal DictionaryElements _elements;
/// <summary>
/// Returns an enumerator that iterates through the dictionary elements.
/// </summary>
public IEnumerator<KeyValuePair<string, PdfItem>> GetEnumerator()
{
return Elements.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Returns a string with the content of this object in a readable form. Useful for debugging purposes only.
/// </summary>
public override string ToString()
{
// Get keys and sort.
PdfName[] keys = Elements.KeyNames;
List<PdfName> list = new List<PdfName>(keys);
list.Sort(PdfName.Comparer);
list.CopyTo(keys, 0);
StringBuilder pdf = new StringBuilder();
pdf.Append("<< ");
foreach (PdfName key in keys)
pdf.Append(key + " " + Elements[key] + " ");
pdf.Append(">>");
return pdf.ToString();
}
internal override void WriteObject(PdfWriter writer)
{
writer.WriteBeginObject(this);
//int count = Elements.Count;
PdfName[] keys = Elements.KeyNames;
#if DEBUG
// TODO: automatically set length
if (_stream != null)
Debug.Assert(Elements.ContainsKey(PdfStream.Keys.Length), "Dictionary has a stream but no length is set.");
#endif
#if DEBUG
// Sort keys for debugging purposes. Comparing PDF files with for example programs like
// Araxis Merge is easier with sorted keys.
if (writer.Layout == PdfWriterLayout.Verbose)
{
List<PdfName> list = new List<PdfName>(keys);
list.Sort(PdfName.Comparer);
list.CopyTo(keys, 0);
}
#endif
foreach (PdfName key in keys)
WriteDictionaryElement(writer, key);
if (Stream != null)
WriteDictionaryStream(writer);
writer.WriteEndObject();
}
/// <summary>
/// Writes a key/value pair of this dictionary. This function is intended to be overridden
/// in derived classes.
/// </summary>
internal virtual void WriteDictionaryElement(PdfWriter writer, PdfName key)
{
if (key == null)
throw new ArgumentNullException("key");
PdfItem item = Elements[key];
#if DEBUG
// TODO: simplify PDFsharp
if (item is PdfObject && ((PdfObject)item).IsIndirect)
{
// Replace an indirect object by its Reference.
item = ((PdfObject)item).Reference;
Debug.Assert(false, "Check when we come here.");
}
#endif
key.WriteObject(writer);
item.WriteObject(writer);
writer.NewLine();
}
/// <summary>
/// Writes the stream of this dictionary. This function is intended to be overridden
/// in a derived class.
/// </summary>
internal virtual void WriteDictionaryStream(PdfWriter writer)
{
writer.WriteStream(this, (writer.Options & PdfWriterOptions.OmitStream) == PdfWriterOptions.OmitStream);
}
/// <summary>
/// Gets or sets the PDF stream belonging to this dictionary. Returns null if the dictionary has
/// no stream. To create the stream, call the CreateStream function.
/// </summary>
public PdfStream Stream
{
get { return _stream; }
set { _stream = value; }
}
PdfStream _stream;
/// <summary>
/// Creates the stream of this dictionary and initializes it with the specified byte array.
/// The function must not be called if the dictionary already has a stream.
/// </summary>
public PdfStream CreateStream(byte[] value)
{
if (_stream != null)
throw new InvalidOperationException("The dictionary already has a stream.");
_stream = new PdfStream(value, this);
// Always set the length.
Elements[PdfStream.Keys.Length] = new PdfInteger(_stream.Length);
return _stream;
}
/// <summary>
/// When overridden in a derived class, gets the KeysMeta of this dictionary type.
/// </summary>
internal virtual DictionaryMeta Meta
{
get { return null; }
}
/// <summary>
/// Represents the interface to the elements of a PDF dictionary.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay}")]
public sealed class DictionaryElements : IDictionary<string, PdfItem>, ICloneable
{
internal DictionaryElements(PdfDictionary ownerDictionary)
{
_elements = new Dictionary<string, PdfItem>();
_ownerDictionary = ownerDictionary;
}
object ICloneable.Clone()
{
DictionaryElements dictionaryElements = (DictionaryElements)MemberwiseClone();
dictionaryElements._elements = new Dictionary<string, PdfItem>(dictionaryElements._elements);
dictionaryElements._ownerDictionary = null;
return dictionaryElements;
}
/// <summary>
/// Creates a shallow copy of this object. The clone is not owned by a dictionary anymore.
/// </summary>
public DictionaryElements Clone()
{
return (DictionaryElements)((ICloneable)this).Clone();
}
/// <summary>
/// Moves this instance to another dictionary during object type transformation.
/// </summary>
internal void ChangeOwner(PdfDictionary ownerDictionary)
{
if (_ownerDictionary != null)
{
// ???
}
// Set new owner.
_ownerDictionary = ownerDictionary;
// Set owners elements to this.
ownerDictionary._elements = this;
}
/// <summary>
/// Gets the dictionary to which this elements object belongs to.
/// </summary>
internal PdfDictionary Owner
{
get { return _ownerDictionary; }
}
/// <summary>
/// Converts the specified value to boolean.
/// If the value does not exist, the function returns false.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public bool GetBoolean(string key, bool create)
{
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfBoolean();
return false;
}
if (obj is PdfReference)
obj = ((PdfReference)obj).Value;
PdfBoolean boolean = obj as PdfBoolean;
if (boolean != null)
return boolean.Value;
PdfBooleanObject booleanObject = obj as PdfBooleanObject;
if (booleanObject != null)
return booleanObject.Value;
throw new InvalidCastException("GetBoolean: Object is not a boolean.");
}
/// <summary>
/// Converts the specified value to boolean.
/// If the value does not exist, the function returns false.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public bool GetBoolean(string key)
{
return GetBoolean(key, false);
}
/// <summary>
/// Sets the entry to a direct boolean value.
/// </summary>
public void SetBoolean(string key, bool value)
{
this[key] = new PdfBoolean(value);
}
/// <summary>
/// Converts the specified value to integer.
/// If the value does not exist, the function returns 0.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public int GetInteger(string key, bool create)
{
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfInteger();
return 0;
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfInteger integer = obj as PdfInteger;
if (integer != null)
return integer.Value;
PdfIntegerObject integerObject = obj as PdfIntegerObject;
if (integerObject != null)
return integerObject.Value;
throw new InvalidCastException("GetInteger: Object is not an integer.");
}
/// <summary>
/// Converts the specified value to integer.
/// If the value does not exist, the function returns 0.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public int GetInteger(string key)
{
return GetInteger(key, false);
}
/// <summary>
/// Sets the entry to a direct integer value.
/// </summary>
public void SetInteger(string key, int value)
{
this[key] = new PdfInteger(value);
}
/// <summary>
/// Converts the specified value to double.
/// If the value does not exist, the function returns 0.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public double GetReal(string key, bool create)
{
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfReal();
return 0;
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfReal real = obj as PdfReal;
if (real != null)
return real.Value;
PdfRealObject realObject = obj as PdfRealObject;
if (realObject != null)
return realObject.Value;
PdfInteger integer = obj as PdfInteger;
if (integer != null)
return integer.Value;
PdfIntegerObject integerObject = obj as PdfIntegerObject;
if (integerObject != null)
return integerObject.Value;
throw new InvalidCastException("GetReal: Object is not a number.");
}
/// <summary>
/// Converts the specified value to double.
/// If the value does not exist, the function returns 0.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public double GetReal(string key)
{
return GetReal(key, false);
}
/// <summary>
/// Sets the entry to a direct double value.
/// </summary>
public void SetReal(string key, double value)
{
this[key] = new PdfReal(value);
}
/// <summary>
/// Converts the specified value to String.
/// If the value does not exist, the function returns the empty string.
/// </summary>
public string GetString(string key, bool create)
{
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfString();
return "";
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfString str = obj as PdfString;
if (str != null)
return str.Value;
PdfStringObject strObject = obj as PdfStringObject;
if (strObject != null)
return strObject.Value;
PdfName name = obj as PdfName;
if (name != null)
return name.Value;
PdfNameObject nameObject = obj as PdfNameObject;
if (nameObject != null)
return nameObject.Value;
throw new InvalidCastException("GetString: Object is not a string.");
}
/// <summary>
/// Converts the specified value to String.
/// If the value does not exist, the function returns the empty string.
/// </summary>
public string GetString(string key)
{
return GetString(key, false);
}
/// <summary>
/// Tries to get the string. TODO: more TryGet...
/// </summary>
public bool TryGetString(string key, out string value)
{
value = null;
object obj = this[key];
if (obj == null)
return false;
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfString str = obj as PdfString;
if (str != null)
{
value = str.Value;
return true;
}
PdfStringObject strObject = obj as PdfStringObject;
if (strObject != null)
{
value = strObject.Value;
return true;
}
PdfName name = obj as PdfName;
if (name != null)
{
value = name.Value;
return true;
}
PdfNameObject nameObject = obj as PdfNameObject;
if (nameObject != null)
{
value = nameObject.Value;
return true;
}
return false;
}
/// <summary>
/// Sets the entry to a direct string value.
/// </summary>
public void SetString(string key, string value)
{
this[key] = new PdfString(value);
}
/// <summary>
/// Converts the specified value to a name.
/// If the value does not exist, the function returns the empty string.
/// </summary>
public string GetName(string key)
{
object obj = this[key];
if (obj == null)
{
//if (create)
// this[key] = new Pdf();
return String.Empty;
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfName name = obj as PdfName;
if (name != null)
return name.Value;
PdfNameObject nameObject = obj as PdfNameObject;
if (nameObject != null)
return nameObject.Value;
throw new InvalidCastException("GetName: Object is not a name.");
}
/// <summary>
/// Sets the specified name value.
/// If the value doesn't start with a slash, it is added automatically.
/// </summary>
public void SetName(string key, string value)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length == 0 || value[0] != '/')
value = "/" + value;
this[key] = new PdfName(value);
}
/// <summary>
/// Converts the specified value to PdfRectangle.
/// If the value does not exist, the function returns an empty rectangle.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public PdfRectangle GetRectangle(string key, bool create)
{
PdfRectangle value = new PdfRectangle();
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = value = new PdfRectangle();
return value;
}
if (obj is PdfReference)
obj = ((PdfReference)obj).Value;
PdfArray array = obj as PdfArray;
if (array != null && array.Elements.Count == 4)
{
value = new PdfRectangle(array.Elements.GetReal(0), array.Elements.GetReal(1),
array.Elements.GetReal(2), array.Elements.GetReal(3));
this[key] = value;
}
else
value = (PdfRectangle)obj;
return value;
}
/// <summary>
/// Converts the specified value to PdfRectangle.
/// If the value does not exist, the function returns an empty rectangle.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public PdfRectangle GetRectangle(string key)
{
return GetRectangle(key, false);
}
/// <summary>
/// Sets the entry to a direct rectangle value, represented by an array with four values.
/// </summary>
public void SetRectangle(string key, PdfRectangle rect)
{
_elements[key] = rect;
}
/// Converts the specified value to XMatrix.
/// If the value does not exist, the function returns an identity matrix.
/// If the value is not convertible, the function throws an InvalidCastException.
public XMatrix GetMatrix(string key, bool create)
{
XMatrix value = new XMatrix();
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfLiteral("[1 0 0 1 0 0]"); // cannot be parsed, implement a PdfMatrix...
return value;
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfArray array = obj as PdfArray;
if (array != null && array.Elements.Count == 6)
{
value = new XMatrix(array.Elements.GetReal(0), array.Elements.GetReal(1), array.Elements.GetReal(2),
array.Elements.GetReal(3), array.Elements.GetReal(4), array.Elements.GetReal(5));
}
else if (obj is PdfLiteral)
{
throw new NotImplementedException("Parsing matrix from literal.");
}
else
throw new InvalidCastException("Element is not an array with 6 values.");
return value;
}
/// Converts the specified value to XMatrix.
/// If the value does not exist, the function returns an identity matrix.
/// If the value is not convertible, the function throws an InvalidCastException.
public XMatrix GetMatrix(string key)
{
return GetMatrix(key, false);
}
/// <summary>
/// Sets the entry to a direct matrix value, represented by an array with six values.
/// </summary>
public void SetMatrix(string key, XMatrix matrix)
{
_elements[key] = PdfLiteral.FromMatrix(matrix);
}
/// <summary>
/// Converts the specified value to DateTime.
/// If the value does not exist, the function returns the specified default value.
/// If the value is not convertible, the function throws an InvalidCastException.
/// </summary>
public DateTime GetDateTime(string key, DateTime defaultValue)
{
object obj = this[key];
if (obj == null)
{
return defaultValue;
}
PdfReference reference = obj as PdfReference;
if (reference != null)
obj = reference.Value;
PdfDate date = obj as PdfDate;
if (date != null)
return date.Value;
string strDate;
PdfString pdfString = obj as PdfString;
if (pdfString != null)
strDate = pdfString.Value;
else
{
PdfStringObject stringObject = obj as PdfStringObject;
if (stringObject != null)
strDate = stringObject.Value;
else
throw new InvalidCastException("GetName: Object is not a name.");
}
if (strDate != "")
{
try
{
defaultValue = Parser.ParseDateTime(strDate, defaultValue);
}
// ReSharper disable EmptyGeneralCatchClause
catch { }
// ReSharper restore EmptyGeneralCatchClause
}
return defaultValue;
}
/// <summary>
/// Sets the entry to a direct datetime value.
/// </summary>
public void SetDateTime(string key, DateTime value)
{
_elements[key] = new PdfDate(value);
}
internal int GetEnumFromName(string key, object defaultValue, bool create)
{
if (!(defaultValue is Enum))
throw new ArgumentException("defaultValue");
object obj = this[key];
if (obj == null)
{
if (create)
this[key] = new PdfName(defaultValue.ToString());
// ReSharper disable once PossibleInvalidCastException because Enum objects can always be casted to int.
return (int)defaultValue;
}
Debug.Assert(obj is Enum);
return (int)Enum.Parse(defaultValue.GetType(), obj.ToString().Substring(1), false);
}
internal int GetEnumFromName(string key, object defaultValue)
{
return GetEnumFromName(key, defaultValue, false);
}
internal void SetEnumAsName(string key, object value)
{
if (!(value is Enum))
throw new ArgumentException("value");
_elements[key] = new PdfName("/" + value);
}
/// <summary>
/// Gets the value for the specified key. If the value does not exist, it is optionally created.
/// </summary>
public PdfItem GetValue(string key, VCF options)
{
PdfObject obj;
PdfDictionary dict;
PdfArray array;
PdfReference iref;
PdfItem value = this[key];
if (value == null ||
value is PdfNull ||
value is PdfReference && ((PdfReference)value).Value is PdfNullObject)
{
if (options != VCF.None)
{
#if NETFX_CORE && DEBUG_
if (key == "/Resources")
Debug-Break.Break();
#endif
Type type = GetValueType(key);
if (type != null)
{
#if !NETFX_CORE
Debug.Assert(typeof(PdfItem).IsAssignableFrom(type), "Type not allowed.");
if (typeof(PdfDictionary).IsAssignableFrom(type))
{
value = obj = CreateDictionary(type, null);
}
else if (typeof(PdfArray).IsAssignableFrom(type))
{
value = obj = CreateArray(type, null);
}
else
throw new NotImplementedException("Type other than array or dictionary.");
#else
// Rewritten WinRT style.
TypeInfo typeInfo = type.GetTypeInfo();
Debug.Assert(typeof(PdfItem).GetTypeInfo().IsAssignableFrom(typeInfo), "Type not allowed.");
if (typeof(PdfDictionary).GetTypeInfo().IsAssignableFrom(typeInfo))
{
value = obj = CreateDictionary(type, null);
}
else if (typeof(PdfArray).GetTypeInfo().IsAssignableFrom(typeInfo))
{
value = obj = CreateArray(type, null);
}
else
throw new NotImplementedException("Type other than array or dictionary.");
#endif
if (options == VCF.CreateIndirect)
{
_ownerDictionary.Owner._irefTable.Add(obj);
this[key] = obj.Reference;
}
else
this[key] = obj;
}
else
throw new NotImplementedException("Cannot create value for key: " + key);
}
}
else
{
// The value exists and can be returned. But for imported documents check for necessary
// object type transformation.
if ((iref = value as PdfReference) != null)
{
// Case: value is an indirect reference.
value = iref.Value;
if (value == null)
{
// If we come here PDF file is corrupted.
throw new InvalidOperationException("Indirect reference without value.");
}
if (true) // || _owner.Document.IsImported)
{
Type type = GetValueType(key);
Debug.Assert(type != null, "No value type specified in meta information. Please send this file to PDFsharp support.");
#if !NETFX_CORE
if (type != null && type != value.GetType())
{
if (typeof(PdfDictionary).IsAssignableFrom(type))
{
Debug.Assert(value is PdfDictionary, "Bug in PDFsharp. Please send this file to PDFsharp support.");
value = CreateDictionary(type, (PdfDictionary)value);
}
else if (typeof(PdfArray).IsAssignableFrom(type))
{
Debug.Assert(value is PdfArray, "Bug in PDFsharp. Please send this file to PDFsharp support.");
value = CreateArray(type, (PdfArray)value);
}
else
throw new NotImplementedException("Type other than array or dictionary.");
}
#else
// Rewritten WinRT style.
TypeInfo typeInfo = type.GetTypeInfo();
if (type != null && type != value.GetType())
{
if (typeof(PdfDictionary).GetTypeInfo().IsAssignableFrom(typeInfo))
{
Debug.Assert(value is PdfDictionary, "Bug in PDFsharp. Please send this file to PDFsharp support.");
value = CreateDictionary(type, (PdfDictionary)value);
}
else if (typeof(PdfArray).GetTypeInfo().IsAssignableFrom(typeInfo))
{
Debug.Assert(value is PdfArray, "Bug in PDFsharp. Please send this file to PDFsharp support.");
value = CreateArray(type, (PdfArray)value);
}
else
throw new NotImplementedException("Type other than array or dictionary.");
}
#endif
}
return value;
}
// Transformation is only possible after PDF import.
if (true) // || _owner.Document.IsImported)
{
// Case: value is a direct object
if ((dict = value as PdfDictionary) != null)
{
Debug.Assert(!dict.IsIndirect);
Type type = GetValueType(key);
Debug.Assert(type != null, "No value type specified in meta information. Please send this file to PDFsharp support.");
if (dict.GetType() != type)
dict = CreateDictionary(type, dict);
return dict;
}
if ((array = value as PdfArray) != null)
{
Debug.Assert(!array.IsIndirect);
Type type = GetValueType(key);
// This is more complicated. If type is null do nothing
//Debug.Assert(type != null, "No value type specified in meta information. Please send this file to PDFsharp support.");
if (type != null && type != array.GetType())
array = CreateArray(type, array);
return array;
}
}
}
return value;
}
/// <summary>
/// Short cut for GetValue(key, VCF.None).
/// </summary>
public PdfItem GetValue(string key)
{
return GetValue(key, VCF.None);
}
/// <summary>
/// Returns the type of the object to be created as value of the specified key.
/// </summary>
Type GetValueType(string key) // TODO: move to PdfObject
{
Type type = null;
DictionaryMeta meta = _ownerDictionary.Meta;
if (meta != null)
{
KeyDescriptor kd = meta[key];
if (kd != null)
type = kd.GetValueType();
//else
// Debug.WriteLine("Warning: Key not descriptor table: " + key); // TODO: check what this means...
}
//else
// Debug.WriteLine("Warning: No meta provided for type: " + _owner.GetType().Name); // TODO: check what this means...
return type;
}
PdfArray CreateArray(Type type, PdfArray oldArray)
{
#if !NETFX_CORE && !UWP
ConstructorInfo ctorInfo;
PdfArray array;
if (oldArray == null)
{
// Use constructor with signature 'Ctor(PdfDocument owner)'.
ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[] { typeof(PdfDocument) }, null);
Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name);
array = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfArray;
}
else
{
// Use constructor with signature 'Ctor(PdfDictionary dict)'.
ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[] { typeof(PdfArray) }, null);
Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name);
array = ctorInfo.Invoke(new object[] { oldArray }) as PdfArray;
}
return array;
#else
// Rewritten WinRT style.
PdfArray array = null;
if (oldArray == null)
{
// Use constructor with signature 'Ctor(PdfDocument owner)'.
var ctorInfos = type.GetTypeInfo().DeclaredConstructors; //.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
//null, new Type[] { typeof(PdfDocument) }, null);
foreach (var ctorInfo in ctorInfos)
{
var parameters = ctorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PdfDocument))
{
array = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfArray;
break;
}
}
Debug.Assert(array != null, "No appropriate constructor found for type: " + type.Name);
}
else
{
// Use constructor with signature 'Ctor(PdfDictionary dict)'.
var ctorInfos = type.GetTypeInfo().DeclaredConstructors; // .GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
//null, new Type[] { typeof(PdfArray) }, null);
foreach (var ctorInfo in ctorInfos)
{
var parameters = ctorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PdfArray))
{
array = ctorInfo.Invoke(new object[] { oldArray }) as PdfArray;
break;
}
}
Debug.Assert(array != null, "No appropriate constructor found for type: " + type.Name);
}
return array;
#endif
}
PdfDictionary CreateDictionary(Type type, PdfDictionary oldDictionary)
{
#if !NETFX_CORE && !UWP
ConstructorInfo ctorInfo;
PdfDictionary dict;
if (oldDictionary == null)
{
// Use constructor with signature 'Ctor(PdfDocument owner)'.
ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[] { typeof(PdfDocument) }, null);
Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name);
dict = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfDictionary;
}
else
{
// Use constructor with signature 'Ctor(PdfDictionary dict)'.
ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[] { typeof(PdfDictionary) }, null);
Debug.Assert(ctorInfo != null, "No appropriate constructor found for type: " + type.Name);
dict = ctorInfo.Invoke(new object[] { oldDictionary }) as PdfDictionary;
}
return dict;
#else
// Rewritten WinRT style.
PdfDictionary dict = null;
if (oldDictionary == null)
{
// Use constructor with signature 'Ctor(PdfDocument owner)'.
var ctorInfos = type.GetTypeInfo().DeclaredConstructors; //GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
//null, new Type[] { typeof(PdfDocument) }, null);
foreach (var ctorInfo in ctorInfos)
{
var parameters = ctorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PdfDocument))
{
dict = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfDictionary;
break;
}
}
Debug.Assert(dict != null, "No appropriate constructor found for type: " + type.Name);
}
else
{
var ctorInfos = type.GetTypeInfo().DeclaredConstructors; // GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(PdfDictionary) }, null);
foreach (var ctorInfo in ctorInfos)
{
var parameters = ctorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PdfDictionary))
{
dict = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfDictionary;
break;
}
}
Debug.Assert(dict != null, "No appropriate constructor found for type: " + type.Name);
}
return dict;
#endif
}
PdfItem CreateValue(Type type, PdfDictionary oldValue)
{
#if !NETFX_CORE && !UWP
ConstructorInfo ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[] { typeof(PdfDocument) }, null);
PdfObject obj = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfObject;
if (oldValue != null)
{
obj.Reference = oldValue.Reference;
obj.Reference.Value = obj;
if (obj is PdfDictionary)
{
PdfDictionary dict = (PdfDictionary)obj;
dict._elements = oldValue._elements;
}
}
return obj;
#else
// Rewritten WinRT style.
PdfObject obj = null;
var ctorInfos = type.GetTypeInfo().DeclaredConstructors; // GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(PdfDocument) }, null);
foreach (var ctorInfo in ctorInfos)
{
var parameters = ctorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PdfDocument))
{
obj = ctorInfo.Invoke(new object[] { _ownerDictionary.Owner }) as PdfObject;
break;
}
}
Debug.Assert(obj != null, "No appropriate constructor found for type: " + type.Name);
if (oldValue != null)
{
obj.Reference = oldValue.Reference;
obj.Reference.Value = obj;
if (obj is PdfDictionary)
{
PdfDictionary dict = (PdfDictionary)obj;
dict._elements = oldValue._elements;
}
}
return obj;
#endif
}
/// <summary>
/// Sets the entry with the specified value. DON'T USE THIS FUNCTION - IT MAY BE REMOVED.
/// </summary>
public void SetValue(string key, PdfItem value)
{
Debug.Assert((value is PdfObject && ((PdfObject)value).Reference == null) | !(value is PdfObject),
"You try to set an indirect object directly into a dictionary.");
// HACK?
_elements[key] = value;
}
///// <summary>
///// Returns the indirect object if the value of the specified key is a PdfReference.
///// </summary>
//[Obsolete("Use GetObject, GetDictionary, GetArray, or GetReference")]
//public PdfObject GetIndirectObject(string key)
//{
// PdfItem item = this[key];
// if (item is PdfReference)
// return ((PdfReference)item).Value;
// return null;
//}
/// <summary>
/// Gets the PdfObject with the specified key, or null, if no such object exists. If the key refers to
/// a reference, the referenced PdfObject is returned.
/// </summary>
public PdfObject GetObject(string key)
{
PdfItem item = this[key];
PdfReference reference = item as PdfReference;
if (reference != null)
return reference.Value;
return item as PdfObject;
}
/// <summary>
/// Gets the PdfDictionary with the specified key, or null, if no such object exists. If the key refers to
/// a reference, the referenced PdfDictionary is returned.
/// </summary>
public PdfDictionary GetDictionary(string key)
{
return GetObject(key) as PdfDictionary;
}
/// <summary>
/// Gets the PdfArray with the specified key, or null, if no such object exists. If the key refers to
/// a reference, the referenced PdfArray is returned.
/// </summary>
public PdfArray GetArray(string key)
{
return GetObject(key) as PdfArray;
}
/// <summary>
/// Gets the PdfReference with the specified key, or null, if no such object exists.
/// </summary>
public PdfReference GetReference(string key)
{
PdfItem item = this[key];
return item as PdfReference;
}
/// <summary>
/// Sets the entry to the specified object. The object must not be an indirect object,
/// otherwise an exception is raised.
/// </summary>
public void SetObject(string key, PdfObject obj)
{
if (obj.Reference != null)
throw new ArgumentException("PdfObject must not be an indirect object.", "obj");
this[key] = obj;
}
/// <summary>
/// Sets the entry as a reference to the specified object. The object must be an indirect object,
/// otherwise an exception is raised.
/// </summary>
public void SetReference(string key, PdfObject obj)
{
if (obj.Reference == null)
throw new ArgumentException("PdfObject must be an indirect object.", "obj");
this[key] = obj.Reference;
}
/// <summary>
/// Sets the entry as a reference to the specified iref.
/// </summary>
public void SetReference(string key, PdfReference iref)
{
if (iref == null)
throw new ArgumentNullException("iref");
this[key] = iref;
}
#region IDictionary Members
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.IDictionary"></see> object is read-only.
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Returns an <see cref="T:System.Collections.IDictionaryEnumerator"></see> object for the <see cref="T:System.Collections.IDictionary"></see> object.
/// </summary>
public IEnumerator<KeyValuePair<string, PdfItem>> GetEnumerator()
{
return _elements.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((ICollection)_elements).GetEnumerator();
}
/// <summary>
/// Gets or sets an entry in the dictionary. The specified key must be a valid PDF name
/// starting with a slash '/'. This property provides full access to the elements of the
/// PDF dictionary. Wrong use can lead to errors or corrupt PDF files.
/// </summary>
public PdfItem this[string key]
{
get
{
PdfItem item;
_elements.TryGetValue(key, out item);
return item;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
#if DEBUG_
if (key == "/MediaBox")
key.GetType();
//if (value is PdfObject)
//{
// PdfObject obj = (PdfObject)value;
// if (obj.Reference != null)
// throw new ArgumentException("An object with an indirect reference cannot be a direct value. Try to set an indirect reference.");
//}
if (value is PdfDictionary)
{
PdfDictionary dict = (PdfDictionary)value;
if (dict._stream != null)
throw new ArgumentException("A dictionary with stream cannot be a direct value.");
}
#endif
PdfObject obj = value as PdfObject;
if (obj != null && obj.IsIndirect)
value = obj.Reference;
_elements[key] = value;
}
}
/// <summary>
/// Gets or sets an entry in the dictionary identified by a PdfName object.
/// </summary>
public PdfItem this[PdfName key]
{
get { return this[key.Value]; }
set
{
if (value == null)
throw new ArgumentNullException("value");
#if DEBUG
PdfDictionary dictionary = value as PdfDictionary;
if (dictionary != null)
{
PdfDictionary dict = dictionary;
if (dict._stream != null)
throw new ArgumentException("A dictionary with stream cannot be a direct value.");
}
#endif
PdfObject obj = value as PdfObject;
if (obj != null && obj.IsIndirect)
value = obj.Reference;
_elements[key.Value] = value;
}
}
/// <summary>
/// Removes the value with the specified key.
/// </summary>
public bool Remove(string key)
{
return _elements.Remove(key);
}
/// <summary>
/// Removes the value with the specified key.
/// </summary>
public bool Remove(KeyValuePair<string, PdfItem> item)
{
throw new NotImplementedException();
}
///// <summary>
///// Determines whether the dictionary contains the specified name.
///// </summary>
//[Obsolete("Use ContainsKey.")]
//public bool Contains(string key)
//{
// return _elements.ContainsKey(key);
//}
/// <summary>
/// Determines whether the dictionary contains the specified name.
/// </summary>
public bool ContainsKey(string key)
{
return _elements.ContainsKey(key);
}
/// <summary>
/// Determines whether the dictionary contains a specific value.
/// </summary>
public bool Contains(KeyValuePair<string, PdfItem> item)
{
throw new NotImplementedException();
}
/// <summary>
/// Removes all elements from the dictionary.
/// </summary>
public void Clear()
{
_elements.Clear();
}
/// <summary>
/// Adds the specified value to the dictionary.
/// </summary>
public void Add(string key, PdfItem value)
{
if (String.IsNullOrEmpty(key))
throw new ArgumentNullException("key");
if (key[0] != '/')
throw new ArgumentException("The key must start with a slash '/'.");
// If object is indirect automatically convert value to reference.
PdfObject obj = value as PdfObject;
if (obj != null && obj.IsIndirect)
value = obj.Reference;
_elements.Add(key, value);
}
/// <summary>
/// Adds an item to the dictionary.
/// </summary>
public void Add(KeyValuePair<string, PdfItem> item)
{
Add(item.Key, item.Value);
}
/// <summary>
/// Gets all keys currently in use in this dictionary as an array of PdfName objects.
/// </summary>
public PdfName[] KeyNames
{
get
{
ICollection values = _elements.Keys;
int count = values.Count;
string[] strings = new string[count];
values.CopyTo(strings, 0);
PdfName[] names = new PdfName[count];
for (int idx = 0; idx < count; idx++)
names[idx] = new PdfName(strings[idx]);
return names;
}
}
/// <summary>
/// Get all keys currently in use in this dictionary as an array of string objects.
/// </summary>
public ICollection<string> Keys
{
// It is by design not to return _elements.Keys, but a copy.
get
{
ICollection values = _elements.Keys;
int count = values.Count;
string[] keys = new string[count];
values.CopyTo(keys, 0);
return keys;
}
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
public bool TryGetValue(string key, out PdfItem value)
{
return _elements.TryGetValue(key, out value);
}
/// <summary>
/// Gets all values currently in use in this dictionary as an array of PdfItem objects.
/// </summary>
//public ICollection<PdfItem> Values
public ICollection<PdfItem> Values
{
// It is by design not to return _elements.Values, but a copy.
get
{
ICollection values = _elements.Values;
PdfItem[] items = new PdfItem[values.Count];
values.CopyTo(items, 0);
return items;
}
}
/// <summary>
/// Return false.
/// </summary>
public bool IsFixedSize
{
get { return false; }
}
#endregion
#region ICollection Members
/// <summary>
/// Return false.
/// </summary>
public bool IsSynchronized
{
get { return false; }
}
/// <summary>
/// Gets the number of elements contained in the dictionary.
/// </summary>
public int Count
{
get { return _elements.Count; }
}
/// <summary>
/// Copies the elements of the dictionary to an array, starting at a particular index.
/// </summary>
public void CopyTo(KeyValuePair<string, PdfItem>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
/// <summary>
/// The current implementation returns null.
/// </summary>
public object SyncRoot
{
get { return null; }
}
#endregion
/// <summary>
/// Gets the DebuggerDisplayAttribute text.
/// </summary>
// ReSharper disable UnusedMember.Local
internal string DebuggerDisplay
// ReSharper restore UnusedMember.Local
{
get
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat(CultureInfo.InvariantCulture, "key={0}:(", _elements.Count);
bool addSpace = false;
ICollection<string> keys = _elements.Keys;
foreach (string key in keys)
{
if (addSpace)
sb.Append(' ');
addSpace = true;
sb.Append(key);
}
sb.Append(")");
return sb.ToString();
}
}
/// <summary>
/// The elements of the dictionary with a string as key.
/// Because the string is a name it starts always with a '/'.
/// </summary>
Dictionary<string, PdfItem> _elements;
/// <summary>
/// The dictionary this objects belongs to.
/// </summary>
PdfDictionary _ownerDictionary;
}
/// <summary>
/// The PDF stream objects.
/// </summary>
public sealed class PdfStream
{
internal PdfStream(PdfDictionary ownerDictionary)
{
if (ownerDictionary == null)
throw new ArgumentNullException("ownerDictionary");
_ownerDictionary = ownerDictionary;
}
/// <summary>
/// A .NET string can contain char(0) as a valid character.
/// </summary>
internal PdfStream(byte[] value, PdfDictionary owner)
: this(owner)
{
_value = value;
}
/// <summary>
/// Clones this stream by creating a deep copy.
/// </summary>
public PdfStream Clone()
{
PdfStream stream = (PdfStream)MemberwiseClone();
stream._ownerDictionary = null;
if (stream._value != null)
{
stream._value = new byte[stream._value.Length];
_value.CopyTo(stream._value, 0);
}
return stream;
}
/// <summary>
/// Moves this instance to another dictionary during object type transformation.
/// </summary>
internal void ChangeOwner(PdfDictionary dict)
{
if (_ownerDictionary != null)
{
// ???
}
// Set new owner.
_ownerDictionary = dict;
// Set owners stream to this.
_ownerDictionary._stream = this;
}
/// <summary>
/// The dictionary the stream belongs to.
/// </summary>
PdfDictionary _ownerDictionary;
/// <summary>
/// Gets the length of the stream, i.e. the actual number of bytes in the stream.
/// </summary>
public int Length
{
get { return _value != null ? _value.Length : 0; }
}
/// <summary>
/// Gets a value indicating whether this stream has decode parameters.
/// </summary>
internal bool HasDecodeParams
{
// TODO: Move to Stream.Internals
get
{
// TODO: DecodeParams can be an array.
PdfDictionary dictionary = _ownerDictionary.Elements.GetDictionary(Keys.DecodeParms);
if (dictionary != null)
{
// More to do here?
return true;
}
return false;
}
}
/// <summary>
/// Gets the decode predictor for LZW- or FlateDecode.
/// Returns 0 if no such value exists.
/// </summary>
internal int DecodePredictor // Reference: TABLE 3.8 Predictor values / Page 76
{
get
{
PdfDictionary dictionary = _ownerDictionary.Elements.GetDictionary(Keys.DecodeParms);
if (dictionary != null)
{
return dictionary.Elements.GetInteger("/Predictor");
}
return 0;
}
}
/// <summary>
/// Gets the decode Columns for LZW- or FlateDecode.
/// Returns 0 if no such value exists.
/// </summary>
internal int DecodeColumns // Reference: TABLE 3.8 Predictor values / Page 76
{
get
{
PdfDictionary dictionary = _ownerDictionary.Elements.GetDictionary(Keys.DecodeParms);
if (dictionary != null)
{
return dictionary.Elements.GetInteger("/Columns");
}
return 0;
}
}
/// <summary>
/// Get or sets the bytes of the stream as they are, i.e. if one or more filters exist the bytes are
/// not unfiltered.
/// </summary>
public byte[] Value
{
get { return _value; }
set
{
if (value == null)
throw new ArgumentNullException("value");
_value = value;
_ownerDictionary.Elements.SetInteger(Keys.Length, value.Length);
}
}
byte[] _value;
/// <summary>
/// Gets the value of the stream unfiltered. The stream content is not modified by this operation.
/// </summary>
public byte[] UnfilteredValue
{
get
{
byte[] bytes = null;
if (_value != null)
{
PdfItem filter = _ownerDictionary.Elements["/Filter"];
if (filter != null)
{
bytes = Filtering.Decode(_value, filter);
if (bytes == null)
{
string message = String.Format("«Cannot decode filter '{0}'»", filter);
bytes = PdfEncoders.RawEncoding.GetBytes(message);
}
}
else
{
bytes = new byte[_value.Length];
_value.CopyTo(bytes, 0);
}
}
return bytes ?? new byte[0];
}
}
/// <summary>
/// Tries to unfilter the bytes of the stream. If the stream is filtered and PDFsharp knows the filter
/// algorithm, the stream content is replaced by its unfiltered value and the function returns true.
/// Otherwise the content remains untouched and the function returns false.
/// The function is useful for analyzing existing PDF files.
/// </summary>
public bool TryUnfilter() // TODO: Take DecodeParams into account.
{
if (_value != null)
{
PdfItem filter = _ownerDictionary.Elements["/Filter"];
if (filter != null)
{
// PDFsharp can only uncompress streams that are compressed with the ZIP or LZH algorithm.
byte[] bytes = Filtering.Decode(_value, filter);
if (bytes != null)
{
_ownerDictionary.Elements.Remove(Keys.Filter);
Value = bytes;
}
else
return false;
}
}
return true;
}
/// <summary>
/// Compresses the stream with the FlateDecode filter.
/// If a filter is already defined, the function has no effect.
/// </summary>
public void Zip()
{
if (_value == null)
return;
if (!_ownerDictionary.Elements.ContainsKey("/Filter"))
{
_value = Filtering.FlateDecode.Encode(_value, _ownerDictionary._document.Options.FlateEncodeMode);
_ownerDictionary.Elements["/Filter"] = new PdfName("/FlateDecode");
_ownerDictionary.Elements["/Length"] = new PdfInteger(_value.Length);
}
}
/// <summary>
/// Returns the stream content as a raw string.
/// </summary>
public override string ToString()
{
if (_value == null)
return "«null»";
string stream;
PdfItem filter = _ownerDictionary.Elements["/Filter"];
if (filter != null)
{
#if true
byte[] bytes = Filtering.Decode(_value, filter);
if (bytes != null)
stream = PdfEncoders.RawEncoding.GetString(bytes, 0, bytes.Length);
#else
if (_owner.Elements.GetString("/Filter") == "/FlateDecode")
{
stream = Filtering.FlateDecode.DecodeToString(_value);
}
#endif
else
throw new NotImplementedException("Unknown filter");
}
else
stream = PdfEncoders.RawEncoding.GetString(_value, 0, _value.Length);
return stream;
}
//internal void WriteObject_(Stream stream)
//{
// if (_value != null)
// stream.Write(_value, 0, value.Length);
//}
///// <summary>
///// Converts a raw encoded string into a byte array.
///// </summary>
//public static byte[] RawEncode(string content)
//{
// return PdfEncoders.RawEncoding.GetBytes(content);
//}
/// <summary>
/// Common keys for all streams.
/// </summary>
public class Keys : KeysBase
{
// ReSharper disable InconsistentNaming
/// <summary>
/// (Required) The number of bytes from the beginning of the line following the keyword
/// stream to the last byte just before the keyword endstream. (There may be an additional
/// EOL marker, preceding endstream, that is not included in the count and is not logically
/// part of the stream data.)
/// </summary>
[KeyInfo(KeyType.Integer | KeyType.Required)]
public const string Length = "/Length";
/// <summary>
/// (Optional) The name of a filter to be applied in processing the stream data found between
/// the keywords stream and endstream, or an array of such names. Multiple filters should be
/// specified in the order in which they are to be applied.
/// </summary>
[KeyInfo(KeyType.NameOrArray | KeyType.Optional)]
public const string Filter = "/Filter";
/// <summary>
/// (Optional) A parameter dictionary or an array of such dictionaries, used by the filters
/// specified by Filter. If there is only one filter and that filter has parameters, DecodeParms
/// must be set to the filters parameter dictionary unless all the filters parameters have
/// their default values, in which case the DecodeParms entry may be omitted. If there are
/// multiple filters and any of the filters has parameters set to nondefault values, DecodeParms
/// must be an array with one entry for each filter: either the parameter dictionary for that
/// filter, or the null object if that filter has no parameters (or if all of its parameters have
/// their default values). If none of the filters have parameters, or if all their parameters
/// have default values, the DecodeParms entry may be omitted.
/// </summary>
[KeyInfo(KeyType.ArrayOrDictionary | KeyType.Optional)]
public const string DecodeParms = "/DecodeParms";
/// <summary>
/// (Optional; PDF 1.2) The file containing the stream data. If this entry is present, the bytes
/// between stream and endstream are ignored, the filters are specified by FFilter rather than
/// Filter, and the filter parameters are specified by FDecodeParms rather than DecodeParms.
/// However, the Length entry should still specify the number of those bytes. (Usually, there are
/// no bytes and Length is 0.)
/// </summary>
[KeyInfo("1.2", KeyType.String | KeyType.Optional)]
public const string F = "/F";
/// <summary>
/// (Optional; PDF 1.2) The name of a filter to be applied in processing the data found in the
/// streams external file, or an array of such names. The same rules apply as for Filter.
/// </summary>
[KeyInfo("1.2", KeyType.NameOrArray | KeyType.Optional)]
public const string FFilter = "/FFilter";
/// <summary>
/// (Optional; PDF 1.2) A parameter dictionary, or an array of such dictionaries, used by the
/// filters specified by FFilter. The same rules apply as for DecodeParms.
/// </summary>
[KeyInfo("1.2", KeyType.ArrayOrDictionary | KeyType.Optional)]
public const string FDecodeParms = "/FDecodeParms";
/// <summary>
/// Optional; PDF 1.5) A non-negative integer representing the number of bytes in the decoded
/// (defiltered) stream. It can be used to determine, for example, whether enough disk space is
/// available to write a stream to a file.
/// This value should be considered a hint only; for some stream filters, it may not be possible
/// to determine this value precisely.
/// </summary>
[KeyInfo("1.5", KeyType.Integer | KeyType.Optional)]
public const string DL = "/DL";
// ReSharper restore InconsistentNaming
}
}
/// <summary>
/// Gets the DebuggerDisplayAttribute text.
/// </summary>
// ReSharper disable UnusedMember.Local
string DebuggerDisplay
// ReSharper restore UnusedMember.Local
{
get
{
#if true
return String.Format(CultureInfo.InvariantCulture, "dictionary({0},[{1}])={2}",
ObjectID.DebuggerDisplay,
Elements.Count,
_elements.DebuggerDisplay);
#else
return String.Format(CultureInfo.InvariantCulture, "dictionary({0},[{1}])=", ObjectID.DebuggerDisplay, _elements.DebuggerDisplay);
#endif
}
}
}
}