diff --git a/.ci/tasks/build.yaml b/.ci/tasks/build.yaml index b6717c82..ddcc2df9 100644 --- a/.ci/tasks/build.yaml +++ b/.ci/tasks/build.yaml @@ -4,7 +4,7 @@ image_resource: type: docker-image source: repository: mcr.microsoft.com/dotnet/sdk - tag: 5.0.103-alpine3.12-amd64 + tag: 8.0.101-alpine3.18-amd64 inputs: - name: source params: diff --git a/.ci/tasks/publish-nugget.yaml b/.ci/tasks/publish-nugget.yaml index 8c84d2fc..53812edd 100644 --- a/.ci/tasks/publish-nugget.yaml +++ b/.ci/tasks/publish-nugget.yaml @@ -4,7 +4,7 @@ image_resource: type: docker-image source: repository: mcr.microsoft.com/dotnet/sdk - tag: 5.0.103-alpine3.12-amd64 + tag: 8.0.101-alpine3.18-amd64 inputs: - name: source - name: version diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20513d77..2132ffb0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: dotnet package -on: [push] +on: + push: + pull_request: + branches: + - master jobs: build: @@ -8,13 +12,29 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - options: - - framework: net5.0 - - framework: netcoreapp3.1 + dotnet: + - 3.1.x + - 5.0.x + - 6.0.x + - 7.0.x + - 8.0.x steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 3.1.x + 5.0.x + 6.0.x + 7.0.x + 8.0.x - name: DotNetBuild shell: pwsh - run: ./ci-build.ps1 "${{matrix.options.framework}}" + run: ./ci-build.ps1 + - name: Install Ghostscript + run: sudo apt-get install -y ghostscript - name: Test - run: dotnet test --no-restore --verbosity normal \ No newline at end of file + run: dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + - name: Codecov + uses: codecov/codecov-action@v3 diff --git a/.gitignore b/.gitignore index 3c4efe20..a35345fb 100644 --- a/.gitignore +++ b/.gitignore @@ -258,4 +258,7 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc + +# OSX +.DS_Store diff --git a/LICENCE.md b/LICENSE.md similarity index 100% rename from LICENCE.md rename to LICENSE.md diff --git a/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMemberTypes.cs b/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMemberTypes.cs new file mode 100644 index 00000000..8aae474f --- /dev/null +++ b/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMemberTypes.cs @@ -0,0 +1,127 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NETCOREAPP3_1 || NETSTANDARD2_0 +// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Specifies the types of members that are dynamically accessed. + /// + /// This enumeration has a attribute that allows a + /// bitwise combination of its member values. + /// + [Flags] + internal enum DynamicallyAccessedMemberTypes + { + /// + /// Specifies no members. + /// + None = 0, + + /// + /// Specifies the default, parameterless public constructor. + /// + PublicParameterlessConstructor = 0x0001, + + /// + /// Specifies all public constructors. + /// + PublicConstructors = 0x0002 | PublicParameterlessConstructor, + + /// + /// Specifies all non-public constructors. + /// + NonPublicConstructors = 0x0004, + + /// + /// Specifies all public methods. + /// + PublicMethods = 0x0008, + + /// + /// Specifies all non-public methods. + /// + NonPublicMethods = 0x0010, + + /// + /// Specifies all public fields. + /// + PublicFields = 0x0020, + + /// + /// Specifies all non-public fields. + /// + NonPublicFields = 0x0040, + + /// + /// Specifies all public nested types. + /// + PublicNestedTypes = 0x0080, + + /// + /// Specifies all non-public nested types. + /// + NonPublicNestedTypes = 0x0100, + + /// + /// Specifies all public properties. + /// + PublicProperties = 0x0200, + + /// + /// Specifies all non-public properties. + /// + NonPublicProperties = 0x0400, + + /// + /// Specifies all public events. + /// + PublicEvents = 0x0800, + + /// + /// Specifies all non-public events. + /// + NonPublicEvents = 0x1000, + + /// + /// Specifies all interfaces implemented by the type. + /// + Interfaces = 0x2000, + + /// + /// Specifies all members. + /// + All = ~None + } +} +#endif \ No newline at end of file diff --git a/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMembersAttribute.cs b/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMembersAttribute.cs new file mode 100644 index 00000000..6407ddf2 --- /dev/null +++ b/MigraDocCore.DocumentObjectModel/CompileFixes/DynamicallyAccessedMembersAttribute.cs @@ -0,0 +1,56 @@ + +#if NETCOREAPP3_1 || NETSTANDARD2_0 + + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that certain members on a specified are accessed dynamically, + /// for example through . + /// + /// + /// This allows tools to understand which members are being accessed during the execution + /// of a program. + /// + /// This attribute is valid on members whose type is or . + /// + /// When this attribute is applied to a location of type , the assumption is + /// that the string represents a fully qualified type name. + /// + /// When this attribute is applied to a class, interface, or struct, the members specified + /// can be accessed dynamically on instances returned from calling + /// on instances of that class, interface, or struct. + /// + /// If the attribute is applied to a method it's treated as a special case and it implies + /// the attribute should be applied to the "this" parameter of the method. As such the attribute + /// should only be used on instance methods of types assignable to System.Type (or string, but no methods + /// will use it there). + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, + Inherited = false)] + internal sealed class DynamicallyAccessedMembersAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified member types. + /// + /// The types of members dynamically accessed. + public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) + { + MemberTypes = memberTypes; + } + + /// + /// Gets the which specifies the type + /// of members dynamically accessed. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + } +} + +#endif diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DVAttribute.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DVAttribute.cs index 51c6cd8a..df87cd76 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DVAttribute.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DVAttribute.cs @@ -52,11 +52,14 @@ public DVAttribute() /// /// Gets or sets the type of the reflected value. Must be specified by NEnum. /// + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public Type Type { get { return this.type; } set { this.type = value; } } + + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] internal Type type; /// diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DomValueDescriptorCollection.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DomValueDescriptorCollection.cs index 1b197656..fadc2c62 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DomValueDescriptorCollection.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/DomValueDescriptorCollection.cs @@ -90,6 +90,6 @@ public IEnumerator GetEnumerator() } ArrayList arrayList = new ArrayList(); - Hashtable hashTable = new Hashtable(StringComparer.CurrentCultureIgnoreCase); + Hashtable hashTable = new Hashtable(StringComparer.InvariantCultureIgnoreCase); } } diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/ValueDescriptor.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/ValueDescriptor.cs index 3c2873a7..8dd1e991 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/ValueDescriptor.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Internals/ValueDescriptor.cs @@ -44,7 +44,14 @@ namespace MigraDocCore.DocumentObjectModel.Internals /// public abstract class ValueDescriptor { - internal ValueDescriptor(string valueName, Type valueType, Type memberType, MemberInfo memberInfo, VDFlags flags) + internal ValueDescriptor( + string valueName, + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type valueType, + Type memberType, + MemberInfo memberInfo, + VDFlags flags + ) { this.ValueName = valueName; this.ValueType = valueType; @@ -56,6 +63,7 @@ internal ValueDescriptor(string valueName, Type valueType, Type memberType, Memb public object CreateValue() { ConstructorInfo constructorInfoObj = ValueType.GetConstructor(Type.EmptyTypes); + return constructorInfoObj.Invoke(null); } @@ -71,7 +79,7 @@ internal static ValueDescriptor CreateValueDescriptor(MemberInfo memberInfo, DVA flags |= VDFlags.RefOnly; string name = memberInfo.Name; - + Type type; if (memberInfo is FieldInfo) type = ((FieldInfo)memberInfo).FieldType; @@ -136,6 +144,8 @@ public PropertyInfo PropertyInfo /// /// Type of the described value, e.g. typeof(Int32) for an NInt. /// + /// + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public Type ValueType; /// @@ -159,7 +169,7 @@ public PropertyInfo PropertyInfo /// internal class NullableDescriptor : ValueDescriptor { - internal NullableDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) + internal NullableDescriptor(string valueName, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) : base(valueName, valueType, fieldType, memberInfo, flags) { } @@ -240,7 +250,7 @@ public override bool IsNull(DocumentObject dom) /// internal class ValueTypeDescriptor : ValueDescriptor { - internal ValueTypeDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) + internal ValueTypeDescriptor(string valueName, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) : base(valueName, valueType, fieldType, memberInfo, flags) { @@ -315,7 +325,7 @@ public override bool IsNull(DocumentObject dom) /// internal class DocumentObjectDescriptor : ValueDescriptor { - internal DocumentObjectDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) + internal DocumentObjectDescriptor(string valueName, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) : base(valueName, valueType, fieldType, memberInfo, flags) { @@ -416,7 +426,7 @@ public override bool IsNull(DocumentObject dom) /// internal class DocumentObjectCollectionDescriptor : ValueDescriptor { - internal DocumentObjectCollectionDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) + internal DocumentObjectCollectionDescriptor(string valueName, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags) : base(valueName, valueType, fieldType, memberInfo, flags) { diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/Cell.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/Cell.cs index f5f77511..271b6c89 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/Cell.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/Cell.cs @@ -333,6 +333,16 @@ public Shading Shading [DV] internal Shading shading; + /// + /// Specifies if the Cell should be rendered as a rounded corner. + /// + public RoundedCorner RoundedCorner { + get { return (RoundedCorner)this.roundedCorner.Value; } + set { this.roundedCorner.Value = (int)value; } + } + [DV(Type = typeof(RoundedCorner))] + internal NEnum roundedCorner = NEnum.NullValue(typeof(RoundedCorner)); + /// /// Gets or sets the number of cells to be merged right. /// @@ -420,6 +430,9 @@ internal override void Serialize(Serializer serializer) if (!this.IsNull("Shading")) this.shading.Serialize(serializer); + if (!this.roundedCorner.IsNull) + serializer.WriteSimpleAttribute("RoundedCorner", this.RoundedCorner); + serializer.EndAttributes(pos); pos = serializer.BeginContent(); diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/enums/RoundedCorner.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/enums/RoundedCorner.cs new file mode 100644 index 00000000..c39f3fe9 --- /dev/null +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Tables/enums/RoundedCorner.cs @@ -0,0 +1,46 @@ +#region MigraDoc - Creating Documents on the Fly +// +// Authors: +// Stefan Lange (mailto:Stefan.Lange@PdfSharpCore.com) +// Klaus Potzesny (mailto:Klaus.Potzesny@PdfSharpCore.com) +// David Stephensen (mailto:David.Stephensen@PdfSharpCore.com) +// +// Copyright (c) 2001-2009 empira Software GmbH, Cologne (Germany) +// +// http://www.PdfSharpCore.com +// http://www.migradoc.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 + +namespace MigraDocCore.DocumentObjectModel.Tables +{ + /// + /// Specifies if the Cell should be rendered as a rounded corner. + /// + public enum RoundedCorner + { + None, + TopLeft, + TopRight, + BottomLeft, + BottomRight + } +} diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Visitors/PdfFlattenVisitor.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Visitors/PdfFlattenVisitor.cs index 4143e638..054fa63e 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Visitors/PdfFlattenVisitor.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel.Visitors/PdfFlattenVisitor.cs @@ -118,20 +118,21 @@ internal override void VisitDocumentObjectCollection(DocumentObjectCollection el ++insertedObjects; break; + case Chars.ZeroWidthSpace: case '-': //minus elements.InsertObject(idx + insertedObjects, new Text(currentString + ch)); ++insertedObjects; currentString = ""; break; - case '': //soft hyphen + case Chars.SoftHyphen: //soft hyphen if (currentString != "") { elements.InsertObject(idx + insertedObjects, new Text(currentString)); ++insertedObjects; currentString = ""; } - elements.InsertObject(idx + insertedObjects, new Text("")); + elements.InsertObject(idx + insertedObjects, new Text(new string(Chars.SoftHyphen, 1))); ++insertedObjects; currentString = ""; break; diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Border.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Border.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Border.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Border.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Borders.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Borders.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Borders.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Borders.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Character.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Character.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Character.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Character.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Chars.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Chars.cs similarity index 96% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Chars.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Chars.cs index 13e3709c..9bd963a1 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Chars.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Chars.cs @@ -77,7 +77,8 @@ public sealed class Chars public const char NumberSign = '#'; public const char Question = '?'; public const char Hyphen = '-'; // char(45) - public const char SoftHyphen = ''; // char(173) + public const char SoftHyphen = '\u00ad'; // char(173) public const char Currency = ''; + public const char ZeroWidthSpace = '\u200b'; } } diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Color.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Color.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Color.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Color.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Colors.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Colors.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Colors.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Colors.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DdlEncoder.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DdlEncoder.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DdlEncoder.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DdlEncoder.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DdlVisibleAttribute.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DdlVisibleAttribute.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DdlVisibleAttribute.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DdlVisibleAttribute.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Document.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Document.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Document.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Document.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentElements.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentElements.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentElements.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentElements.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentInfo.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentInfo.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentInfo.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentInfo.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentObject.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentObject.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentObject.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentObject.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentObjectCollection.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentObjectCollection.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentObjectCollection.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentObjectCollection.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentRelations.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentRelations.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/DocumentRelations.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/DocumentRelations.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Font.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Font.cs similarity index 88% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Font.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Font.cs index b3d6092b..a3b1a237 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Font.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Font.cs @@ -110,6 +110,9 @@ internal void ApplyFont(Font font, Font refFont) if (!font.underline.IsNull && (refFont == null || font.Underline != refFont.Underline)) this.Underline = font.Underline; + if (!font.strikethrough.IsNull && (refFont == null || font.Strikethrough != refFont.Strikethrough)) + this.Strikethrough = font.Strikethrough; + if (!font.color.IsNull && (refFont == null || font.Color.Argb != refFont.Color.Argb)) this.Color = font.Color; } @@ -142,6 +145,9 @@ public void ApplyFont(Font font) if (!font.underline.IsNull) this.Underline = font.Underline; + if (!font.strikethrough.IsNull) + this.Strikethrough = font.Strikethrough; + if (!font.color.IsNull) this.Color = font.Color; } @@ -244,6 +250,15 @@ public bool Subscript [DV] internal NBool subscript = NBool.NullValue; + + public Strikethrough Strikethrough + { + get { return (Strikethrough)this.strikethrough.Value; } + set { this.strikethrough.Value = (int)value; } + } + [DV(Type = typeof(Strikethrough))] + internal NEnum strikethrough = NEnum.NullValue(typeof(Strikethrough)); + // + .Name = "Verdana" // + .Size = 8 // + .Bold = False @@ -269,23 +284,6 @@ public bool Subscript // .Animation = wdAnimationNone #endregion -#if !PORTABLE - /// - /// Gets a value indicating whether the specified font exists. - /// - public static bool Exists(string fontName) - { - System.Drawing.FontFamily[] families = System.Drawing.FontFamily.Families; - foreach (System.Drawing.FontFamily family in families) - { - if (String.Compare(family.Name, fontName, true) == 0) - return true; - } - return false; - } -#endif - - #region Internal /// /// Get a bitmask of all non-null properties. @@ -379,6 +377,9 @@ internal void Serialize(Serializer serializer, Font font) if (!this.underline.IsNull) serializer.WriteSimpleAttribute("Underline", this.Underline); + if (!this.strikethrough.IsNull) + serializer.WriteSimpleAttribute("Strikethrough", this.Strikethrough); + if (!this.superscript.IsNull) serializer.WriteSimpleAttribute("Superscript", this.Superscript); @@ -394,7 +395,6 @@ internal void Serialize(Serializer serializer, Font font) { int pos = serializer.BeginContent("Font"); -#if true // Don't write null values if font is null. // Do write null values if font is not null! if ((!name.IsNull && Name != String.Empty && font == null) || @@ -417,6 +417,9 @@ internal void Serialize(Serializer serializer, Font font) if (!underline.IsNull && (font == null || Underline != font.Underline || font.underline.IsNull)) serializer.WriteSimpleAttribute("Underline", Underline); + if (!strikethrough.IsNull && (font == null || Strikethrough != font.Strikethrough || font.strikethrough.IsNull)) + serializer.WriteSimpleAttribute("Strikethrough", Strikethrough); + if (!superscript.IsNull && (font == null || Superscript != font.Superscript || font.superscript.IsNull)) serializer.WriteSimpleAttribute("Superscript", Superscript); @@ -425,31 +428,7 @@ internal void Serialize(Serializer serializer, Font font) if (!color.IsNull && (font == null || this.Color.Argb != font.Color.Argb))// && this.Color.RGB != Color.Transparent.RGB) serializer.WriteSimpleAttribute("Color", this.Color); -#else - if ((!this.name.IsNull && this.Name != String.Empty) && (font == null || this.Name != font.Name)) - serializer.WriteSimpleAttribute("Name", this.Name); - - if (!this.size.IsNull && (font == null || this.Size != font.Size)) - serializer.WriteSimpleAttribute("Size", this.Size); - //NBool and NEnum have to be compared directly to check whether the value Null is - if (!this.bold.IsNull && (font == null || this.Bold != font.Bold)) - serializer.WriteSimpleAttribute("Bold", this.Bold); - if (!this.italic.IsNull && (font == null || this.Italic != font.Italic)) - serializer.WriteSimpleAttribute("Italic", this.Italic); - - if (!this.underline.IsNull && (font == null || this.Underline != font.Underline)) - serializer.WriteSimpleAttribute("Underline", this.Underline); - - if (!this.superscript.IsNull && (font == null || this.Superscript != font.Superscript)) - serializer.WriteSimpleAttribute("Superscript", this.Superscript); - - if (!this.subscript.IsNull && (font == null || this.Subscript != font.Subscript)) - serializer.WriteSimpleAttribute("Subscript", this.Subscript); - - if (!this.color.IsNull && (font == null || this.Color.Argb != font.Color.Argb))// && this.Color.RGB != Color.Transparent.RGB) - serializer.WriteSimpleAttribute("Color", this.Color); -#endif serializer.EndContent(pos); } } diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Footnote.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Footnote.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Footnote.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Footnote.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/FormattedText.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/FormattedText.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/FormattedText.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/FormattedText.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/HeaderFooter.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/HeaderFooter.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/HeaderFooter.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/HeaderFooter.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/HeadersFooters.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/HeadersFooters.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/HeadersFooters.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/HeadersFooters.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Hyperlink.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Hyperlink.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Hyperlink.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Hyperlink.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ImageHelper.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ImageHelper.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ImageHelper.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ImageHelper.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ListInfo.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ListInfo.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ListInfo.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ListInfo.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/PageBreak.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/PageBreak.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/PageBreak.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/PageBreak.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/PageSetup.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/PageSetup.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/PageSetup.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/PageSetup.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Paragraph.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Paragraph.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Paragraph.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Paragraph.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ParagraphElements.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ParagraphElements.cs similarity index 99% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ParagraphElements.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ParagraphElements.cs index c55fbf55..3397112a 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ParagraphElements.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ParagraphElements.cs @@ -86,7 +86,6 @@ public Text AddText(string text) { if (text == null) throw new ArgumentNullException("text"); -#if true Text txt = null; string[] lines = text.Split('\n'); int lineCount = lines.Length; @@ -108,12 +107,6 @@ public Text AddText(string text) this.AddLineBreak(); } return txt; -#else - Text txt = new Text(); - txt.Content = text; - this.Add(txt); - return txt; -#endif } /// diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ParagraphFormat.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ParagraphFormat.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/ParagraphFormat.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/ParagraphFormat.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Section.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Section.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Section.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Section.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Sections.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Sections.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Sections.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Sections.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Serializer.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Serializer.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Serializer.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Serializer.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Shading.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Shading.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Shading.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Shading.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Style.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Style.cs similarity index 99% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Style.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Style.cs index 4f62f8b0..a27be459 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Style.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Style.cs @@ -409,15 +409,10 @@ internal override void Serialize(Serializer serializer) string name = DdlEncoder.QuoteIfNameContainsBlanks(this.Name); string baseName = DdlEncoder.QuoteIfNameContainsBlanks(this.BaseStyle); serializer.WriteLine(name + " : " + baseName); - -#if true Style refStyle0 = Document.Styles[Document.Styles.GetIndex(this.baseStyle.Value)]; refStyle = Document.Styles[this.baseStyle.Value]; refFormat = refStyle != null ? refStyle.ParagraphFormat : null; refFont = refStyle.Font; -#else - refFormat = null; -#endif } serializer.BeginContent(); diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/StyleNames.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/StyleNames.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/StyleNames.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/StyleNames.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Styles.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Styles.cs similarity index 99% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Styles.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Styles.cs index 3743cc56..e4f58398 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Styles.cs +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Styles.cs @@ -228,6 +228,7 @@ internal void SetupStyles() style.Font.Color = Colors.Black; style.Font.Subscript = false; style.Font.Superscript = false; + style.Font.Strikethrough = Strikethrough.None; style.ParagraphFormat.Alignment = ParagraphAlignment.Left; style.ParagraphFormat.FirstLineIndent = 0; style.ParagraphFormat.LeftIndent = 0; diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TabStop.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TabStop.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TabStop.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TabStop.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TabStops.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TabStops.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TabStops.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TabStops.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Text.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Text.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Text.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Text.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TextMeasurement.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TextMeasurement.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/TextMeasurement.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/TextMeasurement.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Unit.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Unit.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Unit.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/Unit.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BorderStyle.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BorderStyle.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BorderStyle.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BorderStyle.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BorderType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BorderType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BorderType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BorderType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BreakType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BreakType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/BreakType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/BreakType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ColorName.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ColorName.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ColorName.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ColorName.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/DomMsgID.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/DomMsgID.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/DomMsgID.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/DomMsgID.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FontProperties.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FontProperties.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FontProperties.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FontProperties.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteLocation.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteLocation.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteLocation.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteLocation.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteNumberStyle.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteNumberStyle.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteNumberStyle.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteNumberStyle.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteNumberingRule.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteNumberingRule.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/FootnoteNumberingRule.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/FootnoteNumberingRule.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/HeaderFooterIndex.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/HeaderFooterIndex.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/HeaderFooterIndex.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/HeaderFooterIndex.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/HyperlinkType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/HyperlinkType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/HyperlinkType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/HyperlinkType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/LineSpacingRule.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/LineSpacingRule.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/LineSpacingRule.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/LineSpacingRule.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ListType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ListType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ListType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ListType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/Orientation.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Orientation.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/Orientation.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Orientation.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/OutlineLevel.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/OutlineLevel.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/OutlineLevel.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/OutlineLevel.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/PageFormat.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/PageFormat.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/PageFormat.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/PageFormat.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ParagraphAlignment.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ParagraphAlignment.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/ParagraphAlignment.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/ParagraphAlignment.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Strikethrough.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Strikethrough.cs new file mode 100644 index 00000000..a58cfd52 --- /dev/null +++ b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Strikethrough.cs @@ -0,0 +1,66 @@ +#region MigraDoc - Creating Documents on the Fly +// +// Authors: +// Stefan Lange (mailto:Stefan.Lange@PdfSharpCore.com) +// Klaus Potzesny (mailto:Klaus.Potzesny@PdfSharpCore.com) +// David Stephensen (mailto:David.Stephensen@PdfSharpCore.com) +// +// Copyright (c) 2001-2009 empira Software GmbH, Cologne (Germany) +// +// http://www.PdfSharpCore.com +// http://www.migradoc.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.Collections.Generic; +using System.Text; + +namespace MigraDocCore.DocumentObjectModel +{ + /// + /// Specify the strike out type for font + /// + public enum Strikethrough + { + None, + Single, + Words, + Dotted, + Dash, + DotDash, + DotDotDash, + + /* --- unsupported --- + Double = 3, + Thick = 6, + Wavy = 11, + WavyHeavy = 27, + DottedHeavy = 20, + DashHeavy = 23, + DotDashHeavy = 25, + DotDotDashHeavy = 26, + DashLong = 39, + DashLongHeavy = 55, + WavyDouble = 43 + */ + } +} diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/StyleType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/StyleType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/StyleType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/StyleType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/SymbolName.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/SymbolName.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/SymbolName.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/SymbolName.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TabAlignment.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TabAlignment.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TabAlignment.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TabAlignment.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TabLeader.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TabLeader.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TabLeader.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TabLeader.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TextFormat.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TextFormat.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/TextFormat.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/TextFormat.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/Underline.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Underline.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/Underline.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/Underline.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/UnitType.cs b/MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/UnitType.cs similarity index 100% rename from MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/enums/UnitType.cs rename to MigraDocCore.DocumentObjectModel/MigraDoc.DocumentObjectModel/enums/UnitType.cs diff --git a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Color.backup.cs b/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Color.backup.cs deleted file mode 100644 index 23a09933..00000000 --- a/MigraDocCore.DocumentObjectModel/MigraDoc/MigraDoc.DocumentObjectModel/Color.backup.cs +++ /dev/null @@ -1,323 +0,0 @@ -#region MigraDoc - Creating Documents on the Fly -// -// Authors: -// Stefan Lange (mailto:Stefan.Lange@PdfSharpCore.com) -// Klaus Potzesny (mailto:Klaus.Potzesny@PdfSharpCore.com) -// David Stephensen (mailto:David.Stephensen@PdfSharpCore.com) -// -// Copyright (c) 2001-2009 empira Software GmbH, Cologne (Germany) -// -// http://www.PdfSharpCore.com -// http://www.migradoc.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.Collections; -using System.Diagnostics; -using System.Reflection; -using MigraDocCore.DocumentObjectModel.Internals; - -#if old -namespace MigraDocCore.DocumentObjectModel -{ - /// - /// The Color class represents an ARGB color value. - /// - public struct Color : INullableValue - { - /// - /// Initializes a new instance of the Color class. - /// - public Color(uint argb) - { - this.argb = argb; - } - - /// - /// Initializes a new instance of the Color class. - /// - public Color(byte r, byte g, byte b) - { - this.argb = 0xFF000000 | ((uint)r << 16) | ((uint)g << 8) | (uint)b; - } - - /// - /// Initializes a new instance of the Color class. - /// - public Color(byte a, byte r, byte g, byte b) - { - this.argb = ((uint)a << 24) | ((uint)r << 16) | ((uint)g << 8) | (uint)b; - } - - /// - /// Determines whether this color is empty. - /// - public bool IsEmpty - { - get { return this == Color.Empty; } - } - - /// - /// Returns the value. - /// - object INullableValue.GetValue() - { - return this; - } - - /// - /// Sets the given value. - /// - void INullableValue.SetValue(object value) - { - if (value is uint) - this.argb = (uint)value; - else - this = Color.Parse(value.ToString()); - } - - /// - /// Resets this instance, i.e. IsNull() will return true afterwards. - /// - void INullableValue.SetNull() - { - this = Color.Empty; - } - - /// - /// Determines whether this instance is null (not set). - /// - bool INullableValue.IsNull - { - get { return this == Color.Empty; } - } - - /// - /// Determines whether this instance is null (not set). - /// - internal bool IsNull - { - get { return this == Color.Empty; } - } - - /// - /// Gets or sets the ARGB value. - /// - public uint Argb - { - get { return argb; } - set { argb = value; } - } - uint argb; - - /// - /// Gets or sets the RGB value. - /// - public uint RGB - { - get { return argb; } - set { argb = value; } - } - - /// - /// Calls base class Equals. - /// - public override bool Equals(Object obj) - { - if (obj is Color) - return this.argb == ((Color)obj).argb; - return false; - } - - /// - /// Gets the ARGB value that this Color instance represents. - /// - public override int GetHashCode() - { - return (int)this.argb; - } - - /// - /// Compares two color objects. True if both argb values are equal, false otherwise. - /// - public static bool operator ==(Color clr1, Color clr2) - { - return clr1.argb == clr2.argb; - } - - /// - /// Compares two color objects. True if both argb values are not equal, false otherwise. - /// - public static bool operator !=(Color clr1, Color clr2) - { - return clr1.argb != clr2.argb; - } - - /// - /// Parses the string and returns a color object. - /// Throws ArgumentException if color is invalid. - /// - /// integer, hex or color name. - public static Color Parse(string color) - { - if (color == null) - throw new ArgumentNullException("color"); - if (color == "") - throw new ArgumentException("color"); - - try - { - uint clr = 0; - // Must use Enum.Parse because Enum.IsDefined is case sensitive - try - { - object obj = Enum.Parse(typeof(ColorName), color, true); - clr = (uint)obj; - return new Color(clr); - } - catch - { - //ignore exception cause it's not a ColorName. - } - - System.Globalization.NumberStyles numberStyle = System.Globalization.NumberStyles.Integer; - string number = color.ToLower(); - if (number.StartsWith("0x")) - { - numberStyle = System.Globalization.NumberStyles.HexNumber; - number = color.Substring(2); - } - clr = uint.Parse(number, numberStyle); - return new Color(clr); - } - catch (FormatException ex) - { - throw new ArgumentException(DomSR.InvalidColorString(color), ex); - } - } - - /// - /// Gets the alpha (transparency) part of the Color. - /// - public uint A - { - get { return (this.argb & 0xFF000000) >> 24; } - } - - /// - /// Gets the red part of the Color. - /// - public uint R - { - get { return (this.argb & 0xFF0000) >> 16; } - } - - /// - /// Gets the green part of the Color. - /// - public uint G - { - get { return (this.argb & 0x00FF00) >> 8; } - } - - /// - /// Gets the blue part of the Color. - /// - public uint B - { - get { return this.argb & 0x0000FF; } - } - - /// - /// Gets a non transparent color brightened in terms of transparency if any is given(A < 255), - /// otherwise this instance itself. - /// - public Color GetMixedTransparencyColor() - { - int alpha = (int)A; - if (alpha == 0xFF) - return this; - - int red = (int)R; - int green = (int)G; - int blue = (int)B; - - double whiteFactor = 1 - alpha / 255.0; - - red = (int)(red + (255 - red) * whiteFactor); - green = (int)(green + (255 - green) * whiteFactor); - blue = (int)(blue + (255 - blue) * whiteFactor); - return new Color((uint)(0xFF << 24 | (red << 16) | (green << 8) | blue)); - } - - /// - /// Writes the Color object in its hexadecimal value. - /// - public override string ToString() - { - if (stdColors == null) - { - Array colorNames = Enum.GetNames(typeof(ColorName)); - Array colorValues = Enum.GetValues(typeof(ColorName)); - int count = colorNames.GetLength(0); - stdColors = new Hashtable(count); - for (int index = 0; index < count; index++) - { - string c = (string)colorNames.GetValue(index); - uint d = (uint)colorValues.GetValue(index); - // Some color are double named... - // Aqua == Cyan - // Fuchsia == Magenta - if (!stdColors.ContainsKey(d)) - stdColors.Add(d, c); - } - } - if (stdColors.ContainsKey(argb)) - return (string)stdColors[argb]; - else - { - if ((this.argb & 0xFF000000) == 0xFF000000) - return "RGB(" + - ((this.argb & 0xFF0000) >> 16).ToString() + "," + - ((this.argb & 0x00FF00) >> 8).ToString() + "," + - (this.argb & 0x0000FF).ToString() + ")"; - else - return "0x" + argb.ToString("X"); - } - } - static Hashtable stdColors; - - /// - /// Creates a color from an existing color with a new alpha (transparency) value. - /// - public static Color FromColor(byte a, Color clr) - { - return new Color(a, (byte)clr.R, (byte)clr.G, (byte)clr.B); - } - - /// - /// Represents a null color. - /// - public static readonly Color Empty = new Color(0); - } -} -#endif \ No newline at end of file diff --git a/MigraDocCore.DocumentObjectModel/MigraDocCore.DocumentObjectModel.csproj b/MigraDocCore.DocumentObjectModel/MigraDocCore.DocumentObjectModel.csproj index 1b125c95..5646487b 100644 --- a/MigraDocCore.DocumentObjectModel/MigraDocCore.DocumentObjectModel.csproj +++ b/MigraDocCore.DocumentObjectModel/MigraDocCore.DocumentObjectModel.csproj @@ -1,33 +1,36 @@  - netstandard1.3;netstandard2.0;netcoreapp3.1;net5.0 + netstandard2.0;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + false True Stefan Steiger and Contributors MigraDocCore.DocumentObjectModel for .NET Core MigraDocCore.DocumentObjectModel was ported from MigraDoc version 1.32 Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany) - LICENCE.md + README.md + LICENSE.md https://github.com/ststeiger/PdfSharpCore https://github.com/ststeiger/PdfSharpCore MigraDocCore.DocumentObjectModel was ported from MigraDoc version 1.32 MigraDocCore.DocumentObjectModel for .NET Core + true + false - TRACE;DEBUG;NETCOREAPP1_1;PORTABLE + TRACE;DEBUG; - TRACE;RELEASE;NETCOREAPP1_1;PORTABLE + TRACE;RELEASE; - - - + + diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering.ChartMapper/FontMapper.cs b/MigraDocCore.Rendering/MigraDoc.Rendering.ChartMapper/FontMapper.cs index fa764f55..7517ded1 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering.ChartMapper/FontMapper.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering.ChartMapper/FontMapper.cs @@ -60,6 +60,7 @@ void MapObject(Font font, DocumentObjectModel.Font domFont) font.Size = domFont.Size.Point; font.Subscript = domFont.Subscript; font.Superscript = domFont.Superscript; + font.Strikethrough = (Strikethrough)domFont.Strikethrough; font.Underline = (Underline)domFont.Underline; } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering.UnitTest/TestParagraphRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering.UnitTest/TestParagraphRenderer.cs index e5a231b6..101379f8 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering.UnitTest/TestParagraphRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering.UnitTest/TestParagraphRenderer.cs @@ -48,7 +48,7 @@ public static void Formatted(string pdfOutputFile) internal static void FillFormattedParagraph(Paragraph par) { - for (int idx = 0; idx <= 140; ++idx) + for (int idx = 0; idx <= 200; ++idx) { if (idx < 60) { @@ -61,12 +61,42 @@ internal static void FillFormattedParagraph(Paragraph par) par.AddText((idx).ToString()); par.AddText(" "); } - else + else if (idx < 140) { FormattedText formText = par.AddFormattedText((idx).ToString(), TextFormat.Italic); formText.Font.Size = 6; formText.AddText(" "); } + // Strikethrough tests + else if (idx < 150) + { + FormattedText formText = par.AddFormattedText((idx).ToString()); + formText.Font.Size = 16; + formText.Font.Strikethrough = Strikethrough.Single; + formText.AddText(" "); + } + else if (idx < 160) + { + FormattedText formText = par.AddFormattedText((idx).ToString()); + formText.Font.Size = 8; + formText.Font.Strikethrough = Strikethrough.DotDash; + formText.AddText(" "); + } + else if (idx < 170) + { + FormattedText formText = par.AddFormattedText((idx).ToString()); + formText.Font.Size = 14; + formText.Font.Strikethrough = Strikethrough.DotDotDash; + formText.AddText(" "); + } + else if (idx < 180) + { + FormattedText formText = par.AddFormattedText((idx).ToString()); + formText.Font.Size = 20; + formText.Font.Strikethrough = Strikethrough.Dotted; + formText.AddText(" "); + } + if (idx % 50 == 0) par.AddLineBreak(); } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/Area.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/Area.cs index ab2ade53..565baa42 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/Area.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/Area.cs @@ -36,7 +36,7 @@ namespace MigraDocCore.Rendering /// /// Abstract base class for all areas to render in. /// - internal abstract class Area + public abstract class Area { internal Area() { @@ -45,7 +45,7 @@ internal Area() /// /// Gets the left boundary of the area. /// - internal abstract XUnit X + public abstract XUnit X { get; set; @@ -54,7 +54,7 @@ internal abstract XUnit X /// /// Gets the top boundary of the area. /// - internal abstract XUnit Y + public abstract XUnit Y { get; set; @@ -74,7 +74,7 @@ internal abstract XUnit Y /// /// Gets or sets the height of the smallest rectangle containing the area. /// - internal abstract XUnit Height + public abstract XUnit Height { get; set; @@ -83,7 +83,7 @@ internal abstract XUnit Height /// /// Gets or sets the width of the smallest rectangle containing the area. /// - internal abstract XUnit Width + public abstract XUnit Width { get; set; @@ -152,7 +152,7 @@ internal override Rectangle GetFittingRect(XUnit yPosition, XUnit height) /// /// Gets or sets the left boundary of the rectangle. /// - internal override XUnit X + public override XUnit X { get { return this.x; } set { this.x = value; } @@ -162,7 +162,7 @@ internal override XUnit X /// /// Gets or sets the top boundary of the rectangle. /// - internal override XUnit Y + public override XUnit Y { get { return this.y; } set { this.y = value; } @@ -172,7 +172,7 @@ internal override XUnit Y /// /// Gets or sets the top boundary of the rectangle. /// - internal override XUnit Width + public override XUnit Width { get { return this.width; } set { this.width = value; } @@ -182,7 +182,7 @@ internal override XUnit Width /// /// Gets or sets the height of the rectangle. /// - internal override XUnit Height + public override XUnit Height { get { return this.height; } set { this.height = value; } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/BordersRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/BordersRenderer.cs index 2fc53e1c..d18de38c 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/BordersRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/BordersRenderer.cs @@ -34,6 +34,7 @@ using PdfSharpCore.Drawing; using MigraDocCore.DocumentObjectModel.IO; using MigraDocCore.DocumentObjectModel.Internals; +using MigraDocCore.DocumentObjectModel.Tables; namespace MigraDocCore.Rendering { @@ -180,7 +181,47 @@ internal void RenderDiagonally(BorderType type, XUnit left, XUnit top, XUnit wid this.gfx.Restore(state); } - private XPen GetPen(BorderType type) + internal void RenderRounded(RoundedCorner roundedCorner, XUnit x, XUnit y, XUnit width, XUnit height) + { + if (roundedCorner == RoundedCorner.None) + return; + + // As source we use the vertical borders. + // If not set originally, they have been set to the horizontal border values in TableRenderer.EqualizeRoundedCornerBorders(). + BorderType borderType = BorderType.Top; + if (roundedCorner == RoundedCorner.TopLeft || roundedCorner == RoundedCorner.BottomLeft) + borderType = BorderType.Left; + if (roundedCorner == RoundedCorner.TopRight || roundedCorner == RoundedCorner.BottomRight) + borderType = BorderType.Right; + + XUnit borderWidth = GetWidth(borderType); + XPen borderPen = GetPen(borderType); + + if (borderWidth == 0) + return; + + x -= borderWidth / 2; + y -= borderWidth / 2; + XUnit ellipseWidth = width * 2 + borderWidth; + XUnit ellipseHeight = height * 2 + borderWidth; + + switch (roundedCorner) { + case RoundedCorner.TopLeft: + this.gfx.DrawArc(borderPen, new XRect(x, y, ellipseWidth, ellipseHeight), 180, 90); + break; + case RoundedCorner.TopRight: + this.gfx.DrawArc(borderPen, new XRect(x - width, y, ellipseWidth, ellipseHeight), 270, 90); + break; + case RoundedCorner.BottomRight: + this.gfx.DrawArc(borderPen, new XRect(x - width, y - height, ellipseWidth, ellipseHeight), 0, 90); + break; + case RoundedCorner.BottomLeft: + this.gfx.DrawArc(borderPen, new XRect(x, y - height, ellipseWidth, ellipseHeight), 90, 90); + break; + } + } + + private XPen GetPen(BorderType type) { XUnit borderWidth = GetWidth(type); if (borderWidth == 0) diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/DocumentRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/DocumentRenderer.cs index 4ac383b4..e9d799fb 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/DocumentRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/DocumentRenderer.cs @@ -73,16 +73,7 @@ public void PrepareDocument() this.previousListNumbers[ListType.NumberList3] = 0; this.formattedDocument = new FormattedDocument(this.document, this); //REM: Size should not be necessary in this case. -#if true XGraphics gfx = XGraphics.CreateMeasureContext(new XSize(2000, 2000), XGraphicsUnit.Point, XPageDirection.Downwards); -#else -#if GDI - XGraphics gfx = XGraphics.FromGraphics(Graphics.FromHwnd(IntPtr.Zero), new XSize(2000, 2000)); -#endif -#if WPF - XGraphics gfx = XGraphics.FromDrawingContext(null, new XSize(2000, 2000), XGraphicsUnit.Point); -#endif -#endif // this.previousListNumber = int.MinValue; //gfx.MUH = this.unicode; //gfx.MFEH = this.fontEmbedding; @@ -183,6 +174,14 @@ public DocumentObject[] GetDocumentObjectsFromPage(int page) return documentObjects; } + /// + /// Gets the render information for document objects that get rendered on the specified page. + /// + public RenderInfo[] GetRenderInfoFromPage(int page) + { + return this.formattedDocument.GetRenderInfos(page); + } + /// /// Renders a single object to the specified graphics object at the given point. /// @@ -358,7 +357,6 @@ public PrepareDocumentProgressEventArgs(int value, int maximum) internal int ProgressMaximum; internal int ProgressCompleted; -#if true /// /// Gets or sets the private fonts of the document. /// @@ -369,6 +367,5 @@ public XPrivateFontCollection PrivateFonts } //[DV] internal XPrivateFontCollection privateFonts; -#endif } } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/FontHandler.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/FontHandler.cs index c87be070..eef28821 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/FontHandler.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/FontHandler.cs @@ -55,70 +55,6 @@ internal static XFont FontToXFont(Font font, XPrivateFontCollection pfc, PdfFontEncoding encoding) { XFont xFont = null; -#if GDI____ // done in PDFsharp -#if CACHE_FONTS - string signature = BuildSignature(font, unicode, fontEmbedding); - xFont = fontCache[signature] as XFont; - if (xFont == null) - { - XPdfFontOptions options = null; - options = new XPdfFontOptions(fontEmbedding, unicode); - XFontStyle style = GetXStyle(font); - xFont = new XFont(font.Name, font.Size, style, options); - fontCache[signature] = xFont; - } -#else - XPdfFontOptions options = null; - options = new XPdfFontOptions(encoding, fontEmbedding); - XFontStyle style = GetXStyle(font); - if (pfc != null && pfc.PrivateFontCollection != null) - { - // Is it a private font? - try - { - foreach (System.Drawing.FontFamily ff in pfc.PrivateFontCollection.Families) - { - if (String.Compare(ff.Name, font.Name, true) == 0) - { - xFont = new XFont(ff, font.Size, style, options, pfc); - break; - } - } - } - catch - { -#if DEBUG - pfc.GetType(); -#endif - } - } -#endif -#endif - -#if WPF___ - XPdfFontOptions options = null; - options = new XPdfFontOptions(encoding, fontEmbedding); - XFontStyle style = GetXStyle(font); - //if (pfc != null && - // pfc.PrivateFontCollection != null) - //{ - // // Is it a private font? - // try - // { - // foreach (System.Drawing.FontFamily ff in pfc.PrivateFontCollection.Families) - // { - // if (String.Compare(ff.Name, font.Name, true) == 0) - // { - // xFont = new XFont(ff, font.Size, style, options, pfc); - // break; - // } - // } - // } - // catch - // { - // } - //} -#endif // #PFC XPdfFontOptions options = null; @@ -176,18 +112,6 @@ internal static XFont ToSubSuperFont(XFont font) // #PFC return new XFont(font.Name, size, font.Style, font.PdfOptions); - -// //THHO4STLA: falscher Konstruktor! -// // => wg. pfc FontFamily verwenden! -//#if GDI -//#warning falscher Konstruktor! -// // nur GDI oder immer??? -// if (font.GdiFamily != null && font.PrivateFontCollection != null) -// return new XFont(font.GdiFamily, size, font.Style, font.PdfOptions, font.PrivateFontCollection); -// return new XFont(font.Name, size, font.Style, font.PdfOptions); -//#else -// return new XFont(font.Name, size, font.Style, font.PdfOptions); -//#endif } internal static XBrush FontColorToXBrush(Font font) diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/FormattedDocument.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/FormattedDocument.cs index d9885b69..b7d1b411 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/FormattedDocument.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/FormattedDocument.cs @@ -580,17 +580,13 @@ bool PositionHorizontallyToPage(LayoutInfo layoutInfo) switch (align) { case ElementAlignment.Near: -#if true // Allow negative offsets (supporting "Anschnitt" for images) if (layoutInfo.HorizontalReference == HorizontalReference.Page || layoutInfo.HorizontalReference == HorizontalReference.PageMargin) xPos = layoutInfo.MarginLeft; // Ignore layoutInfo.Left if absolute position is specified else xPos = Math.Max(layoutInfo.MarginLeft, layoutInfo.Left); -#else - //!!!delTHHO 22.10.2008 - xPos = Math.Max(layoutInfo.MarginLeft, layoutInfo.Left); -#endif + layoutInfo.ContentArea.X = xPos; break; diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/LayoutInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/LayoutInfo.cs index a9ad34bb..ecd45032 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/LayoutInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/LayoutInfo.cs @@ -36,7 +36,7 @@ namespace MigraDocCore.Rendering /// /// Abstract base class to serve as a layoutable unit. /// - internal class LayoutInfo + public class LayoutInfo { internal LayoutInfo() { @@ -125,7 +125,7 @@ internal XUnit MarginLeft /// /// Gets or sets the Area needed by the content (including padding and borders for e.g. paragraphs). /// - internal Area ContentArea + public Area ContentArea { get { return this.contentArea; } set { this.contentArea = value; } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/PageBreakRenderInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/PageBreakRenderInfo.cs index a1aa5797..f92f3d87 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/PageBreakRenderInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/PageBreakRenderInfo.cs @@ -47,7 +47,7 @@ internal override FormatInfo FormatInfo } internal PageBreakFormatInfo pageBreakFormatInfo; - internal override DocumentObject DocumentObject + public override DocumentObject DocumentObject { get { return this.pageBreak; } } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderInfo.cs index 4eee558b..c49da825 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderInfo.cs @@ -47,7 +47,7 @@ internal override FormatInfo FormatInfo } ParagraphFormatInfo formatInfo = new ParagraphFormatInfo(); - internal override DocumentObject DocumentObject + public override DocumentObject DocumentObject { get { return this.paragraph; } } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderer.cs index 96aeb6ba..2a3b7dd9 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/ParagraphRenderer.cs @@ -869,6 +869,7 @@ void RenderImage(Image image) RenderByInfos(this.currentXPosition, top, new RenderInfo[] { renderInfo }); RenderUnderline(contentArea.Width, true); + RenderStrikethrough(contentArea.Width, true); RealizeHyperlink(contentArea.Width); this.currentXPosition += contentArea.Width; @@ -907,6 +908,7 @@ void RenderSectionPagesField(SectionPagesField sectionPagesField) void RenderBookmarkField() { RenderUnderline(0, false); + RenderStrikethrough(0, false); } void RenderPageRefField(PageRefField pageRefField) @@ -946,6 +948,7 @@ void RenderSpace(Character character) void RenderLinebreak() { this.RenderUnderline(0, false); + this.RenderStrikethrough(0, false); this.RealizeHyperlink(0); } @@ -963,6 +966,7 @@ void RenderTab() { TabOffset tabOffset = NextTabOffset(); RenderUnderline(tabOffset.offset, false); + RenderStrikethrough(tabOffset.offset, false); RenderTabLeader(tabOffset); RealizeHyperlink(tabOffset.offset); this.currentXPosition += tabOffset.offset; @@ -1014,14 +1018,10 @@ void RenderTabLeader(TabOffset tabOffset) TabOffset NextTabOffset() { -#if false - TabOffset offset = - (TabOffset)this.tabOffsets[this.tabIdx]; -#else + TabOffset offset = this.tabOffsets.Count > this.tabIdx ? (TabOffset)this.tabOffsets[this.tabIdx] : new TabOffset(0, 0); -#endif ++this.tabIdx; return offset; } @@ -1069,12 +1069,14 @@ void RenderBlank() { XUnit wordDistance = this.CurrentWordDistance; RenderUnderline(wordDistance, false); + RenderStrikethrough(wordDistance, false); RealizeHyperlink(wordDistance); this.currentXPosition += wordDistance; } else { RenderUnderline(0, false); + RenderStrikethrough(0, false); RealizeHyperlink(0); } } @@ -1100,6 +1102,7 @@ void RenderWord(string word) this.gfx.DrawString(word, xFont, CurrentBrush, this.currentXPosition, CurrentBaselinePosition); XUnit wordWidth = MeasureString(word); RenderUnderline(wordWidth, true); + RenderStrikethrough(wordWidth, true); RealizeHyperlink(wordWidth); this.currentXPosition += wordWidth; } @@ -2119,7 +2122,6 @@ bool StartNewLine() this.lastTab = null; this.lastTabPosition = 0; this.currentYPosition += this.currentVerticalInfo.height; -#if true Rectangle rect = this.formattingArea.GetFittingRect(currentYPosition, this.currentVerticalInfo.height + BottomBorderOffset); if (rect == null) return false; @@ -2128,15 +2130,6 @@ bool StartNewLine() this.currentXPosition = StartXPosition; // depends on "currentVerticalInfo" this.currentVerticalInfo = new VerticalLineInfo(); this.currentVerticalInfo = CalcCurrentVerticalInfo(); -#else - if (this.formattingArea.GetFittingRect(currentYPosition, this.currentVerticalInfo.height + BottomBorderOffset) == null) - return false; - - this.currentVerticalInfo = new VerticalLineInfo(); - this.currentVerticalInfo = CalcCurrentVerticalInfo(); - this.isFirstLine = false; - this.currentXPosition = this.StartXPosition; -#endif this.startLeaf = this.currentLeaf; this.currentBlankCount = 0; this.currentWordsWidth = 0; @@ -2424,6 +2417,66 @@ bool UnderlinePenChanged(XPen pen) return pen.Width != this.currentUnderlinePen.Width; } + + void RenderStrikethrough(XUnit width, bool isWord) + { + XPen pen = GetStrikethroughPen(isWord); + + bool penChanged = StrikethroughPenChanged(pen); + if (penChanged) + { + if (this.currentStrikethroughPen != null) + EndStrikethrough(this.currentStrikethroughPen, this.currentXPosition); + + if (pen != null) + StartStrikethrough(this.currentXPosition); + + this.currentStrikethroughPen = pen; + } + + if (this.currentLeaf.Current == this.endLeaf.Current) + { + if (this.currentStrikethroughPen != null) + EndStrikethrough(this.currentStrikethroughPen, this.currentXPosition + width); + + this.currentStrikethroughPen = null; + } + } + + void StartStrikethrough(XUnit xPosition) + { + this.strikethroughStartPos = xPosition; + } + + void EndStrikethrough(XPen pen, XUnit xPosition) + { + XUnit yPosition = CurrentBaselinePosition; + yPosition -= pen.Width / 2; + yPosition -= this.currentVerticalInfo.descent; + + this.gfx.DrawLine(pen, this.strikethroughStartPos, yPosition, xPosition, yPosition); + } + + XPen currentStrikethroughPen = null; + XUnit strikethroughStartPos; + + bool StrikethroughPenChanged(XPen pen) + { + if (pen == null && this.currentStrikethroughPen == null) + return false; + + if (pen == null && this.currentStrikethroughPen != null) + return true; + + if (pen != null && this.currentStrikethroughPen == null) + return true; + + if (pen.Color != this.currentStrikethroughPen.Color) + return true; + + return pen.Width != this.currentStrikethroughPen.Width; + } + RenderInfo CurrentImageRenderInfo { get @@ -2488,6 +2541,47 @@ XPen GetUnderlinePen(bool isWord) return pen; } + XPen GetStrikethroughPen(bool isWord) + { + Font font = CurrentDomFont; + Strikethrough strikethroughType = font.Strikethrough; + if (strikethroughType == Strikethrough.None) + return null; + + if (strikethroughType == Strikethrough.Words && !isWord) + return null; + +#if noCMYK + XPen pen = new XPen(XColor.FromArgb(font.Color.Argb), font.Size / 16); +#else + XPen pen = new XPen(ColorHelper.ToXColor(font.Color, this.paragraph.Document.UseCmykColor), font.Size / 16); +#endif + switch (font.Strikethrough) + { + case Strikethrough.DotDash: + pen.DashStyle = XDashStyle.DashDot; + break; + + case Strikethrough.DotDotDash: + pen.DashStyle = XDashStyle.DashDotDot; + break; + + case Strikethrough.Dash: + pen.DashStyle = XDashStyle.Dash; + break; + + case Strikethrough.Dotted: + pen.DashStyle = XDashStyle.Dot; + break; + + case Strikethrough.Single: + default: + pen.DashStyle = XDashStyle.Solid; + break; + } + return pen; + } + private static XStringFormat StringFormat { get diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/PdfDocumentRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/PdfDocumentRenderer.cs index ce3be62c..c1da9717 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/PdfDocumentRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/PdfDocumentRenderer.cs @@ -139,20 +139,7 @@ void PrepareDocumentRenderer(bool prepareCompletely) /// public void RenderDocument() { -#if true PrepareRenderPages(); -#else - if (this.documentRenderer == null) - PrepareDocumentRenderer(); - - if (this.pdfDocument == null) - { - this.pdfDocument = new PdfDocument(); - this.pdfDocument.Info.Creator = VersionInfo.Creator; - } - - WriteDocumentInformation(); -#endif RenderPages(1, this.documentRenderer.FormattedDocument.PageCount); } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/RenderInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/RenderInfo.cs index 6aafe3c8..bdba26d5 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/RenderInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/RenderInfo.cs @@ -29,6 +29,7 @@ #endregion using System; +using System.Diagnostics; using MigraDocCore.DocumentObjectModel; using PdfSharpCore.Drawing; @@ -37,27 +38,27 @@ namespace MigraDocCore.Rendering /// /// Abstract base class for all classes that store rendering information. /// - internal abstract class RenderInfo + public abstract class RenderInfo { internal abstract FormatInfo FormatInfo { get; } - internal LayoutInfo LayoutInfo + public LayoutInfo LayoutInfo { get { return this.layoutInfo; } } LayoutInfo layoutInfo = new LayoutInfo(); - internal abstract DocumentObject DocumentObject + public abstract DocumentObject DocumentObject { get; } internal virtual void RemoveEnding() { - System.Diagnostics.Debug.Assert(false, "Unexpected call of RemoveEnding"); + Debug.Assert(false, "Unexpected call of RemoveEnding"); } internal static XUnit GetTotalHeight(RenderInfo[] renderInfos) diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/ShadingRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/ShadingRenderer.cs index 7d75a690..fe04ca6d 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/ShadingRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/ShadingRenderer.cs @@ -32,6 +32,7 @@ using PdfSharpCore.Drawing; using MigraDocCore.DocumentObjectModel; using MigraDocCore.DocumentObjectModel.IO; +using MigraDocCore.DocumentObjectModel.Tables; namespace MigraDocCore.Rendering { @@ -55,6 +56,42 @@ internal void Render(XUnit x, XUnit y, XUnit width, XUnit height) this.gfx.DrawRectangle(this.brush, x.Point, y.Point, width.Point, height.Point); } + internal void Render(XUnit x, XUnit y, XUnit width, XUnit height, RoundedCorner roundedCorner) + { + // If there is no rounded corner, we can use the usual Render method. + if (roundedCorner == RoundedCorner.None) { + Render(x, y, width, height); + return; + } + + if (this.shading == null || this.brush == null) + return; + + XGraphicsPath path = new XGraphicsPath(); + + switch (roundedCorner) { + case RoundedCorner.TopLeft: + path.AddArc(new XRect(x, y, width * 2, height * 2), 180, 90); // Error in CORE: _corePath.AddArc(). + path.AddLine(new XPoint(x + width, y), new XPoint(x + width, y + height)); + break; + case RoundedCorner.TopRight: + path.AddArc(new XRect(x - width, y, width * 2, height * 2), 270, 90); // Error in CORE: _corePath.AddArc(). + path.AddLine(new XPoint(x + width, y + height), new XPoint(x, y + height)); + break; + case RoundedCorner.BottomRight: + path.AddArc(new XRect(x - width, y - height, width * 2, height * 2), 0, 90); // Error in CORE: _corePath.AddArc(). + path.AddLine(new XPoint(x, y + height), new XPoint(x, y)); + break; + case RoundedCorner.BottomLeft: + path.AddArc(new XRect(x, y - height, width * 2, height * 2), 90, 90); // Error in CORE: _corePath.AddArc(). + path.AddLine(new XPoint(x, y), new XPoint(x + width, y)); + break; + } + + path.CloseFigure(); + this.gfx.DrawPath(this.brush, path); + } + private bool IsVisible() { if (!this.shading.IsNull("Visible")) diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/ShapeRenderInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/ShapeRenderInfo.cs index b5d7b92f..5aa0cc55 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/ShapeRenderInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/ShapeRenderInfo.cs @@ -44,7 +44,7 @@ internal ShapeRenderInfo() { } - internal override DocumentObject DocumentObject + public override DocumentObject DocumentObject { get { return this.shape; } } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderInfo.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderInfo.cs index 2cffcdfe..21eb35cb 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderInfo.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderInfo.cs @@ -49,7 +49,7 @@ internal override FormatInfo FormatInfo } private TableFormatInfo formatInfo = new TableFormatInfo(); - internal override DocumentObject DocumentObject + public override DocumentObject DocumentObject { get { return this.table; } } diff --git a/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderer.cs b/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderer.cs index 19e472ee..62c1416b 100644 --- a/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderer.cs +++ b/MigraDocCore.Rendering/MigraDoc.Rendering/TableRenderer.cs @@ -36,6 +36,7 @@ using MigraDocCore.DocumentObjectModel.Visitors; using MigraDocCore.DocumentObjectModel.Tables; using MigraDocCore.DocumentObjectModel.IO; +using MigraDocCore.DocumentObjectModel.Internals; namespace MigraDocCore.Rendering { @@ -114,10 +115,51 @@ void RenderCell(Cell cell) RenderBorders(cell, innerRect); } + private void EqualizeRoundedCornerBorders(Cell cell) { + // If any of a corner relevant border is set, we want to copy its values to the second corner relevant border, + // to ensure the innerWidth of the cell is the same, regardless of which border is used. + // If set, we use the vertical borders as source for the values, otherwise we use the horizontal borders. + RoundedCorner roundedCorner = cell.RoundedCorner; + + if (roundedCorner == RoundedCorner.None) + return; + + BorderType primaryBorderType = BorderType.Top, secondaryBorderType = BorderType.Top; + + if (roundedCorner == RoundedCorner.TopLeft || roundedCorner == RoundedCorner.BottomLeft) + primaryBorderType = BorderType.Left; + if (roundedCorner == RoundedCorner.TopRight || roundedCorner == RoundedCorner.BottomRight) + primaryBorderType = BorderType.Right; + + if (roundedCorner == RoundedCorner.TopLeft || roundedCorner == RoundedCorner.TopRight) + secondaryBorderType = BorderType.Top; + if (roundedCorner == RoundedCorner.BottomLeft || roundedCorner == RoundedCorner.BottomRight) + secondaryBorderType = BorderType.Bottom; + + // If both borders don't exist, there's nothing to do and we should not create one by accessing it. + if (!cell.Borders.HasBorder(primaryBorderType) && !cell.Borders.HasBorder(secondaryBorderType)) + return; + + // Get the borders. By using GV.ReadWrite we create the border, if not existing. + Border primaryBorder = (Border) cell.Borders.GetValue(primaryBorderType.ToString(), GV.ReadWrite); + Border secondaryBorder = (Border) cell.Borders.GetValue(secondaryBorderType.ToString(), GV.ReadWrite); + + Border source = primaryBorder.Visible ? primaryBorder : secondaryBorder.Visible ? secondaryBorder : null; + Border target = primaryBorder.Visible ? secondaryBorder : secondaryBorder.Visible ? primaryBorder : null; + + if (source == null || target == null) + return; + + target.Visible = source.Visible; + target.Width = source.Width; + target.Style = source.Style; + target.Color = source.Color; + } + void RenderShading(Cell cell, Rectangle innerRect) { - ShadingRenderer shadeRenderer = new ShadingRenderer(this.gfx, cell.Shading); - shadeRenderer.Render(innerRect.X, innerRect.Y, innerRect.Width, innerRect.Height); + ShadingRenderer shadeRenderer = new ShadingRenderer(this.gfx, cell.Shading); + shadeRenderer.Render(innerRect.X, innerRect.Y, innerRect.Width, innerRect.Height, cell.RoundedCorner); } void RenderBorders(Cell cell, Rectangle innerRect) @@ -134,10 +176,27 @@ void RenderBorders(Cell cell, Rectangle innerRect) XUnit topWidth = bordersRenderer.GetWidth(BorderType.Top); XUnit rightWidth = bordersRenderer.GetWidth(BorderType.Right); - bordersRenderer.RenderVertically(BorderType.Right, rightPos, topPos, bottomPos + bottomWidth - topPos); - bordersRenderer.RenderVertically(BorderType.Left, leftPos - leftWidth, topPos, bottomPos + bottomWidth - topPos); - bordersRenderer.RenderHorizontally(BorderType.Bottom, leftPos - leftWidth, bottomPos, rightPos + rightWidth + leftWidth - leftPos); - bordersRenderer.RenderHorizontally(BorderType.Top, leftPos - leftWidth, topPos - topWidth, rightPos + rightWidth + leftWidth - leftPos); + if (cell.RoundedCorner == RoundedCorner.TopLeft) + bordersRenderer.RenderRounded(cell.RoundedCorner, innerRect.X, innerRect.Y, innerRect.Width + rightWidth, innerRect.Height + bottomWidth); + else if (cell.RoundedCorner == RoundedCorner.TopRight) + bordersRenderer.RenderRounded(cell.RoundedCorner, innerRect.X - leftWidth, innerRect.Y, innerRect.Width + leftWidth, innerRect.Height + bottomWidth); + else if (cell.RoundedCorner == RoundedCorner.BottomLeft) + bordersRenderer.RenderRounded(cell.RoundedCorner, innerRect.X, innerRect.Y - topWidth, innerRect.Width + rightWidth, innerRect.Height + topWidth); + else if (cell.RoundedCorner == RoundedCorner.BottomRight) + bordersRenderer.RenderRounded(cell.RoundedCorner, innerRect.X - leftWidth, innerRect.Y - topWidth, innerRect.Width + leftWidth, innerRect.Height + topWidth); + + // Render horizontal and vertical borders only if touching no rounded corner. + if (cell.RoundedCorner != RoundedCorner.TopRight && cell.RoundedCorner != RoundedCorner.BottomRight) + bordersRenderer.RenderVertically(BorderType.Right, rightPos, topPos, bottomPos + bottomWidth - topPos); + + if (cell.RoundedCorner != RoundedCorner.TopLeft && cell.RoundedCorner != RoundedCorner.BottomLeft) + bordersRenderer.RenderVertically(BorderType.Left, leftPos - leftWidth, topPos, bottomPos + bottomWidth - topPos); + + if (cell.RoundedCorner != RoundedCorner.BottomLeft && cell.RoundedCorner != RoundedCorner.BottomRight) + bordersRenderer.RenderHorizontally(BorderType.Bottom, leftPos - leftWidth, bottomPos, rightPos + rightWidth + leftWidth - leftPos); + + if (cell.RoundedCorner != RoundedCorner.TopLeft && cell.RoundedCorner != RoundedCorner.TopRight) + bordersRenderer.RenderHorizontally(BorderType.Top, leftPos - leftWidth, topPos - topWidth, rightPos + rightWidth + leftWidth - leftPos); RenderDiagonalBorders(mergedBorders, innerRect); } @@ -245,6 +304,12 @@ void InitFormat(Area area, FormatInfo previousFormatInfo) TableRenderInfo tblRenderInfo = new TableRenderInfo(); tblRenderInfo.table = this.table; + // Equalize the two borders, that are used to determine a rounded corner's border. + // This way the innerWidth of the cell, which is got by the saved _formattedCells, is the same regardless of which corner relevant border is set. + foreach (Row row in this.table.Rows) + foreach (Cell cell in row.Cells) + EqualizeRoundedCornerBorders(cell); + this.renderInfo = tblRenderInfo; if (prevTableFormatInfo != null) diff --git a/MigraDocCore.Rendering/MigraDocCore.Rendering.csproj b/MigraDocCore.Rendering/MigraDocCore.Rendering.csproj index a5ad183e..0ccbc3f9 100644 --- a/MigraDocCore.Rendering/MigraDocCore.Rendering.csproj +++ b/MigraDocCore.Rendering/MigraDocCore.Rendering.csproj @@ -1,37 +1,40 @@  - netstandard1.3;netstandard2.0;netcoreapp3.1;net5.0 + netstandard2.0;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + false True Stefan Steiger and Contributors MigraDocCore.Rendering for .NET Core MigraDocCore.Rendering was ported from MigraDoc version 1.32 Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany) - LICENCE.md + README.md + LICENSE.md https://github.com/ststeiger/PdfSharpCore https://github.com/ststeiger/PdfSharpCore MigraDocCore.Rendering was ported from MigraDoc version 1.32 MigraDocCore.Rendering for .NET Core + true + true - TRACE;DEBUG;NETCOREAPP1_1;PORTABLE + TRACE;DEBUG; - TRACE;RELEASE;NETCOREAPP1_1;PORTABLE + TRACE;RELEASE; - - - + + diff --git a/PdfSharpCore.Charting/PdfSharp.Charting/Font.cs b/PdfSharpCore.Charting/PdfSharp.Charting/Font.cs index 28d1013f..fe969d70 100644 --- a/PdfSharpCore.Charting/PdfSharp.Charting/Font.cs +++ b/PdfSharpCore.Charting/PdfSharp.Charting/Font.cs @@ -122,6 +122,16 @@ public Underline Underline } internal Underline underline; + /// + /// Gets or sets the strikethrough property. + /// + public Strikethrough Strikethrough + { + get { return this.strikethrough; } + set { this.strikethrough = value; } + } + internal Strikethrough strikethrough; + /// /// Gets or sets the color property. /// diff --git a/PdfSharpCore.Charting/PdfSharp.Charting/enums/Strikethrough.cs b/PdfSharpCore.Charting/PdfSharp.Charting/enums/Strikethrough.cs new file mode 100644 index 00000000..3c25ea2f --- /dev/null +++ b/PdfSharpCore.Charting/PdfSharp.Charting/enums/Strikethrough.cs @@ -0,0 +1,63 @@ +#region PDFsharp Charting - A .NET charting library based on PDFsharp +// +// Authors: +// Niklas Schneider (mailto:Niklas.Schneider@PdfSharpCore.com) +// +// Copyright (c) 2005-2009 empira Software GmbH, Cologne (Germany) +// +// http://www.PdfSharpCore.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.Collections.Generic; +using System.Text; + +namespace PdfSharpCore.Charting +{ + /// + /// Specify the strike out type for font + /// + public enum Strikethrough + { + None, + Single, + Words, + Dotted, + Dash, + DotDash, + DotDotDash, + + /* --- unsupported --- + Double = 3, + Thick = 6, + Wavy = 11, + WavyHeavy = 27, + DottedHeavy = 20, + DashHeavy = 23, + DotDashHeavy = 25, + DotDotDashHeavy = 26, + DashLong = 39, + DashLongHeavy = 55, + WavyDouble = 43 + */ + } +} diff --git a/PdfSharpCore.Charting/PdfSharpCore.Charting.csproj b/PdfSharpCore.Charting/PdfSharpCore.Charting.csproj index 7edd429e..f3c24cf1 100644 --- a/PdfSharpCore.Charting/PdfSharpCore.Charting.csproj +++ b/PdfSharpCore.Charting/PdfSharpCore.Charting.csproj @@ -1,32 +1,36 @@  - netstandard1.3;netstandard2.0;netcoreapp3.1;net5.0 + netstandard2.0;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + false True Stefan Steiger and Contributors PdfSharpCore.Charting for .NET Core PdfSharpCore.Charting was ported from PdfSharp Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany) - LICENCE.md + README.md + LICENSE.md https://github.com/ststeiger/PdfSharpCore https://github.com/ststeiger/PdfSharpCore PdfSharpCore.Charting was ported from PdfSharp PdfSharpCore.Charting for .NET Core + true + true - TRACE;DEBUG;NETCOREAPP1_1;PORTABLE + TRACE;DEBUG; - TRACE;RELEASE;NETCOREAPP1_1;PORTABLE + TRACE;RELEASE; - - + + diff --git a/PdfSharpCore.Test/Assets/AesEncrypted.pdf b/PdfSharpCore.Test/Assets/AesEncrypted.pdf new file mode 100644 index 00000000..14544f9f Binary files /dev/null and b/PdfSharpCore.Test/Assets/AesEncrypted.pdf differ diff --git a/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringWithOverflow_1.png b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringWithOverflow_1.png new file mode 100644 index 00000000..e3ddee48 Binary files /dev/null and b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringWithOverflow_1.png differ diff --git a/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithAlignment_1.png b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithAlignment_1.png new file mode 100644 index 00000000..00b316f8 Binary files /dev/null and b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithAlignment_1.png differ diff --git a/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithLineHeight_1.png b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithLineHeight_1.png new file mode 100644 index 00000000..abdf51fb Binary files /dev/null and b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultiLineStringsWithLineHeight_1.png differ diff --git a/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultilineStringWithTruncate_1.png b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultilineStringWithTruncate_1.png new file mode 100644 index 00000000..d3ad5d59 Binary files /dev/null and b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawMultilineStringWithTruncate_1.png differ diff --git a/PdfSharpCore.Test/Assets/Drawing/Layout/DrawSingleLineString_1.png b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawSingleLineString_1.png new file mode 100644 index 00000000..f0064184 Binary files /dev/null and b/PdfSharpCore.Test/Assets/Drawing/Layout/DrawSingleLineString_1.png differ diff --git a/PdfSharpCore.Test/Assets/frog-and-toad.jpg b/PdfSharpCore.Test/Assets/frog-and-toad.jpg new file mode 100644 index 00000000..62543cce Binary files /dev/null and b/PdfSharpCore.Test/Assets/frog-and-toad.jpg differ diff --git a/PdfSharpCore.Test/Assets/protected-adobe.pdf b/PdfSharpCore.Test/Assets/protected-adobe.pdf new file mode 100644 index 00000000..b0b0ff0c Binary files /dev/null and b/PdfSharpCore.Test/Assets/protected-adobe.pdf differ diff --git a/PdfSharpCore.Test/Assets/protected-ilovepdf.pdf b/PdfSharpCore.Test/Assets/protected-ilovepdf.pdf new file mode 100644 index 00000000..50f15371 Binary files /dev/null and b/PdfSharpCore.Test/Assets/protected-ilovepdf.pdf differ diff --git a/PdfSharpCore.Test/Assets/protected-pdfencrypt.pdf b/PdfSharpCore.Test/Assets/protected-pdfencrypt.pdf new file mode 100644 index 00000000..2922e4b8 Binary files /dev/null and b/PdfSharpCore.Test/Assets/protected-pdfencrypt.pdf differ diff --git a/PdfSharpCore.Test/Assets/protected-sodapdf.pdf b/PdfSharpCore.Test/Assets/protected-sodapdf.pdf new file mode 100644 index 00000000..64a00cb3 Binary files /dev/null and b/PdfSharpCore.Test/Assets/protected-sodapdf.pdf differ diff --git a/PdfSharpCore.Test/CreateSimplePDF.cs b/PdfSharpCore.Test/CreateSimplePDF.cs index ff9cc285..ce9a4d49 100644 --- a/PdfSharpCore.Test/CreateSimplePDF.cs +++ b/PdfSharpCore.Test/CreateSimplePDF.cs @@ -5,6 +5,10 @@ using PdfSharpCore.Drawing; using PdfSharpCore.Pdf; using PdfSharpCore.Test.Helpers; +using PdfSharpCore.Utils; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using Xunit; namespace PdfSharpCore.Test @@ -33,6 +37,28 @@ public void CreateTestPdf() ValidateFileIsPdf(outName); } + [Fact] + public void CreateTestPdfWithUnicodeMetadata() + { + const string data = "English, Ελληνικά, 漢語"; + + var document = new PdfDocument(); + document.Info.Title = data; + document.Info.Subject = data; + document.Info.Author = data; + + using var ms = new MemoryStream(); + document.AddPage(); + document.Save(ms); + ms.Position = 0; + + PdfDocument generatedDocument = Pdf.IO.PdfReader.Open(ms); + + Assert.Equal(data, generatedDocument.Info.Title); + Assert.Equal(data, generatedDocument.Info.Subject); + Assert.Equal(data, generatedDocument.Info.Author); + } + [Fact] public void CreateTestPdfWithImage() { @@ -51,6 +77,32 @@ public void CreateTestPdfWithImage() ReadStreamAndVerifyPdfHeaderSignature(stream); } + [Fact] + public void CreateTestPdfWithImageViaImageSharp() + { + using var stream = new MemoryStream(); + var document = new PdfDocument(); + + var pageNewRenderer = document.AddPage(); + + var renderer = XGraphics.FromPdfPage(pageNewRenderer); + + // Load image for ImageSharp and apply a simple mutation: + var image = Image.Load(PathHelper.GetInstance().GetAssetPath("lenna.png"), out var format); + image.Mutate(ctx => ctx.Grayscale()); + + // create XImage from that same ImageSharp image: + var source = ImageSharpImageSource.FromImageSharpImage(image, format); + var img = XImage.FromImageSource(source); + + renderer.DrawImage(img, new XPoint(0, 0)); + + document.Save(stream); + stream.Position = 0; + Assert.True(stream.Length > 1); + ReadStreamAndVerifyPdfHeaderSignature(stream); + } + private void SaveDocument(PdfDocument document, string name) { var outFilePath = GetOutFilePath(name); diff --git a/PdfSharpCore.Test/Drawing/Layout/XTextFormatterTest.cs b/PdfSharpCore.Test/Drawing/Layout/XTextFormatterTest.cs new file mode 100644 index 00000000..9fa8e0ab --- /dev/null +++ b/PdfSharpCore.Test/Drawing/Layout/XTextFormatterTest.cs @@ -0,0 +1,127 @@ +using System.IO; +using FluentAssertions; +using ImageMagick; +using PdfSharpCore.Drawing; +using PdfSharpCore.Drawing.Layout; +using PdfSharpCore.Drawing.Layout.enums; +using PdfSharpCore.Pdf; +using PdfSharpCore.Test.Helpers; +using Xunit; + +namespace PdfSharpCore.Test.Drawing.Layout +{ + public class XTextFormatterTest + { + private static readonly string _outDir = "TestResults/XTextFormatterTest"; + private static readonly string _expectedImagesPath = Path.Combine("Drawing", "Layout"); + + private PdfDocument _document; + private XGraphics _renderer; + private XTextFormatter _textFormatter; + + // Run before each test + public XTextFormatterTest() + { + _document = new PdfDocument(); + var page = _document.AddPage(); + page.Size = PageSize.A6; // 295 x 417 pts + _renderer = XGraphics.FromPdfPage(page); + _textFormatter = new XTextFormatter(_renderer); + } + + [Fact] + public void DrawSingleLineString() + { + var layout = new XRect(12, 12, 200, 50); + _textFormatter.DrawString("This is a simple single line test", new XFont("Arial", 12), XBrushes.Black, layout); + + var diffResult = DiffPage(_document, "DrawSingleLineString", 1); + + diffResult.DiffValue.Should().Be(0); + } + + [Fact] + public void DrawMultilineStringWithTruncate() + { + var layout = new XRect(12, 12, 200, 40); + _renderer.DrawRectangle(XBrushes.LightGray, layout); + _textFormatter.DrawString("This is text\nspanning 3 lines\nbut only space for 2", new XFont("Arial", 12), XBrushes.Black, layout); + + var diffResult = DiffPage(_document, "DrawMultilineStringWithTruncate", 1); + + diffResult.DiffValue.Should().Be(0); + } + + [Fact] + public void DrawMultiLineStringWithOverflow() + { + var layout = new XRect(12, 12, 200, 40); + _renderer.DrawRectangle(XBrushes.LightGray, layout); + _textFormatter.AllowVerticalOverflow = true; + _textFormatter.DrawString("This is text\nspanning 3 lines\nand overflow shows all three", new XFont("Arial", 12), XBrushes.Black, layout); + + var diffResult = DiffPage(_document, "DrawMultiLineStringWithOverflow", 1); + + diffResult.DiffValue.Should().Be(0); + } + + [Fact] + public void DrawMultiLineStringsWithAlignment() + { + var layout1 = new XRect(12, 12, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout1); + _textFormatter.DrawString("This is text\naligned to the top-left", new XFont("Arial", 12), XBrushes.Black, layout1); + + var layout2 = new XRect(12, 100, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout2); + _textFormatter.SetAlignment(new TextFormatAlignment { Horizontal = XParagraphAlignment.Center, Vertical = XVerticalAlignment.Middle}); + _textFormatter.DrawString("This is text\naligned to the middle-center", new XFont("Arial", 12), XBrushes.Black, layout2); + + var layout3 = new XRect(12, 200, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout3); + _textFormatter.SetAlignment(new TextFormatAlignment { Horizontal = XParagraphAlignment.Right, Vertical = XVerticalAlignment.Bottom}); + _textFormatter.DrawString("This is text\naligned to the bottom-right", new XFont("Arial", 12), XBrushes.Black, layout3); + + var diffResult = DiffPage(_document, "DrawMultiLineStringsWithAlignment", 1); + + diffResult.DiffValue.Should().Be(0); + } + + [Fact] + public void DrawMultiLineStringsWithLineHeight() + { + var font = new XFont("Arial", 12); + + var layout1 = new XRect(10, 10, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout1); + _textFormatter.DrawString("This is text\naligned to the top-left\nand a custom line height", font, XBrushes.Black, layout1, 16); + + var layout2 = new XRect(10, 110, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout2); + _textFormatter.SetAlignment(new TextFormatAlignment { Horizontal = XParagraphAlignment.Center, Vertical = XVerticalAlignment.Middle}); + _textFormatter.DrawString("This is text\naligned to the middle-center\nand a custom line height", font, XBrushes.Black, layout2, 16); + + var layout3 = new XRect(10, 210, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout3); + _textFormatter.SetAlignment(new TextFormatAlignment { Horizontal = XParagraphAlignment.Right, Vertical = XVerticalAlignment.Bottom}); + _textFormatter.DrawString("This is text\naligned to the bottom-right\nand a custom line height", font, XBrushes.Black, layout3, 16); + + var layout4 = new XRect(10, 310, 200, 80); + _renderer.DrawRectangle(XBrushes.LightGray, layout4); + _textFormatter.SetAlignment(new TextFormatAlignment { Horizontal = XParagraphAlignment.Center, Vertical = XVerticalAlignment.Middle}); + _textFormatter.DrawString("This is text\nwith a very small\nline height", font, XBrushes.Black, layout4, 6); + + var diffResult = DiffPage(_document, "DrawMultiLineStringsWithLineHeight", 1); + + diffResult.DiffValue.Should().Be(0); + } + + private static DiffOutput DiffPage(PdfDocument document, string filePrefix, int pageNum) + { + var rasterized = PdfHelper.Rasterize(document); + var rasterizedFiles = PdfHelper.WriteImageCollection(rasterized.ImageCollection, _outDir, filePrefix); + var expectedImagePath = PathHelper.GetInstance().GetAssetPath(_expectedImagesPath, $"{filePrefix}_{pageNum}.png"); + return PdfHelper.Diff(rasterizedFiles[pageNum-1], expectedImagePath, _outDir, filePrefix); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/Helpers/PathHelper.cs b/PdfSharpCore.Test/Helpers/PathHelper.cs index d16f9a08..e77ca865 100644 --- a/PdfSharpCore.Test/Helpers/PathHelper.cs +++ b/PdfSharpCore.Test/Helpers/PathHelper.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Reflection; namespace PdfSharpCore.Test.Helpers @@ -10,9 +11,11 @@ public PathHelper() RootDir = Path.GetDirectoryName(GetType().GetTypeInfo().Assembly.Location); } - public string GetAssetPath(string name) + public string GetAssetPath(params string[] names) { - return Path.Combine(RootDir, "Assets", name); + var segments = new List { RootDir, "Assets" }; + segments.AddRange(names); + return Path.Combine(segments.ToArray()); } public string RootDir { get; } @@ -24,4 +27,4 @@ public static PathHelper GetInstance() private static PathHelper _instance; } -} \ No newline at end of file +} diff --git a/PdfSharpCore.Test/Helpers/PdfHelper.cs b/PdfSharpCore.Test/Helpers/PdfHelper.cs new file mode 100644 index 00000000..e4c1781f --- /dev/null +++ b/PdfSharpCore.Test/Helpers/PdfHelper.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.IO; +using ImageMagick; +using PdfSharpCore.Pdf; + +namespace PdfSharpCore.Test.Helpers +{ + public class PdfHelper + { + private static readonly string _rootPath = PathHelper.GetInstance().RootDir; + + /// + /// Rasterize all pages within a PDF to PNG images + /// + /// + /// + public static RasterizeOutput Rasterize(PdfDocument document) + { + var readerSettings = new MagickReadSettings + { + Density = new Density(300, 300), + BackgroundColor = MagickColors.White + }; + var images = new MagickImageCollection(); + + // Add all pages to the collection + using var ms = new MemoryStream(); + document.Save(ms); + + try + { + images.Read(ms, readerSettings); + } + catch (MagickDelegateErrorException ex) + { + throw new Exception("Ghostscript is not installed or is an incompatible version, unable to rasterize PDF", ex); + } + + // Remove transparency to guarantee a standard white background + foreach (var img in images) + { + img.Alpha(AlphaOption.Deactivate); + img.BackgroundColor = MagickColors.White; + } + + return new RasterizeOutput + { + ImageCollection = images, + }; + } + + public static List WriteImageCollection(MagickImageCollection images, string outDir, string filePrefix) + { + var outPaths = new List(); + for (var pageNum = 0; pageNum < images.Count; pageNum++) + { + var outPath = GetOutFilePath(outDir, $"{filePrefix}_{pageNum+1}.png"); + images[pageNum].Write(outPath); + outPaths.Add(outPath); + } + + return outPaths; + } + + public static string WriteImage(IMagickImage image, string outDir, string fileNameWithoutExtension) + { + var outPath = GetOutFilePath(outDir, $"{fileNameWithoutExtension}.png"); + image.Write(outPath); + return outPath; + } + + // Note: For diff to function properly, it requires the underlying image to be in the proper format + // For instance, actual and expected must both be sourced from .png files + public static DiffOutput Diff(string actualImagePath, string expectedImagePath, string outputPath = null, string filePrefix = null, int fuzzPct = 4) + { + var diffImg = new MagickImage(); + var actual = new MagickImage(actualImagePath); + var expected = new MagickImage(expectedImagePath); + + // Allow for subtle differences due to cross-platform rendering of the PDF fonts + actual.ColorFuzz = new Percentage(fuzzPct); + var diffVal = actual.Compare(expected, ErrorMetric.Absolute, diffImg); + + if (diffVal > 0 && outputPath != null && filePrefix != null) + { + WriteImage(diffImg, outputPath, $"{filePrefix}_diff"); + } + + return new DiffOutput + { + DiffValue = diffVal, + DiffImage = diffImg + }; + } + + private static string GetOutFilePath(string outDir, string name) + { + var dir = Path.Combine(_rootPath, outDir); + Directory.CreateDirectory(dir); + return Path.Combine(dir, name); + } + } + + public class RasterizeOutput + { + public List OutputPaths; + public MagickImageCollection ImageCollection; + } + + public class DiffOutput + { + public IMagickImage DiffImage; + public double DiffValue; + } +} diff --git a/PdfSharpCore.Test/Helpers/TestData.cs b/PdfSharpCore.Test/Helpers/TestData.cs new file mode 100644 index 00000000..c703e31c --- /dev/null +++ b/PdfSharpCore.Test/Helpers/TestData.cs @@ -0,0 +1,22 @@ +namespace PdfSharpCore.Test.Helpers +{ + public static class TestData + { + public static string LoremIpsumText = + @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non sapien leo. Aliquam elementum volutpat lacus, sit amet aliquet est volutpat at. Nam eleifend vehicula bibendum. Sed lacinia velit ex, id auctor tellus varius a. Vivamus cursus ut nulla quis pretium. Nunc accumsan felis nec tortor fermentum iaculis. Vivamus non lacus ullamcorper, porta justo ut, dictum nibh. Cras scelerisque in risus vitae hendrerit. Duis venenatis felis in lacinia vestibulum. Proin mauris ex, efficitur nec tincidunt in, imperdiet eget risus. Nulla porttitor mollis pellentesque. Fusce pretium ut odio et imperdiet. + +Vivamus euismod velit id massa mollis, quis congue metus faucibus. Donec ante enim, vehicula a cursus ut, porta vel dui. Proin porta faucibus dolor non consequat. Mauris aliquam, leo a interdum pretium, tellus nisi semper libero, at suscipit dui mi bibendum turpis. Phasellus tempor mauris a eleifend placerat. Fusce in velit ut lectus sagittis varius. Etiam vulputate, libero sit amet posuere posuere, orci nunc ultricies velit, non porttitor dui ante feugiat purus. Ut semper congue lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed facilisis ante at sapien dignissim, ut volutpat elit dictum. Morbi nulla ante, laoreet non vulputate et, facilisis ut lectus. Mauris mollis mi nec venenatis congue. Fusce efficitur vitae massa non vehicula. Fusce euismod molestie posuere. Nunc facilisis ipsum nec justo scelerisque, nec cursus diam gravida. + +Morbi at sapien risus. Nunc dui tellus, faucibus rhoncus euismod vitae, maximus at lacus. Nam neque dui, venenatis at euismod vel, ullamcorper a velit. Maecenas placerat tellus quis justo feugiat molestie. Mauris tristique sollicitudin nisi at sagittis. Integer eleifend, velit et facilisis rutrum, nisi ipsum sodales turpis, non dictum odio dui sed velit. Aliquam consequat ac lorem non hendrerit. Morbi quis mollis nibh, et mattis nisi. Donec nec ultricies dui, nec pellentesque sapien. Vivamus sed lectus fermentum mauris placerat sodales ut sed quam. Nam facilisis, risus quis hendrerit mattis, velit nisi placerat neque, in feugiat urna nisl in nibh. Suspendisse potenti. Proin sollicitudin maximus ligula, eu sodales tellus posuere vitae. Integer orci magna, ultricies in luctus a, euismod quis lectus. Phasellus blandit justo mauris, nec maximus sapien tempor non. Ut eu quam aliquam, facilisis nibh sit amet, blandit eros. + +Nulla accumsan augue diam, sed egestas ipsum vestibulum vel. Praesent vitae dignissim quam. Nunc mollis tincidunt vehicula. In vitae euismod urna, eget tincidunt magna. In quis ligula eu magna vehicula venenatis. Vestibulum sapien sem, congue in congue et, vehicula et risus. Suspendisse aliquam, est et commodo porta, nibh tortor mollis nisi, quis porttitor ligula leo a ipsum. Aliquam viverra sodales leo quis faucibus. + +In sit amet laoreet nisl. Aenean et tortor diam. Maecenas imperdiet massa eget justo faucibus dignissim. Donec nec finibus diam, vel lobortis neque. Ut justo felis, suscipit et justo ultrices, fringilla convallis nisi. Vestibulum egestas felis vehicula tellus maximus, a ultrices magna aliquet. Cras eu laoreet mauris. Duis id euismod est. Nulla facilisi. Vivamus fermentum metus velit, vitae vulputate lectus laoreet in. Aenean semper ante odio. Ut aliquam ligula eu enim ullamcorper, ac pellentesque enim hendrerit. Vestibulum eu efficitur nisl. Aenean tempor diam nec nulla rutrum, sit amet congue urna blandit. + +Duis ullamcorper tellus ac mattis vestibulum. Integer nibh nunc, commodo sit amet pharetra sit amet, molestie a sapien. Nulla magna orci, semper at enim non, ultricies faucibus nulla. Aenean leo ex, rutrum ut fermentum ut, fringilla sit amet diam. Morbi et congue tortor, non maximus tellus. Nunc sit amet placerat ipsum, at molestie tellus. Etiam tincidunt eleifend ligula, quis dapibus elit tempus tempor. Curabitur feugiat mattis leo eu blandit. Maecenas sed vestibulum mi. In molestie eleifend euismod. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus id turpis a magna sollicitudin pellentesque. + +Donec sollicitudin efficitur sapien iaculis fringilla. Donec rutrum sagittis dolor, at auctor turpis finibus et. Aliquam et dictum risus. Praesent viverra efficitur congue. Suspendisse condimentum posuere risus, id dignissim enim viverra ut. Aliquam eleifend nisl eu dolor luctus, nec rhoncus nisi porta. Donec ut lacinia risus. Curabitur bibendum lacus consequat sem consequat euismod. Donec auctor cursus ante quis rutrum. Aliquam mattis eget libero non porta. + +Maecenas mollis sollicitudin felis at imperdiet. Duis dignissim purus quis interdum mattis. Nam sit amet quam quis enim hendrerit tincidunt. Aliquam euismod metus justo, non lobortis risus vehicula in. Pellentesque tempus, leo at placerat interdum, diam lectus gravida purus, id placerat justo quam nec mauris. Ut ullamcorper commodo dui in pretium. Suspendisse luctus mauris lacinia neque faucibus sollicitudin. Pellentesque ut ipsum metus. Quisque rutrum, risus eget feugiat vestibulum, enim nisl ornare risus, sit amet interdum arcu lacus at turpis. Mauris nec tristique massa. Curabitur diam urna, dapibus eget lorem porta, venenatis mattis justo. Sed eleifend accumsan lectus, id tempor metus semper in."; + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/IO/IoBaseTest.cs b/PdfSharpCore.Test/IO/IoBaseTest.cs new file mode 100644 index 00000000..26742746 --- /dev/null +++ b/PdfSharpCore.Test/IO/IoBaseTest.cs @@ -0,0 +1,73 @@ +using System.IO; +using System.Text; +using FluentAssertions; +using PdfSharpCore.Pdf; +using PdfSharpCore.Pdf.IO; +using PdfSharpCore.Test.Helpers; +using Xunit; + +namespace PdfSharpCore.Test.IO +{ + public abstract class IoBaseTest + { + private readonly string _rootPath = PathHelper.GetInstance().RootDir; + private const string _outputDirName = "Out"; + + public void CanReadPdf(string fileName) + { + var path = GetOutFilePath(fileName); + using var fs = File.OpenRead(path); + var inputDocument = Pdf.IO.PdfReader.Open(fs, PdfDocumentOpenMode.Import); + var info = inputDocument.Info; + info.Should().NotBeNullOrEmpty(); + } + + protected void SaveDocument(PdfDocument document, string name) + { + var outFilePath = GetOutFilePath(name); + var dir = Path.GetDirectoryName(outFilePath); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + document.Save(outFilePath); + } + + protected void ValidateFileIsPdf(string v) + { + var path = GetOutFilePath(v); + Assert.True(File.Exists(path)); + var fi = new FileInfo(path); + Assert.True(fi.Length > 1); + + using var stream = File.OpenRead(path); + ReadStreamAndVerifyPdfHeaderSignature(stream); + } + + private static void ReadStreamAndVerifyPdfHeaderSignature(Stream stream) + { + var readBuffer = new byte[5]; + var pdfSignature = Encoding.ASCII.GetBytes("%PDF-"); // PDF must start with %PDF- + + stream.Read(readBuffer, 0, readBuffer.Length); + readBuffer.Should().Equal(pdfSignature); + } + + protected void ValidateTargetAvailable(string file) + { + var path = GetOutFilePath(file); + if (File.Exists(path)) + { + File.Delete(path); + } + + Assert.False(File.Exists(path)); + } + + protected string GetOutFilePath(string name) + { + return Path.Combine(_rootPath, _outputDirName, name); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/IO/LargePDFReadWrite.cs b/PdfSharpCore.Test/IO/LargePDFReadWrite.cs new file mode 100644 index 00000000..db91d056 --- /dev/null +++ b/PdfSharpCore.Test/IO/LargePDFReadWrite.cs @@ -0,0 +1,59 @@ +using PdfSharpCore.Drawing; +using PdfSharpCore.Drawing.Layout; +using PdfSharpCore.Pdf; +using PdfSharpCore.Test.Helpers; +using PdfSharpCore.Test.IO; +using Xunit; +using Xunit.Abstractions; + +namespace PdfSharpCore.Test +{ + public class LargePDFReadWrite : IoBaseTest + { + private readonly ITestOutputHelper output; + + public LargePDFReadWrite(ITestOutputHelper output) + { + this.output = output; + } + + [Fact(Skip = "Too slow for Unit test runner")] + public void CanCreatePdfOver2gb() + { + const string outName = "CreateLargePdf.pdf"; + int pageCount = 70000; //2.1gb @ 369sec to create + ValidateTargetAvailable(outName); + + var document = new PdfDocument(); + var watch = new System.Diagnostics.Stopwatch(); + var font = new XFont("Arial", 10); + + watch.Start(); + for (var i = 0; i < pageCount; i++) + { + AddAPage(document, font); + } + + watch.Stop(); + + SaveDocument(document, outName); + output.WriteLine($"CreatePDF took {watch.Elapsed.TotalSeconds} sec"); + ValidateFileIsPdf(outName); + CanReadPdf(outName); + } + + private void AddAPage(PdfDocument document, XFont font) + { + const int x = 40; + const int y = 50; + var page = document.AddPage(); + var renderer = XGraphics.FromPdfPage(page); + var tf = new XTextFormatter(renderer); + var width = page.Width.Value - 50 - x; + var height = page.Height.Value - 50 - y; + var rect = new XRect(40, 50, width, height); + renderer.DrawRectangle(XBrushes.SeaShell, rect); + tf.DrawString(TestData.LoremIpsumText, font, XBrushes.Black, rect); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/IO/PdfReader.cs b/PdfSharpCore.Test/IO/PdfReader.cs index 6a38dd62..a8883625 100644 --- a/PdfSharpCore.Test/IO/PdfReader.cs +++ b/PdfSharpCore.Test/IO/PdfReader.cs @@ -1,9 +1,9 @@ -using System; -using System.IO; -using FluentAssertions; +using FluentAssertions; using PdfSharpCore.Pdf; using PdfSharpCore.Pdf.IO; using PdfSharpCore.Test.Helpers; +using System; +using System.IO; using Xunit; namespace PdfSharpCore.Test.IO @@ -26,11 +26,12 @@ public void WillThrowExceptionWhenReadingInvalidPdf() act.Should().Throw().WithMessage("The file is not a valid PDF document."); } - private void AssertIsAValidPdfDocumentWithProperties(PdfDocument inputDocument, int expectedFileSize) + internal static void AssertIsAValidPdfDocumentWithProperties(PdfDocument inputDocument, int expectedFileSize) { inputDocument.Should().NotBeNull(); inputDocument.FileSize.Should().Be(expectedFileSize); inputDocument.Info.Should().NotBeNull(); + inputDocument.PageCount.Should().BeGreaterThan(0); } } } \ No newline at end of file diff --git a/PdfSharpCore.Test/Merge.cs b/PdfSharpCore.Test/Merge.cs index ec1e6eed..e3bab0d7 100644 --- a/PdfSharpCore.Test/Merge.cs +++ b/PdfSharpCore.Test/Merge.cs @@ -1,25 +1,74 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using PdfSharpCore.Drawing; +using PdfSharpCore.Drawing.Layout; using PdfSharpCore.Pdf; using PdfSharpCore.Pdf.IO; using PdfSharpCore.Test.Helpers; using Xunit; +using Xunit.Abstractions; namespace PdfSharpCore.Test { public class Merge { + private readonly ITestOutputHelper _output; + + public Merge(ITestOutputHelper output) + { + _output = output; + } + [Fact] public void CanMerge2Documents() { var pdf1Path = PathHelper.GetInstance().GetAssetPath("FamilyTree.pdf"); var pdf2Path = PathHelper.GetInstance().GetAssetPath("test.pdf"); + var outputDocument = MergeDocuments(new[] { pdf1Path, pdf2Path }); + + var outFilePath = CreateOutFilePath("merge.pdf"); + outputDocument.Save(outFilePath); + } + + [Fact] + public void CanConsolidateImageDataInDocument() + { + var doc1 = CreateTestDocumentWithImage("lenna.png"); + var doc2 = CreateTestDocumentWithImage("frog-and-toad.jpg"); + + var pdf1Path = CreateOutFilePath("image-doc1.pdf"); + doc1.Save(pdf1Path); + + var pdf2Path = CreateOutFilePath("image-doc2.pdf"); + doc2.Save(pdf2Path); + + var pdfPathsForMerge = Enumerable.Range(1, 50).SelectMany(_ => new[] { pdf1Path, pdf2Path }); + var outputDocument = MergeDocuments(pdfPathsForMerge); + + var mergedFilePath = CreateOutFilePath("images-merged.pdf"); + outputDocument.Save(mergedFilePath); + + outputDocument.ConsolidateImages(); + var consolidatedFilePath = CreateOutFilePath("images-merged-consolidated.pdf"); + outputDocument.Save(consolidatedFilePath); + + long mergedLength = new FileInfo(mergedFilePath).Length; + long consolidatedLength = new FileInfo(consolidatedFilePath).Length; + Assert.True(consolidatedLength < mergedLength / 4); + } + + private static PdfDocument MergeDocuments(IEnumerable pdfPaths) + { var outputDocument = new PdfDocument(); - foreach (var pdfPath in new[] { pdf1Path, pdf2Path }) + foreach (var pdfPath in pdfPaths) { using var fs = File.OpenRead(pdfPath); var inputDocument = Pdf.IO.PdfReader.Open(fs, PdfDocumentOpenMode.Import); + var count = inputDocument.PageCount; for (var idx = 0; idx < count; idx++) { @@ -28,14 +77,34 @@ public void CanMerge2Documents() } } - var outFilePath = Path.Combine(PathHelper.GetInstance().RootDir, "Out", "merge.pdf"); + return outputDocument; + } + + private static string CreateOutFilePath(string filename) + { + var outFilePath = Path.Combine(PathHelper.GetInstance().RootDir, "Out", filename); var dir = Path.GetDirectoryName(outFilePath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } - outputDocument.Save(outFilePath); + return outFilePath; + } + + private static PdfDocument CreateTestDocumentWithImage(string imageFilename) + { + var document = new PdfDocument(); + + var pageNewRenderer = document.AddPage(); + var renderer = XGraphics.FromPdfPage(pageNewRenderer); + var textFormatter = new XTextFormatter(renderer); + + var layout = new XRect(12, 12, 400, 50); + textFormatter.DrawString(imageFilename, new XFont("Arial", 12), XBrushes.Black, layout); + renderer.DrawImage(XImage.FromFile(PathHelper.GetInstance().GetAssetPath(imageFilename)), new XPoint(12, 100)); + + return document; } } } \ No newline at end of file diff --git a/PdfSharpCore.Test/MigradocTurkishTest.cs b/PdfSharpCore.Test/MigradocTurkishTest.cs new file mode 100644 index 00000000..1cc28781 --- /dev/null +++ b/PdfSharpCore.Test/MigradocTurkishTest.cs @@ -0,0 +1,41 @@ +using MigraDocCore.Rendering; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Threading; +using Xunit; +using MigraDocCore.DocumentObjectModel; + +namespace PdfSharpCore.Test +{ + public class MigradocTurkishTest + { + private CultureInfo originalCulture; + private CultureInfo originalUICulture; + + [Fact] + public void RenderDocument_TurkishCulture_NoCrashing() + { + originalCulture = Thread.CurrentThread.CurrentCulture; + originalUICulture = Thread.CurrentThread.CurrentUICulture; + var cultureInfo = CultureInfo.GetCultureInfo("tr-TR"); + Thread.CurrentThread.CurrentCulture = cultureInfo; + Thread.CurrentThread.CurrentUICulture = cultureInfo; + + try + { + Document doc = new Document(); + PdfDocumentRenderer printer = new PdfDocumentRenderer() { Document = doc }; + printer.RenderDocument(); + } + finally + { + Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentUICulture = originalUICulture; + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + } + } +} diff --git a/PdfSharpCore.Test/Outlines/OutlineTests.cs b/PdfSharpCore.Test/Outlines/OutlineTests.cs new file mode 100644 index 00000000..0d39eba4 --- /dev/null +++ b/PdfSharpCore.Test/Outlines/OutlineTests.cs @@ -0,0 +1,44 @@ +using System.IO; +using FluentAssertions; +using PdfSharpCore.Drawing; +using PdfSharpCore.Pdf; +using Xunit; + +namespace PdfSharpCore.Test.Outlines +{ + public class OutlineTests + { + [Fact] + public void CanCreateDocumentWithOutlines() + { + var document = new PdfDocument(); + var font = new XFont("Verdana", 16); + var page = document.AddPage(); + var gfx = XGraphics.FromPdfPage(page); + gfx.DrawString("Page 1", font, XBrushes.Black, 20, 50, XStringFormats.Default); + + // Create the root bookmark. You can set the style and the color. + var outline = document.Outlines.Add("Root", page, true, + PdfOutlineStyle.Bold, XColors.Red); + + // Create some more pages + for (var idx = 2; idx <= 5; idx++) + { + page = document.AddPage(); + gfx = XGraphics.FromPdfPage(page); + + var text = $"Page {idx}"; + gfx.DrawString(text, font, XBrushes.Black, 20, 50, XStringFormats.Default); + + // Create a sub bookmark + outline.Outlines.Add(text, page, true); + } + + document.Outlines.Count.Should().Be(1); + + using var ms = new MemoryStream(); + document.Save(ms); + ms.ToArray().Length.Should().BeGreaterThan(1); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/PdfSharpCore.Test.csproj b/PdfSharpCore.Test/PdfSharpCore.Test.csproj index fb0861c9..1752a920 100644 --- a/PdfSharpCore.Test/PdfSharpCore.Test.csproj +++ b/PdfSharpCore.Test/PdfSharpCore.Test.csproj @@ -1,16 +1,25 @@ - netcoreapp3.1;net5.0 - + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + false false - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -19,19 +28,17 @@ + - - PreserveNewest - - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/PdfSharpCore.Test/Pdfs/Content/Objects/CNameTests.cs b/PdfSharpCore.Test/Pdfs/Content/Objects/CNameTests.cs new file mode 100644 index 00000000..455b6978 --- /dev/null +++ b/PdfSharpCore.Test/Pdfs/Content/Objects/CNameTests.cs @@ -0,0 +1,44 @@ +using System; +using FluentAssertions; +using PdfSharpCore.Pdf.Content.Objects; +using Xunit; + +namespace PdfSharpCore.Test.Pdfs.Content.Objects +{ + public class CNameTests + { + [Theory] + [InlineData("/Foo")] + public void SetNameTests(string name) + { + var cName = new CName + { + Name = name + }; + + cName.Name.Should().Be(name); + } + + [Fact] + public void SetNameNullThrowsException() + { + Action act = () => new CName + { + Name = null + }; + act.Should().Throw(); + } + + [Theory] + [InlineData("Foo")] + [InlineData("")] + public void SetNameWithoutPrefixThrowsException(string name) + { + Action act = () => new CName + { + Name = name + }; + act.Should().Throw(); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/Pdfs/PdfDateTests.cs b/PdfSharpCore.Test/Pdfs/PdfDateTests.cs new file mode 100644 index 00000000..5ed240d4 --- /dev/null +++ b/PdfSharpCore.Test/Pdfs/PdfDateTests.cs @@ -0,0 +1,28 @@ +using System; +using FluentAssertions; +using PdfSharpCore.Pdf; +using Xunit; + +namespace PdfSharpCore.Test.Pdfs +{ + public class PdfDateTests + { + // format for pdf date is generally D:YYYYMMDDHHmmSSOHH'mm' + + [Fact] + public void ParseDateString_WithTimezoneOffset() + { + var pdfDate = new PdfDate("D:19981223195200-02'00'"); + var expectedDateWithOffset = new DateTimeOffset(new DateTime(1998, 12, 23, 19, 52, 0), new TimeSpan(-2, 0, 0)); + pdfDate.Value.ToUniversalTime().Should().Be(expectedDateWithOffset.UtcDateTime); + } + + [Fact] + public void ParseDateString_WithNoOffset() + { + var pdfDate = new PdfDate("D:19981223195200Z"); + var expectedDateWithOffset = new DateTimeOffset(new DateTime(1998, 12, 23, 19, 52, 0), new TimeSpan(0, 0, 0)); + pdfDate.Value.ToUniversalTime().Should().Be(expectedDateWithOffset.UtcDateTime); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.Test/Security/PdfSecurity.cs b/PdfSharpCore.Test/Security/PdfSecurity.cs new file mode 100644 index 00000000..328ba6cd --- /dev/null +++ b/PdfSharpCore.Test/Security/PdfSecurity.cs @@ -0,0 +1,126 @@ +using FluentAssertions; +using PdfSharpCore.Drawing; +using PdfSharpCore.Pdf; +using PdfSharpCore.Pdf.IO; +using PdfSharpCore.Pdf.Security; +using PdfSharpCore.Test.Helpers; +using System.IO; +using Xunit; +using Xunit.Abstractions; + +namespace PdfSharpCore.Test.Security +{ + public class PdfSecurity + { + private readonly ITestOutputHelper output; + + public PdfSecurity(ITestOutputHelper testOutputHelper) + { + output = testOutputHelper; + } + + [Theory] + [InlineData(PdfDocumentSecurityLevel.Encrypted40Bit, "hunter1")] + [InlineData(PdfDocumentSecurityLevel.Encrypted128Bit, "hunter1")] + public void CreateAndReadPasswordProtectedPdf(PdfDocumentSecurityLevel securityLevel, string password) + { + var document = new PdfDocument(); + var pageNewRenderer = document.AddPage(); + var renderer = XGraphics.FromPdfPage(pageNewRenderer); + renderer.DrawString("Test Test Test", new XFont("Arial", 12), XBrushes.Black, new XPoint(12, 12)); + // validate correct handling of unicode strings (issue #264) + document.Outlines.Add("The only page", pageNewRenderer); + document.SecuritySettings.DocumentSecurityLevel = securityLevel; + document.SecuritySettings.UserPassword = password; + + using var ms = new MemoryStream(); + document.Save(ms); + ms.Position = 0; + + var loadDocument = Pdf.IO.PdfReader.Open(ms, PdfDocumentOpenMode.Modify, + delegate(PdfPasswordProviderArgs args) { args.Password = password; }); + + loadDocument.PageCount.Should().Be(1); + loadDocument.Outlines[0].Title.Should().Be("The only page"); + loadDocument.Info.Producer.Should().Contain("PDFsharp"); + } + + [Fact] + public void ShouldBeAbleToOpenAesEncryptedDocuments() + { + // this document has a V value of 4 (see PdfReference 1.7, Chapter 7.6.1, Table 20) + // and an R value of 4 (see PdfReference 1.7, Chapter 7.6.3.2, Table 21) + // see also: Adobe Supplement to the ISO 32000, BaseVersion: 1.7, ExtensionLevel: 3 + // Chapter 3.5.2, Table 3.19 + var file = PathHelper.GetInstance().GetAssetPath("AesEncrypted.pdf"); + var fi = new FileInfo(file); + var document = Pdf.IO.PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // verify document was actually AES-encrypted + var cf = document.SecurityHandler.Elements.GetDictionary("/CF"); + var stdCf = cf.Elements.GetDictionary("/StdCF"); + stdCf.Elements.GetString("/CFM").Should().Be("/AESV2"); + + IO.PdfReader.AssertIsAValidPdfDocumentWithProperties(document, (int)fi.Length); + } + + [Fact] + public void DocumentWithUserPasswordCannotBeOpenedWithoutPassword() + { + var file = PathHelper.GetInstance().GetAssetPath("AesEncrypted.pdf"); + var document = Pdf.IO.PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // import pages into a new document + var encryptedDoc = new PdfDocument(); + foreach (var page in document.Pages) + encryptedDoc.AddPage(page); + + // save enrypted + encryptedDoc.SecuritySettings.UserPassword = "supersecret!11"; + var saveFileName = PathHelper.GetInstance().GetAssetPath("SavedEncrypted.pdf"); + encryptedDoc.Save(saveFileName); + + // should throw because no password was provided + var ex = Assert.Throws(() => + { + var readBackDoc = Pdf.IO.PdfReader.Open(saveFileName, PdfDocumentOpenMode.Import); + }); + ex.Message.Should().Contain("A password is required to open the PDF document"); + + // check with password + // TODO: should be checked in a separate test, but i was lazy... + var fi = new FileInfo(saveFileName); + var readBackDoc = Pdf.IO.PdfReader.Open(saveFileName, "supersecret!11", PdfDocumentOpenMode.Import); + IO.PdfReader.AssertIsAValidPdfDocumentWithProperties(readBackDoc, (int)fi.Length); + readBackDoc.PageCount.Should().Be(document.PageCount); + } + + // Same PDF protected by different tools or online-services + [Theory] + // https://www.ilovepdf.com/protect-pdf, 128 bit, /V 2 /R 3 + [InlineData(@"protected-ilovepdf.pdf", "test123")] + + // https://www.adobe.com/de/acrobat/online/password-protect-pdf.html, 128 bit, /V 4 /R 4 + [InlineData(@"protected-adobe.pdf", "test123")] + + // https://pdfencrypt.net, 256 bit, /V 5 /R 5 + [InlineData(@"protected-pdfencrypt.pdf", "test123")] + + // https://www.sodapdf.com/password-protect-pdf/ + // this is the only tool tested, that encrypts with the latest known algorithm (256 bit, /V 5 /R 6) + // Note: SodaPdf also produced a pdf that would be considered "invalid" by PdfSharp, because of incorrect stream-lengths + // (in the Stream-Dictionary, the length was reported as 32, but in fact the length was 16) + // this needed to be handled as well + [InlineData(@"protected-sodapdf.pdf", "test123")] + public void CanReadPdfEncryptedWithSupportedAlgorithms(string fileName, string password) + { + var path = PathHelper.GetInstance().GetAssetPath(fileName); + + var doc = Pdf.IO.PdfReader.Open(path, password, PdfDocumentOpenMode.Import); + doc.Should().NotBeNull(); + doc.PageCount.Should().BeGreaterThan(0); + output.WriteLine("Creator : {0}", doc.Info.Creator); + output.WriteLine("Producer: {0}", doc.Info.Producer); + } + } +} \ No newline at end of file diff --git a/PdfSharpCore.sln b/PdfSharpCore.sln index 4343b14f..4a722d34 100644 --- a/PdfSharpCore.sln +++ b/PdfSharpCore.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharpCore.Test", "PdfSharpCore.Test\PdfSharpCore.Test.csproj", "{A862C0CE-C095-459C-A32B-8FCDD15A93BF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "SampleApp\SampleApp.csproj", "{E2F17280-6C54-4711-AF1C-3286D2C45526}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,6 +46,10 @@ Global {A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Debug|Any CPU.Build.0 = Debug|Any CPU {A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Release|Any CPU.ActiveCfg = Release|Any CPU {A862C0CE-C095-459C-A32B-8FCDD15A93BF}.Release|Any CPU.Build.0 = Release|Any CPU + {E2F17280-6C54-4711-AF1C-3286D2C45526}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2F17280-6C54-4711-AF1C-3286D2C45526}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2F17280-6C54-4711-AF1C-3286D2C45526}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2F17280-6C54-4711-AF1C-3286D2C45526}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PdfSharpCore/!internal/DynamicallyAccessedMemberTypes.cs b/PdfSharpCore/!internal/DynamicallyAccessedMemberTypes.cs new file mode 100644 index 00000000..9c1369fb --- /dev/null +++ b/PdfSharpCore/!internal/DynamicallyAccessedMemberTypes.cs @@ -0,0 +1,103 @@ +// Included in .net 5 and later +#if !NET5_0_OR_GREATER +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Specifies the types of members that are dynamically accessed. + /// + /// This enumeration has a attribute that allows a + /// bitwise combination of its member values. + /// + [Flags] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + enum DynamicallyAccessedMemberTypes + { + /// + /// Specifies no members. + /// + None = 0, + + /// + /// Specifies the default, parameterless public constructor. + /// + PublicParameterlessConstructor = 0x0001, + + /// + /// Specifies all public constructors. + /// + PublicConstructors = 0x0002 | PublicParameterlessConstructor, + + /// + /// Specifies all non-public constructors. + /// + NonPublicConstructors = 0x0004, + + /// + /// Specifies all public methods. + /// + PublicMethods = 0x0008, + + /// + /// Specifies all non-public methods. + /// + NonPublicMethods = 0x0010, + + /// + /// Specifies all public fields. + /// + PublicFields = 0x0020, + + /// + /// Specifies all non-public fields. + /// + NonPublicFields = 0x0040, + + /// + /// Specifies all public nested types. + /// + PublicNestedTypes = 0x0080, + + /// + /// Specifies all non-public nested types. + /// + NonPublicNestedTypes = 0x0100, + + /// + /// Specifies all public properties. + /// + PublicProperties = 0x0200, + + /// + /// Specifies all non-public properties. + /// + NonPublicProperties = 0x0400, + + /// + /// Specifies all public events. + /// + PublicEvents = 0x0800, + + /// + /// Specifies all non-public events. + /// + NonPublicEvents = 0x1000, + + /// + /// Specifies all interfaces implemented by the type. + /// + Interfaces = 0x2000, + + /// + /// Specifies all members. + /// + All = ~None + } +} +#endif \ No newline at end of file diff --git a/PdfSharpCore/!internal/DynamicallyAccessedMembersAttribute.cs b/PdfSharpCore/!internal/DynamicallyAccessedMembersAttribute.cs new file mode 100644 index 00000000..b20b1015 --- /dev/null +++ b/PdfSharpCore/!internal/DynamicallyAccessedMembersAttribute.cs @@ -0,0 +1,59 @@ +// Included in .net 5 and later +#if !NET5_0_OR_GREATER +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that certain members on a specified are accessed dynamically, + /// for example through . + /// + /// + /// This allows tools to understand which members are being accessed during the execution + /// of a program. + /// + /// This attribute is valid on members whose type is or . + /// + /// When this attribute is applied to a location of type , the assumption is + /// that the string represents a fully qualified type name. + /// + /// When this attribute is applied to a class, interface, or struct, the members specified + /// can be accessed dynamically on instances returned from calling + /// on instances of that class, interface, or struct. + /// + /// If the attribute is applied to a method it's treated as a special case and it implies + /// the attribute should be applied to the "this" parameter of the method. As such the attribute + /// should only be used on instance methods of types assignable to System.Type (or string, but no methods + /// will use it there). + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, + Inherited = false)] +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + sealed class DynamicallyAccessedMembersAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified member types. + /// + /// The types of members dynamically accessed. + public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) + { + MemberTypes = memberTypes; + } + + /// + /// Gets the which specifies the type + /// of members dynamically accessed. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + } +} +#endif \ No newline at end of file diff --git a/PdfSharpCore/Drawing.BarCodes/CodeDataMatrix.cs b/PdfSharpCore/Drawing.BarCodes/CodeDataMatrix.cs index f64c8716..409594ab 100644 --- a/PdfSharpCore/Drawing.BarCodes/CodeDataMatrix.cs +++ b/PdfSharpCore/Drawing.BarCodes/CodeDataMatrix.cs @@ -29,13 +29,6 @@ #endregion using System; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif namespace PdfSharpCore.Drawing.BarCodes { diff --git a/PdfSharpCore/Drawing.BarCodes/CodeOmr.cs b/PdfSharpCore/Drawing.BarCodes/CodeOmr.cs index b29fc37c..81ffd010 100644 --- a/PdfSharpCore/Drawing.BarCodes/CodeOmr.cs +++ b/PdfSharpCore/Drawing.BarCodes/CodeOmr.cs @@ -67,11 +67,10 @@ protected internal override void Render(XGraphics gfx, XBrush brush, XFont font, XPoint pt = position - CodeBase.CalcDistance(AnchorType.TopLeft, Anchor, Size); uint value; uint.TryParse(Text, out value); -#if true // HACK: Project Wallenwein: set LK value |= 1; _synchronizeCode = true; -#endif + if (_synchronizeCode) { XRect rect = new XRect(pt.X, pt.Y, _makerThickness, Size.Height); diff --git a/PdfSharpCore/Drawing.BarCodes/DataMatrixImage.opensource.cs b/PdfSharpCore/Drawing.BarCodes/DataMatrixImage.opensource.cs index abefb1c6..120f5485 100644 --- a/PdfSharpCore/Drawing.BarCodes/DataMatrixImage.opensource.cs +++ b/PdfSharpCore/Drawing.BarCodes/DataMatrixImage.opensource.cs @@ -28,16 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif - - // ======================================================================================== // ======================================================================================== @@ -188,30 +178,7 @@ public XImage CreateImage(char[] code, int rows, int columns) /// public XImage CreateImage(char[] code, int rows, int columns, int pixelsize) { -#if GDI - Bitmap bm = new Bitmap(columns * pixelsize, rows * pixelsize); - using (Graphics gfx = Graphics.FromImage(bm)) - { - gfx.FillRectangle(System.Drawing.Brushes.White, new Rectangle(0, 0, columns * pixelsize, rows * pixelsize)); - - for (int i = rows - 1; i >= 0; i--) - { - for (int j = 0; j < columns; j++) - { - if (code[((rows - 1) - i) * columns + j] == (char)1) - gfx.FillRectangle(System.Drawing.Brushes.Black, j * pixelsize, i * pixelsize, pixelsize, pixelsize); - } - } - System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Firebrick, pixelsize); - gfx.DrawLine(pen, 0, 0, rows * pixelsize, columns * pixelsize); - gfx.DrawLine(pen, columns * pixelsize, 0, 0, rows * pixelsize); - } - XImage image = XImage.FromGdiPlusImage(bm); - image.Interpolate = false; - return image; -#elif WPF || __IOS__ || __ANDROID__ || PORTABLE return null; -#endif } } diff --git a/PdfSharpCore/Drawing.Internal/IImageImporter.cs b/PdfSharpCore/Drawing.Internal/IImageImporter.cs index ae92bee5..ec39b82e 100644 --- a/PdfSharpCore/Drawing.Internal/IImageImporter.cs +++ b/PdfSharpCore/Drawing.Internal/IImageImporter.cs @@ -58,20 +58,6 @@ internal class StreamReaderHelper { internal StreamReaderHelper(Stream stream) { -#if GDI || WPF - _stream = stream; - MemoryStream ms = stream as MemoryStream; - if (ms == null) - { - // THHO4STLA byte[] or MemoryStream? - _ownedMemoryStream = ms = new MemoryStream(); - CopyStream(stream, ms); - // For .NET 4: stream.CopyTo(ms); - } - _data = ms.GetBuffer(); - _length = (int)ms.Length; -#else - // For WinRT there is no GetBuffer() => alternative implementation for WinRT. // TODO: Are there advantages of GetBuffer()? It should reduce LOH fragmentation. _stream = stream; _stream.Position = 0; @@ -80,7 +66,6 @@ internal StreamReaderHelper(Stream stream) _length = (int)_stream.Length; _data = new byte[_length]; _stream.Read(_data, 0, _length); -#endif } internal byte GetByte(int offset) @@ -159,17 +144,6 @@ public int Length } private readonly int _length; - -#if GDI || WPF - /// - /// Gets the owned memory stream. Can be null if no MemoryStream was created. - /// - public MemoryStream OwnedMemoryStream - { - get { return _ownedMemoryStream; } - } - private readonly MemoryStream _ownedMemoryStream; -#endif } /// diff --git a/PdfSharpCore/Drawing.Internal/ImageImporter.cs b/PdfSharpCore/Drawing.Internal/ImageImporter.cs index f8b2a101..24b21d16 100644 --- a/PdfSharpCore/Drawing.Internal/ImageImporter.cs +++ b/PdfSharpCore/Drawing.Internal/ImageImporter.cs @@ -72,21 +72,6 @@ public ImportedImage ImportImage(Stream stream, PdfDocument document) return null; } -#if GDI || WPF || CORE - /// - /// Imports the image. - /// - public ImportedImage ImportImage(string filename, PdfDocument document) - { - ImportedImage ii; - using (Stream fs = File.OpenRead(filename)) - { - ii = ImportImage(fs, document); - } - return ii; - } -#endif - private readonly List _importers = new List(); } } diff --git a/PdfSharpCore/Drawing.Layout/XTextFormatter.cs b/PdfSharpCore/Drawing.Layout/XTextFormatter.cs index 6e699209..c3367059 100644 --- a/PdfSharpCore/Drawing.Layout/XTextFormatter.cs +++ b/PdfSharpCore/Drawing.Layout/XTextFormatter.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; +using System.Linq; using PdfSharpCore.Drawing.Layout.enums; using PdfSharpCore.Pdf.IO; @@ -89,6 +90,10 @@ public XFont Font double _cyAscent; double _cyDescent; double _spaceWidth; + double _lineHeight; + + // Bounding box of the formatted text after layout + private XRect _textLayout; /// /// Gets or sets the bounding box of the layout. @@ -101,15 +106,31 @@ public XRect LayoutRectangle XRect _layoutRectangle; /// - /// Gets or sets the alignment of the text. + /// When true, ignore the height of text areas when rendering multiline strings + /// + public bool AllowVerticalOverflow { get; set; } = false; + + /// + /// Gets or sets the horizontal alignment of the text. + /// + public XParagraphAlignment Alignment { get; set; } = XParagraphAlignment.Left; + + /// + /// Gets or sets the vertical alignment of the text. + /// + public XVerticalAlignment VerticalAlignment { get; set; } = XVerticalAlignment.Top; + + /// + /// Set vertical and horizontal alignment /// - public XParagraphAlignment Alignment + /// + public void SetAlignment(TextFormatAlignment alignments) { - get { return _alignment; } - set { _alignment = value; } + Alignment = alignments.Horizontal; + VerticalAlignment = alignments.Vertical; } - XParagraphAlignment _alignment = XParagraphAlignment.Left; - + + /// /// Draws the text. /// @@ -117,20 +138,25 @@ public XParagraphAlignment Alignment /// The font. /// The text brush. /// The layout rectangle. - public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle) + /// The line height. + public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XUnit? lineHeight = null) { - DrawString(text, font, brush, layoutRectangle, XStringFormats.TopLeft); + DrawString(text, font, brush, layoutRectangle, new TextFormatAlignment() + { + Horizontal = XParagraphAlignment.Justify, Vertical = XVerticalAlignment.Top + }, lineHeight); } /// - /// Draws the text. + /// Get the layout rectangle required. /// /// The text to be drawn. /// The font. /// The text brush. /// The layout rectangle. - /// The format. Must be XStringFormat.TopLeft - public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XStringFormat format) + /// The height of each line + public XRect GetLayout(string text, XFont font, XBrush brush, XRect layoutRectangle, + XUnit? lineHeight = null) { if (text == null) throw new ArgumentNullException("text"); @@ -138,34 +164,92 @@ public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectan throw new ArgumentNullException("font"); if (brush == null) throw new ArgumentNullException("brush"); - if (format.Alignment != XStringAlignment.Near || format.LineAlignment != XLineAlignment.Near) - throw new ArgumentException("Only TopLeft alignment is currently implemented."); Text = text; Font = font; LayoutRectangle = layoutRectangle; + + _lineHeight = lineHeight?.Point ?? _lineSpace; if (text.Length == 0) - return; + return new XRect(layoutRectangle.Location.X, layoutRectangle.Location.Y, 0, 0); CreateBlocks(); CreateLayout(); + return _layoutRectangle; + } + + /// + /// Draws the text. + /// + /// The text to be drawn. + /// The font. + /// The text brush. + /// The layout rectangle. + /// The alignments. + /// The height of each line. + public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, TextFormatAlignment alignments, + XUnit? lineHeight = null) + { + if (alignments == null) + throw new ArgumentNullException(nameof(alignments)); + + if (text.Length == 0) + return; + + GetLayout(text, font, brush, layoutRectangle, lineHeight); + + SetAlignment(alignments); + double dx = layoutRectangle.Location.X; - double dy = layoutRectangle.Location.Y + _cyAscent; + double dy = layoutRectangle.Location.Y; + + var lines = GetLines(_blocks).ToArray(); + + if (VerticalAlignment == XVerticalAlignment.Middle) + { + dy += (layoutRectangle.Height - _layoutRectangle.Height) / 2; + } + else if (VerticalAlignment == XVerticalAlignment.Bottom) + { + dy = layoutRectangle.Location.Y + layoutRectangle.Height - _layoutRectangle.Height + _lineHeight - + _cyDescent; + } + int count = _blocks.Count; - for (int idx = 0; idx < count; idx++) + foreach (var line in lines) { - Block block = _blocks[idx]; - if (block.Stop) - break; - if (block.Type == BlockType.LineBreak) - continue; - _gfx.DrawString(block.Text, font, brush, dx + block.Location.X, dy + block.Location.Y); + var lineBlocks = line as Block[] ?? line.ToArray(); + if (Alignment == XParagraphAlignment.Justify) + { + var locationX = dx; + var gapSize = (layoutRectangle.Width - lineBlocks.Select(l => l.Width).Sum())/ (lineBlocks.Count() - 1); + foreach (var block in lineBlocks) + { + _gfx.DrawString(block.Text.Trim(), font, brush, locationX, dy + lineBlocks.First().Location.Y, XStringFormats.TopLeft); + locationX += block.Width + gapSize; + } + } + else + { + var lineText = string.Join(" ", lineBlocks.Select(l => l.Text)); + var locationX = dx; + if (Alignment == XParagraphAlignment.Center) + locationX = dx + layoutRectangle.Width / 2; + if (Alignment == XParagraphAlignment.Right) + locationX += layoutRectangle.Width; + _gfx.DrawString(lineText, font, brush, locationX, dy + lineBlocks.First().Location.Y, GetXStringFormat()); + } } } + private static IEnumerable> GetLines(List blocks) + { + return blocks.GroupBy(b => b.Location.Y); + } + void CreateBlocks() { _blocks.Clear(); @@ -238,11 +322,11 @@ void CreateLayout() { if (Alignment == XParagraphAlignment.Justify) _blocks[firstIndex].Alignment = XParagraphAlignment.Left; - AlignLine(firstIndex, idx - 1, rectWidth); + HorizontalAlignLine(firstIndex, idx - 1, rectWidth); firstIndex = idx + 1; x = 0; - y += _lineSpace; - if (y > rectHeight) + y += _lineHeight; + if (!AllowVerticalOverflow && y > rectHeight) { block.Stop = true; break; @@ -258,10 +342,12 @@ void CreateLayout() } else { - AlignLine(firstIndex, idx - 1, rectWidth); + HorizontalAlignLine(firstIndex, idx - 1, rectWidth); + + // Begin implicit line break firstIndex = idx; - y += _lineSpace; - if (y > rectHeight) + y += _lineHeight; + if (!AllowVerticalOverflow && y > rectHeight) { block.Stop = true; break; @@ -272,16 +358,28 @@ void CreateLayout() } } if (firstIndex < count && Alignment != XParagraphAlignment.Justify) - AlignLine(firstIndex, count - 1, rectWidth); + HorizontalAlignLine(firstIndex, count - 1, rectWidth); + + var minY = _blocks.Min(b => b.Location.Y); + var maxY = _blocks.Max(b => b.Location.Y + _lineHeight); + var minX = _blocks.Min(b => b.Location.X); + var maxX = _blocks.Max(b => b.Location.X + b.Width); + _layoutRectangle = new XRect + { + X = minX, + Y = minY, + Height = maxY - minY, + Width = maxX - minX + }; } /// /// Align center, right, or justify. /// - void AlignLine(int firstIndex, int lastIndex, double layoutWidth) + void HorizontalAlignLine(int firstIndex, int lastIndex, double layoutWidth) { XParagraphAlignment blockAlignment = _blocks[firstIndex].Alignment; - if (_alignment == XParagraphAlignment.Left || blockAlignment == XParagraphAlignment.Left) + if (Alignment == XParagraphAlignment.Left || blockAlignment == XParagraphAlignment.Left) return; int count = lastIndex - firstIndex + 1; @@ -294,9 +392,9 @@ void AlignLine(int firstIndex, int lastIndex, double layoutWidth) double dx = Math.Max(layoutWidth - totalWidth, 0); //Debug.Assert(dx >= 0); - if (_alignment != XParagraphAlignment.Justify) + if (Alignment != XParagraphAlignment.Justify) { - if (_alignment == XParagraphAlignment.Center) + if (Alignment == XParagraphAlignment.Center) dx /= 2; for (int idx = firstIndex; idx <= lastIndex; idx++) { @@ -319,7 +417,6 @@ void AlignLine(int firstIndex, int lastIndex, double layoutWidth) // TODO: // - more XStringFormat variations - // - calculate bounding box // - left and right indent // - first line indent // - margins and paddings @@ -329,9 +426,30 @@ void AlignLine(int firstIndex, int lastIndex, double layoutWidth) // - hyphens, soft hyphens, hyphenation // - kerning // - change font, size, text color etc. - // - line spacing // - underline and strike-out variation // - super- and sub-script // - ... + + private XStringFormat GetXStringFormat() + { + switch (Alignment) + { + case XParagraphAlignment.Center: + return XStringFormats.TopCenter; + case XParagraphAlignment.Right: + return XStringFormats.TopRight; + case XParagraphAlignment.Default: + case XParagraphAlignment.Justify: + case XParagraphAlignment.Left: + default: + return XStringFormats.TopLeft; + } + } + } + + public class TextFormatAlignment + { + public XParagraphAlignment Horizontal { get; set; } = XParagraphAlignment.Left; + public XVerticalAlignment Vertical { get; set; } = XVerticalAlignment.Top; } } diff --git a/PdfSharpCore/Drawing.Layout/XTextSegmentFormatter.cs b/PdfSharpCore/Drawing.Layout/XTextSegmentFormatter.cs index 8879c147..87f045a7 100644 --- a/PdfSharpCore/Drawing.Layout/XTextSegmentFormatter.cs +++ b/PdfSharpCore/Drawing.Layout/XTextSegmentFormatter.cs @@ -85,7 +85,8 @@ public void DrawString(IEnumerable textSegments, XRect layoutRectan textSegments, layoutRectangle, format, - (block, dx, dy) => _gfx.DrawString(block.Text, block.Environment.Font, block.Environment.Brush, dx + block.Location.X, dy + block.Location.Y) + (block, dx, dy) => _gfx.DrawString(block.Text, block.Environment.Font, block.Environment.Brush, dx + block.Location.X, dy + block.Location.Y), + false ); } @@ -144,9 +145,11 @@ public XSize CalculateTextSize(IEnumerable textSegments, double wid var layoutRectangle = new XRect(0, 0, width, 100000000); var blocks = new List(); - ProcessTextSegments(textSegments, layoutRectangle, format, (block, dx, dy) => blocks.Add(block)); + ProcessTextSegments(textSegments, layoutRectangle, format, (block, dx, dy) => blocks.Add(block), true); - var height = blocks.Max(b => b.Location.Y); + var height = blocks.Any() + ? blocks.Max(b => b.Location.Y) + : 0; var maxLineHeight = 0.0; for (int i = blocks.Count - 1; i >= 0; i--) { @@ -158,10 +161,19 @@ public XSize CalculateTextSize(IEnumerable textSegments, double wid maxLineHeight = Math.Max(maxLineHeight, blocks[i].Environment.LineSpace); } - return new XSize(width, height + maxLineHeight); + var calculatedWith = blocks.Any() + ? blocks.Max(b => b.Location.X + b.Width) + : width; + + if (width < calculatedWith) + { + calculatedWith = width; + } + + return new XSize(calculatedWith, height + maxLineHeight); } - private void ProcessTextSegments(IEnumerable textSegments, XRect layoutRectangle, XStringFormat format, Action applyBlock) + private void ProcessTextSegments(IEnumerable textSegments, XRect layoutRectangle, XStringFormat format, Action applyBlock, bool applyBlockIfLineBreak) { if (textSegments.All(ts => string.IsNullOrEmpty(ts.Text))) { @@ -233,7 +245,7 @@ private void ProcessTextSegments(IEnumerable textSegments, XRect la break; } - if (block.Type == BlockType.LineBreak) + if (block.Type == BlockType.LineBreak && !applyBlockIfLineBreak) { continue; } @@ -388,6 +400,9 @@ private void CreateLayout(List> blockUnits, XRect layoutRectangle) break; } + + // necessary to correctly calculate closing line breaks + block.Location = new XPoint(0, y); } else { diff --git a/PdfSharpCore/Drawing.Layout/enums/XVerticalAlignment.cs b/PdfSharpCore/Drawing.Layout/enums/XVerticalAlignment.cs new file mode 100644 index 00000000..c204864b --- /dev/null +++ b/PdfSharpCore/Drawing.Layout/enums/XVerticalAlignment.cs @@ -0,0 +1,9 @@ +namespace PdfSharpCore.Drawing.Layout.enums +{ + public enum XVerticalAlignment + { + Top, + Middle, + Bottom, + } +} \ No newline at end of file diff --git a/PdfSharpCore/Drawing.Pdf/PdfGraphicsState.cs b/PdfSharpCore/Drawing.Pdf/PdfGraphicsState.cs index 77ccd9d5..2dda0101 100644 --- a/PdfSharpCore/Drawing.Pdf/PdfGraphicsState.cs +++ b/PdfSharpCore/Drawing.Pdf/PdfGraphicsState.cs @@ -31,13 +31,6 @@ using System.Diagnostics; using System.Globalization; using System.Text; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -#endif -using PdfSharpCore.Internal; using PdfSharpCore.Pdf; using PdfSharpCore.Pdf.Advanced; using PdfSharpCore.Pdf.Internal; @@ -515,36 +508,9 @@ public void SetAndRealizeClipPath(XGraphicsPath clipPath) void RealizeClipPath(XGraphicsPath clipPath) { -#if CORE - DiagnosticsHelper.HandleNotImplemented("RealizeClipPath"); -#endif -#if GDI - // Do not render an empty path. - if (clipPath._gdipPath.PointCount < 0) - return; -#endif -#if WPF - // Do not render an empty path. - if (clipPath._pathGeometry.Bounds.IsEmpty) - return; -#endif _renderer.BeginGraphicMode(); RealizeCtm(); -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _renderer.AppendPath(clipPath._corePath); -#endif -#if GDI && !WPF - _renderer.AppendPath(clipPath._gdipPath); -#endif -#if WPF && !GDI - _renderer.AppendPath(clipPath._pathGeometry); -#endif -#if WPF && GDI - if (_renderer.Gfx.TargetContext == XGraphicTargetContext.GDI) - _renderer.AppendPath(clipPath._gdipPath); - else - _renderer.AppendPath(clipPath._pathGeometry); -#endif _renderer.Append(clipPath.FillMode == XFillMode.Winding ? "W n\n" : "W* n\n"); } diff --git a/PdfSharpCore/Drawing.Pdf/XGraphicsPdfRenderer.cs b/PdfSharpCore/Drawing.Pdf/XGraphicsPdfRenderer.cs index ff1d6185..62e53fcf 100644 --- a/PdfSharpCore/Drawing.Pdf/XGraphicsPdfRenderer.cs +++ b/PdfSharpCore/Drawing.Pdf/XGraphicsPdfRenderer.cs @@ -34,21 +34,6 @@ using System.Globalization; using System.Collections.Generic; using System.Text; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -#endif using PdfSharpCore.Fonts.OpenType; using PdfSharpCore.Internal; using PdfSharpCore.Pdf; @@ -392,34 +377,9 @@ public void DrawPath(XPen pen, XBrush brush, XGraphicsPath path) if (pen == null && brush == null) throw new ArgumentNullException("pen"); -#if CORE || PORTABLE Realize(pen, brush); AppendPath(path._corePath); AppendStrokeFill(pen, brush, path.FillMode, false); -#endif -#if GDI && !WPF - Realize(pen, brush); - AppendPath(path._gdipPath); - AppendStrokeFill(pen, brush, path.FillMode, false); -#endif -#if WPF && !GDI - Realize(pen, brush); - AppendPath(path._pathGeometry); - AppendStrokeFill(pen, brush, path.FillMode, false); -#endif -#if WPF && GDI - Realize(pen, brush); - if (_gfx.TargetContext == XGraphicTargetContext.GDI) - AppendPath(path._gdipPath); - else - AppendPath(path._pathGeometry); - AppendStrokeFill(pen, brush, path.FillMode, false); -#endif -#if NETFX_CORE - Realize(pen, brush); - AppendPath(path._pathGeometry); - AppendStrokeFill(pen, brush, path.FillMode, false); -#endif } // ----- DrawString --------------------------------------------------------------------------- @@ -1139,30 +1099,6 @@ void AppendPartialArcQuadrant(double x, double y, double width, double height, d } } -#if WPF || NETFX_CORE - void AppendPartialArc(SysPoint point1, SysPoint point2, double rotationAngle, - SysSize size, bool isLargeArc, SweepDirection sweepDirection, PathStart pathStart) - { - const string format = Config.SignificantFigures4; - - Debug.Assert(pathStart == PathStart.Ignore1st); - - int pieces; - PointCollection points = GeometryHelper.ArcToBezier(point1.X, point1.Y, size.Width, size.Height, rotationAngle, isLargeArc, - sweepDirection == SweepDirection.Clockwise, point2.X, point2.Y, out pieces); - - int count = points.Count; - int start = count % 3 == 1 ? 1 : 0; - if (start == 1) - AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y); - for (int idx = start; idx < count; idx += 3) - AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", - points[idx].X, points[idx].Y, - points[idx + 1].X, points[idx + 1].Y, - points[idx + 2].X, points[idx + 2].Y); - } -#endif - /// /// Appends a Bézier curve for a cardinal spline through pt1 and pt2. /// @@ -1175,60 +1111,6 @@ void AppendCurveSegment(XPoint pt0, XPoint pt1, XPoint pt2, XPoint pt3, double t pt2.X, pt2.Y); } -#if CORE_ - /// - /// Appends the content of a GraphicsPath object. - /// - internal void AppendPath(GraphicsPath path) - { - int count = path.PointCount; - if (count == 0) - return; - PointF[] points = path.PathPoints; - Byte[] types = path.PathTypes; - - for (int idx = 0; idx < count; idx++) - { - // From GDI+ documentation: - const byte PathPointTypeStart = 0; // move - const byte PathPointTypeLine = 1; // line - const byte PathPointTypeBezier = 3; // default Bezier (= cubic Bezier) - const byte PathPointTypePathTypeMask = 0x07; // type mask (lowest 3 bits). - //const byte PathPointTypeDashMode = 0x10; // currently in dash mode. - //const byte PathPointTypePathMarker = 0x20; // a marker for the path. - const byte PathPointTypeCloseSubpath = 0x80; // closed flag - - byte type = types[idx]; - switch (type & PathPointTypePathTypeMask) - { - case PathPointTypeStart: - //PDF_moveto(pdf, points[idx].X, points[idx].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} m\n", points[idx].X, points[idx].Y); - break; - - case PathPointTypeLine: - //PDF_lineto(pdf, points[idx].X, points[idx].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y); - if ((type & PathPointTypeCloseSubpath) != 0) - Append("h\n"); - break; - - case PathPointTypeBezier: - Debug.Assert(idx + 2 < count); - //PDF_curveto(pdf, points[idx].X, points[idx].Y, - // points[idx + 1].X, points[idx + 1].Y, - // points[idx + 2].X, points[idx + 2].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", points[idx].X, points[idx].Y, - points[++idx].X, points[idx].Y, points[++idx].X, points[idx].Y); - if ((types[idx] & PathPointTypeCloseSubpath) != 0) - Append("h\n"); - break; - } - } - } -#endif - -#if CORE || __IOS__ || __ANDROID__ || PORTABLE /// /// Appends the content of a GraphicsPath object. /// @@ -1281,66 +1163,7 @@ internal void AppendPath(CoreGraphicsPath path) // } //} } -#endif - -#if GDI - /// - /// Appends the content of a GraphicsPath object. - /// - internal void AppendPath(GraphicsPath path) - { -#if true - AppendPath(XGraphics.MakeXPointArray(path.PathPoints, 0, path.PathPoints.Length), path.PathTypes); -#else - int count = path.PointCount; - if (count == 0) - return; - PointF[] points = path.PathPoints; - Byte[] types = path.PathTypes; - - for (int idx = 0; idx < count; idx++) - { - // From GDI+ documentation: - const byte PathPointTypeStart = 0; // move - const byte PathPointTypeLine = 1; // line - const byte PathPointTypeBezier = 3; // default Bezier (= cubic Bezier) - const byte PathPointTypePathTypeMask = 0x07; // type mask (lowest 3 bits). - //const byte PathPointTypeDashMode = 0x10; // currently in dash mode. - //const byte PathPointTypePathMarker = 0x20; // a marker for the path. - const byte PathPointTypeCloseSubpath = 0x80; // closed flag - - byte type = types[idx]; - switch (type & PathPointTypePathTypeMask) - { - case PathPointTypeStart: - //PDF_moveto(pdf, points[idx].X, points[idx].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} m\n", points[idx].X, points[idx].Y); - break; - - case PathPointTypeLine: - //PDF_lineto(pdf, points[idx].X, points[idx].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y); - if ((type & PathPointTypeCloseSubpath) != 0) - Append("h\n"); - break; - - case PathPointTypeBezier: - Debug.Assert(idx + 2 < count); - //PDF_curveto(pdf, points[idx].X, points[idx].Y, - // points[idx + 1].X, points[idx + 1].Y, - // points[idx + 2].X, points[idx + 2].Y); - AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", points[idx].X, points[idx].Y, - points[++idx].X, points[idx].Y, points[++idx].X, points[idx].Y); - if ((types[idx] & PathPointTypeCloseSubpath) != 0) - Append("h\n"); - break; - } - } -#endif - } -#endif -#if CORE || GDI || __IOS__ || __ANDROID__ || PORTABLE void AppendPath(XPoint[] points, Byte[] types) { const string format = Config.SignificantFigures4; @@ -1389,117 +1212,6 @@ void AppendPath(XPoint[] points, Byte[] types) } } } -#endif - -#if WPF || NETFX_CORE - /// - /// Appends the content of a PathGeometry object. - /// - internal void AppendPath(PathGeometry geometry) - { - const string format = Config.SignificantFigures4; - - foreach (PathFigure figure in geometry.Figures) - { -#if DEBUG - //#warning For DdlGBE_Chart_Layout (WPF) execution stucks at this Assertion. - // The empty Figure is added via XGraphicsPath.CurrentPathFigure Getter. - // Some methods like XGraphicsPath.AddRectangle() or AddLine() use this emtpy Figure to add Segments, others like AddEllipse() don't. - // Here, _pathGeometry.AddGeometry() of course ignores this first Figure and adds a second. - // Encapsulate relevant Add methods to delete a first emty Figure or move the Addition of an first empty Figure to a GetOrCreateCurrentPathFigure() or simply remove Assertion? - // Look for: - // MAOS4STLA: CurrentPathFigure. - - - if (figure.Segments.Count == 0) - 42.GetType(); - Debug.Assert(figure.Segments.Count > 0); -#endif - // Skip the Move if the segment is empty. Workaround for empty segments. Empty segments should not occur (see Debug.Assert above). - if (figure.Segments.Count > 0) - { - // Move to start point. - SysPoint currentPoint = figure.StartPoint; - AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", currentPoint.X, currentPoint.Y); - - foreach (PathSegment segment in figure.Segments) - { - Type type = segment.GetType(); - if (type == typeof(LineSegment)) - { - // Draw a single line. - SysPoint point = ((LineSegment)segment).Point; - currentPoint = point; - AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", point.X, point.Y); - } - else if (type == typeof(PolyLineSegment)) - { - // Draw connected lines. - PointCollection points = ((PolyLineSegment)segment).Points; - foreach (SysPoint point in points) - { - currentPoint = point; // I forced myself not to optimize this assignment. - AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", point.X, point.Y); - } - } - else if (type == typeof(BezierSegment)) - { - // Draw Bézier curve. - BezierSegment seg = (BezierSegment)segment; - SysPoint point1 = seg.Point1; - SysPoint point2 = seg.Point2; - SysPoint point3 = seg.Point3; - AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", - point1.X, point1.Y, point2.X, point2.Y, point3.X, point3.Y); - currentPoint = point3; - } - else if (type == typeof(PolyBezierSegment)) - { - // Draw connected Bézier curves. - PointCollection points = ((PolyBezierSegment)segment).Points; - int count = points.Count; - if (count > 0) - { - Debug.Assert(count % 3 == 0, "Number of Points in PolyBezierSegment are not a multiple of 3."); - for (int idx = 0; idx < count - 2; idx += 3) - { - SysPoint point1 = points[idx]; - SysPoint point2 = points[idx + 1]; - SysPoint point3 = points[idx + 2]; - AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", - point1.X, point1.Y, point2.X, point2.Y, point3.X, point3.Y); - } - currentPoint = points[count - 1]; - } - } - else if (type == typeof(ArcSegment)) - { - // Draw arc. - ArcSegment seg = (ArcSegment)segment; - AppendPartialArc(currentPoint, seg.Point, seg.RotationAngle, seg.Size, seg.IsLargeArc, seg.SweepDirection, PathStart.Ignore1st); - currentPoint = seg.Point; - } - else if (type == typeof(QuadraticBezierSegment)) - { - QuadraticBezierSegment seg = (QuadraticBezierSegment)segment; - currentPoint = seg.Point2; - // TODOWPF: Undone because XGraphics has no such curve type - throw new NotImplementedException("AppendPath with QuadraticBezierSegment."); - } - else if (type == typeof(PolyQuadraticBezierSegment)) - { - PolyQuadraticBezierSegment seg = (PolyQuadraticBezierSegment)segment; - currentPoint = seg.Points[seg.Points.Count - 1]; - // TODOWPF: Undone because XGraphics has no such curve type - throw new NotImplementedException("AppendPath with PolyQuadraticBezierSegment."); - } - } - if (figure.IsClosed) - Append("h\n"); - } - } - } -#endif internal void Append(string value) { @@ -1917,30 +1629,6 @@ internal XPoint WorldToView(XPoint point) } #endregion -#if GDI - [Conditional("DEBUG")] - void DumpPathData(PathData pathData) - { - XPoint[] points = new XPoint[pathData.Points.Length]; - for (int i = 0; i < points.Length; i++) - points[i] = new XPoint(pathData.Points[i].X, pathData.Points[i].Y); - - DumpPathData(points, pathData.Types); - } -#endif -#if CORE || GDI - [Conditional("DEBUG")] - void DumpPathData(XPoint[] points, byte[] types) - { - int count = points.Length; - for (int idx = 0; idx < count; idx++) - { - string info = PdfEncoders.Format("{0:X} {1:####0.000} {2:####0.000}", types[idx], points[idx].X, points[idx].Y); - Debug.WriteLine(info, "PathData"); - } - } -#endif - /// /// Gets the owning PdfDocument of this page or form. /// diff --git a/PdfSharpCore/Drawing/FontFamilyCache.cs b/PdfSharpCore/Drawing/FontFamilyCache.cs index 398690a2..65d61edd 100644 --- a/PdfSharpCore/Drawing/FontFamilyCache.cs +++ b/PdfSharpCore/Drawing/FontFamilyCache.cs @@ -33,15 +33,6 @@ using System.Globalization; using System.IO; using System.Text; -#if CORE || GDI -using System.Drawing; -using GdiFontFamily = System.Drawing.FontFamily; -#endif -#if WPF -using System.Windows.Media; -using System.Windows.Markup; -using WpfFontFamily = System.Windows.Media.FontFamily; -#endif using PdfSharpCore.Fonts; using PdfSharpCore.Fonts.OpenType; using PdfSharpCore.Internal; diff --git a/PdfSharpCore/Drawing/FontFamilyInternal.cs b/PdfSharpCore/Drawing/FontFamilyInternal.cs index 32bfd4c9..8698a6c0 100644 --- a/PdfSharpCore/Drawing/FontFamilyInternal.cs +++ b/PdfSharpCore/Drawing/FontFamilyInternal.cs @@ -30,15 +30,6 @@ using System.Diagnostics; using System.Globalization; using PdfSharpCore.Internal; -#if CORE || GDI -using System.Drawing; -using GdiFontFamily = System.Drawing.FontFamily; -#endif -#if WPF -using System.Windows.Media; -using System.Windows.Markup; -using WpfFontFamily = System.Windows.Media.FontFamily; -#endif namespace PdfSharpCore.Drawing { @@ -60,55 +51,7 @@ internal class FontFamilyInternal FontFamilyInternal(string familyName, bool createPlatformObjects) { _sourceName = _name = familyName; -#if CORE || GDI - if (createPlatformObjects) - { - _gdiFontFamily = new GdiFontFamily(familyName); - _name = _gdiFontFamily.Name; - } -#endif -#if WPF && !SILVERLIGHT - if (createPlatformObjects) - { - _wpfFontFamily = new WpfFontFamily(familyName); - _name = _wpfFontFamily.FamilyNames[FontHelper.XmlLanguageEnUs]; - } -#endif -#if SILVERLIGHT - _wpfFontFamily = new WpfFontFamily(_name); - _name = _wpfFontFamily.Source; // Not expected to change _name. -#endif - } - -#if CORE || GDI - FontFamilyInternal(GdiFontFamily gdiFontFamily) - { - _sourceName = _name = gdiFontFamily.Name; - _gdiFontFamily = gdiFontFamily; -#if WPF - // Hybrid build only. - _wpfFontFamily = new WpfFontFamily(gdiFontFamily.Name); -#endif - } -#endif - -#if WPF - FontFamilyInternal(WpfFontFamily wpfFontFamily) - { -#if !SILVERLIGHT - _sourceName = wpfFontFamily.Source; - _name = wpfFontFamily.FamilyNames[FontHelper.XmlLanguageEnUs]; - _wpfFontFamily = wpfFontFamily; -#else - _sourceName = _name = wpfFontFamily.Source; - _wpfFontFamily = wpfFontFamily; -#endif -#if GDI - // Hybrid build only. - _gdiFontFamily = new GdiFontFamily(_sourceName); -#endif } -#endif internal static FontFamilyInternal GetOrCreateFromName(string familyName, bool createPlatformObject) { @@ -126,29 +69,6 @@ internal static FontFamilyInternal GetOrCreateFromName(string familyName, bool c finally { Lock.ExitFontFactory(); } } -#if CORE || GDI - internal static FontFamilyInternal GetOrCreateFromGdi(GdiFontFamily gdiFontFamily) - { - try - { - Lock.EnterFontFactory(); - FontFamilyInternal fontFamily = new FontFamilyInternal(gdiFontFamily); - fontFamily = FontFamilyCache.CacheOrGetFontFamily(fontFamily); - return fontFamily; - } - finally { Lock.ExitFontFactory(); } - } -#endif - -#if WPF - internal static FontFamilyInternal GetOrCreateFromWpf(WpfFontFamily wpfFontFamily) - { - FontFamilyInternal fontFamily = new FontFamilyInternal(wpfFontFamily); - fontFamily = FontFamilyCache.CacheOrGetFontFamily(fontFamily); - return fontFamily; - } -#endif - /// /// Gets the family name this family was originally created with. /// @@ -168,30 +88,6 @@ public string Name } readonly string _name; -#if CORE || GDI - /// - /// Gets the underlying GDI+ font family object. - /// Is null if the font was created by a font resolver. - /// - public GdiFontFamily GdiFamily - { - get { return _gdiFontFamily; } - } - readonly GdiFontFamily _gdiFontFamily; -#endif - -#if WPF - /// - /// Gets the underlying WPF font family object. - /// Is null if the font was created by a font resolver. - /// - public WpfFontFamily WpfFamily - { - get { return _wpfFontFamily; } - } - readonly WpfFontFamily _wpfFontFamily; -#endif - /// /// Gets the DebuggerDisplayAttribute text. /// diff --git a/PdfSharpCore/Drawing/FontHelper.cs b/PdfSharpCore/Drawing/FontHelper.cs index fd93e628..0ba8eadf 100644 --- a/PdfSharpCore/Drawing/FontHelper.cs +++ b/PdfSharpCore/Drawing/FontHelper.cs @@ -31,29 +31,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -#if CORE || GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Markup; -using WpfFontStyle = System.Windows.FontStyle; -using WpfFontWeight = System.Windows.FontWeight; -using WpfBrush = System.Windows.Media.Brush; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -#endif -#if NETFX_CORE -using Windows.UI.Text; -using Windows.UI.Xaml.Media; -#endif using PdfSharpCore.Fonts; using PdfSharpCore.Fonts.OpenType; @@ -146,194 +123,6 @@ public static XSize MeasureString(string text, XFont font, XStringFormat stringF return size; } -#if CORE || GDI - public static GdiFont CreateFont(string familyName, double emSize, GdiFontStyle style, out XFontSource fontSource) - { - fontSource = null; - // ReSharper disable once JoinDeclarationAndInitializer - GdiFont font; - - // Use font resolver in CORE build. XPrivateFontCollection exists only in GDI and WPF build. -#if GDI - // Try private font collection first. - font = XPrivateFontCollection.TryCreateFont(familyName, emSize, style, out fontSource); - if (font != null) - { - // Get font source is different for this font because Win32 does not know it. - return font; - } -#endif - // Create ordinary Win32 font. - font = new GdiFont(familyName, (float)emSize, style, GraphicsUnit.World); - return font; - } -#endif - -#if WPF -#if !SILVERLIGHT - public static readonly CultureInfo CultureInfoEnUs = CultureInfo.GetCultureInfo("en-US"); - public static readonly XmlLanguage XmlLanguageEnUs = XmlLanguage.GetLanguage("en-US"); -#endif - /// - /// Creates a typeface. - /// - public static Typeface CreateTypeface(WpfFontFamily family, XFontStyle style) - { - // BUG: does not work with fonts that have others than the four default styles - WpfFontStyle fontStyle = FontStyleFromStyle(style); - WpfFontWeight fontWeight = FontWeightFromStyle(style); -#if !SILVERLIGHT - WpfTypeface typeface = new WpfTypeface(family, fontStyle, fontWeight, FontStretches.Normal); -#else - WpfTypeface typeface = null; -#endif - return typeface; - } - -#if !SILVERLIGHT - /// - /// Creates the formatted text. - /// - public static FormattedText CreateFormattedText(string text, Typeface typeface, double emSize, WpfBrush brush) - { - //FontFamily fontFamily = new FontFamily(testFontName); - //typeface = new Typeface(fontFamily, FontStyles.Normal, FontWeights.Bold, FontStretches.Condensed); - //List typefaces = new List(fontFamily.GetTypefaces()); - //typefaces.GetType(); - //typeface = s_typefaces[0]; - - // BUG: does not work with fonts that have others than the four default styles - FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"), FlowDirection.LeftToRight, typeface, emSize, brush); - // .NET 4.0 feature new NumberSubstitution(), TextFormattingMode.Display); - //formattedText.SetFontWeight(FontWeights.Bold); - //formattedText.SetFontStyle(FontStyles.Oblique); - //formattedText.SetFontStretch(FontStretches.Condensed); - return formattedText; - } -#endif - -#if SILVERLIGHT_ - /// - /// Creates the TextBlock. - /// - public static TextBlock CreateTextBlock(string text, XGlyphTypeface glyphTypeface, double emSize, Brush brush) - { - TextBlock textBlock = new TextBlock(); - textBlock.FontFamily = glyphTypeface.FontFamily; - textBlock.FontSource = glyphTypeface.FontSource; - textBlock.FontSize = emSize; - textBlock.FontWeight = glyphTypeface.IsBold ? FontWeights.Bold : FontWeights.Normal; - textBlock.FontStyle = glyphTypeface.IsItalic ? FontStyles.Italic : FontStyles.Normal; - textBlock.Foreground = brush; - textBlock.Text = text; - - return textBlock; - } -#endif - - /// - /// Simple hack to make it work... - /// - public static WpfFontStyle FontStyleFromStyle(XFontStyle style) - { - switch (style & XFontStyle.BoldItalic) // Mask out Underline, Strikeout, etc. - { - case XFontStyle.Regular: - return FontStyles.Normal; - - case XFontStyle.Bold: - return FontStyles.Normal; - - case XFontStyle.Italic: - return FontStyles.Italic; - - case XFontStyle.BoldItalic: - return FontStyles.Italic; - } - return FontStyles.Normal; - } - - /// - /// Simple hack to make it work... - /// - public static FontWeight FontWeightFromStyle(XFontStyle style) - { - switch (style) - { - case XFontStyle.Regular: - return FontWeights.Normal; - - case XFontStyle.Bold: - return FontWeights.Bold; - - case XFontStyle.Italic: - return FontWeights.Normal; - - case XFontStyle.BoldItalic: - return FontWeights.Bold; - } - return FontWeights.Normal; - } - - /// - /// Determines whether the style is available as a glyph type face in the specified font family, i.e. the specified style is not simulated. - /// - public static bool IsStyleAvailable(XFontFamily family, XGdiFontStyle style) - { - style &= XGdiFontStyle.BoldItalic; -#if !SILVERLIGHT - // TODOWPF: check for correctness - // FontDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptor(family.Name, style); - //XFontMetrics metrics = descriptor.FontMetrics; - - // style &= XFontStyle.Regular | XFontStyle.Bold | XFontStyle.Italic | XFontStyle.BoldItalic; // same as XFontStyle.BoldItalic - List typefaces = new List(family.WpfFamily.GetTypefaces()); - foreach (WpfTypeface typeface in typefaces) - { - bool bold = typeface.Weight == FontWeights.Bold; - bool italic = typeface.Style == FontStyles.Italic; - switch (style) - { - case XGdiFontStyle.Regular: - if (!bold && !italic) - return true; - break; - - case XGdiFontStyle.Bold: - if (bold && !italic) - return true; - break; - - case XGdiFontStyle.Italic: - if (!bold && italic) - return true; - break; - - case XGdiFontStyle.BoldItalic: - if (bold && italic) - return true; - break; - } - ////// typeface.sty - ////// bool available = false; - ////// GlyphTypeface glyphTypeface; - ////// if (typeface.TryGetGlyphTypeface(out glyphTypeface)) - ////// { - //////#if DEBUG_ - ////// glyphTypeface.GetType(); - //////#endif - ////// available = true; - ////// } - ////// if (available) - ////// return true; - } - return false; -#else - return true; // AGHACK -#endif - } -#endif - /// /// Calculates an Adler32 checksum combined with the buffer length /// in a 64 bit unsigned integer. @@ -362,7 +151,6 @@ public static ulong CalcChecksum(byte[] buffer) s1 %= prime; s2 %= prime; } - //return ((ulong)((ulong)(((ulong)s2 << 16) | (ulong)s1)) << 32) | (ulong)buffer.Length; ulong ul1 = (ulong)s2 << 16; ul1 = ul1 | s1; ulong ul2 = (ulong)buffer.Length; diff --git a/PdfSharpCore/Drawing/GeometryHelper.cs b/PdfSharpCore/Drawing/GeometryHelper.cs index 833a2da2..4f8e30f7 100644 --- a/PdfSharpCore/Drawing/GeometryHelper.cs +++ b/PdfSharpCore/Drawing/GeometryHelper.cs @@ -30,21 +30,6 @@ using System; using System.Diagnostics; using System.Collections.Generic; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -#endif -#if NETFX_CORE || UWP -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -#endif using PdfSharpCore.Internal; // ReSharper disable RedundantNameQualifier @@ -57,164 +42,6 @@ namespace PdfSharpCore.Drawing /// static class GeometryHelper { -#if WPF || NETFX_CORE - /// - /// Appends a Bézier segment from a curve. - /// - public static BezierSegment CreateCurveSegment(XPoint pt0, XPoint pt1, XPoint pt2, XPoint pt3, double tension3) - { -#if !SILVERLIGHT && !NETFX_CORE - return new BezierSegment( - new SysPoint(pt1.X + tension3 * (pt2.X - pt0.X), pt1.Y + tension3 * (pt2.Y - pt0.Y)), - new SysPoint(pt2.X - tension3 * (pt3.X - pt1.X), pt2.Y - tension3 * (pt3.Y - pt1.Y)), - new SysPoint(pt2.X, pt2.Y), true); -#else - BezierSegment bezierSegment = new BezierSegment(); - bezierSegment.Point1 = new SysPoint(pt1.X + tension3 * (pt2.X - pt0.X), pt1.Y + tension3 * (pt2.Y - pt0.Y)); - bezierSegment.Point2 = new SysPoint(pt2.X - tension3 * (pt3.X - pt1.X), pt2.Y - tension3 * (pt3.Y - pt1.Y)); - bezierSegment.Point3 = new SysPoint(pt2.X, pt2.Y); - return bezierSegment; -#endif - } -#endif - -#if WPF || NETFX_CORE - /// - /// Creates a path geometry from a polygon. - /// - public static PathGeometry CreatePolygonGeometry(SysPoint[] points, XFillMode fillMode, bool closed) - { - PolyLineSegment seg = new PolyLineSegment(); - int count = points.Length; - // For correct drawing the start point of the segment must not be the same as the first point. - for (int idx = 1; idx < count; idx++) - seg.Points.Add(new SysPoint(points[idx].X, points[idx].Y)); -#if !SILVERLIGHT && !NETFX_CORE - seg.IsStroked = true; -#endif - PathFigure fig = new PathFigure(); - fig.StartPoint = new SysPoint(points[0].X, points[0].Y); - fig.Segments.Add(seg); - fig.IsClosed = closed; - PathGeometry geo = new PathGeometry(); - geo.FillRule = fillMode == XFillMode.Winding ? FillRule.Nonzero : FillRule.EvenOdd; - geo.Figures.Add(fig); - return geo; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Creates a path geometry from a polygon. - /// - public static PolyLineSegment CreatePolyLineSegment(SysPoint[] points, XFillMode fillMode, bool closed) - { - PolyLineSegment seg = new PolyLineSegment(); - int count = points.Length; - // For correct drawing the start point of the segment must not be the same as the first point. - for (int idx = 1; idx < count; idx++) - seg.Points.Add(new SysPoint(points[idx].X, points[idx].Y)); -#if !SILVERLIGHT && !NETFX_CORE - seg.IsStroked = true; -#endif - return seg; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Creates the arc segment from parameters of the GDI+ DrawArc function. - /// - public static ArcSegment CreateArcSegment(double x, double y, double width, double height, double startAngle, - double sweepAngle, out SysPoint startPoint) - { - // Normalize the angles. - double α = startAngle; - if (α < 0) - α = α + (1 + Math.Floor((Math.Abs(α) / 360))) * 360; - else if (α > 360) - α = α - Math.Floor(α / 360) * 360; - Debug.Assert(α >= 0 && α <= 360); - - if (Math.Abs(sweepAngle) >= 360) - sweepAngle = Math.Sign(sweepAngle) * 360; - double β = startAngle + sweepAngle; - if (β < 0) - β = β + (1 + Math.Floor((Math.Abs(β) / 360))) * 360; - else if (β > 360) - β = β - Math.Floor(β / 360) * 360; - - if (α == 0 && β < 0) - α = 360; - else if (α == 360 && β > 0) - α = 0; - - // Scanling factor. - double δx = width / 2; - double δy = height / 2; - - // Center of ellipse. - double x0 = x + δx; - double y0 = y + δy; - - double cosα, cosβ, sinα, sinβ; - if (width == height) - { - // Circular arc needs no correction. - α = α * Calc.Deg2Rad; - β = β * Calc.Deg2Rad; - } - else - { - // Elliptic arc needs the angles to be adjusted such that the scaling transformation is compensated. - α = α * Calc.Deg2Rad; - sinα = Math.Sin(α); - if (Math.Abs(sinα) > 1E-10) - { - if (α < Math.PI) - α = Math.PI / 2 - Math.Atan(δy * Math.Cos(α) / (δx * sinα)); - else - α = 3 * Math.PI / 2 - Math.Atan(δy * Math.Cos(α) / (δx * sinα)); - } - //α = Calc.πHalf - Math.Atan(δy * Math.Cos(α) / (δx * sinα)); - β = β * Calc.Deg2Rad; - sinβ = Math.Sin(β); - if (Math.Abs(sinβ) > 1E-10) - { - if (β < Math.PI) - β = Math.PI / 2 - Math.Atan(δy * Math.Cos(β) / (δx * sinβ)); - else - β = 3 * Math.PI / 2 - Math.Atan(δy * Math.Cos(β) / (δx * sinβ)); - } - //β = Calc.πHalf - Math.Atan(δy * Math.Cos(β) / (δx * sinβ)); - } - - sinα = Math.Sin(α); - cosα = Math.Cos(α); - sinβ = Math.Sin(β); - cosβ = Math.Cos(β); - - startPoint = new SysPoint(x0 + δx * cosα, y0 + δy * sinα); - SysPoint destPoint = new SysPoint(x0 + δx * cosβ, y0 + δy * sinβ); - SysSize size = new SysSize(δx, δy); - bool isLargeArc = Math.Abs(sweepAngle) >= 180; - SweepDirection sweepDirection = sweepAngle > 0 ? SweepDirection.Clockwise : SweepDirection.Counterclockwise; -#if !SILVERLIGHT && !NETFX_CORE - bool isStroked = true; - ArcSegment seg = new ArcSegment(destPoint, size, 0, isLargeArc, sweepDirection, isStroked); -#else - ArcSegment seg = new ArcSegment(); - seg.Point = destPoint; - seg.Size = size; - seg.RotationAngle = 0; - seg.IsLargeArc = isLargeArc; - seg.SweepDirection = sweepDirection; - // isStroked does not exist in Silverlight 3 -#endif - return seg; - } -#endif - /// /// Creates between 1 and 5 Béziers curves from parameters specified like in GDI+. /// @@ -486,389 +313,5 @@ public static List BezierCurveFromArc(XPoint point1, XPoint point2, XSiz return BezierCurveFromArc(center.X - δx * factor, center.Y - δy, 2 * δx * factor, 2 * δy, α / Calc.Deg2Rad, sweepAngle / Calc.Deg2Rad, pathStart, ref matrix); } - - - - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - // The code below comes from WPF source code, because I was not able to convert an arc - // to a series of Bezier curves exactly the way WPF renders the arc. I tested my own code - // with the MinBar Test Suite from QualityLogic and could not find out why it does not match. - // My Bezier curves came very close to the arc, but in some cases they do simply not match. - // So I gave up and use the WPF code. -#if WPF || NETFX_CORE - - // ReSharper disable InconsistentNaming - const double FUZZ = 1e-6; // Relative 0 - // ReSharper restore InconsistentNaming - - //+------------------------------------------------------------------------------------------------- - - // - // Function: GetArcAngle - // - // Synopsis: Get the number of Bezier arcs, and sine & cosine of each - // - // Notes: This is a private utility used by ArcToBezier - // We break the arc into pieces so that no piece will span more than 90 degrees. - // The input points are on the unit circle - // - //------------------------------------------------------------------------------------------------- - public static void - GetArcAngle( - XPoint startPoint, // Start point - XPoint endPoint, // End point - bool isLargeArc, // Choose the larger of the 2 possible arcs if TRUE - //SweepDirection sweepDirection, // Direction n which to sweep the arc. - bool isClockwise, - out double cosArcAngle, // Cosine of a the sweep angle of one arc piece - out double sinArcAngle, // Sine of a the sweep angle of one arc piece - out int pieces) // Out: The number of pieces - { - double angle; - - // The points are on the unit circle, so: - cosArcAngle = startPoint.X * endPoint.X + startPoint.Y * endPoint.Y; - sinArcAngle = startPoint.X * endPoint.Y - startPoint.Y * endPoint.X; - - if (cosArcAngle >= 0) - { - if (isLargeArc) - { - // The angle is between 270 and 360 degrees, so - pieces = 4; - } - else - { - // The angle is between 0 and 90 degrees, so - pieces = 1; - return; // We already have the cosine and sine of the angle - } - } - else - { - if (isLargeArc) - { - // The angle is between 180 and 270 degrees, so - pieces = 3; - } - else - { - // The angle is between 90 and 180 degrees, so - pieces = 2; - } - } - - // We have to chop the arc into the computed number of pieces. For cPieces=2 and 4 we could - // have uses the half-angle trig formulas, but for pieces=3 it requires solving a cubic - // equation; the performance difference is not worth the extra code, so we'll get the angle, - // divide it, and get its sine and cosine. - - Debug.Assert(pieces > 0); - angle = Math.Atan2(sinArcAngle, cosArcAngle); - - if (isClockwise) - { - if (angle < 0) - angle += Math.PI * 2; - } - else - { - if (angle > 0) - angle -= Math.PI * 2; - } - - angle /= pieces; - cosArcAngle = Math.Cos(angle); - sinArcAngle = Math.Sin(angle); - } - - /******************************************************************************\ - * - * Function Description: - * - * Get the distance from a circular arc's endpoints to the control points of the - * Bezier arc that approximates it, as a fraction of the arc's radius. - * - * Since the result is relative to the arc's radius, it depends strictly on the - * arc's angle. The arc is assumed to be of 90 degrees of less, so the angle is - * determined by the cosine of that angle, which is derived from rDot = the dot - * product of two radius vectors. We need the Bezier curve that agrees with - * the arc's points and tangents at the ends and midpoint. Here we compute the - * distance from the curve's endpoints to its control points. - * - * Since we are looking for the relative distance, we can work on the unit - * circle. Place the center of the circle at the origin, and put the X axis as - * the bisector between the 2 vectors. Let a be the angle between the vectors. - * Then the X coordinates of the 1st & last points are cos(a/2). Let x be the X - * coordinate of the 2nd & 3rd points. At t=1/2 we have a point at (1,0). - * But the terms of the polynomial there are all equal: - * - * (1-t)^3 = t*(1-t)^2 = 2^2*(1-t) = t^3 = 1/8, - * - * so from the Bezier formula there we have: - * - * 1 = (1/8) * (cos(a/2) + 3x + 3x + cos(a/2)), - * hence - * x = (1 - cos(a/2)) / 3 - * - * The X difference between that and the 1st point is: - * - * DX = x - cos(a/2) = 4(1 - cos(a/2)) / 3. - * - * But DX = distance / sin(a/2), hence the distance is - * - * dist = (4/3)*(1 - cos(a/2)) / sin(a/2). - * - * Created: 5/29/2001 [....] - * - /*****************************************************************************/ - public static double - GetBezierDistance( // Return the distance as a fraction of the radius - double dot, // In: The dot product of the two radius vectors - double radius) // In: The radius of the arc's circle (optional=1) - { - double radSquared = radius * radius; // Squared radius - - Debug.Assert(dot >= -radSquared * .1); // angle < 90 degrees - Debug.Assert(dot <= radSquared * 1.1); // as dot product of 2 radius vectors - - double dist = 0; // Acceptable fallback value - - /* Rather than the angle a, we are given rDot = R^2 * cos(a), so we - multiply top and bottom by R: - - dist = (4/3)*(R - Rcos(a/2)) / Rsin(a/2) - - and use some trig: - __________ - cos(a/2) = \/1 + cos(a) / 2 - ________________ __________ - R*cos(a/2) = \/R^2 + R^2 cos(a) / 2 = \/R^2 + rDot / 2 */ - - double cos = (radSquared + dot) / 2; // =(R*cos(a))^2 - if (cos < 0) - return dist; - // __________________ - // R*sin(a/2) = \/R^2 - R^2 cos(a/2) - - double sin = radSquared - cos; // =(R*sin(a))^2 - if (sin <= 0) - return dist; - - sin = Math.Sqrt(sin); // = R*cos(a) - cos = Math.Sqrt(cos); // = R*sin(a) - - dist = 4 * (radius - cos) / 3; - if (dist <= sin * FUZZ) - dist = 0; - else - dist = 4 * (radius - cos) / sin / 3; - - return dist; - } - - //+------------------------------------------------------------------------------------------------- - // - // Function: ArcToBezier - // - // Synopsis: Compute the Bezier approximation of an arc - // - // Notes: This utilitycomputes the Bezier approximation for an elliptical arc as it is defined - // in the SVG arc spec. The ellipse from which the arc is carved is axis-aligned in its - // own coordinates, and defined there by its x and y radii. The rotation angle defines - // how the ellipse's axes are rotated relative to our x axis. The start and end points - // define one of 4 possible arcs; the sweep and large-arc flags determine which one of - // these arcs will be chosen. See SVG spec for details. - // - // Returning pieces = 0 indicates a line instead of an arc - // pieces = -1 indicates that the arc degenerates to a point - // - //-------------------------------------------------------------------------------------------------- - public static PointCollection ArcToBezier(double xStart, double yStart, double xRadius, double yRadius, double rotationAngle, - bool isLargeArc, bool isClockwise, double xEnd, double yEnd, out int pieces) - { - double cosArcAngle, sinArcAngle, xCenter, yCenter, r, bezDist; - XVector vecToBez1, vecToBez2; - XMatrix matToEllipse; - - double fuzz2 = FUZZ * FUZZ; - bool isZeroCenter = false; - - pieces = -1; - - // In the following, the line segment between between the arc's start and - // end points is referred to as "the chord". - - // Transform 1: Shift the origin to the chord's midpoint - double x = (xEnd - xStart) / 2; - double y = (yEnd - yStart) / 2; - - double halfChord2 = x * x + y * y; // (half chord length)^2 - - // Degenerate case: single point - if (halfChord2 < fuzz2) - { - // The chord degeneartes to a point, the arc will be ignored - return null; - } - - // Degenerate case: straight line - if (!AcceptRadius(halfChord2, fuzz2, ref xRadius) || !AcceptRadius(halfChord2, fuzz2, ref yRadius)) - { - // We have a zero radius, add a straight line segment instead of an arc - pieces = 0; - return null; - } - - if (xRadius == 0 || yRadius == 0) - { - // We have a zero radius, add a straight line segment instead of an arc - pieces = 0; - return null; - } - - // Transform 2: Rotate to the ellipse's coordinate system - rotationAngle = -rotationAngle * Calc.Deg2Rad; - - double cos = Math.Cos(rotationAngle); - double sin = Math.Sin(rotationAngle); - - r = x * cos - y * sin; - y = x * sin + y * cos; - x = r; - - // Transform 3: Scale so that the ellipse will become a unit circle - x /= xRadius; - y /= yRadius; - - // We get to the center of that circle along a verctor perpendicular to the chord - // from the origin, which is the chord's midpoint. By Pythagoras, the length of that - // vector is sqrt(1 - (half chord)^2). - - halfChord2 = x * x + y * y; // now in the circle coordinates - - if (halfChord2 > 1) - { - // The chord is longer than the circle's diameter; we scale the radii uniformly so - // that the chord will be a diameter. The center will then be the chord's midpoint, - // which is now the origin. - r = Math.Sqrt(halfChord2); - xRadius *= r; - yRadius *= r; - xCenter = yCenter = 0; - isZeroCenter = true; - - // Adjust the unit-circle coordinates x and y - x /= r; - y /= r; - } - else - { - // The length of (-y,x) or (x,-y) is sqrt(rHalfChord2), and we want a vector - // of length sqrt(1 - rHalfChord2), so we'll multiply it by: - r = Math.Sqrt((1 - halfChord2) / halfChord2); - //if (isLargeArc != (eSweepDirection == SweepDirection.Clockwise)) - if (isLargeArc != isClockwise) - // Going to the center from the origin=chord-midpoint - { - // in the direction of (-y, x) - xCenter = -r * y; - yCenter = r * x; - } - else - { - // in the direction of (y, -x) - xCenter = r * y; - yCenter = -r * x; - } - } - - // Transformation 4: shift the origin to the center of the circle, which then becomes - // the unit circle. Since the chord's midpoint is the origin, the start point is (-x, -y) - // and the endpoint is (x, y). - XPoint ptStart = new XPoint(-x - xCenter, -y - yCenter); - XPoint ptEnd = new XPoint(x - xCenter, y - yCenter); - - // Set up the matrix that will take us back to our coordinate system. This matrix is - // the inverse of the combination of transformation 1 thru 4. - matToEllipse = new XMatrix(cos * xRadius, -sin * xRadius, - sin * yRadius, cos * yRadius, - (xEnd + xStart) / 2, (yEnd + yStart) / 2); - - if (!isZeroCenter) - { - // Prepend the translation that will take the origin to the circle's center - matToEllipse.OffsetX += (matToEllipse.M11 * xCenter + matToEllipse.M21 * yCenter); - matToEllipse.OffsetY += (matToEllipse.M12 * xCenter + matToEllipse.M22 * yCenter); - } - - // Get the sine & cosine of the angle that will generate the arc pieces - GetArcAngle(ptStart, ptEnd, isLargeArc, isClockwise, out cosArcAngle, out sinArcAngle, out pieces); - - // Get the vector to the first Bezier control point - bezDist = GetBezierDistance(cosArcAngle, 1); - - //if (eSweepDirection == SweepDirection.Counterclockwise) - if (!isClockwise) - bezDist = -bezDist; - - vecToBez1 = new XVector(-bezDist * ptStart.Y, bezDist * ptStart.X); - - PointCollection result = new PointCollection(); - - // Add the arc pieces, except for the last - for (int idx = 1; idx < pieces; idx++) - { - // Get the arc piece's endpoint - XPoint ptPieceEnd = new XPoint(ptStart.X * cosArcAngle - ptStart.Y * sinArcAngle, ptStart.X * sinArcAngle + ptStart.Y * cosArcAngle); - vecToBez2 = new XVector(-bezDist * ptPieceEnd.Y, bezDist * ptPieceEnd.X); - - result.Add(matToEllipse.Transform(ptStart + vecToBez1)); - result.Add(matToEllipse.Transform(ptPieceEnd - vecToBez2)); - result.Add(matToEllipse.Transform(ptPieceEnd)); - - // Move on to the next arc - ptStart = ptPieceEnd; - vecToBez1 = vecToBez2; - } - - // Last arc - we know the endpoint - vecToBez2 = new XVector(-bezDist * ptEnd.Y, bezDist * ptEnd.X); - - result.Add(matToEllipse.Transform(ptStart + vecToBez1)); - result.Add(matToEllipse.Transform(ptEnd - vecToBez2)); - result.Add(new XPoint(xEnd, yEnd)); - - return result; - } - - /// - /// Gets a value indicating whether radius large enough compared to the chord length. - /// - /// (1/2 chord length)squared - /// Squared fuzz. - /// The radius to accept (or not). - static bool AcceptRadius(double halfChord2, double fuzz2, ref double radius) - { - Debug.Assert(halfChord2 >= fuzz2); // Otherewise we have no guarantee that the radius is not 0, and we need to divide by the radius - bool accept = radius * radius > halfChord2 * fuzz2; - if (accept) - { - if (radius < 0) - radius = 0; - } - return accept; - } -#endif } } \ No newline at end of file diff --git a/PdfSharpCore/Drawing/GraphicsStateStack.cs b/PdfSharpCore/Drawing/GraphicsStateStack.cs index af5162e9..676b9c5b 100644 --- a/PdfSharpCore/Drawing/GraphicsStateStack.cs +++ b/PdfSharpCore/Drawing/GraphicsStateStack.cs @@ -29,13 +29,6 @@ using System; using System.Collections.Generic; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif namespace PdfSharpCore.Drawing { diff --git a/PdfSharpCore/Drawing/IXGraphicsRenderer.cs b/PdfSharpCore/Drawing/IXGraphicsRenderer.cs index 4379f28b..63c17c22 100644 --- a/PdfSharpCore/Drawing/IXGraphicsRenderer.cs +++ b/PdfSharpCore/Drawing/IXGraphicsRenderer.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// diff --git a/PdfSharpCore/Drawing/ImageHelper.cs b/PdfSharpCore/Drawing/ImageHelper.cs deleted file mode 100644 index 28e1b8cb..00000000 --- a/PdfSharpCore/Drawing/ImageHelper.cs +++ /dev/null @@ -1,136 +0,0 @@ -#region PDFsharp - A .NET library for processing PDF -// -// Authors: -// Stefan Lange -// -// Copyright (c) 2005-2016 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.IO; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif - -namespace PdfSharpCore.Drawing -{ - /// - /// Helper class for processing image files. - /// - static class ImageHelper - { -#if WPF && GDI - /// - /// Creates a WPF bitmap source from an GDI image. - /// - public static BitmapSource CreateBitmapSource(Image image) - { - MemoryStream stream = new MemoryStream(); - //int width = image.Width; - //int height = image.Height; - //double dpiX = image.HorizontalResolution; - //double dpiY = image.VerticalResolution; - //System.Windows.Media.PixelFormat pixelformat = PixelFormats.Default; - BitmapSource bitmapSource = null; - - try - { - string guid = image.RawFormat.Guid.ToString("B").ToUpper(); - switch (guid) - { - case "{B96B3CAA-0728-11D3-9D7B-0000F81EF32E}": // memoryBMP - case "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}": // bmp - image.Save(stream, ImageFormat.Bmp); - stream.Position = 0; - BmpBitmapDecoder bmpDecoder = new BmpBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - bitmapSource = bmpDecoder.Frames[0]; - break; - - case "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}": // png - image.Save(stream, ImageFormat.Png); - stream.Position = 0; - PngBitmapDecoder pngDecoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - bitmapSource = pngDecoder.Frames[0]; - break; - - case "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}": // jpeg - image.Save(stream, ImageFormat.Jpeg); - JpegBitmapDecoder jpegDecoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - stream.Position = 0; - bitmapSource = jpegDecoder.Frames[0]; - break; - - case "{B96B3CB0-0728-11D3-9D7B-0000F81EF32E}": // gif - image.Save(stream, ImageFormat.Gif); - GifBitmapDecoder gifDecoder = new GifBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - stream.Position = 0; - bitmapSource = gifDecoder.Frames[0]; - break; - - case "{B96B3CB1-0728-11D3-9D7B-0000F81EF32E}": // tiff - image.Save(stream, ImageFormat.Tiff); - TiffBitmapDecoder tiffDecoder = new TiffBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - stream.Position = 0; - bitmapSource = tiffDecoder.Frames[0]; - break; - - case "{B96B3CB5-0728-11D3-9D7B-0000F81EF32E}": // icon - image.Save(stream, ImageFormat.Icon); - IconBitmapDecoder iconDecoder = new IconBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.Default); - stream.Position = 0; - bitmapSource = iconDecoder.Frames[0]; - break; - - case "{B96B3CAC-0728-11D3-9D7B-0000F81EF32E}": // emf - case "{B96B3CAD-0728-11D3-9D7B-0000F81EF32E}": // wmf - case "{B96B3CB2-0728-11D3-9D7B-0000F81EF32E}": // exif - case "{B96B3CB3-0728-11D3-9D7B-0000F81EF32E}": // photoCD - case "{B96B3CB4-0728-11D3-9D7B-0000F81EF32E}": // flashPIX - - default: - throw new InvalidOperationException("Unsupported image format."); - } - } - catch (Exception ex) - { - Debug.WriteLine("ImageHelper.CreateBitmapSource failed:" + ex.Message); - } - finally - { - //if (stream != null) - // stream.Close(); - } - return bitmapSource; - } -#endif - } -} diff --git a/PdfSharpCore/Drawing/InternalGraphicsState.cs b/PdfSharpCore/Drawing/InternalGraphicsState.cs index 3acffece..439177da 100644 --- a/PdfSharpCore/Drawing/InternalGraphicsState.cs +++ b/PdfSharpCore/Drawing/InternalGraphicsState.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { // In GDI+ the functions Save/Restore, BeginContainer/EndContainer, Transform, SetClip and ResetClip @@ -105,18 +97,6 @@ public XMatrix Transform /// public void Pushed() { -#if GDI - // Nothing to do. -#endif -#if WPF && !SILVERLIGHT - // Nothing to do. -#endif -#if SILVERLIGHT - // Save current level of Canvas stack. - _stackLevel = _gfx._dc.Level; - // Create new Canvas for subsequent UIElements. - _gfx._dc.PushCanvas(); -#endif } /// @@ -125,66 +105,10 @@ public void Pushed() public void Popped() { Invalid = true; -#if GDI - // Nothing to do. -#endif -#if WPF && !SILVERLIGHT - // Pop all objects pushed in this state. - if (_gfx.TargetContext == XGraphicTargetContext.WPF) - { - for (int idx = 0; idx < _transformPushLevel; idx++) - _gfx._dc.Pop(); - _transformPushLevel = 0; - for (int idx = 0; idx < _geometryPushLevel; idx++) - _gfx._dc.Pop(); - _geometryPushLevel = 0; - } -#endif -#if SILVERLIGHT - // Pop all Canvas objects created in this state. - _gfx._dc.Pop(_gfx._dc.Level - _stackLevel); -#endif } public bool Invalid; -#if GDI_ - /// - /// The GDI+ GraphicsState if contructed from XGraphicsState. - /// - public GraphicsState GdiGraphicsState; -#endif - -#if WPF && !SILVERLIGHT - public void PushTransform(MatrixTransform transform) - { - _gfx._dc.PushTransform(transform); - _transformPushLevel++; - } - int _transformPushLevel; - - public void PushClip(Geometry geometry) - { - _gfx._dc.PushClip(geometry); - _geometryPushLevel++; - } - int _geometryPushLevel; -#endif - -#if SILVERLIGHT - public void PushTransform(MatrixTransform transform) - { - _gfx._dc.PushTransform(transform); - } - - public void PushClip(Geometry geometry) - { - _gfx._dc.PushClip(geometry); - } - - int _stackLevel; -#endif - readonly XGraphics _gfx; internal XGraphicsState State; diff --git a/PdfSharpCore/Drawing/PdfFontOptions.cs b/PdfSharpCore/Drawing/PdfFontOptions.cs index 0f3b39e7..c04faeaa 100644 --- a/PdfSharpCore/Drawing/PdfFontOptions.cs +++ b/PdfSharpCore/Drawing/PdfFontOptions.cs @@ -28,13 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Pdf; namespace PdfSharpCore.Drawing diff --git a/PdfSharpCore/Drawing/XBaseGradientBrush.cs b/PdfSharpCore/Drawing/XBaseGradientBrush.cs index c6d5b0f5..a58421bf 100644 --- a/PdfSharpCore/Drawing/XBaseGradientBrush.cs +++ b/PdfSharpCore/Drawing/XBaseGradientBrush.cs @@ -30,25 +30,6 @@ using System; using System.ComponentModel; using PdfSharpCore.Internal; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -//using GdiLinearGradientBrush = System.Drawing.Drawing2D.LinearGradientBrush; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -using WpfBrush = System.Windows.Media.Brush; -#endif -#if UWP -using Windows.UI; -using Windows.UI.Xaml.Media; -using Microsoft.Graphics.Canvas; -using Microsoft.Graphics.Canvas.Brushes; -#endif // ReSharper disable RedundantNameQualifier because it is required for hybrid build namespace PdfSharpCore.Drawing @@ -62,20 +43,6 @@ protected XBaseGradientBrush(XColor color1, XColor color2) } - //private Blend _GetBlend(); - //private ColorBlend _GetInterpolationColors(); - //private XColor[] _GetLinearColors(); - //private RectangleF _GetRectangle(); - //private Matrix _GetTransform(); - //private WrapMode _GetWrapMode(); - //private void _SetBlend(Blend blend); - //private void _SetInterpolationColors(ColorBlend blend); - //private void _SetLinearColors(XColor color1, XColor color2); - //private void _SetTransform(Matrix matrix); - //private void _SetWrapMode(WrapMode wrapMode); - - //public override object Clone(); - /// /// Gets or sets an XMatrix that defines a local geometric transform for this LinearGradientBrush. /// diff --git a/PdfSharpCore/Drawing/XBitmapDecoder.cs b/PdfSharpCore/Drawing/XBitmapDecoder.cs index f81768de..e6f31aaf 100644 --- a/PdfSharpCore/Drawing/XBitmapDecoder.cs +++ b/PdfSharpCore/Drawing/XBitmapDecoder.cs @@ -27,22 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if CORE -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media.Imaging; -#endif - namespace PdfSharpCore.Drawing { /// diff --git a/PdfSharpCore/Drawing/XBitmapEncoder.cs b/PdfSharpCore/Drawing/XBitmapEncoder.cs index c5437cc7..b3e47730 100644 --- a/PdfSharpCore/Drawing/XBitmapEncoder.cs +++ b/PdfSharpCore/Drawing/XBitmapEncoder.cs @@ -28,29 +28,7 @@ #endregion using System; -using System.Diagnostics; using System.IO; -using PdfSharpCore.Internal; -#if CORE -#endif -#if CORE_WITH_GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media.Imaging; -#endif namespace PdfSharpCore.Drawing { @@ -101,22 +79,6 @@ public override void Save(Stream stream) { if (Source == null) throw new InvalidOperationException("No image source."); -#if CORE_WITH_GDI || GDI - if (Source.AssociatedGraphics != null) - { - Source.DisassociateWithGraphics(); - Debug.Assert(Source.AssociatedGraphics == null); - } - try - { - Lock.EnterGdiPlus(); - Source._gdiImage.Save(stream, ImageFormat.Png); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - DiagnosticsHelper.ThrowNotImplementedException("Save..."); -#endif } } } diff --git a/PdfSharpCore/Drawing/XBitmapImage.cs b/PdfSharpCore/Drawing/XBitmapImage.cs index feef81b2..2ea23108 100644 --- a/PdfSharpCore/Drawing/XBitmapImage.cs +++ b/PdfSharpCore/Drawing/XBitmapImage.cs @@ -27,42 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if CORE -#endif -#if CORE_WITH_GDI -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using PdfSharpCore.Internal; - -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using PdfSharpCore.Internal; - -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#if !GDI -using PdfSharpCore.Internal; -#endif - -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media.Imaging; -using PdfSharpCore.Internal; - -#endif - -// WPFHACK -#pragma warning disable 0169 -#pragma warning disable 0649 - namespace PdfSharpCore.Drawing { /// @@ -77,24 +41,6 @@ public sealed class XBitmapImage : XBitmapSource /// internal XBitmapImage(int width, int height) { -#if GDI || CORE_WITH_GDI - try - { - Lock.EnterGdiPlus(); - // Create a default 24 bit ARGB bitmap. - _gdiImage = new Bitmap(width, height); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - DiagnosticsHelper.ThrowNotImplementedException("CreateBitmap"); -#endif -#if NETFX_CORE - DiagnosticsHelper.ThrowNotImplementedException("CreateBitmap"); -#endif -#if CORE || GDI && !WPF // Prevent unreachable code error - Initialize(); -#endif } /// diff --git a/PdfSharpCore/Drawing/XBitmapSource.cs b/PdfSharpCore/Drawing/XBitmapSource.cs index 2e2d03c2..93b12f71 100644 --- a/PdfSharpCore/Drawing/XBitmapSource.cs +++ b/PdfSharpCore/Drawing/XBitmapSource.cs @@ -27,29 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if CORE -#endif - -using System.Diagnostics; -using PdfSharpCore.Internal; - -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media.Imaging; -#endif - -// WPFHACK -#pragma warning disable 0169 -#pragma warning disable 0649 namespace PdfSharpCore.Drawing { @@ -67,35 +44,7 @@ public override int PixelWidth { get { -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Width; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - int gdiWidth = _gdiImage.Width; - int wpfWidth = _wpfImage.PixelWidth; - Debug.Assert(gdiWidth == wpfWidth); - return wpfWidth; -#endif -#if WPF && !GDI - return _wpfImage.PixelWidth; -#endif -#if NETFX_CORE || UWP - return _wrtImage.PixelWidth; -#endif -#if __IOS__ - return (int)_iosImage.CGImage.Width; -#endif -#if __ANDROID__ - return _androidImage.Width; -#endif -#if PORTABLE return PixelWidth; -#endif } } @@ -106,35 +55,7 @@ public override int PixelHeight { get { -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Height; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - int gdiHeight = _gdiImage.Height; - int wpfHeight = _wpfImage.PixelHeight; - Debug.Assert(gdiHeight == wpfHeight); - return wpfHeight; -#endif -#if WPF && !GDI - return _wpfImage.PixelHeight; -#endif -#if NETFX_CORE || UWP - return _wrtImage.PixelHeight; -#endif -#if __IOS__ - return (int)_iosImage.CGImage.Height; -#endif -#if __ANDROID__ - return _androidImage.Height; -#endif -#if PORTABLE return PixelHeight; -#endif } } } diff --git a/PdfSharpCore/Drawing/XBrush.cs b/PdfSharpCore/Drawing/XBrush.cs index 224fc440..b2fb561d 100644 --- a/PdfSharpCore/Drawing/XBrush.cs +++ b/PdfSharpCore/Drawing/XBrush.cs @@ -27,19 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif -#if UWP -using Microsoft.Graphics.Canvas.Brushes; -using UwpColor = Windows.UI.Color; -#endif - namespace PdfSharpCore.Drawing { /// @@ -48,40 +35,5 @@ namespace PdfSharpCore.Drawing /// public abstract class XBrush { -#if GDI - internal abstract System.Drawing.Brush RealizeGdiBrush(); - -#if UseGdiObjects - /// - /// Converts from a System.Drawing.Brush. - /// - public static implicit operator XBrush(Brush brush) - { - XBrush xbrush; - SolidBrush solidBrush; - LinearGradientBrush lgBrush; - if ((solidBrush = brush as SolidBrush) != null) - { - xbrush = new XSolidBrush(solidBrush.Color); - } - else if ((lgBrush = brush as LinearGradientBrush) != null) - { - // TODO: xbrush = new LinearGradientBrush(lgBrush.Rectangle, lgBrush.co(solidBrush.Color); - throw new NotImplementedException("Brush type not yet supported by PdfSharpCore."); - } - else - { - throw new NotImplementedException("Brush type not supported by PdfSharpCore."); - } - return xbrush; - } -#endif -#endif -#if WPF - internal abstract System.Windows.Media.Brush RealizeWpfBrush(); -#endif -#if UWP - internal abstract ICanvasBrush RealizeCanvasBrush(); -#endif } } diff --git a/PdfSharpCore/Drawing/XColor.cs b/PdfSharpCore/Drawing/XColor.cs index 14b0e06a..a5c377f3 100644 --- a/PdfSharpCore/Drawing/XColor.cs +++ b/PdfSharpCore/Drawing/XColor.cs @@ -31,17 +31,6 @@ using System.Diagnostics; using System.Globalization; using System.ComponentModel; -#if GDI -using System.Drawing; -#endif -#if WPF -using WpfColor = System.Windows.Media.Color; -#endif -#if UWP -using UwpColor = Windows.UI.Color; -#endif - - // ReSharper disable RedundantNameQualifier namespace PdfSharpCore.Drawing @@ -122,31 +111,6 @@ public struct XColor _k = 0; GrayChanged(); } - -#if GDI - XColor(System.Drawing.Color color) - : this(color.A, color.R, color.G, color.B) - { } -#endif - -#if WPF - XColor(WpfColor color) - : this(color.A, color.R, color.G, color.B) - { } -#endif - -#if GDI - XColor(KnownColor knownColor) - : this(System.Drawing.Color.FromKnownColor(knownColor)) - { } -#endif - -#if UWP - XColor(UwpColor color) - : this(color.A, color.R, color.G, color.B) - { } -#endif - internal XColor(XKnownColor knownColor) : this(XKnownColorTable.KnownColorToArgb(knownColor)) { } @@ -198,36 +162,6 @@ public static XColor FromArgb(int alpha, int red, int green, int blue) return new XColor((byte)alpha, (byte)red, (byte)green, (byte)blue); } -#if GDI - /// - /// Creates an XColor structure from the specified System.Drawing.Color. - /// - public static XColor FromArgb(System.Drawing.Color color) - { - return new XColor(color); - } -#endif - -#if WPF - /// - /// Creates an XColor structure from the specified System.Drawing.Color. - /// - public static XColor FromArgb(WpfColor color) - { - return new XColor(color); - } -#endif - -#if UWP - /// - /// Creates an XColor structure from the specified Windows.UI.Color. - /// - public static XColor FromArgb(UwpColor color) - { - return new XColor(color); - } -#endif - /// /// Creates an XColor structure from the specified alpha value and color. /// @@ -237,39 +171,6 @@ public static XColor FromArgb(int alpha, XColor color) return color; } -#if GDI - /// - /// Creates an XColor structure from the specified alpha value and color. - /// - public static XColor FromArgb(int alpha, System.Drawing.Color color) - { - // Cast required to use correct constructor. - return new XColor((byte)alpha, color.R, color.G, color.B); - } -#endif - -#if WPF - /// - /// Creates an XColor structure from the specified alpha value and color. - /// - public static XColor FromArgb(int alpha, WpfColor color) - { - // Cast required to use correct constructor. - return new XColor((byte)alpha, color.R, color.G, color.B); - } -#endif - -#if UWP - /// - /// Creates an XColor structure from the specified alpha value and color. - /// - public static XColor FromArgb(int alpha, UwpColor color) - { - // Cast required to use correct constructor. - return new XColor((byte)alpha, color.R, color.G, color.B); - } -#endif - /// /// Creates an XColor structure from the specified CMYK values. /// @@ -302,33 +203,11 @@ public static XColor FromKnownColor(XKnownColor color) return new XColor(color); } -#if GDI - /// - /// Creates an XColor from the specified pre-defined color. - /// - public static XColor FromKnownColor(KnownColor color) - { - return new XColor(color); - } -#endif - /// /// Creates an XColor from the specified name of a pre-defined color. /// public static XColor FromName(string name) { -#if GDI - // The implementation in System.Drawing.dll is interesting. It uses a ColorConverter - // with hash tables, locking mechanisms etc. I'm not sure what problems that solves. - // So I don't use the source, but the reflection. - try - { - return new XColor((KnownColor)Enum.Parse(typeof(KnownColor), name, true)); - } - // ReSharper disable EmptyGeneralCatchClause - catch { } - // ReSharper restore EmptyGeneralCatchClause -#endif return Empty; } @@ -354,46 +233,6 @@ public bool IsEmpty get { return this == Empty; } } -#if GDI -#if UseGdiObjects - /// - /// Implicit conversion from Color to XColor - /// - public static implicit operator XColor(Color color) - { - return new XColor(color); - } -#endif - - /// - /// Creates a System.Drawing.Color object from this color. - /// - public System.Drawing.Color ToGdiColor() - { - return System.Drawing.Color.FromArgb((int)(_a * 255), _r, _g, _b); - } -#endif - -#if WPF - /// - /// Creates a WpfColor object from this color. - /// - public WpfColor ToWpfColor() - { - return WpfColor.FromArgb((byte)(_a * 255), _r, _g, _b); - } -#endif - -#if UWP - /// - /// Creates a Windows.UI.Color object from this color. - /// - public UwpColor ToUwpColor() - { - return UwpColor.FromArgb((byte)(_a * 255), _r, _g, _b); - } -#endif - /// /// Determines whether the specified object is a Color structure and is equivalent to this /// Color structure. diff --git a/PdfSharpCore/Drawing/XColorResourceManager.cs b/PdfSharpCore/Drawing/XColorResourceManager.cs index 81d3aea3..b944acff 100644 --- a/PdfSharpCore/Drawing/XColorResourceManager.cs +++ b/PdfSharpCore/Drawing/XColorResourceManager.cs @@ -31,12 +31,6 @@ using System.Globalization; using System.ComponentModel; using System.Threading; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif namespace PdfSharpCore.Drawing { @@ -49,11 +43,7 @@ public class XColorResourceManager /// Initializes a new instance of the class. /// public XColorResourceManager() -#if !NETFX_CORE && !UWP && !PORTABLE - : this(Thread.CurrentThread.CurrentUICulture) -#else : this(CultureInfo.CurrentUICulture) -#endif { } /// diff --git a/PdfSharpCore/Drawing/XColors.cs b/PdfSharpCore/Drawing/XColors.cs index 8025568d..c6ef545b 100644 --- a/PdfSharpCore/Drawing/XColors.cs +++ b/PdfSharpCore/Drawing/XColors.cs @@ -27,13 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// diff --git a/PdfSharpCore/Drawing/XConvert.cs b/PdfSharpCore/Drawing/XConvert.cs index 469cb41b..a9bf992f 100644 --- a/PdfSharpCore/Drawing/XConvert.cs +++ b/PdfSharpCore/Drawing/XConvert.cs @@ -27,18 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if CORE -#endif -#if CORE -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// @@ -46,52 +34,5 @@ namespace PdfSharpCore.Drawing /// internal static class XConvert { -#if GDI -//#if UseGdiObjects - /// - /// Converts XLineJoin to LineJoin. - /// - public static LineJoin ToLineJoin(XLineJoin lineJoin) - { - return GdiLineJoin[(int)lineJoin]; - } - static readonly LineJoin[] GdiLineJoin = new LineJoin[] { LineJoin.Miter, LineJoin.Round, LineJoin.Bevel }; -//#endif -#endif - -#if GDI -//#if UseGdiObjects - /// - /// Converts XLineCap to LineCap. - /// - public static LineCap ToLineCap(XLineCap lineCap) - { - return _gdiLineCap[(int)lineCap]; - } - static readonly LineCap[] _gdiLineCap = new LineCap[] { LineCap.Flat, LineCap.Round, LineCap.Square }; - //#endif -#endif - -#if WPF - /// - /// Converts XLineJoin to PenLineJoin. - /// - public static PenLineJoin ToPenLineJoin(XLineJoin lineJoin) - { - return WpfLineJoin[(int)lineJoin]; - } - static readonly PenLineJoin[] WpfLineJoin = new PenLineJoin[] { PenLineJoin.Miter, PenLineJoin.Round, PenLineJoin.Bevel }; -#endif - -#if WPF - /// - /// Converts XLineCap to PenLineCap. - /// - public static PenLineCap ToPenLineCap(XLineCap lineCap) - { - return WpfLineCap[(int)lineCap]; - } - static readonly PenLineCap[] WpfLineCap = new PenLineCap[] { PenLineCap.Flat, PenLineCap.Round, PenLineCap.Square }; -#endif } } \ No newline at end of file diff --git a/PdfSharpCore/Drawing/XFont.cs b/PdfSharpCore/Drawing/XFont.cs index c2df4fc7..fdca53d5 100644 --- a/PdfSharpCore/Drawing/XFont.cs +++ b/PdfSharpCore/Drawing/XFont.cs @@ -33,32 +33,10 @@ using System.Diagnostics; using System.Globalization; using System.ComponentModel; -#if CORE || GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows.Markup; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -#endif -#if UWP -using UwpFontFamily = Windows.UI.Xaml.Media.FontFamily; -#endif using PdfSharpCore.Fonts; using PdfSharpCore.Fonts.OpenType; -using PdfSharpCore.Internal; using PdfSharpCore.Pdf; -#if SILVERLIGHT -#pragma warning disable 649 -#endif -// ReSharper disable ConvertToAutoProperty - namespace PdfSharpCore.Drawing { /// @@ -113,200 +91,6 @@ internal XFont(string familyName, double emSize, XFontStyle style, XPdfFontOptio Initialize(); } -#if CORE || GDI - /// - /// Initializes a new instance of the class from a System.Drawing.FontFamily. - /// - /// The System.Drawing.FontFamily. - /// The em size. - /// The font style. - public XFont(GdiFontFamily fontFamily, double emSize, XFontStyle style) - : this(fontFamily, emSize, style, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Drawing.FontFamily. - /// - /// The System.Drawing.FontFamily. - /// The em size. - /// The font style. - /// Additional PDF options. - public XFont(GdiFontFamily fontFamily, double emSize, XFontStyle style, XPdfFontOptions pdfOptions) - { - _familyName = fontFamily.Name; - _gdiFontFamily = fontFamily; - _emSize = emSize; - _style = style; - _pdfOptions = pdfOptions; - InitializeFromGdi(); - } - - /// - /// Initializes a new instance of the class from a System.Drawing.Font. - /// - /// The System.Drawing.Font. - public XFont(GdiFont font) - : this(font, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Drawing.Font. - /// - /// The System.Drawing.Font. - /// Additional PDF options. - public XFont(GdiFont font, XPdfFontOptions pdfOptions) - { - if (font.Unit != GraphicsUnit.World) - throw new ArgumentException("Font must use GraphicsUnit.World."); - _gdiFont = font; - Debug.Assert(font.Name == font.FontFamily.Name); - _familyName = font.Name; - _emSize = font.Size; - _style = FontStyleFrom(font); - _pdfOptions = pdfOptions; - InitializeFromGdi(); - } -#endif - -#if WPF && !SILVERLIGHT - /// - /// Initializes a new instance of the class from a System.Windows.Media.FontFamily. - /// - /// The System.Windows.Media.FontFamily. - /// The em size. - /// The font style. - public XFont(WpfFontFamily fontFamily, double emSize, XFontStyle style) - : this(fontFamily, emSize, style, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Drawing.FontFamily. - /// - /// The System.Windows.Media.FontFamily. - /// The em size. - /// The font style. - /// Additional PDF options. - public XFont(WpfFontFamily fontFamily, double emSize, XFontStyle style, XPdfFontOptions pdfOptions) - { -#if !SILVERLIGHT - _familyName = fontFamily.FamilyNames[XmlLanguage.GetLanguage("en-US")]; -#else - // Best we can do in Silverlight. - _familyName = fontFamily.Source; -#endif - _wpfFontFamily = fontFamily; - _emSize = emSize; - _style = style; - _pdfOptions = pdfOptions; - InitializeFromWpf(); - } - - /// - /// Initializes a new instance of the class from a System.Windows.Media.Typeface. - /// - /// The System.Windows.Media.Typeface. - /// The em size. - public XFont(WpfTypeface typeface, double emSize) - : this(typeface, emSize, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Windows.Media.Typeface. - /// - /// The System.Windows.Media.Typeface. - /// The em size. - /// Additional PDF options. - public XFont(WpfTypeface typeface, double emSize, XPdfFontOptions pdfOptions) - { - _wpfTypeface = typeface; - //Debug.Assert(font.Name == font.FontFamily.Name); - //_familyName = font.Name; - _emSize = emSize; - _pdfOptions = pdfOptions; - InitializeFromWpf(); - } -#endif - -#if UWP_ - /// - /// Initializes a new instance of the class from a System.Drawing.FontFamily. - /// - /// The System.Drawing.FontFamily. - /// The em size. - /// The font style. - public XFont(UwpFontFamily fontFamily, double emSize, XFontStyle style) - : this(fontFamily, emSize, style, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Drawing.FontFamily. - /// - /// The System.Drawing.FontFamily. - /// The em size. - /// The font style. - /// Additional PDF options. - public XFont(UwpFontFamily fontFamily, double emSize, XFontStyle style, XPdfFontOptions pdfOptions) - { - _familyName = fontFamily.Source; - _gdiFontFamily = fontFamily; - _emSize = emSize; - _style = style; - _pdfOptions = pdfOptions; - InitializeFromGdi(); - } - - /// - /// Initializes a new instance of the class from a System.Drawing.Font. - /// - /// The System.Drawing.Font. - public XFont(GdiFont font) - : this(font, new XPdfFontOptions(GlobalFontSettings.DefaultFontEncoding)) - { } - - /// - /// Initializes a new instance of the class from a System.Drawing.Font. - /// - /// The System.Drawing.Font. - /// Additional PDF options. - public XFont(GdiFont font, XPdfFontOptions pdfOptions) - { - if (font.Unit != GraphicsUnit.World) - throw new ArgumentException("Font must use GraphicsUnit.World."); - _gdiFont = font; - Debug.Assert(font.Name == font.FontFamily.Name); - _familyName = font.Name; - _emSize = font.Size; - _style = FontStyleFrom(font); - _pdfOptions = pdfOptions; - InitializeFromGdi(); - } -#endif - - //// Methods - //public Font(Font prototype, FontStyle newStyle); - //public Font(FontFamily family, float emSize); - //public Font(string familyName, float emSize); - //public Font(FontFamily family, float emSize, FontStyle style); - //public Font(FontFamily family, float emSize, GraphicsUnit unit); - //public Font(string familyName, float emSize, FontStyle style); - //public Font(string familyName, float emSize, GraphicsUnit unit); - //public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit); - //public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit); - ////public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet); - ////public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet); - ////public Font(FontFamily family, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont); - ////public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont); - //public object Clone(); - //private static FontFamily CreateFontFamilyWithFallback(string familyName); - //private void Dispose(bool disposing); - //public override bool Equals(object obj); - //protected override void Finalize(); - //public static Font FromHdc(IntPtr hdc); - //public static Font FromHfont(IntPtr hfont); - //public static Font FromLogFont(object lf); - //public static Font FromLogFont(object lf, IntPtr hdc); - //public override int GetHashCode(); - /// /// Initializes this instance by computing the glyph typeface, font family, font source and TrueType fontface. /// (PDFsharp currently only deals with TrueType fonts.) @@ -325,119 +109,13 @@ void Initialize() // HACK: 'PlatformDefault' is used in unit test code. if (StringComparer.OrdinalIgnoreCase.Compare(_familyName, GlobalFontSettings.DefaultFontName) == 0) { -#if CORE || GDI || WPF - _familyName = "Calibri"; -#endif } // In principle an XFont is an XGlyphTypeface plus an em-size. _glyphTypeface = XGlyphTypeface.GetOrCreateFrom(_familyName, fontResolvingOptions); -#if GDI // TODO: In CORE build it is not necessary to create a GDI font at all - // Create font by using font family. - XFontSource fontSource; // Not needed here. - _gdiFont = FontHelper.CreateFont(_familyName, (float)_emSize, (GdiFontStyle)(_style & XFontStyle.BoldItalic), out fontSource); -#endif -#if WPF && !SILVERLIGHT // Pure WPF - _wpfFontFamily = _glyphTypeface.FontFamily.WpfFamily; - _wpfTypeface = _glyphTypeface.WpfTypeface; - - if (_wpfFontFamily == null) - _wpfFontFamily = new WpfFontFamily(Name); - - if (_wpfTypeface == null) - _wpfTypeface = FontHelper.CreateTypeface(WpfFontFamily, _style); -#endif -#if WPF && SILVERLIGHT_ // Pure Silverlight 5 - if (GlyphTypeface == null) - { - //Debug.Assert(Typeface == null); - // #P F C - //GlyphTypeface = XPrivateFontCollection.TryGetXGlyphTypeface(Name, _style); - //if (GlyphTypeface == null) - //{ - // // HACK: Just make it work... - // GlyphTypeface = GlobalFontSettings.TryGetXGlyphTypeface(Name, _style, out Data); - //} -#if DEBUG - if (GlyphTypeface == null) - throw new Exception("No font: " + Name); -#endif - _wpfFamily = GlyphTypeface.FontFamily; - } - - //if (Family == null) - // Family = new System.Windows.Media.FontFamily(Name); - - //if (Typeface == null) - // Typeface = FontHelper.CreateTypeface(Family, _style); -#endif CreateDescriptorAndInitializeFontMetrics(); } -#if CORE || GDI - /// - /// A GDI+ font object is used to setup the internal font objects. - /// - void InitializeFromGdi() - { - try - { - Lock.EnterFontFactory(); - if (_gdiFontFamily != null) - { - // Create font based on its family. - _gdiFont = new Font(_gdiFontFamily, (float)_emSize, (GdiFontStyle)_style, GraphicsUnit.World); - } - - if (_gdiFont != null) - { -#if DEBUG_ - string name1 = _gdiFont.Name; - string name2 = _gdiFont.OriginalFontName; - string name3 = _gdiFont.SystemFontName; -#endif - _familyName = _gdiFont.FontFamily.Name; - // TODO: _glyphTypeface = XGlyphTypeface.GetOrCreateFrom(_gdiFont); - } - else - { - Debug.Assert(false); - } - - if (_glyphTypeface == null) - _glyphTypeface = XGlyphTypeface.GetOrCreateFromGdi(_gdiFont); - - CreateDescriptorAndInitializeFontMetrics(); - } - finally { Lock.ExitFontFactory(); } - } -#endif - -#if WPF && !SILVERLIGHT - void InitializeFromWpf() - { - if (_wpfFontFamily != null) - { - _wpfTypeface = FontHelper.CreateTypeface(_wpfFontFamily, _style); - } - - if (_wpfTypeface != null) - { - _familyName = _wpfTypeface.FontFamily.FamilyNames[XmlLanguage.GetLanguage("en-US")]; - _glyphTypeface = XGlyphTypeface.GetOrCreateFromWpf(_wpfTypeface); - } - else - { - Debug.Assert(false); - } - - if (_glyphTypeface == null) - _glyphTypeface = XGlyphTypeface.GetOrCreateFrom(_familyName, new FontResolvingOptions(_style)); - - CreateDescriptorAndInitializeFontMetrics(); - } -#endif - /// /// Code separated from Metric getter to make code easier to debug. /// (Setup properties in their getters caused side effects during debugging because Visual Studio calls a getter @@ -461,21 +139,6 @@ void CreateDescriptorAndInitializeFontMetrics() // TODO: refactor CellAscent = _descriptor.Ascender; CellDescent = _descriptor.Descender; CellSpace = _descriptor.LineSpacing; - -#if DEBUG_ && GDI - int gdiValueUnitsPerEm = Font.FontFamily.GetEmHeight(Font.Style); - Debug.Assert(gdiValueUnitsPerEm == UnitsPerEm); - int gdiValueAscent = Font.FontFamily.GetCellAscent(Font.Style); - Debug.Assert(gdiValueAscent == CellAscent); - int gdiValueDescent = Font.FontFamily.GetCellDescent(Font.Style); - Debug.Assert(gdiValueDescent == CellDescent); - int gdiValueLineSpacing = Font.FontFamily.GetLineSpacing(Font.Style); - Debug.Assert(gdiValueLineSpacing == CellSpace); -#endif -#if DEBUG_ && WPF && !SILVERLIGHT - int wpfValueLineSpacing = (int)Math.Round(Family.LineSpacing * _descriptor.UnitsPerEm); - Debug.Assert(wpfValueLineSpacing == CellSpace); -#endif Debug.Assert(fm.UnitsPerEm == _descriptor.UnitsPerEm); } @@ -646,28 +309,7 @@ public XFontMetrics Metrics public double GetHeight() { double value = CellSpace * _emSize / UnitsPerEm; -#if CORE || NETFX_CORE || UWP - return value; -#endif -#if GDI && !WPF -#if DEBUG_ - double gdiValue = Font.GetHeight(); - Debug.Assert(DoubleUtil.AreRoughlyEqual(gdiValue, value, 5)); -#endif - return value; -#endif -#if WPF && !GDI return value; -#endif -#if WPF && GDI // Testing only - return value; -#endif -#if __IOS__ || __ANDROID__ - return value; -#endif -#if PORTABLE - return value; -#endif } /// @@ -721,67 +363,6 @@ internal int UnitsPerEm /// internal XStyleSimulations StyleSimulations; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -#if CORE || GDI - /// - /// Gets the GDI family. - /// - /// The GDI family. - public GdiFontFamily GdiFontFamily - { - get { return _gdiFontFamily; } - } - readonly GdiFontFamily _gdiFontFamily; - - internal GdiFont GdiFont - { - get { return _gdiFont; } - } - Font _gdiFont; - - internal static XFontStyle FontStyleFrom(GdiFont font) - { - return - (font.Bold ? XFontStyle.Bold : 0) | - (font.Italic ? XFontStyle.Italic : 0) | - (font.Strikeout ? XFontStyle.Strikeout : 0) | - (font.Underline ? XFontStyle.Underline : 0); - } - -#if true || UseGdiObjects - /// - /// Implicit conversion form Font to XFont - /// - public static implicit operator XFont(GdiFont font) - { - return new XFont(font); - } -#endif -#endif - -#if WPF - /// - /// Gets the WPF font family. - /// Can be null. - /// - internal WpfFontFamily WpfFontFamily - { - get { return _wpfFontFamily; } - } - WpfFontFamily _wpfFontFamily; - - internal WpfTypeface WpfTypeface - { - get { return _wpfTypeface; } - } - WpfTypeface _wpfTypeface; -#endif - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// /// Cache PdfFontTable.FontSelector to speed up finding the right PdfFont /// if this font is used more than once. diff --git a/PdfSharpCore/Drawing/XFontFamily.cs b/PdfSharpCore/Drawing/XFontFamily.cs index 9535d05a..0927b9eb 100644 --- a/PdfSharpCore/Drawing/XFontFamily.cs +++ b/PdfSharpCore/Drawing/XFontFamily.cs @@ -28,18 +28,6 @@ #endregion using System; -#if CORE || GDI -using System.Drawing; -using GdiFont = System.Drawing.Font; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows.Media; -using System.Windows.Markup; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfFontStyle = System.Windows.FontStyle; -#endif using PdfSharpCore.Fonts; using PdfSharpCore.Fonts.OpenType; @@ -71,38 +59,9 @@ internal XFontFamily(string familyName, bool createPlatformObjects) { FamilyInternal = fontFamilyInternal; } - -#if CORE || GDI - //public XFontFamily(GdiFontFamily gdiFontFamily) - //{ - // FamilyInternal = FontFamilyInternal.GetOrCreateFromGdi(gdiFontFamily); - //} -#endif - -#if WPF - //public XFontFamily(WpfFontFamily wpfFontFamily) - //{ - // FamilyInternal = FontFamilyInternal.GetOrCreateFromWpf(wpfFontFamily); - // //// HACK - // //int idxHash = _name.LastIndexOf('#'); - // //if (idxHash > 0) - // // _name = _name.Substring(idxHash + 1); - // //_wpfFamily = family; - //} -#endif - internal static XFontFamily CreateFromName_not_used(string name, bool createPlatformFamily) { XFontFamily fontFamily = new XFontFamily(name); - if (createPlatformFamily) - { -#if GDI - //fontFamily._gdiFamily = new System.Drawing.FontFamily(name); -#endif -#if WPF - //fontFamily._wpfFamily = new System.Windows.Media.FontFamily(name); -#endif - } return fontFamily; } @@ -136,30 +95,6 @@ internal static XFontFamily CreateSolitary(string name) //return new XFontFamily(fontFamilyInternal); } -#if CORE || GDI - internal static XFontFamily GetOrCreateFromGdi(GdiFont font) - { - FontFamilyInternal fontFamilyInternal = FontFamilyInternal.GetOrCreateFromGdi(font.FontFamily); - return new XFontFamily(fontFamilyInternal); - } -#endif - -#if WPF - internal static XFontFamily GetOrCreateFromWpf(WpfFontFamily wpfFontFamily) - { - FontFamilyInternal fontFamilyInternal = FontFamilyInternal.GetOrCreateFromWpf(wpfFontFamily); - return new XFontFamily(fontFamilyInternal); - } -#endif -#if SILVERLIGHT - //internal static XFontFamily CreateFromWpf(System.Windows.Media.FontFamily wpfFontFamily) - //{ - // XFontFamily fontFamily = new XFontFamily(wpfFontFamily.FamilyNames[XmlLanguage.GetLanguage("en")]); - // fontFamily._wpfFamily = wpfFontFamily; - // return fontFamily; - //} -#endif - /// /// Gets the name of the font family. /// @@ -186,10 +121,6 @@ public int GetCellAscent(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.Ascender; -#if DEBUG_ && GDI - int gdiValue = _gdiFamily.GetCellAscent((FontStyle)style); - Debug.Assert(gdiValue == result); -#endif return result; } @@ -200,10 +131,6 @@ public int GetCellDescent(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.Descender; -#if DEBUG_ && GDI - int gdiValue = _gdiFamily.GetCellDescent((FontStyle)style); - Debug.Assert(gdiValue == result); -#endif return result; } @@ -214,10 +141,6 @@ public int GetEmHeight(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.UnitsPerEm; -#if DEBUG_ && GDI - int gdiValue = _gdiFamily.GetEmHeight((FontStyle)style); - Debug.Assert(gdiValue == result); -#endif #if DEBUG_ int headValue = descriptor.FontFace.head.unitsPerEm; Debug.Assert(headValue == result); @@ -233,14 +156,6 @@ public int GetLineSpacing(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.LineSpacing; -#if DEBUG_ && GDI - int gdiValue = _gdiFamily.GetLineSpacing((FontStyle)style); - Debug.Assert(gdiValue == result); -#endif -#if DEBUG_ && WPF && !SILVERLIGHT - int wpfValue = (int)Math.Round(_wpfFamily.LineSpacing * GetEmHeight(style)); - Debug.Assert(wpfValue == result); -#endif return result; } @@ -252,62 +167,9 @@ public int GetLineSpacing(XFontStyle style) public bool IsStyleAvailable(XFontStyle style) { XGdiFontStyle xStyle = ((XGdiFontStyle)style) & XGdiFontStyle.BoldItalic; -#if CORE - throw new InvalidOperationException("In CORE build it is the responsibility of the developer to provide all required font faces."); -#endif -#if GDI && !WPF - if (GdiFamily != null) - return GdiFamily.IsStyleAvailable((GdiFontStyle)xStyle); return false; -#endif -#if WPF && !GDI - if (WpfFamily != null) - return FontHelper.IsStyleAvailable(this, xStyle); - return false; -#endif -#if WPF && GDI -#if DEBUG - //bool gdiResult = _gdiFamily.IsStyle Available((FontStyle)style); - //bool wpfResult = FontHelper.IsStyle Available(this, style); - //// TODOWPF: check when fails - //Debug.Assert(gdiResult == wpfResult, "GDI+ and WPF provide different values."); -#endif - return FontHelper.IsStyleAvailable(this, xStyle); -#endif -#if NETFX_CORE || UWP - throw new InvalidOperationException("In NETFX_CORE build it is the responsibility of the developer to provide all required font faces."); -#endif -#if __IOS__ || __ANDROID__ - return true; // IOS_ANDROID_TODO -#endif -#if PORTABLE - return false; -#endif - } -#if GDI - /// - /// Gets the underlying GDI+ font family object. - /// Is null if the font was created by a font resolver. - /// - internal GdiFontFamily GdiFamily - { - get { return FamilyInternal.GdiFamily; } - } -#endif - -#if WPF - /// - /// Gets the underlying WPF font family object. - /// Is null if the font was created by a font resolver. - /// - internal WpfFontFamily WpfFamily - { - get { return FamilyInternal.WpfFamily; } - } -#endif - /// /// The implementation sigleton of font family; /// diff --git a/PdfSharpCore/Drawing/XFontSource.cs b/PdfSharpCore/Drawing/XFontSource.cs index d16adf16..662f01da 100644 --- a/PdfSharpCore/Drawing/XFontSource.cs +++ b/PdfSharpCore/Drawing/XFontSource.cs @@ -30,22 +30,7 @@ using System; using System.Diagnostics; using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; using PdfSharpCore.Fonts; -#if CORE || GDI -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows; -using System.Windows.Documents; -using System.Windows.Media; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -#endif -using PdfSharpCore.Internal; using PdfSharpCore.Fonts.OpenType; namespace PdfSharpCore.Drawing @@ -89,112 +74,6 @@ public static XFontSource GetOrCreateFrom(byte[] bytes) } return fontSource; } - -#if CORE || GDI - internal static XFontSource GetOrCreateFromGdi(string typefaceKey, GdiFont gdiFont) - { - byte[] bytes = ReadFontBytesFromGdi(gdiFont); - XFontSource fontSource = GetOrCreateFrom(typefaceKey, bytes); - return fontSource; - } - - static byte[] ReadFontBytesFromGdi(GdiFont gdiFont) - { - // Weird: LastError is always 123 or 127. Comment out Debug.Assert. - int error = Marshal.GetLastWin32Error(); - //Debug.Assert(error == 0); - error = Marshal.GetLastWin32Error(); - //Debug.Assert(error == 0); - - IntPtr hfont = gdiFont.ToHfont(); -#if true - IntPtr hdc = NativeMethods.GetDC(IntPtr.Zero); -#else - NativeMethods.LOGFONT logFont = new NativeMethods.LOGFONT(); - logFont.lfHeight = 30; - logFont.lfWidth = 0; - logFont.lfEscapement = 0; - logFont.lfOrientation = 0; - logFont.lfWeight = 400; - logFont.lfItalic = 0; - logFont.lfUnderline = 0; - logFont.lfStrikeOut = 0; - logFont.lfCharSet = 0; - logFont.lfOutPrecision = 0; - logFont.lfClipPrecision = 0; - logFont.lfQuality = 0; - logFont.lfPitchAndFamily = 0; - logFont.lfFaceName = "Arial"; - - gdiFont.ToLogFont(logFont); - - hfont = NativeMethods.CreateFontIndirect(logFont); - - - // IntPtr hdc = NativeMethods.CreateDC("DISPLAY", null, null, IntPtr.Zero); - IntPtr hdc = NativeMethods.CreateCompatibleDC(IntPtr.Zero); -#endif - error = Marshal.GetLastWin32Error(); - //Debug.Assert(error == 0); - - IntPtr oldFont = NativeMethods.SelectObject(hdc, hfont); - error = Marshal.GetLastWin32Error(); - //Debug.Assert(error == 0); - - // Get size of the font file. - bool isTtcf = false; - // In Azure I get 0xc0000022 - int size = NativeMethods.GetFontData(hdc, 0, 0, null, 0); - - // Check for ntstatus.h: #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) - if ((uint)size == 0xc0000022) - throw new InvalidOperationException("Microsoft Azure returns STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) from GetFontData. This is a bug in Azure. You must implement a FontResolver to circumvent this issue."); - - if (size == NativeMethods.GDI_ERROR) - { - // Assume that the font file is a true type collection. - size = NativeMethods.GetFontData(hdc, ttcf, 0, null, 0); - isTtcf = true; - } - error = Marshal.GetLastWin32Error(); - //Debug.Assert(error == 0); - - if (size == 0) - throw new InvalidOperationException("Cannot retrieve font data."); - - byte[] bytes = new byte[size]; - int effectiveSize = NativeMethods.GetFontData(hdc, isTtcf ? ttcf : 0, 0, bytes, size); - Debug.Assert(size == effectiveSize); - // Clean up. - NativeMethods.SelectObject(hdc, oldFont); - NativeMethods.ReleaseDC(IntPtr.Zero, hdc); - - return bytes; - } -#endif - -#if WPF && !SILVERLIGHT - internal static XFontSource GetOrCreateFromWpf(string typefaceKey, WpfGlyphTypeface wpfGlyphTypeface) - { - byte[] bytes = ReadFontBytesFromWpf(wpfGlyphTypeface); - XFontSource fontSource = GetOrCreateFrom(typefaceKey, bytes); - return fontSource; - } - - internal static byte[] ReadFontBytesFromWpf(WpfGlyphTypeface wpfGlyphTypeface) - { - using (Stream fontStream = wpfGlyphTypeface.GetFontStream()) - { - if (fontStream == null) - throw new InvalidOperationException("Cannot retrieve font data."); - int size = (int)fontStream.Length; - byte[] bytes = new byte[size]; - fontStream.Read(bytes, 0, size); - return bytes; - } - } -#endif - public static XFontSource GetOrCreateFrom(string typefaceKey, byte[] fontBytes) { XFontSource fontSource; diff --git a/PdfSharpCore/Drawing/XFontWeight.cs b/PdfSharpCore/Drawing/XFontWeight.cs index a4908b3c..4887b025 100644 --- a/PdfSharpCore/Drawing/XFontWeight.cs +++ b/PdfSharpCore/Drawing/XFontWeight.cs @@ -27,17 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif - -// Not used in PDFsharp 1.x. - namespace PdfSharpCore.Drawing { #if true_ // PDFSHARP20 diff --git a/PdfSharpCore/Drawing/XForm.cs b/PdfSharpCore/Drawing/XForm.cs index 3926e338..1cc223b8 100644 --- a/PdfSharpCore/Drawing/XForm.cs +++ b/PdfSharpCore/Drawing/XForm.cs @@ -29,15 +29,6 @@ using System; using System.Diagnostics; -using System.IO; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing.Pdf; using PdfSharpCore.Pdf; using PdfSharpCore.Pdf.Advanced; @@ -80,49 +71,6 @@ internal enum FormState protected XForm() { } -#if GDI - /// - /// Initializes a new instance of the XForm class such that it can be drawn on the specified graphics - /// object. - /// - /// The graphics object that later is used to draw this form. - /// The size in points of the form. - public XForm(XGraphics gfx, XSize size) - { - if (gfx == null) - throw new ArgumentNullException("gfx"); - if (size.Width < 1 || size.Height < 1) - throw new ArgumentNullException("size", "The size of the XPdfForm is to small."); - - _formState = FormState.Created; - //templateSize = size; - _viewBox.Width = size.Width; - _viewBox.Height = size.Height; - - // If gfx belongs to a PdfPage also create the PdfFormXObject - if (gfx.PdfPage != null) - { - _document = gfx.PdfPage.Owner; - _pdfForm = new PdfFormXObject(_document, this); - PdfRectangle rect = new PdfRectangle(new XPoint(), size); - _pdfForm.Elements.SetRectangle(PdfFormXObject.Keys.BBox, rect); - } - } -#endif - -#if GDI - /// - /// Initializes a new instance of the XForm class such that it can be drawn on the specified graphics - /// object. - /// - /// The graphics object that later is used to draw this form. - /// The width of the form. - /// The height of the form. - public XForm(XGraphics gfx, XUnit width, XUnit height) - : this(gfx, new XSize(width, height)) - { } -#endif - /// /// Initializes a new instance of the class that represents a page of a PDF document. /// @@ -230,14 +178,14 @@ protected override void Dispose(bool disposing) /// internal virtual void Finish() { -#if GDI if (_formState == FormState.NotATemplate || _formState == FormState.Finished) return; - if (Gfx.Metafile != null) - _gdiImage = Gfx.Metafile; + if (!(_formState == FormState.Created || _formState == FormState.UnderConstruction)) + { + throw new InvalidOperationException("Expected the form to be Created or UnderConstruction"); + } - Debug.Assert(_formState == FormState.Created || _formState == FormState.UnderConstruction); _formState = FormState.Finished; Gfx.Dispose(); Gfx = null; @@ -246,7 +194,6 @@ internal virtual void Finish() { //pdfForm.CreateStream(PdfEncoders.RawEncoding.GetBytes(PdfRenderer.GetContent())); PdfRenderer.Close(); - Debug.Assert(PdfRenderer == null); if (_document.Options.CompressContentStreams) { @@ -256,9 +203,6 @@ internal virtual void Finish() int length = _pdfForm.Stream.Length; _pdfForm.Elements.SetInteger("/Length", length); } -#endif -#if WPF -#endif } /// @@ -518,33 +462,5 @@ string IContentStream.GetFormName(XForm form) internal XGraphicsPdfRenderer PdfRenderer; -#if WPF && !SILVERLIGHT - /// - /// Gets a value indicating whether this image is cmyk. - /// - /// true if this image is cmyk; otherwise, false. - internal override bool IsCmyk - { - get { return false; } // not supported and not relevant - } - - /// - /// Gets a value indicating whether this image is JPEG. - /// - /// true if this image is JPEG; otherwise, false. - internal override bool IsJpeg - { - get { return base.IsJpeg; }// not supported and not relevant - } - - /// - /// Gets the JPEG memory stream (if IsJpeg returns true). - /// - /// The memory. - public override MemoryStream Memory - { - get { throw new NotImplementedException(); } - } -#endif } -} \ No newline at end of file +} diff --git a/PdfSharpCore/Drawing/XGlyphTypeface.cs b/PdfSharpCore/Drawing/XGlyphTypeface.cs index 10dff970..855a95bc 100644 --- a/PdfSharpCore/Drawing/XGlyphTypeface.cs +++ b/PdfSharpCore/Drawing/XGlyphTypeface.cs @@ -30,36 +30,9 @@ using System; using System.Diagnostics; using System.Globalization; -#if CORE || GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows; -using System.Windows.Documents; -using System.Windows.Media; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -using WpfStyleSimulations = System.Windows.Media.StyleSimulations; -#endif -#if UWP -using Windows.UI.Xaml.Media; -#endif using PdfSharpCore.Fonts; using PdfSharpCore.Fonts.OpenType; -#pragma warning disable 649 -#if SILVERLIGHT -#pragma warning disable 219 -#endif -#if NETFX_CORE -#pragma warning disable 649 -#endif - namespace PdfSharpCore.Drawing { /// @@ -80,28 +53,7 @@ internal sealed class XGlyphTypeface const string KeyPrefix = "tk:"; // "typeface key" -#if CORE || GDI - XGlyphTypeface(string key, XFontFamily fontFamily, XFontSource fontSource, XStyleSimulations styleSimulations, GdiFont gdiFont) - { - _key = key; - _fontFamily = fontFamily; - _fontSource = fontSource; - - _fontface = OpenTypeFontface.CetOrCreateFrom(fontSource); - Debug.Assert(ReferenceEquals(_fontSource.Fontface, _fontface)); - - _gdiFont = gdiFont; - - _styleSimulations = styleSimulations; - Initialize(); - } -#endif - -#if GDI - /// - /// Initializes a new instance of the class by a font source. - /// - public XGlyphTypeface(XFontSource fontSource) + public XGlyphTypeface(string key, XFontSource fontSource) { string familyName = fontSource.Fontface.name.Name; _fontFamily = new XFontFamily(familyName, false); @@ -109,81 +61,21 @@ public XGlyphTypeface(XFontSource fontSource) _isBold = _fontface.os2.IsBold; _isItalic = _fontface.os2.IsItalic; - _key = ComputeKey(familyName, _isBold, _isItalic); - //_fontFamily =xfont FontFamilyCache.GetFamilyByName(familyName); - _fontSource = fontSource; - - Initialize(); - } -#endif - -#if WPF - XGlyphTypeface(string key, XFontFamily fontFamily, XFontSource fontSource, XStyleSimulations styleSimulations, WpfTypeface wpfTypeface, WpfGlyphTypeface wpfGlyphTypeface) - { _key = key; - _fontFamily = fontFamily; + //_fontFamily =xfont FontFamilyCache.GetFamilyByName(familyName); _fontSource = fontSource; - _styleSimulations = styleSimulations; - - _fontface = OpenTypeFontface.CetOrCreateFrom(fontSource); - Debug.Assert(ReferenceEquals(_fontSource.Fontface, _fontface)); - - _wpfTypeface = wpfTypeface; - _wpfGlyphTypeface = wpfGlyphTypeface; Initialize(); } -#endif -#if NETFX_CORE || UWP - XGlyphTypeface(string key, XFontFamily fontFamily, XFontSource fontSource, XStyleSimulations styleSimulations) + // ReSharper disable once UnusedMember.Global + public XGlyphTypeface(string key, XFontFamily fontFamily, XFontSource fontSource, XStyleSimulations styleSimulations) { _key = key; _fontFamily = fontFamily; _fontSource = fontSource; _styleSimulations = styleSimulations; - _fontface = OpenTypeFontface.CetOrCreateFrom(fontSource); - Debug.Assert(ReferenceEquals(_fontSource.Fontface, _fontface)); - - //_wpfTypeface = wpfTypeface; - //_wpfGlyphTypeface = wpfGlyphTypeface; - - Initialize(); - } -#endif - -#if __IOS__ - /// - /// Initializes a new instance of the class by a font source. - /// - public XGlyphTypeface(string key, XFontSource fontSource) - { - string familyName = fontSource.Fontface.name.Name; - _fontFamily = new XFontFamily(familyName, false); - _fontface = fontSource.Fontface; - _isBold = _fontface.os2.IsBold; - _isItalic = _fontface.os2.IsItalic; - - _key = key; - //_fontFamily =xfont FontFamilyCache.GetFamilyByName(familyName); - _fontSource = fontSource; - - Initialize(); - } -#endif - - public XGlyphTypeface(string key, XFontSource fontSource) - { - string familyName = fontSource.Fontface.name.Name; - _fontFamily = new XFontFamily(familyName, false); - _fontface = fontSource.Fontface; - _isBold = _fontface.os2.IsBold; - _isItalic = _fontface.os2.IsItalic; - - _key = key; - //_fontFamily =xfont FontFamilyCache.GetFamilyByName(familyName); - _fontSource = fontSource; Initialize(); } @@ -192,8 +84,7 @@ public static XGlyphTypeface GetOrCreateFrom(string familyName, FontResolvingOpt { // Check cache for requested type face. string typefaceKey = ComputeKey(familyName, fontResolvingOptions); - XGlyphTypeface glyphTypeface; - if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) + if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out var glyphTypeface)) { // Just return existing one. return glyphTypeface; @@ -206,43 +97,10 @@ public static XGlyphTypeface GetOrCreateFrom(string familyName, FontResolvingOpt // No fallback - just stop. throw new InvalidOperationException("No appropriate font found."); } - -#if CORE || GDI - GdiFont gdiFont = null; -#endif -#if WPF - WpfFontFamily wpfFontFamily = null; - WpfTypeface wpfTypeface = null; - WpfGlyphTypeface wpfGlyphTypeface = null; -#endif -#if UWP - // Nothing to do. -#endif // Now create the font family at the first. XFontFamily fontFamily; - PlatformFontResolverInfo platformFontResolverInfo = fontResolverInfo as PlatformFontResolverInfo; - if (platformFontResolverInfo != null) + if (fontResolverInfo is PlatformFontResolverInfo platformFontResolverInfo) { -#if CORE || GDI - // $TODO THHO Lock??? - // Reuse GDI+ font from platform font resolver. - gdiFont = platformFontResolverInfo.GdiFont; - fontFamily = XFontFamily.GetOrCreateFromGdi(gdiFont); -#endif -#if WPF -#if !SILVERLIGHT - // Reuse WPF font family created from platform font resolver. - wpfFontFamily = platformFontResolverInfo.WpfFontFamily; - wpfTypeface = platformFontResolverInfo.WpfTypeface; - wpfGlyphTypeface = platformFontResolverInfo.WpfGlyphTypeface; - fontFamily = XFontFamily.GetOrCreateFromWpf(wpfFontFamily); -#else - fontFamily = XFontFamily.GetOrCreateFromWpf(new WpfFontFamily(familyName)); -#endif -#endif -#if NETFX_CORE || UWP - fontFamily = null; -#endif } else { @@ -256,101 +114,11 @@ public static XGlyphTypeface GetOrCreateFrom(string familyName, FontResolvingOpt Debug.Assert(fontSource != null); // Each font source already contains its OpenTypeFontface. -#if CORE || GDI - glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, fontResolverInfo.StyleSimulations, gdiFont); -#endif -#if WPF - glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, fontResolverInfo.StyleSimulations, wpfTypeface, wpfGlyphTypeface); -#endif -#if NETFX_CORE || UWP - glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, fontResolverInfo.StyleSimulations); -#endif -#if __IOS__ glyphTypeface = new XGlyphTypeface(typefaceKey, fontSource); -#endif - glyphTypeface = new XGlyphTypeface(typefaceKey, fontSource); - GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); - - return glyphTypeface; - } - -#if CORE || GDI - public static XGlyphTypeface GetOrCreateFromGdi(GdiFont gdiFont) - { - // $TODO THHO Lock??? - string typefaceKey = ComputeKey(gdiFont); - XGlyphTypeface glyphTypeface; - if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) - { - // We have the glyph typeface already in cache. - return glyphTypeface; - } - - XFontFamily fontFamily = XFontFamily.GetOrCreateFromGdi(gdiFont); - XFontSource fontSource = XFontSource.GetOrCreateFromGdi(typefaceKey, gdiFont); - - // Check if styles must be simulated. - XStyleSimulations styleSimulations = XStyleSimulations.None; - if (gdiFont.Bold && !fontSource.Fontface.os2.IsBold) - styleSimulations |= XStyleSimulations.BoldSimulation; - if (gdiFont.Italic && !fontSource.Fontface.os2.IsItalic) - styleSimulations |= XStyleSimulations.ItalicSimulation; - - glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, styleSimulations, gdiFont); GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); return glyphTypeface; } -#endif - -#if WPF && !SILVERLIGHT - public static XGlyphTypeface GetOrCreateFromWpf(WpfTypeface wpfTypeface) - { -#if DEBUG - if (wpfTypeface.FontFamily.Source == "Segoe UI Semilight") - wpfTypeface.GetType(); -#endif - //string typefaceKey = ComputeKey(wpfTypeface); - //XGlyphTypeface glyphTypeface; - //if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) - //{ - // // We have the glyph typeface already in cache. - // return glyphTypeface; - //} - - // Create WPF glyph typeface. - WpfGlyphTypeface wpfGlyphTypeface; - if (!wpfTypeface.TryGetGlyphTypeface(out wpfGlyphTypeface)) - return null; - - string typefaceKey = ComputeKey(wpfGlyphTypeface); - - string name1 = wpfGlyphTypeface.DesignerNames[FontHelper.CultureInfoEnUs]; - string name2 = wpfGlyphTypeface.FaceNames[FontHelper.CultureInfoEnUs]; - string name3 = wpfGlyphTypeface.FamilyNames[FontHelper.CultureInfoEnUs]; - string name4 = wpfGlyphTypeface.ManufacturerNames[FontHelper.CultureInfoEnUs]; - string name5 = wpfGlyphTypeface.Win32FaceNames[FontHelper.CultureInfoEnUs]; - string name6 = wpfGlyphTypeface.Win32FamilyNames[FontHelper.CultureInfoEnUs]; - - XGlyphTypeface glyphTypeface; - if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) - { - // We have the glyph typeface already in cache. - return glyphTypeface; - } - - XFontFamily fontFamily = XFontFamily.GetOrCreateFromWpf(wpfTypeface.FontFamily); - XFontSource fontSource = XFontSource.GetOrCreateFromWpf(typefaceKey, wpfGlyphTypeface); - - glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, - (XStyleSimulations)wpfGlyphTypeface.StyleSimulations, - wpfTypeface, wpfGlyphTypeface); - GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); - - return glyphTypeface; - } -#endif - public XFontFamily FontFamily { get { return _fontFamily; } @@ -533,107 +301,12 @@ internal static string ComputeKey(string familyName, bool isBold, bool isItalic) { return ComputeKey(familyName, new FontResolvingOptions(FontHelper.CreateStyle(isBold, isItalic))); } - -#if CORE || GDI - internal static string ComputeKey(GdiFont gdiFont) - { - string name1 = gdiFont.Name; - string name2 = gdiFont.OriginalFontName; - string name3 = gdiFont.SystemFontName; - - string name = name1; - GdiFontStyle style = gdiFont.Style; - - string key = KeyPrefix + name.ToLowerInvariant() + ((style & GdiFontStyle.Italic) == GdiFontStyle.Italic ? "/i" : "/n") + ((style & GdiFontStyle.Bold) == GdiFontStyle.Bold ? "/700" : "/400") + "/5"; // Stretch.Normal - return key; - } -#endif -#if WPF && !SILVERLIGHT - internal static string ComputeKey(WpfGlyphTypeface wpfGlyphTypeface) - { - string name1 = wpfGlyphTypeface.DesignerNames[FontHelper.CultureInfoEnUs]; - string faceName = wpfGlyphTypeface.FaceNames[FontHelper.CultureInfoEnUs]; - string familyName = wpfGlyphTypeface.FamilyNames[FontHelper.CultureInfoEnUs]; - string name4 = wpfGlyphTypeface.ManufacturerNames[FontHelper.CultureInfoEnUs]; - string name5 = wpfGlyphTypeface.Win32FaceNames[FontHelper.CultureInfoEnUs]; - string name6 = wpfGlyphTypeface.Win32FamilyNames[FontHelper.CultureInfoEnUs]; - - - string name = familyName.ToLower() + '/' + faceName.ToLowerInvariant(); - string style = wpfGlyphTypeface.Style.ToString(); - string weight = wpfGlyphTypeface.Weight.ToString(); - string stretch = wpfGlyphTypeface.Stretch.ToString(); - string simulations = wpfGlyphTypeface.StyleSimulations.ToString(); - - //string key = name + '/' + style + '/' + weight + '/' + stretch + '/' + simulations; - - string key = KeyPrefix + name + '/' + style.Substring(0, 1) + '/' + wpfGlyphTypeface.Weight.ToOpenTypeWeight().ToString(CultureInfo.InvariantCulture) + '/' + wpfGlyphTypeface.Stretch.ToOpenTypeStretch().ToString(CultureInfo.InvariantCulture); - switch (wpfGlyphTypeface.StyleSimulations) - { - case WpfStyleSimulations.BoldSimulation: key += "|b+/i-"; break; - case WpfStyleSimulations.ItalicSimulation: key += "|b-/i+"; break; - case WpfStyleSimulations.BoldItalicSimulation: key += "|b+/i+"; break; - case WpfStyleSimulations.None: break; - } - return key.ToLowerInvariant(); - } -#endif - public string Key { get { return _key; } } readonly string _key; -#if CORE || GDI - internal GdiFont GdiFont - { - get { return _gdiFont; } - } - - private readonly GdiFont _gdiFont; -#endif - -#if WPF - internal WpfTypeface WpfTypeface - { - get { return _wpfTypeface; } - } - readonly WpfTypeface _wpfTypeface; - - internal WpfGlyphTypeface WpfGlyphTypeface - { - get { return _wpfGlyphTypeface; } - } - readonly WpfGlyphTypeface _wpfGlyphTypeface; -#endif - -#if SILVERLIGHT_ - /// - /// Gets the FontSource object used in Silverlight 4. - /// - public FontSource FontSource - { - get - { - if (_fontSource == null) - { -#if true - MemoryStream stream = new MemoryStream(_fontface.FontData.Bytes); - _fontSource = new FontSource(stream); -#else - using (MemoryStream stream = new MemoryStream(_fontface.Data)) - { - _fontSource = new FontSource(stream); - } -#endif - } - return _fontSource; - } - } - FontSource _fontSource; -#endif - /// /// Gets the DebuggerDisplayAttribute text. /// diff --git a/PdfSharpCore/Drawing/XGraphics.cs b/PdfSharpCore/Drawing/XGraphics.cs index c3083237..26dfc628 100644 --- a/PdfSharpCore/Drawing/XGraphics.cs +++ b/PdfSharpCore/Drawing/XGraphics.cs @@ -28,52 +28,8 @@ #endregion using System; -using System.Diagnostics; -using System.IO; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GdiPoint = System.Drawing.Point; -using GdiSize = System.Drawing.Size; -using GdiRect = System.Drawing.Rectangle; -using GdiPointF = System.Drawing.PointF; -using GdiSizeF = System.Drawing.SizeF; -using GdiRectF = System.Drawing.RectangleF; -using GdiMatrix = System.Drawing.Drawing2D.Matrix; -#endif -#if WPF -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using PdfSharpCore.Windows; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -using SysMatrix = System.Windows.Media.Matrix; -using WpfBrush = System.Windows.Media.Brush; -using WpfPen = System.Windows.Media.Pen; -#if !SILVERLIGHT -using WpfBrushes = System.Windows.Media.Brushes; -#endif -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -using SysRect = Windows.Foundation.Rect; -#endif -#if UWP -using Windows.UI; -using Windows.UI.Xaml.Controls; -using Microsoft.Graphics.Canvas; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -using SysRect = Windows.Foundation.Rect; -#endif using PdfSharpCore.Pdf; using PdfSharpCore.Drawing.Pdf; -using PdfSharpCore.Internal; using PdfSharpCore.Pdf.Advanced; #pragma warning disable 1587 @@ -93,252 +49,13 @@ enum InternalGraphicsMode DrawingPdfContent, DrawingBitmap, } - + + /// /// Represents a drawing surface for a fixed size page. /// public sealed class XGraphics : IDisposable { -#if CORE - // TODO: Implement better concept of a measure context. -#endif - -#if GDI - /// - /// Initializes a new instance of the XGraphics class. - /// - /// The gfx. - /// The size. - /// The page unit. - /// The page direction. - XGraphics(Graphics gfx, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) - { - if (gfx == null) - { - // MigraDoc comes here when creating a MeasureContext. - try - { - Lock.EnterGdiPlus(); - gfx = Graphics.FromHwnd(IntPtr.Zero); // BUG: Use measure image - } - finally { Lock.ExitGdiPlus(); } - } - - _gsStack = new GraphicsStateStack(this); - TargetContext = XGraphicTargetContext.GDI; - _gfx = gfx; - _drawGraphics = true; - _pageSize = new XSize(size.Width, size.Height); - _pageUnit = pageUnit; - switch (pageUnit) - { - case XGraphicsUnit.Point: - _pageSizePoints = new XSize(size.Width, size.Height); - break; - - case XGraphicsUnit.Inch: - _pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height)); - break; - - case XGraphicsUnit.Millimeter: - _pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height)); - break; - - case XGraphicsUnit.Centimeter: - _pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height)); - break; - - case XGraphicsUnit.Presentation: - _pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height)); - break; - - default: - throw new NotImplementedException("unit"); - } - - _pageDirection = pageDirection; - Initialize(); - } -#endif - -#if WPF && !SILVERLIGHT - /// - /// Initializes a new instance of the XGraphics class. - /// - /// The drawing context. - /// The size. - /// The page unit. - /// The page direction. - XGraphics(DrawingContext dc, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) - { - if (dc == null) - { - //throw new ArgumentNullException("dc"); - _dv = new DrawingVisual(); - dc = _dv.RenderOpen(); - } - - _gsStack = new GraphicsStateStack(this); - TargetContext = XGraphicTargetContext.WPF; - _dc = dc; - _drawGraphics = true; - _pageSize = new XSize(size.Width, size.Height); - _pageUnit = pageUnit; - switch (pageUnit) - { - case XGraphicsUnit.Point: - _pageSizePoints = new XSize(size.Width, size.Height); - break; - - case XGraphicsUnit.Inch: - _pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height)); - break; - - case XGraphicsUnit.Millimeter: - _pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height)); - break; - - case XGraphicsUnit.Centimeter: - _pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height)); - break; - - case XGraphicsUnit.Presentation: - _pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height)); - break; - - default: - throw new NotImplementedException("unit"); - } - - _pageDirection = pageDirection; - Initialize(); - } -#endif - -#if WPF - /// - /// Initializes a new instance of the XGraphics class. - /// - /// The canvas. - /// The size. - /// The page unit. - /// The page direction. - XGraphics(Canvas canvas, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) - { - //throw new ArgumentNullException("canvas"); - if (canvas == null) - canvas = new Canvas(); - -#if !SILVERLIGHT - // Create DrawingVisual as container for the content of the page. - _dv = new DrawingVisual(); - // Create a host that shows the visual. - VisualPresenter vp = new VisualPresenter(); - vp.Children.Add(_dv); - // The canvan only contains the host of the DrawingVisual. - canvas.Children.Add(vp); - _dc = _dv.RenderOpen(); - TargetContext = XGraphicTargetContext.WPF; - //////VisualBrush brush = new VisualBrush(_dv); - ////////brush.ViewboxUnits = BrushMappingMode. - //////brush.Viewport=new Rect(new Point(), size.ToSize()); - //////brush.Viewbox=new Rect(new Point(), size.ToSize()); - ////////brush.Viewport=new Rect(new Point(), (Size)size); - //////brush.AutoLayoutContent = true; - //////canvas.Background = brush; -#else - _dc = new AgDrawingContext(canvas); -#endif - - _gsStack = new GraphicsStateStack(this); - TargetContext = XGraphicTargetContext.WPF; - - _drawGraphics = true; - _pageSize = new XSize(size.Width, size.Height); - _pageUnit = pageUnit; - switch (pageUnit) - { - case XGraphicsUnit.Point: - _pageSizePoints = new XSize(size.Width, size.Height); - break; - - case XGraphicsUnit.Inch: - _pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height)); - break; - - case XGraphicsUnit.Millimeter: - _pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height)); - break; - - case XGraphicsUnit.Centimeter: - _pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height)); - break; - - case XGraphicsUnit.Presentation: - _pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height)); - break; - - default: - throw new NotImplementedException("unit"); - } - - _pageDirection = pageDirection; - Initialize(); - } -#endif - -#if UWP - /// - /// Initializes a new instance of the XGraphics class. - /// - /// The canvas. - /// The size. - /// The page unit. - /// The page direction. - XGraphics(CanvasDrawingSession canvasDrawingSession, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) - { - if (canvasDrawingSession == null) - throw new ArgumentNullException("canvasDrawingSession"); - - _cds = canvasDrawingSession; - - _gsStack = new GraphicsStateStack(this); - TargetContext = XGraphicTargetContext.WPF; - - _drawGraphics = true; - _pageSize = new XSize(size.Width, size.Height); - _pageUnit = pageUnit; - switch (pageUnit) - { - case XGraphicsUnit.Point: - _pageSizePoints = new XSize(size.Width, size.Height); - break; - - case XGraphicsUnit.Inch: - _pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height)); - break; - - case XGraphicsUnit.Millimeter: - _pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height)); - break; - - case XGraphicsUnit.Centimeter: - _pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height)); - break; - - case XGraphicsUnit.Presentation: - _pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height)); - break; - - default: - throw new NotImplementedException("unit"); - } - - _pageDirection = pageDirection; - Initialize(); - } -#endif - /// /// Initializes a new instance of the XGraphics class for drawing on a PDF page. /// @@ -373,28 +90,6 @@ public sealed class XGraphics : IDisposable break; } page.RenderContent = content; - -#if CORE - TargetContext = XGraphicTargetContext.CORE; -#endif -#if GDI - // HACK: This does not work with #MediumTrust - //_gfx = Graphics.FromHwnd(IntPtr.Zero); // _gfx should not be necessary anymore. - _gfx = null; - TargetContext = XGraphicTargetContext.GDI; -#endif -#if WPF && !SILVERLIGHT - _dv = new DrawingVisual(); - _dc = _dv.RenderOpen(); - TargetContext = XGraphicTargetContext.WPF; -#endif -#if SILVERLIGHT - _dc = new AgDrawingContext(new Canvas()); - TargetContext = XGraphicTargetContext.WPF; -#endif -#if GDI && WPF - TargetContext = PdfSharpCore.Internal.TargetContextHelper.TargetContext; -#endif _renderer = new XGraphicsPdfRenderer(page, this, options); _pageSizePoints = new XSize(page.Width, page.Height); switch (pageUnit) @@ -429,10 +124,6 @@ public sealed class XGraphics : IDisposable } XGraphics(XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) { - if (size == null) - throw new ArgumentNullException("size"); - - _gsStack = new GraphicsStateStack(this); _pageSizePoints = new XSize(size.Width, size.Height); switch (pageUnit) @@ -514,118 +205,11 @@ public sealed class XGraphics : IDisposable form.AssociateGraphics(this); _gsStack = new GraphicsStateStack(this); -#if CORE - TargetContext = XGraphicTargetContext.CORE; -#endif -#if CORE || NET5_0 _drawGraphics = false; if (form.Owner != null) _renderer = new XGraphicsPdfRenderer(form, this); _pageSize = form.Size; Initialize(); -#endif -#if GDI && !WPF - try - { - Lock.EnterGdiPlus(); - TargetContext = XGraphicTargetContext.GDI; - // If form.Owner is null create a meta file. - if (form.Owner == null) - { - MemoryStream stream = new MemoryStream(); - // BUG: This Windows 1.0 technique issued an exception under Microsoft Azure. // #??? - using (Graphics refgfx = Graphics.FromHwnd(IntPtr.Zero)) - { - IntPtr hdc = refgfx.GetHdc(); -#if true_ - // This code comes from my C++ RenderContext and checks some confusing details in connection - // with metafiles. - // Display | LaserJet - // DPI 96 : 120 | 300 - // physical device size in MM --------------------------------------------- - int horzSizeMM = NativeMethods.GetDeviceCaps(hdc, NativeMethods.HORZSIZE); // = 360 : 360 | 198 (not 210) - int vertSizeMM = NativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTSIZE); // = 290 : 290 | 288 (hot 297) - // Cool: - // My monitor is a Sony SDM-N80 and its size is EXACTLY 360mm x 290mm!! - // It is an 18.1" Flat Panel LCD from 2002 and these are the values - // an older display drivers reports in about 2003: - // Display - // DPI 96 : 120 - // -------------- - // 330 : 254 - // 254 : 203 - // Obviously my ATI driver reports the exact size of the monitor. - - - // device size in pixel - int horzSizePixel = NativeMethods.GetDeviceCaps(hdc, NativeMethods.HORZRES); // = 1280 : 1280 | 4676 - int vertSizePixel = NativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTRES); // = 1024 : 1024 | 6814 - - // 'logical' device resolution in DPI - int logResX = NativeMethods.GetDeviceCaps(hdc, NativeMethods.LOGPIXELSX); // = 96 : 120 | 600 - int logResY = NativeMethods.GetDeviceCaps(hdc, NativeMethods.LOGPIXELSY); // = 96 : 120 | 600 - - // now we can get the 'physical' device resolution... - float phyResX = horzSizePixel / (horzSizeMM / 25.4f); // = 98.521210 : 128.00000 | 599.85052 - float phyResY = vertSizePixel / (vertSizeMM / 25.4f); // = 102.40000 : 128.12611 | 600.95691 - - // ...and rescale the size of the meta rectangle. - float magicX = logResX / phyResX; // = 0.97440946 : 0.93750000 | 1.0002491 - float magicY = logResY / phyResY; // = 0.93750000 : 0.93657720 | 0.99840766 - - // use A4 page in point - // adjust size of A4 page so that meta file fits with DrawImage... - //GdiRectF rcMagic = new GdiRectF(0, 0, magicX * form.Width, magicY * form.Height); - //m_PreviewMetafile = new Metafile(hdc, rcMagic, MetafileFrameUnitPoint, - // EmfTypeEmfPlusOnly, L"some description"); -#endif - GdiRectF rect = new GdiRectF(0, 0, form.PixelWidth, form.PixelHeight); - Metafile = new Metafile(stream, hdc, rect, MetafileFrameUnit.Pixel); //, EmfType.EmfPlusOnly); - - // Petzold disposes the refgfx object, although the hdc is in use of the metafile - refgfx.ReleaseHdc(hdc); - } // refgfx.Dispose(); - - _gfx = Graphics.FromImage(Metafile); - _gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; - _drawGraphics = true; - } - else - { - Metafile = null; - _gfx = Graphics.FromHwnd(IntPtr.Zero); - } - if (form.Owner != null) - _renderer = new PdfSharpCore.Drawing.Pdf.XGraphicsPdfRenderer(form, this); - _pageSize = form.Size; - } - finally { Lock.ExitGdiPlus(); } - Initialize(); -#endif -#if WPF && !GDI - TargetContext = XGraphicTargetContext.WPF; -#if !SILVERLIGHT - // If form.Owner is null create a meta file. - if (form.Owner == null) - { - _dv = new DrawingVisual(); - _dc = _dv.RenderOpen(); - _drawGraphics = true; - } - else - { - _dv = new DrawingVisual(); - _dc = _dv.RenderOpen(); - } - if (form.Owner != null) - _renderer = new PdfSharpCore.Drawing.Pdf.XGraphicsPdfRenderer(form, this); - _pageSize = form.Size; - Initialize(); -#else - throw new NotImplementedException(); // AGHACK - //Initialize(); -#endif -#endif } /// @@ -634,36 +218,7 @@ public sealed class XGraphics : IDisposable /// public static XGraphics CreateMeasureContext(XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) { -#if CORE - //throw new InvalidOperationException("No measure context in CORE build."); - PdfDocument dummy = new PdfDocument(); - PdfPage page = dummy.AddPage(); - //XGraphics gfx = new XGraphics(((System.Drawing.Graphics)null, size, pageUnit, pageDirection); - XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append, pageUnit, pageDirection); - return gfx; -#endif -#if GDI && !WPF - //XGraphics gfx = new XGraphics((System.Drawing.Graphics)null, size, pageUnit, pageDirection); - XGraphics gfx = new XGraphics((System.Drawing.Graphics)null, size, pageUnit, pageDirection); - return gfx; -#endif -#if WPF && !SILVERLIGHT - XGraphics gfx = new XGraphics((System.Windows.Media.DrawingContext)null, size, pageUnit, pageDirection); - return gfx; -#endif -#if SILVERLIGHT - XGraphics gfx = new XGraphics(new Canvas(), size, pageUnit, pageDirection); - return gfx; -#endif -#if NETFX_CORE || UWP // NETFX_CORE_TODO - return null; -#endif -#if __IOS__ || __ANDROID__ // IOS_ANDROID_TODO - return null; -#endif -#if PORTABLE // IOS_ANDROID_TODO return new XGraphics(size, pageUnit, pageDirection); -#endif } public static XGraphics FromRenderer(IXGraphicsRenderer renderer, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection) @@ -671,64 +226,6 @@ public static XGraphics FromRenderer(IXGraphicsRenderer renderer, XSize size, XG return new XGraphics(renderer, size, pageUnit, pageDirection); } -#if GDI - /// - /// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. - /// - public static XGraphics FromGraphics(Graphics graphics, XSize size) - { - // Creating a new instance is by design. - return new XGraphics(graphics, size, XGraphicsUnit.Point, XPageDirection.Downwards); - } - - /// - /// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. - /// - public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit) - { - // Creating a new instance is by design. - return new XGraphics(graphics, size, unit, XPageDirection.Downwards); - } - - ///// - ///// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. - ///// - //public static XGraphics FromGraphics(Graphics graphics, XSize size, XPageDirection pageDirection) - //{ - // // Creating a new instance is by design. - // return new XGraphics(graphics, size, XGraphicsUnit.Point, pageDirection); - //} - - ///// - ///// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. - ///// - //public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit, XPageDirection pageDirection) - //{ - // // Creating a new instance is by design. - // return new XGraphics(graphics, size, XGraphicsUnit.Point, pageDirection); - //} -#endif - -#if WPF && !SILVERLIGHT - /// - /// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object. - /// - public static XGraphics FromDrawingContext(DrawingContext drawingContext, XSize size, XGraphicsUnit unit) - { - return new XGraphics(drawingContext, size, unit, XPageDirection.Downwards); - } -#endif - -#if WPF - /// - /// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object. - /// - public static XGraphics FromCanvas(Canvas canvas, XSize size, XGraphicsUnit unit) - { - return new XGraphics(canvas, size, unit, XPageDirection.Downwards); - } -#endif - /// /// Creates a new instance of the XGraphics class from a PdfSharpCore.Pdf.PdfPage object. /// @@ -826,22 +323,6 @@ public static XGraphics FromImage(XImage image, XGraphicsUnit unit) XBitmapImage bmImage = image as XBitmapImage; if (bmImage != null) { -#if CORE - return null; -#endif -#if GDI && !WPF - Graphics gfx = Graphics.FromImage(image._gdiImage); - image.XImageState = image.XImageState | XImageState.UsedInDrawingContext; - return new XGraphics(gfx, new XSize(image.PixelWidth, image.PixelHeight), unit, XPageDirection.Downwards); -#endif -#if WPF && !GDI - DiagnosticsHelper.ThrowNotImplementedException("WPF image"); - return null; -#endif -#if NETFX_CORE - DiagnosticsHelper.ThrowNotImplementedException("NETFX_CORE image"); - return null; -#endif } return null; } @@ -863,83 +344,6 @@ void Initialize() } XMatrix matrix = new XMatrix(); -#if CORE - // Nothing to do here. - Debug.Assert(TargetContext == XGraphicTargetContext.CORE); -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterFontFactory(); - if (_gfx != null) - matrix = _gfx.Transform; - - if (_pageUnit != XGraphicsUnit.Point) - { - switch (_pageUnit) - { - case XGraphicsUnit.Inch: - matrix.ScalePrepend(XUnit.InchFactor); - break; - - case XGraphicsUnit.Millimeter: - matrix.ScalePrepend(XUnit.MillimeterFactor); - break; - - case XGraphicsUnit.Centimeter: - matrix.ScalePrepend(XUnit.CentimeterFactor); - break; - - case XGraphicsUnit.Presentation: - matrix.ScalePrepend(XUnit.PresentationFactor); - break; - } - if (_gfx != null) - _gfx.Transform = (GdiMatrix)matrix; - } - } - finally { Lock.ExitFontFactory(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - if (_pageUnit != XGraphicsUnit.Presentation) - { - switch (_pageUnit) - { - case XGraphicsUnit.Point: - matrix.ScalePrepend(XUnit.PointFactorWpf); - break; - - case XGraphicsUnit.Inch: - matrix.ScalePrepend(XUnit.InchFactorWpf); - break; - - case XGraphicsUnit.Millimeter: - matrix.ScalePrepend(XUnit.MillimeterFactorWpf); - break; - - case XGraphicsUnit.Centimeter: - matrix.ScalePrepend(XUnit.CentimeterFactorWpf); - break; - } - if (!matrix.IsIdentity) - { -#if !SILVERLIGHT - MatrixTransform transform = new MatrixTransform((SysMatrix)matrix); - _dc.PushTransform(transform); -#else - MatrixTransform transform2 = new MatrixTransform(); - transform2.Matrix = (SysMatrix)matrix; - _dc.PushTransform(transform2); -#endif - } - } - } -#endif if (_pageDirection != XPageDirection.Downwards) matrix.Prepend(new XMatrix(1, 0, 0, -1, 0, pageHeight)); @@ -975,30 +379,7 @@ void Dispose(bool disposing) if (_form != null) _form.Finish(); -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - // GDI+ requires this to disassociate it from metafiles. - if (_gfx != null) - _gfx.Dispose(); - _gfx = null; - Metafile = null; - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (_dc != null) - { - _dc.Close(); -#if !SILVERLIGHT - _dv = null; -#endif - } -#endif + _drawGraphics = false; if (_renderer != null) @@ -1088,37 +469,6 @@ public XSize PageSize // ----- DrawLine ----------------------------------------------------------------------------- -#if GDI - /// - /// Draws a line connecting two Point structures. - /// - public void DrawLine(XPen pen, GdiPoint pt1, GdiPoint pt2) - { - // Because of overloading the cast is NOT redundant. - DrawLine(pen, (double)pt1.X, (double)pt1.Y, (double)pt2.X, (double)pt2.Y); - } -#endif - -#if WPF - /// - /// Draws a line connecting two Point structures. - /// - public void DrawLine(XPen pen, SysPoint pt1, SysPoint pt2) - { - DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y); - } -#endif - -#if GDI - /// - /// Draws a line connecting two GdiPointF structures. - /// - public void DrawLine(XPen pen, GdiPointF pt1, GdiPointF pt2) - { - DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y); - } -#endif - /// /// Draws a line connecting two XPoint structures. /// @@ -1135,56 +485,15 @@ public void DrawLine(XPen pen, double x1, double y1, double x2, double y2) if (pen == null) throw new ArgumentNullException("pen"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawLine(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawLine(pen.RealizeWpfPen(), new SysPoint(x1, y1), new SysPoint(x2, y2)); -#endif - } - if (_renderer != null) _renderer.DrawLines(pen, new XPoint[] { new XPoint(x1, y1), new XPoint(x2, y2) }); } // ----- DrawLines ---------------------------------------------------------------------------- - -#if GDI /// /// Draws a series of line segments that connect an array of points. /// - public void DrawLines(XPen pen, GdiPoint[] points) - { - DrawLines(pen, MakePointFArray(points, 0, points.Length)); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Draws a series of line segments that connect an array of points. - /// - public void DrawLines(XPen pen, SysPoint[] points) - { - DrawLines(pen, XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Draws a series of line segments that connect an array of points. - /// - public void DrawLines(XPen pen, GdiPointF[] points) + public void DrawLines(XPen pen, XPoint[] points) { if (pen == null) throw new ArgumentNullException("pen"); @@ -1193,83 +502,19 @@ public void DrawLines(XPen pen, GdiPointF[] points) if (points.Length < 2) throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); - if (_drawGraphics) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawLines(pen.RealizeGdiPen(), points); - } - finally { Lock.ExitGdiPlus(); } - } - if (_renderer != null) - _renderer.DrawLines(pen, MakeXPointArray(points, 0, points.Length)); + _renderer.DrawLines(pen, points); } -#endif /// - /// Draws a series of line segments that connect an array of points. + /// Draws a series of line segments that connect an array of x and y pairs. /// - public void DrawLines(XPen pen, XPoint[] points) + public void DrawLines(XPen pen, double x, double y, params double[] value) { if (pen == null) throw new ArgumentNullException("pen"); - if (points == null) - throw new ArgumentNullException("points"); - if (points.Length < 2) - throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawLines(pen.RealizeGdiPen(), XGraphics.MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { -#if !SILVERLIGHT - PolyLineSegment seg = new PolyLineSegment(XGraphics.MakePointArray(points), true); -#else - Point[] pts = XGraphics.MakePointArray(points); - PointCollection collection = new PointCollection(); - foreach (Point point in pts) - collection.Add(point); - PolyLineSegment seg = new PolyLineSegment(); - seg.Points = collection; -#endif - PathFigure figure = new PathFigure(); - figure.IsFilled = false; - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - figure.Segments.Add(seg); - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(null, pen.RealizeWpfPen(), geo); - } -#endif - } - - if (_renderer != null) - _renderer.DrawLines(pen, points); - } - - /// - /// Draws a series of line segments that connect an array of x and y pairs. - /// - public void DrawLines(XPen pen, double x, double y, params double[] value) - { - if (pen == null) - throw new ArgumentNullException("pen"); - if (value == null) - throw new ArgumentNullException("value"); + if (value == null) + throw new ArgumentNullException("value"); int length = value.Length; XPoint[] points = new XPoint[length / 2 + 1]; @@ -1284,40 +529,6 @@ public void DrawLines(XPen pen, double x, double y, params double[] value) } // ----- DrawBezier --------------------------------------------------------------------------- - -#if GDI - /// - /// Draws a Bzier spline defined by four points. - /// - public void DrawBezier(XPen pen, GdiPoint pt1, GdiPoint pt2, GdiPoint pt3, GdiPoint pt4) - { - // ReSharper disable RedundantCast because it is required - DrawBezier(pen, (double)pt1.X, (double)pt1.Y, (double)pt2.X, (double)pt2.Y, - (double)pt3.X, (double)pt3.Y, (double)pt4.X, (double)pt4.Y); - // ReSharper restore RedundantCast - } -#endif - -#if WPF - /// - /// Draws a Bzier spline defined by four points. - /// - public void DrawBezier(XPen pen, SysPoint pt1, SysPoint pt2, SysPoint pt3, SysPoint pt4) - { - DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); - } -#endif - -#if GDI - /// - /// Draws a Bzier spline defined by four points. - /// - public void DrawBezier(XPen pen, GdiPointF pt1, GdiPointF pt2, GdiPointF pt3, GdiPointF pt4) - { - DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); - } -#endif - /// /// Draws a Bzier spline defined by four points. /// @@ -1335,40 +546,6 @@ public void DrawBezier(XPen pen, double x1, double y1, double x2, double y2, if (pen == null) throw new ArgumentNullException("pen"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawBezier(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3, (float)x4, (float)y4); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { -#if !SILVERLIGHT - BezierSegment seg = new BezierSegment(new SysPoint(x2, y2), new SysPoint(x3, y3), new SysPoint(x4, y4), true); -#else - BezierSegment seg = new BezierSegment(); - seg.Point1 = new SysPoint(x2, y2); - seg.Point2 = new SysPoint(x3, y3); - seg.Point3 = new SysPoint(x4, y4); -#endif - PathFigure figure = new PathFigure(); - figure.StartPoint = new SysPoint(x1, y1); - figure.Segments.Add(seg); - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(null, pen.RealizeWpfPen(), geo); - } -#endif - } - if (_renderer != null) _renderer.DrawBeziers(pen, new XPoint[] { new XPoint(x1, y1), new XPoint(x2, y2), new XPoint(x3, y3), new XPoint(x4, y4) }); @@ -1376,36 +553,6 @@ public void DrawBezier(XPen pen, double x1, double y1, double x2, double y2, // ----- DrawBeziers -------------------------------------------------------------------------- -#if GDI - /// - /// Draws a series of Bzier splines from an array of points. - /// - public void DrawBeziers(XPen pen, GdiPoint[] points) - { - DrawBeziers(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if WPF - /// - /// Draws a series of Bzier splines from an array of points. - /// - public void DrawBeziers(XPen pen, SysPoint[] points) - { - DrawBeziers(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Draws a series of Bzier splines from an array of points. - /// - public void DrawBeziers(XPen pen, GdiPointF[] points) - { - DrawBeziers(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - /// /// Draws a series of Bzier splines from an array of points. /// @@ -1421,99 +568,12 @@ public void DrawBeziers(XPen pen, XPoint[] points) if ((count - 1) % 3 != 0) throw new ArgumentException("Invalid number of points for bezier curves. Number must fulfil 4+3n.", "points"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawBeziers(pen.RealizeGdiPen(), MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - PathFigure figure = new PathFigure(); - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - for (int idx = 1; idx < count; idx += 3) - { -#if !SILVERLIGHT - BezierSegment seg = new BezierSegment( - new SysPoint(points[idx].X, points[idx].Y), - new SysPoint(points[idx + 1].X, points[idx + 1].Y), - new SysPoint(points[idx + 2].X, points[idx + 2].Y), true); -#else - BezierSegment seg = new BezierSegment(); - seg.Point1 = new SysPoint(points[idx].X, points[idx].Y); - seg.Point2 = new SysPoint(points[idx + 1].X, points[idx + 1].Y); - seg.Point3 = new SysPoint(points[idx + 2].X, points[idx + 2].Y); -#endif - figure.Segments.Add(seg); - } - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(null, pen.RealizeWpfPen(), geo); - } -#endif - } - if (_renderer != null) _renderer.DrawBeziers(pen, points); } // ----- DrawCurve ---------------------------------------------------------------------------- -#if GDI - /// - /// Draws a cardinal spline through a specified array of points. - /// - public void DrawCurve(XPen pen, GdiPoint[] points) - { - DrawCurve(pen, MakePointFArray(points, 0, points.Length), 0.5); - } - - /// - /// Draws a cardinal spline through a specified array of point using a specified tension. - /// The drawing begins offset from the beginning of the array. - /// - public void DrawCurve(XPen pen, GdiPoint[] points, int offset, int numberOfSegments, double tension) - { - DrawCurve(pen, MakePointFArray(points, offset, numberOfSegments), tension); - } -#endif - -#if WPF - /// - /// Draws a cardinal spline through a specified array of points. - /// - public void DrawCurve(XPen pen, SysPoint[] points) - { - DrawCurve(pen, MakeXPointArray(points, 0, points.Length), 0.5); - } - - /// - /// Draws a cardinal spline through a specified array of point. The drawing begins offset from the beginning of the array. - /// - public void DrawCurve(XPen pen, SysPoint[] points, int offset, int numberOfSegments) - { - DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), 0.5); - } -#endif - -#if GDI - /// - /// Draws a cardinal spline through a specified array of points. - /// - public void DrawCurve(XPen pen, GdiPointF[] points) - { - DrawCurve(pen, MakeXPointArray(points, 0, points.Length), 0.5); - } -#endif - /// /// Draws a cardinal spline through a specified array of points. /// @@ -1522,62 +582,6 @@ public void DrawCurve(XPen pen, XPoint[] points) DrawCurve(pen, points, 0.5); } -#if GDI - /// - /// Draws a cardinal spline through a specified array of points using a specified tension. - /// - public void DrawCurve(XPen pen, GdiPoint[] points, double tension) - { - DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension); - } -#endif - -#if WPF - /// - /// Draws a cardinal spline through a specified array of points using a specified tension. - /// - public void DrawCurve(XPen pen, SysPoint[] points, double tension) - { - DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension); - } - - /// - /// Draws a cardinal spline through a specified array of point using a specified tension. - /// The drawing begins offset from the beginning of the array. - /// - public void DrawCurve(XPen pen, SysPoint[] points, int offset, int numberOfSegments, double tension) - { - DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), tension); - } -#endif - -#if GDI - /// - /// Draws a cardinal spline through a specified array of points using a specified tension. - /// - public void DrawCurve(XPen pen, GdiPointF[] points, double tension) - { - DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension); - } - - /// - /// Draws a cardinal spline through a specified array of point. The drawing begins offset from the beginning of the array. - /// - public void DrawCurve(XPen pen, GdiPointF[] points, int offset, int numberOfSegments) - { - DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), 0.5); - } - - /// - /// Draws a cardinal spline through a specified array of point using a specified tension. - /// The drawing begins offset from the beginning of the array. - /// - public void DrawCurve(XPen pen, GdiPointF[] points, int offset, int numberOfSegments, double tension) - { - DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), tension); - } -#endif - /// /// Draws a cardinal spline through a specified array of point using a specified tension. /// The drawing begins offset from the beginning of the array. @@ -1603,71 +607,12 @@ public void DrawCurve(XPen pen, XPoint[] points, double tension) if (count < 2) throw new ArgumentException("DrawCurve requires two or more points.", "points"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawCurve(pen.RealizeGdiPen(), MakePointFArray(points), (float)tension); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - tension /= 3; - - PathFigure figure = new PathFigure(); - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - if (count == 2) - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension)); - } - else - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[2], tension)); - for (int idx = 1; idx < count - 2; idx++) - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[count - 1], tension)); - } - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(null, pen.RealizeWpfPen(), geo); - } -#endif - } - if (_renderer != null) _renderer.DrawCurve(pen, points, tension); } // ----- DrawArc ------------------------------------------------------------------------------ -#if GDI - /// - /// Draws an arc representing a portion of an ellipse. - /// - public void DrawArc(XPen pen, Rectangle rect, double startAngle, double sweepAngle) - { - // Because of overloading the cast is NOT redundant. - DrawArc(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle); - } -#endif - -#if GDI - /// - /// Draws an arc representing a portion of an ellipse. - /// - public void DrawArc(XPen pen, GdiRectF rect, double startAngle, double sweepAngle) - { - DrawArc(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - /// /// Draws an arc representing a portion of an ellipse. /// @@ -1690,34 +635,6 @@ public void DrawArc(XPen pen, double x, double y, double width, double height, d } else { - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - SysPoint startPoint; - ArcSegment seg = GeometryHelper.CreateArcSegment(x, y, width, height, startAngle, sweepAngle, out startPoint); - PathFigure figure = new PathFigure(); - figure.StartPoint = startPoint; - figure.Segments.Add(seg); - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(null, pen.RealizeWpfPen(), geo); - } -#endif - } - if (_renderer != null) _renderer.DrawArc(pen, x, y, width, height, startAngle, sweepAngle); } @@ -1727,27 +644,6 @@ public void DrawArc(XPen pen, double x, double y, double width, double height, d // ----- stroke ----- -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XPen pen, Rectangle rect) - { - // Because of overloading the cast is NOT redundant. - DrawRectangle(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XPen pen, GdiRectF rect) - { - DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Draws a rectangle. /// @@ -1766,29 +662,7 @@ public void DrawRectangle(XPen pen, double x, double y, double width, double hei if (_drawGraphics) { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - _dc.DrawRectangle(null, pen.RealizeWpfPen(), new Rect(x, y, width, height)); - } -#endif -#if UWP - if (TargetContext == XGraphicTargetContext.UWP) - { - _cds.DrawRectangle((float)x, (float)y, (float)width, (float)height, pen.Color.ToUwpColor()); - } -#endif + } if (_renderer != null) @@ -1797,27 +671,6 @@ public void DrawRectangle(XPen pen, double x, double y, double width, double hei // ----- fill ----- -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XBrush brush, Rectangle rect) - { - // Because of overloading the cast is NOT redundant. - DrawRectangle(brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XBrush brush, GdiRectF rect) - { - DrawRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Draws a rectangle. /// @@ -1834,57 +687,12 @@ public void DrawRectangle(XBrush brush, double x, double y, double width, double if (brush == null) throw new ArgumentNullException("brush"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawRectangle(brush.RealizeWpfBrush(), null, new Rect(x, y, width, height)); -#endif -#if UWP - if (TargetContext == XGraphicTargetContext.UWP) - { - _cds.DrawRectangle((float)x, (float)y, (float)width, (float)height, brush.RealizeCanvasBrush()); - } -#endif - } - if (_renderer != null) _renderer.DrawRectangle(null, brush, x, y, width, height); } // ----- stroke and fill ----- -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XPen pen, XBrush brush, Rectangle rect) - { - // Because of overloading the cast is NOT redundant. - DrawRectangle(pen, brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangle. - /// - public void DrawRectangle(XPen pen, XBrush brush, GdiRectF rect) - { - DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif /// /// Draws a rectangle. @@ -1902,31 +710,6 @@ public void DrawRectangle(XPen pen, XBrush brush, double x, double y, double wid if (pen == null && brush == null) throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); - if (pen != null) - _gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawRectangle( - brush != null ? brush.RealizeWpfBrush() : null, - pen != null ? pen.RealizeWpfPen() : null, - new Rect(x, y, width, height)); -#endif - } - if (_renderer != null) _renderer.DrawRectangle(pen, brush, x, y, width, height); } @@ -1935,11 +718,10 @@ public void DrawRectangle(XPen pen, XBrush brush, double x, double y, double wid // ----- stroke ----- -#if GDI /// /// Draws a series of rectangles. /// - public void DrawRectangles(XPen pen, GdiRect[] rectangles) + public void DrawRectangles(XPen pen, XRect[] rectangles) { if (pen == null) throw new ArgumentNullException("pen"); @@ -1948,72 +730,13 @@ public void DrawRectangles(XPen pen, GdiRect[] rectangles) DrawRectangles(pen, null, rectangles); } -#endif -#if GDI + // ----- fill ----- + /// /// Draws a series of rectangles. /// - public void DrawRectangles(XPen pen, GdiRectF[] rectangles) - { - if (pen == null) - throw new ArgumentNullException("pen"); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - DrawRectangles(pen, null, rectangles); - } -#endif - - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XPen pen, XRect[] rectangles) - { - if (pen == null) - throw new ArgumentNullException("pen"); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - DrawRectangles(pen, null, rectangles); - } - - // ----- fill ----- - -#if GDI - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XBrush brush, GdiRect[] rectangles) - { - if (brush == null) - throw new ArgumentNullException("brush"); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - DrawRectangles(null, brush, rectangles); - } -#endif - -#if GDI - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XBrush brush, GdiRectF[] rectangles) - { - if (brush == null) - throw new ArgumentNullException("brush"); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - DrawRectangles(null, brush, rectangles); - } -#endif - - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XBrush brush, XRect[] rectangles) + public void DrawRectangles(XBrush brush, XRect[] rectangles) { if (brush == null) throw new ArgumentNullException("brush"); @@ -2025,76 +748,6 @@ public void DrawRectangles(XBrush brush, XRect[] rectangles) // ----- stroke and fill ----- -#if GDI - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XPen pen, XBrush brush, Rectangle[] rectangles) - { - if (pen == null && brush == null) - throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - if (_drawGraphics) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles); - if (pen != null) - _gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles); - } - finally { Lock.ExitGdiPlus(); } - } - if (_renderer != null) - { - int count = rectangles.Length; - for (int idx = 0; idx < count; idx++) - { - Rectangle rect = rectangles[idx]; - _renderer.DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height); - } - } - } -#endif - -#if GDI - /// - /// Draws a series of rectangles. - /// - public void DrawRectangles(XPen pen, XBrush brush, GdiRectF[] rectangles) - { - if (pen == null && brush == null) - throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (rectangles == null) - throw new ArgumentNullException("rectangles"); - - if (_drawGraphics) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles); - if (pen != null) - _gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles); - } - finally { Lock.ExitGdiPlus(); } - } - if (_renderer != null) - { - int count = rectangles.Length; - for (int idx = 0; idx < count; idx++) - { - GdiRectF rect = rectangles[idx]; - _renderer.DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height); - } - } - } -#endif - /// /// Draws a series of rectangles. /// @@ -2106,36 +759,6 @@ public void DrawRectangles(XPen pen, XBrush brush, XRect[] rectangles) throw new ArgumentNullException("rectangles"); int count = rectangles.Length; - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - GdiRectF[] rects = MakeRectangleFArray(rectangles, 0, rectangles.Length); - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillRectangles(brush.RealizeGdiBrush(), rects); - if (pen != null) - _gfx.DrawRectangles(pen.RealizeGdiPen(), rects); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null; - WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null; - for (int idx = 0; idx < count; idx++) - { - XRect rect = rectangles[idx]; - _dc.DrawRectangle(wpfBrush, wpfPen, new SysRect(new SysPoint(rect.X, rect.Y), new SysSize(rect.Width, rect.Height))); - } - } -#endif - } if (_renderer != null) { @@ -2151,36 +774,6 @@ public void DrawRectangles(XPen pen, XBrush brush, XRect[] rectangles) // ----- stroke ----- -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, Rectangle rect, GdiSize ellipseSize) - { - DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if WPF - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, Rect rect, SysSize ellipseSize) - { - DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, GdiRectF rect, SizeF ellipseSize) - { - DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - /// /// Draws a rectangles with round corners. /// @@ -2202,36 +795,6 @@ public void DrawRoundedRectangle(XPen pen, double x, double y, double width, dou // ----- fill ----- -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XBrush brush, Rectangle rect, GdiSize ellipseSize) - { - DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if WPF - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XBrush brush, Rect rect, SysSize ellipseSize) - { - DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XBrush brush, GdiRectF rect, SizeF ellipseSize) - { - DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - /// /// Draws a rectangles with round corners. /// @@ -2253,39 +816,6 @@ public void DrawRoundedRectangle(XBrush brush, double x, double y, double width, // ----- stroke and fill ----- -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, XBrush brush, Rectangle rect, GdiSize ellipseSize) - { - // ReSharper disable RedundantCast because it is required - DrawRoundedRectangle(pen, brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, - (double)ellipseSize.Width, (double)ellipseSize.Height); - // ReSharper restore RedundantCast - } -#endif - -#if WPF - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, XBrush brush, Rect rect, SysSize ellipseSize) - { - DrawRoundedRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if GDI - /// - /// Draws a rectangles with round corners. - /// - public void DrawRoundedRectangle(XPen pen, XBrush brush, GdiRectF rect, SizeF ellipseSize) - { - DrawRoundedRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - /// /// Draws a rectangles with round corners. /// @@ -2303,32 +833,6 @@ public void DrawRoundedRectangle(XPen pen, XBrush brush, double x, double y, dou if (pen == null && brush == null) throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - XGraphicsPath path = new XGraphicsPath(); - path.AddRoundedRectangle(x, y, width, height, ellipseWidth, ellipseHeight); - DrawPath(pen, brush, path); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - _dc.DrawRoundedRectangle( - brush != null ? brush.RealizeWpfBrush() : null, - pen != null ? pen.RealizeWpfPen() : null, - new Rect(x, y, width, height), ellipseWidth / 2, ellipseHeight / 2); - } -#endif - } - if (_renderer != null) _renderer.DrawRoundedRectangle(pen, brush, x, y, width, height, ellipseWidth, ellipseHeight); } @@ -2337,26 +841,6 @@ public void DrawRoundedRectangle(XPen pen, XBrush brush, double x, double y, dou // ----- stroke ----- -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XPen pen, Rectangle rect) - { - DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XPen pen, GdiRectF rect) - { - DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Draws an ellipse defined by a bounding rectangle. /// @@ -2376,25 +860,7 @@ public void DrawEllipse(XPen pen, double x, double y, double width, double heigh // No DrawArc defined? if (_drawGraphics) { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - double radiusX = width / 2; - double radiusY = height / 2; - _dc.DrawEllipse(null, pen.RealizeWpfPen(), new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY); - } -#endif + } if (_renderer != null) @@ -2403,26 +869,6 @@ public void DrawEllipse(XPen pen, double x, double y, double width, double heigh // ----- fill ----- -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XBrush brush, Rectangle rect) - { - DrawEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XBrush brush, GdiRectF rect) - { - DrawEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Draws an ellipse defined by a bounding rectangle. /// @@ -2441,25 +887,7 @@ public void DrawEllipse(XBrush brush, double x, double y, double width, double h if (_drawGraphics) { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - double radiusX = width / 2; - double radiusY = height / 2; - _dc.DrawEllipse(brush.RealizeWpfBrush(), null, new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY); - } -#endif + } if (_renderer != null) @@ -2468,26 +896,6 @@ public void DrawEllipse(XBrush brush, double x, double y, double width, double h // ----- stroke and fill ----- -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XPen pen, XBrush brush, Rectangle rect) - { - DrawEllipse(pen, brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - -#if GDI - /// - /// Draws an ellipse defined by a bounding rectangle. - /// - public void DrawEllipse(XPen pen, XBrush brush, GdiRectF rect) - { - DrawEllipse(pen, brush, rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Draws an ellipse defined by a bounding rectangle. /// @@ -2504,105 +912,21 @@ public void DrawEllipse(XPen pen, XBrush brush, double x, double y, double width if (pen == null && brush == null) throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); - if (pen != null) - _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - double radiusX = width / 2; - double radiusY = height / 2; - _dc.DrawEllipse( - brush != null ? brush.RealizeWpfBrush() : null, - pen != null ? pen.RealizeWpfPen() : null, - new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY); - } -#endif - } - if (_renderer != null) _renderer.DrawEllipse(pen, brush, x, y, width, height); } - // ----- DrawPolygon -------------------------------------------------------------------------- - - // ----- stroke ----- - -#if GDI /// /// Draws a polygon defined by an array of points. /// - public void DrawPolygon(XPen pen, GdiPoint[] points) + public void DrawPolygon(XPen pen, XPoint[] points) { - DrawPolygon(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if WPF - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, SysPoint[] points) - { - DrawPolygon(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, GdiPointF[] points) - { - DrawPolygon(pen, MakeXPointArray(points, 0, points.Length)); - } -#endif - - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, XPoint[] points) - { - if (pen == null) - throw new ArgumentNullException("pen"); - if (points == null) - throw new ArgumentNullException("points"); - if (points.Length < 2) - throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawPolygon(pen.RealizeGdiPen(), MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - _dc.DrawGeometry(null, pen.RealizeWpfPen(), GeometryHelper.CreatePolygonGeometry(MakePointArray(points), XFillMode.Alternate, true)); - } -#endif - } + if (pen == null) + throw new ArgumentNullException("pen"); + if (points == null) + throw new ArgumentNullException("points"); + if (points.Length < 2) + throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); if (_renderer != null) _renderer.DrawPolygon(pen, null, points, XFillMode.Alternate); // XFillMode is ignored @@ -2610,36 +934,6 @@ public void DrawPolygon(XPen pen, XPoint[] points) // ----- fill ----- -#if GDI - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XBrush brush, GdiPoint[] points, XFillMode fillmode) - { - DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - -#if WPF - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XBrush brush, SysPoint[] points, XFillMode fillmode) - { - DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - -#if GDI - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XBrush brush, GdiPointF[] points, XFillMode fillmode) - { - DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - /// /// Draws a polygon defined by an array of points. /// @@ -2652,617 +946,161 @@ public void DrawPolygon(XBrush brush, XPoint[] points, XFillMode fillmode) if (points.Length < 2) throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.FillPolygon(brush.RealizeGdiBrush(), MakePointFArray(points), (FillMode)fillmode); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawGeometry(brush.RealizeWpfBrush(), null, GeometryHelper.CreatePolygonGeometry(MakePointArray(points), fillmode, true)); -#endif - } - if (_renderer != null) _renderer.DrawPolygon(null, brush, points, fillmode); } - // ----- stroke and fill ----- - -#if GDI - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode) - { - DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - -#if WPF - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode) - { - DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - -#if GDI - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode) - { - DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode); - } -#endif - - /// - /// Draws a polygon defined by an array of points. - /// - public void DrawPolygon(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode) - { - if (pen == null && brush == null) - throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); - if (points == null) - throw new ArgumentNullException("points"); - if (points.Length < 2) - throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - GdiPointF[] pts = MakePointFArray(points); - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillPolygon(brush.RealizeGdiBrush(), pts, (FillMode)fillmode); - if (pen != null) - _gfx.DrawPolygon(pen.RealizeGdiPen(), pts); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null; - WpfPen wpfPen = brush != null ? pen.RealizeWpfPen() : null; - _dc.DrawGeometry(wpfBrush, wpfPen, GeometryHelper.CreatePolygonGeometry(MakePointArray(points), fillmode, true)); - } -#endif - } - - if (_renderer != null) - _renderer.DrawPolygon(pen, brush, points, fillmode); - } - - // ----- DrawPie ------------------------------------------------------------------------------ - - // ----- stroke ----- - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, Rectangle rect, double startAngle, double sweepAngle) - { - // ReSharper disable RedundantCast because it is required - DrawPie(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle); - // ReSharper restore RedundantCast - } -#endif - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, GdiRectF rect, double startAngle, double sweepAngle) - { - DrawPie(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, XRect rect, double startAngle, double sweepAngle) - { - DrawPie(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, double x, double y, double width, double height, double startAngle, double sweepAngle) - { - if (pen == null) - throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - DrawPie(pen, null, x, y, width, height, startAngle, sweepAngle); -#endif - } - - if (_renderer != null) - _renderer.DrawPie(pen, null, x, y, width, height, startAngle, sweepAngle); - } - - // ----- fill ----- - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XBrush brush, Rectangle rect, double startAngle, double sweepAngle) - { - // Because of overloading the cast is NOT redundant. - DrawPie(brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle); - } -#endif - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XBrush brush, GdiRectF rect, double startAngle, double sweepAngle) - { - DrawPie(brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XBrush brush, XRect rect, double startAngle, double sweepAngle) - { - DrawPie(brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle) - { - if (brush == null) - throw new ArgumentNullException("brush", PSSR.NeedPenOrBrush); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - DrawPie(null, brush, x, y, width, height, startAngle, sweepAngle); -#endif - } - - if (_renderer != null) - _renderer.DrawPie(null, brush, x, y, width, height, startAngle, sweepAngle); - } - - // ----- stroke and fill ----- - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, XBrush brush, Rectangle rect, double startAngle, double sweepAngle) - { - DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - -#if GDI - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, XBrush brush, GdiRectF rect, double startAngle, double sweepAngle) - { - DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, XBrush brush, XRect rect, double startAngle, double sweepAngle) - { - DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } - - /// - /// Draws a pie defined by an ellipse. - /// - public void DrawPie(XPen pen, XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle) - { - if (pen == null && brush == null) - throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush); - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - if (pen != null) - _gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null; - WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null; - SysPoint center = new SysPoint(x + width / 2, y + height / 2); - SysPoint startArc; - ArcSegment arc = GeometryHelper.CreateArcSegment(x, y, width, height, startAngle, sweepAngle, out startArc); - PathFigure figure = new PathFigure(); - figure.StartPoint = center; -#if !SILVERLIGHT - LineSegment seg = new LineSegment(startArc, true); -#else - LineSegment seg = new LineSegment { Point = startArc }; -#endif - figure.Segments.Add(seg); - figure.Segments.Add(arc); - figure.IsClosed = true; - PathGeometry geo = new PathGeometry(); - geo.Figures.Add(figure); - _dc.DrawGeometry(wpfBrush, wpfPen, geo); - } -#endif - } - - if (_renderer != null) - _renderer.DrawPie(pen, brush, x, y, width, height, startAngle, sweepAngle); - } - - // ----- DrawClosedCurve ---------------------------------------------------------------------- - - // ----- stroke ----- - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, GdiPoint[] points) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - -#if WPF - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, SysPoint[] points) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, GdiPointF[] points) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, XPoint[] points) - { - DrawClosedCurve(pen, null, points, XFillMode.Alternate, 0.5); - } - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, GdiPoint[] points, double tension) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension); - } -#endif - -#if WPF - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, SysPoint[] points, double tension) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension); - } -#endif - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, GdiPointF[] points, double tension) - { - DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension); - } -#endif - - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XPen pen, XPoint[] points, double tension) - { - DrawClosedCurve(pen, null, points, XFillMode.Alternate, tension); - } - - // ----- fill ----- - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, GdiPoint[] points) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - -#if WPF - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, SysPoint[] points) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, GdiPointF[] points) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); - } -#endif - - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, XPoint[] points) - { - DrawClosedCurve(null, brush, points, XFillMode.Alternate, 0.5); - } - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, GdiPoint[] points, XFillMode fillmode) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); - } -#endif - -#if WPF - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, SysPoint[] points, XFillMode fillmode) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); - } -#endif - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, GdiPointF[] points, XFillMode fillmode) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); - } -#endif - - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode) - { - DrawClosedCurve(null, brush, points, fillmode, 0.5); - } - -#if GDI - /// - /// Draws a closed cardinal spline defined by an array of points. - /// - public void DrawClosedCurve(XBrush brush, GdiPoint[] points, XFillMode fillmode, double tension) - { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); - } -#endif + // ----- stroke and fill ----- -#if WPF /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a polygon defined by an array of points. /// - public void DrawClosedCurve(XBrush brush, SysPoint[] points, XFillMode fillmode, double tension) + public void DrawPolygon(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode) { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); + if (pen == null && brush == null) + throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush); + if (points == null) + throw new ArgumentNullException("points"); + if (points.Length < 2) + throw new ArgumentException("points", PSSR.PointArrayAtLeast(2)); + + if (_renderer != null) + _renderer.DrawPolygon(pen, brush, points, fillmode); } -#endif -#if GDI + // ----- DrawPie ------------------------------------------------------------------------------ + + // ----- stroke ----- + + /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XBrush brush, GdiPointF[] points, XFillMode fillmode, double tension) + public void DrawPie(XPen pen, XRect rect, double startAngle, double sweepAngle) { - DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); + DrawPie(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); } -#endif /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode, double tension) + public void DrawPie(XPen pen, double x, double y, double width, double height, double startAngle, double sweepAngle) { - DrawClosedCurve(null, brush, points, fillmode, tension); + if (pen == null) + throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush); + + if (_renderer != null) + _renderer.DrawPie(pen, null, x, y, width, height, startAngle, sweepAngle); } - // ----- stroke and fill ----- + // ----- fill ----- -#if GDI /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points) + public void DrawPie(XBrush brush, XRect rect, double startAngle, double sweepAngle) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); + DrawPie(brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); } -#endif -#if WPF /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points) + public void DrawPie(XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); + if (brush == null) + throw new ArgumentNullException("brush", PSSR.NeedPenOrBrush); + + if (_renderer != null) + _renderer.DrawPie(null, brush, x, y, width, height, startAngle, sweepAngle); } -#endif -#if GDI + // ----- stroke and fill ----- + /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points) + public void DrawPie(XPen pen, XBrush brush, XRect rect, double startAngle, double sweepAngle) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5); + DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); } -#endif /// - /// Draws a closed cardinal spline defined by an array of points. + /// Draws a pie defined by an ellipse. /// - public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points) + public void DrawPie(XPen pen, XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle) { - DrawClosedCurve(pen, brush, points, XFillMode.Alternate, 0.5); + if (pen == null && brush == null) + throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush); + + if (_renderer != null) + _renderer.DrawPie(pen, brush, x, y, width, height, startAngle, sweepAngle); } -#if GDI + // ----- DrawClosedCurve ---------------------------------------------------------------------- + + // ----- stroke ----- + /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode) + public void DrawClosedCurve(XPen pen, XPoint[] points) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); + DrawClosedCurve(pen, null, points, XFillMode.Alternate, 0.5); } -#endif -#if WPF + /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode) + public void DrawClosedCurve(XPen pen, XPoint[] points, double tension) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); + DrawClosedCurve(pen, null, points, XFillMode.Alternate, tension); } -#endif -#if GDI + // ----- fill ----- + /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode) + public void DrawClosedCurve(XBrush brush, XPoint[] points) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5); + DrawClosedCurve(null, brush, points, XFillMode.Alternate, 0.5); } -#endif /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode) + public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode) { - DrawClosedCurve(pen, brush, points, fillmode, 0.5); + DrawClosedCurve(null, brush, points, fillmode, 0.5); } -#if GDI /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode, double tension) + public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode, double tension) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); + DrawClosedCurve(null, brush, points, fillmode, tension); } -#endif -#if WPF + // ----- stroke and fill ----- + /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode, double tension) + public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); + DrawClosedCurve(pen, brush, points, XFillMode.Alternate, 0.5); } -#endif -#if GDI /// /// Draws a closed cardinal spline defined by an array of points. /// - public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode, double tension) + public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode) { - DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension); + DrawClosedCurve(pen, brush, points, fillmode, 0.5); } -#endif /// /// Draws a closed cardinal spline defined by an array of points. @@ -3281,55 +1119,6 @@ public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points, XFillMode f if (count < 2) throw new ArgumentException("Not enough points.", "points"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillClosedCurve(brush.RealizeGdiBrush(), MakePointFArray(points), (FillMode)fillmode, (float)tension); - if (pen != null) - { - // The fillmode is not used by DrawClosedCurve. - _gfx.DrawClosedCurve(pen.RealizeGdiPen(), MakePointFArray(points), (float)tension, (FillMode)fillmode); - } - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - tension /= 3; // Simply tried out. Not proofed why it is correct. - - PathFigure figure = new PathFigure(); - figure.IsClosed = true; - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - if (count == 2) - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension)); - } - else - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 1], points[0], points[1], points[2], tension)); - for (int idx = 1; idx < count - 2; idx++) - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[0], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 2], points[count - 1], points[0], points[1], tension)); - } - PathGeometry geo = new PathGeometry(); - geo.FillRule = fillmode == XFillMode.Alternate ? FillRule.EvenOdd : FillRule.Nonzero; - geo.Figures.Add(figure); - WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null; - WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null; - _dc.DrawGeometry(wpfBrush, wpfPen, geo); - } -#endif - } - if (_renderer != null) _renderer.DrawClosedCurve(pen, brush, points, tension, fillmode); } @@ -3348,25 +1137,6 @@ public void DrawPath(XPen pen, XGraphicsPath path) if (path == null) throw new ArgumentNullException("path"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.DrawPath(pen.RealizeGdiPen(), path._gdipPath); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawGeometry(null, pen.RealizeWpfPen(), path._pathGeometry); -#endif - } - if (_renderer != null) _renderer.DrawPath(pen, null, path); } @@ -3383,19 +1153,6 @@ public void DrawPath(XBrush brush, XGraphicsPath path) if (path == null) throw new ArgumentNullException("path"); - if (_drawGraphics) - { -#if GDI - // $TODO THHO Lock??? - if (TargetContext == XGraphicTargetContext.GDI) - _gfx.FillPath(brush.RealizeGdiBrush(), path._gdipPath); -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - _dc.DrawGeometry(brush.RealizeWpfBrush(), null, path._pathGeometry); -#endif - } - if (_renderer != null) _renderer.DrawPath(null, brush, path); } @@ -3415,48 +1172,12 @@ public void DrawPath(XPen pen, XBrush brush, XGraphicsPath path) if (path == null) throw new ArgumentNullException("path"); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (brush != null) - _gfx.FillPath(brush.RealizeGdiBrush(), path._gdipPath); - if (pen != null) - _gfx.DrawPath(pen.RealizeGdiPen(), path._gdipPath); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null; - WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null; - _dc.DrawGeometry(wpfBrush, wpfPen, path._pathGeometry); - } -#endif - } - if (_renderer != null) _renderer.DrawPath(pen, brush, path); } // ----- DrawString --------------------------------------------------------------------------- -#if GDI - /// - /// Draws the specified text string. - /// - public void DrawString(string s, XFont font, XBrush brush, GdiPointF point) - { - DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), XStringFormats.Default); - } -#endif - /// /// Draws the specified text string. /// @@ -3465,15 +1186,6 @@ public void DrawString(string s, XFont font, XBrush brush, XPoint point) DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), XStringFormats.Default); } -#if GDI - /// - /// Draws the specified text string. - /// - public void DrawString(string s, XFont font, XBrush brush, GdiPointF point, XStringFormat format) - { - DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), format); - } -#endif /// /// Draws the specified text string. @@ -3499,15 +1211,6 @@ public void DrawString(string s, XFont font, XBrush brush, double x, double y, X DrawString(s, font, brush, new XRect(x, y, 0, 0), format); } -#if GDI - /// - /// Draws the specified text string. - /// - public void DrawString(string s, XFont font, XBrush brush, GdiRectF layoutRectangle) - { - DrawString(s, font, brush, new XRect(layoutRectangle), XStringFormats.Default); - } -#endif /// /// Draws the specified text string. @@ -3517,16 +1220,6 @@ public void DrawString(string s, XFont font, XBrush brush, XRect layoutRectangle DrawString(s, font, brush, layoutRectangle, XStringFormats.Default); } -#if GDI - /// - /// Draws the specified text string. - /// - public void DrawString(string s, XFont font, XBrush brush, GdiRectF layoutRectangle, XStringFormat format) - { - DrawString(s, font, brush, new XRect(layoutRectangle), format); - } -#endif - /// /// Draws the specified text string. /// @@ -3548,152 +1241,6 @@ public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectan if (format == null) format = XStringFormats.Default; - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - // Was font created with font resolver? - if (font.GdiFont == null) - throw new InvalidOperationException("This font cannot be used by GDI+."); - - try - { - Lock.EnterGdiPlus(); - GdiRectF rect = layoutRectangle.ToRectangleF(); - if (format.LineAlignment == XLineAlignment.BaseLine) - { - double lineSpace = font.GetHeight(); //old: font.GetHeight(this); - int cellSpace = font.FontFamily.GetLineSpacing(font.Style); - int cellAscent = font.FontFamily.GetCellAscent(font.Style); - int cellDescent = font.FontFamily.GetCellDescent(font.Style); - double cyAscent = lineSpace * cellAscent / cellSpace; - cyAscent = lineSpace * font.CellAscent / font.CellSpace; - rect.Offset(0, (float)-cyAscent); - } - //_gfx.DrawString(text, font.Realize_GdiFont(), brush.RealizeGdiBrush(), rect, - // format != null ? format.RealizeGdiStringFormat() : null); - _gfx.DrawString(text, font.GdiFont, brush.RealizeGdiBrush(), rect, - format != null ? format.RealizeGdiStringFormat() : null); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { -#if !SILVERLIGHT - double x = layoutRectangle.X; - double y = layoutRectangle.Y; - - double lineSpace = font.GetHeight(); // old: font.GetHeight(this); - double cyAscent = lineSpace * font.CellAscent / font.CellSpace; - double cyDescent = lineSpace * font.CellDescent / font.CellSpace; - - bool bold = (font.Style & XFontStyle.Bold) != 0; - bool italic = (font.Style & XFontStyle.Italic) != 0; - bool strikeout = (font.Style & XFontStyle.Strikeout) != 0; - bool underline = (font.Style & XFontStyle.Underline) != 0; - - //GlyphRun glyphRun=new GlyphRun(font.GlyphTypeface , 0,); -#if DEBUG_ - if (font.WpfTypeface.FontFamily.Source == "Segoe UI Light") - GetType(); -#endif - FormattedText formattedText = FontHelper.CreateFormattedText(text, font.WpfTypeface, font.Size, brush.RealizeWpfBrush()); - - //formattedText.SetTextDecorations(TextDecorations.OverLine); - switch (format.Alignment) - { - case XStringAlignment.Near: - // nothing to do, this is the default - //formattedText.TextAlignment = TextAlignment.Left; - break; - - case XStringAlignment.Center: - x += layoutRectangle.Width / 2; - formattedText.TextAlignment = TextAlignment.Center; - break; - - case XStringAlignment.Far: - x += layoutRectangle.Width; - formattedText.TextAlignment = TextAlignment.Right; - break; - } - if (PageDirection == XPageDirection.Downwards) - { - switch (format.LineAlignment) - { - case XLineAlignment.Near: - //y += cyAscent; - break; - - case XLineAlignment.Center: - // TODO use CapHeight. PDFlib also uses 3/4 of ascent - y += -formattedText.Baseline + (cyAscent * 1 / 3) + layoutRectangle.Height / 2; - //y += -formattedText.Baseline + (font.Size * font.Metrics.CapHeight / font.unitsPerEm / 2) + layoutRectangle.Height / 2; - break; - - case XLineAlignment.Far: - y += -formattedText.Baseline - cyDescent + layoutRectangle.Height; - break; - - case XLineAlignment.BaseLine: - y -= formattedText.Baseline; - break; - } - } - else - { - // TODOWPF: make unit test - switch (format.LineAlignment) - { - case XLineAlignment.Near: - //y += cyDescent; - break; - - case XLineAlignment.Center: - // TODO use CapHeight. PDFlib also uses 3/4 of ascent - //y += -(cyAscent * 3 / 4) / 2 + rect.Height / 2; - break; - - case XLineAlignment.Far: - //y += -cyAscent + rect.Height; - break; - - case XLineAlignment.BaseLine: - // nothing to do - break; - } - } - - // BoldSimulation and ItalicSimulation is done only in PDF, not in UI. - - if (underline) - { - formattedText.SetTextDecorations(TextDecorations.Underline); - //double underlinePosition = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlinePosition / font.cellSpace; - //double underlineThickness = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlineThickness / font.cellSpace; - //DrawRectangle(null, brush, x, y - underlinePosition, width, underlineThickness); - } - - if (strikeout) - { - formattedText.SetTextDecorations(TextDecorations.Strikethrough); - //double strikeoutPosition = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutPosition / font.cellSpace; - //double strikeoutSize = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutSize / font.cellSpace; - //DrawRectangle(null, brush, x, y - strikeoutPosition - strikeoutSize, width, strikeoutSize); - } - - //_dc.DrawText(formattedText, layoutRectangle.Location.ToPoint()); - _dc.DrawText(formattedText, new SysPoint(x, y)); -#else - _dc.DrawString(this, text, font, brush, layoutRectangle, format); -#endif - } -#endif - } - if (_renderer != null) _renderer.DrawString(text, font, brush, layoutRectangle, format); } @@ -3712,125 +1259,8 @@ public XSize MeasureString(string text, XFont font, XStringFormat stringFormat) if (stringFormat == null) throw new ArgumentNullException("stringFormat"); -#if GDI && !WPF - //XSize gdiSize; // #MediumTrust - //if (_gfx != null) - // gdiSize = XSize.FromSizeF(_gfx.MeasureString(text, font.Realize_GdiFont(), new GdiPointF(0, 0), stringFormat.RealizeGdiStringFormat())); - //else - // gdiSize = FontHelper.MeasureString(text, font, XStringFormats.Default); // TODO 4STLA: Why is parameter stringFormat not used here? -#if DEBUG_ - XSize edfSize = FontHelper.MeasureString(text, font, XStringFormats.Default); - //Debug.Assert(gdiSize == edfSize, "Measure string failed."); - if (gdiSize != edfSize) - { - double dx = Math.Abs(gdiSize.Width - edfSize.Width); - double dy = Math.Abs(gdiSize.Height - edfSize.Height); - Debug.Assert(dx < .05 * gdiSize.Width, "MeasureString: width differs."); - Debug.Assert(dy < .05 * gdiSize.Height, "MeasureString: height differs."); - } -#endif - return FontHelper.MeasureString(text, font, XStringFormats.Default); -#endif -#if WPF && !GDI -#if !SILVERLIGHT -#if DEBUG - FormattedText formattedText = FontHelper.CreateFormattedText(text, font.WpfTypeface, font.Size, WpfBrushes.Black); - XSize size1 = FontHelper.MeasureString(text, font, null); - XSize size2 = new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height); - //Debug.Assert(Math.Abs((size1.Height - size2.Height) * 10) < 1.0); - return size1; -#else - // Same as above, but without code needed for Debug.Assert. - XSize size1 = FontHelper.MeasureString(text, font, null); - return size1; -#endif -#else - return _dc.MeasureString(this, text, font, stringFormat); -#endif - -#endif -#if WPF && GDI -#if true_ - if (TargetContext == XGraphicTargetContext.GDI) - { - XSize gdiSize = XSize.FromSizeF(_gfx.MeasureString(text, font.Realize_GdiFont(), new GdiPointF(0, 0), stringFormat.RealizeGdiStringFormat())); -#if DEBUG -#if GDI - { - //Debug.WriteLine(gdiSize); - XSize edfSize = FontHelper14.MeasureStringGdi(_gfx, text, font, XStringFormats.Default); - //Debug.WriteLine(edfSize); - //Debug.Assert(gdiSize == edfSize, "Measure string failed."); - if (gdiSize.Width != edfSize.Width) - { - Debug.WriteLine(String.Format("Width: {0}, {1} : {2}", gdiSize.Width, edfSize.Width, gdiSize.Width / edfSize.Width)); - } - if (gdiSize.Height != edfSize.Height) - { - Debug.WriteLine(String.Format("Height: {0}, {1}", gdiSize.Height, edfSize.Height)); - } - - //double lineSpace = font.GetHeight(this); - //int cellSpace = font.cellSpace; // font.FontFamily.GetLineSpacing(font.Style); - //int cellAscent = font.cellAscent; // font.FontFamily.GetCellAscent(font.Style); - //int cellDescent = font.cellDescent; // font.FontFamily.GetCellDescent(font.Style); - //double cyAscent = lineSpace * cellAscent / cellSpace; - //double cyDescent = lineSpace * cellDescent / cellSpace; - } -#endif -#if WPF - { - //Debug.WriteLine(gdiSize); - XSize edfSize = FontHelper14.MeasureStringWpf(text, font, XStringFormats.Default); - //Debug.WriteLine(edfSize); - //Debug.Assert(gdiSize == edfSize, "Measure string failed."); - if (gdiSize.Width != edfSize.Width) - { - Debug.WriteLine(String.Format("Width: {0}, {1} : {2}", gdiSize.Width, edfSize.Width, gdiSize.Width / edfSize.Width)); - } - if (gdiSize.Height != edfSize.Height) - { - Debug.WriteLine(String.Format("Height: {0}, {1}", gdiSize.Height, edfSize.Height)); - } - - //double lineSpace = font.GetHeight(this); - //int cellSpace = font.cellSpace; // font.FontFamily.GetLineSpacing(font.Style); - //int cellAscent = font.cellAscent; // font.FontFamily.GetCellAscent(font.Style); - //int cellDescent = font.cellDescent; // font.FontFamily.GetCellDescent(font.Style); - //double cyAscent = lineSpace * cellAscent / cellSpace; - //double cyDescent = lineSpace * cellDescent / cellSpace; - } -#endif -#endif - return gdiSize; - } - if (TargetContext == XGraphicTargetContext.WPF) - { - //double h = font.Height; - //FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"), - // FlowDirection.LeftToRight, font.typeface, font.Size, WpfBrushes.Black); - FormattedText formattedText = FontHelper.CreateFormattedText(text, font.Typeface, font.Size, WpfBrushes.Black); - XSize wpfSize = new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height); -#if DEBUG - Debug.WriteLine(wpfSize); -#endif - return wpfSize; - } - Debug.Assert(false); - return XSize.Empty; -#else - XSize size23 = FontHelper.MeasureString(text, font, XStringFormats.Default); - return size23; -#endif -#endif -#if CORE || NETFX_CORE || UWP - XSize size = FontHelper.MeasureString(text, font, XStringFormats.Default); - return size; -#endif -#if __IOS__ || __ANDROID__ || PORTABLE XSize size = FontHelper.MeasureString(text, font, XStringFormats.Default); return size; -#endif } /// @@ -3843,131 +1273,32 @@ public XSize MeasureString(string text, XFont font) // ----- DrawImage ---------------------------------------------------------------------------- -#if GDI - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, GdiPoint point) - { - DrawImage(image, point.X, point.Y); - } -#endif - -#if WPF - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, SysPoint point) - { - DrawImage(image, point.X, point.Y); - } -#endif - -#if GDI - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, GdiPointF point) - { - DrawImage(image, point.X, point.Y); - } -#endif - /// /// Draws the specified image. /// public void DrawImage(XImage image, XPoint point) { - DrawImage(image, point.X, point.Y); - } - - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, double x, double y) - { - if (image == null) - throw new ArgumentNullException("image"); - - CheckXPdfFormConsistence(image); - - double width = image.PointWidth; - double height = image.PointHeight; - - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (image._gdiImage != null) - { - InterpolationMode interpolationMode = InterpolationMode.Invalid; - if (!image.Interpolate) - { - interpolationMode = _gfx.InterpolationMode; - _gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - } - - _gfx.DrawImage(image._gdiImage, (float)x, (float)y, (float)width, (float)height); - - if (!image.Interpolate) - _gfx.InterpolationMode = interpolationMode; - } - else - { - DrawMissingImageRect(new XRect(x, y, width, height)); - //_gfx.DrawRectangle(Pens.Red, (float)x, (float)y, (float)width, (float)height); - //_gfx.DrawLine(Pens.Red, (float)x, (float)y, (float)(x + width), (float)(y + height)); - //_gfx.DrawLine(Pens.Red, (float)(x + width), (float)y, (float)x, (float)(y + height)); - } - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - if (image._wpfImage != null) - { - _dc.DrawImage(image._wpfImage, new Rect(x, y, image.PointWidth, image.PointHeight)); - } - else - { - DrawMissingImageRect(new XRect(x, y, width, height)); - } - } -#endif - } - - if (_renderer != null) - _renderer.DrawImage(image, x, y, image.PointWidth, image.PointHeight); - //image.Width * 72 / image.HorizontalResolution, - //image.Height * 72 / image.HorizontalResolution); - } - -#if GDI - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, Rectangle rect) - { - // Because of overloading the cast is NOT redundant. - DrawImage(image, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height); + DrawImage(image, point.X, point.Y); } -#endif -#if GDI /// /// Draws the specified image. /// - public void DrawImage(XImage image, GdiRectF rect) + public void DrawImage(XImage image, double x, double y) { - DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height); + if (image == null) + throw new ArgumentNullException("image"); + + CheckXPdfFormConsistence(image); + + double width = image.PointWidth; + double height = image.PointHeight; + + if (_renderer != null) + _renderer.DrawImage(image, x, y, image.PointWidth, image.PointHeight); + //image.Width * 72 / image.HorizontalResolution, + //image.Height * 72 / image.HorizontalResolution); } -#endif /// /// Draws the specified image. @@ -3987,86 +1318,6 @@ public void DrawImage(XImage image, double x, double y, double width, double hei CheckXPdfFormConsistence(image); - if (_drawGraphics) - { - // THHO4STLA: Platform-independent images cannot be drawn here, can they? => They can. Lazy create platform-dependent image and draw that. -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (image._gdiImage != null) - { - InterpolationMode interpolationMode = InterpolationMode.Invalid; - if (!image.Interpolate) - { - interpolationMode = _gfx.InterpolationMode; - _gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - } - - _gfx.DrawImage(image._gdiImage, (float)x, (float)y, (float)width, (float)height); - - if (!image.Interpolate) - _gfx.InterpolationMode = interpolationMode; - } - else - { - XImage placeholder = null; - XPdfForm pdfForm = image as XPdfForm; - if (pdfForm != null) - { - //XPdfForm pf = pdfForm; - if (pdfForm.PlaceHolder != null) - placeholder = pdfForm.PlaceHolder; - } - if (placeholder != null) - _gfx.DrawImage(placeholder._gdiImage, (float)x, (float)y, (float)width, - (float)height); - else - { - DrawMissingImageRect(new XRect(x, y, width, height)); - } - } - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - if (image._wpfImage != null) - { - //InterpolationMode interpolationMode = InterpolationMode.Invalid; - //if (!image.Interpolate) - //{ - // interpolationMode = gfx.InterpolationMode; - // gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - //} - - _dc.DrawImage(image._wpfImage, new Rect(x, y, width, height)); - - //if (!image.Interpolate) - // gfx.InterpolationMode = interpolationMode; - } - else - { - XImage placeholder = null; - if (image is XPdfForm) - { - XPdfForm pf = image as XPdfForm; - if (pf.PlaceHolder != null) - placeholder = pf.PlaceHolder; - } - if (placeholder != null) - _dc.DrawImage(placeholder._wpfImage, new Rect(x, y, width, height)); - else - DrawMissingImageRect(new XRect(x, y, width, height)); - } - } -#endif - } - if (_renderer != null) _renderer.DrawImage(image, x, y, width, height); } @@ -4075,30 +1326,6 @@ public void DrawImage(XImage image, double x, double y, double width, double hei //public void DrawImage(XImage image, double x, double y, GdiRectF srcRect, XGraphicsUnit srcUnit) //public void DrawImage(XImage image, double x, double y, XRect srcRect, XGraphicsUnit srcUnit) -#if GDI - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, Rectangle destRect, Rectangle srcRect, XGraphicsUnit srcUnit) - { - XRect destRectX = new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height); - XRect srcRectX = new XRect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height); - DrawImage(image, destRectX, srcRectX, srcUnit); - } -#endif - -#if GDI - /// - /// Draws the specified image. - /// - public void DrawImage(XImage image, GdiRectF destRect, GdiRectF srcRect, XGraphicsUnit srcUnit) - { - XRect destRectX = new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height); - XRect srcRectX = new XRect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height); - DrawImage(image, destRectX, srcRectX, srcUnit); - } -#endif - /// /// Draws the specified image. /// @@ -4109,68 +1336,6 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit CheckXPdfFormConsistence(image); - if (_drawGraphics) - { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - if (image._gdiImage != null) - { - InterpolationMode interpolationMode = InterpolationMode.Invalid; - if (!image.Interpolate) - { - interpolationMode = _gfx.InterpolationMode; - _gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - } - - GdiRectF destRectF = new GdiRectF((float)destRect.X, (float)destRect.Y, - (float)destRect.Width, (float)destRect.Height); - GdiRectF srcRectF = new GdiRectF((float)srcRect.X, (float)srcRect.Y, - (float)srcRect.Width, (float)srcRect.Height); - _gfx.DrawImage(image._gdiImage, destRectF, srcRectF, GraphicsUnit.Pixel); - - if (!image.Interpolate) - _gfx.InterpolationMode = interpolationMode; - } - else - { - DrawMissingImageRect(new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height)); - } - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - if (image._wpfImage != null) - { - //InterpolationMode interpolationMode = InterpolationMode.Invalid; - //if (!image.Interpolate) - //{ - // interpolationMode = gfx.InterpolationMode; - // //gfx.InterpolationMode = InterpolationMode.NearestNeighbor; - //} - - // HACK: srcRect is ignored - //double x = destRect.X; - //double y = destRect.Y; - _dc.DrawImage(image._wpfImage, new SysRect(destRect.X, destRect.Y, destRect.Width, destRect.Height)); - - //if (!image.Interpolate) - // gfx.InterpolationMode = interpolationMode; - } - else - { - DrawMissingImageRect(destRect); - } - } -#endif - } - if (_renderer != null) _renderer.DrawImage(image, destRect, srcRect, srcUnit); } @@ -4181,42 +1346,6 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit void DrawMissingImageRect(XRect rect) { -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - float x = (float)rect.X; - float y = (float)rect.Y; - float width = (float)rect.Width; - float height = (float)rect.Height; - _gfx.DrawRectangle(Pens.Red, x, y, width, height); - _gfx.DrawLine(Pens.Red, x, y, x + width, y + height); - _gfx.DrawLine(Pens.Red, x + width, y, x, y + height); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - double x = rect.X; - double y = rect.Y; - double width = rect.Width; - double height = rect.Height; -#if !SILVERLIGHT - WpfPen pen = new WpfPen(WpfBrushes.Red, 1); -#else - WpfPen pen = new WpfPen(); - pen.Brush = new SolidColorBrush(Colors.Red); - pen.Thickness = 1; -#endif - _dc.DrawRectangle(null, pen, new Rect(x, y, width, height)); - _dc.DrawLine(pen, new SysPoint(x, y), new SysPoint(x + width, y + height)); - _dc.DrawLine(pen, new SysPoint(x + width, y), new SysPoint(x, y + height)); - } -#endif } /// @@ -4301,48 +1430,10 @@ public void DrawMatrixCode(BarCodes.MatrixCode matrixcode, XBrush brush, XPoint public XGraphicsState Save() { XGraphicsState xState = null; -#if CORE || NETFX_CORE - if (TargetContext == XGraphicTargetContext.CORE || TargetContext == XGraphicTargetContext.NONE) - { - xState = new XGraphicsState(); - InternalGraphicsState iState = new InternalGraphicsState(this, xState); - iState.Transform = _transform; - _gsStack.Push(iState); - } - else - { - Debug.Assert(false, "XGraphicTargetContext must be XGraphicTargetContext.CORE."); - } -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - xState = new XGraphicsState(_gfx != null ? _gfx.Save() : null); - InternalGraphicsState iState = new InternalGraphicsState(this, xState); - iState.Transform = _transform; - _gsStack.Push(iState); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - xState = new XGraphicsState(); - InternalGraphicsState iState = new InternalGraphicsState(this, xState); - iState.Transform = _transform; - _gsStack.Push(iState); - } -#endif -#if __ANDROID__ || __IOS__ || PORTABLE xState = new XGraphicsState(); InternalGraphicsState iState = new InternalGraphicsState(this, xState); iState.Transform = _transform; _gsStack.Push(iState); -#endif if (_renderer != null) _renderer.Save(xState); @@ -4358,40 +1449,8 @@ public void Restore(XGraphicsState state) { if (state == null) throw new ArgumentNullException("state"); - -#if CORE - if (TargetContext == XGraphicTargetContext.CORE) - { - _gsStack.Restore(state.InternalState); - _transform = state.InternalState.Transform; - } -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gsStack.Restore(state.InternalState); - if (_gfx != null) - _gfx.Restore(state.GdiState); - _transform = state.InternalState.Transform; - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { - _gsStack.Restore(state.InternalState); - _transform = state.InternalState.Transform; - } -#endif - -#if __ANDROID__ || __IOS__ || PORTABLE _gsStack.Restore(state.InternalState); _transform = state.InternalState.Transform; -#endif if (_renderer != null) _renderer.Restore(state); @@ -4416,39 +1475,6 @@ public XGraphicsContainer BeginContainer() return BeginContainer(new XRect(0, 0, 1, 1), new XRect(0, 0, 1, 1), XGraphicsUnit.Point); } -#if GDI - /// - /// Saves a graphics container with the current state of this XGraphics and - /// opens and uses a new graphics container. - /// - public XGraphicsContainer BeginContainer(Rectangle dstrect, Rectangle srcrect, XGraphicsUnit unit) - { - return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit); - } -#endif - -#if GDI - /// - /// Saves a graphics container with the current state of this XGraphics and - /// opens and uses a new graphics container. - /// - public XGraphicsContainer BeginContainer(GdiRectF dstrect, GdiRectF srcrect, XGraphicsUnit unit) - { - return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit); - } -#endif - -#if WPF - /// - /// Saves a graphics container with the current state of this XGraphics and - /// opens and uses a new graphics container. - /// - public XGraphicsContainer BeginContainer(Rect dstrect, Rect srcrect, XGraphicsUnit unit) - { - return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit); - } -#endif - /// /// Saves a graphics container with the current state of this XGraphics and /// opens and uses a new graphics container. @@ -4460,30 +1486,7 @@ public XGraphicsContainer BeginContainer(XRect dstrect, XRect srcrect, XGraphics throw new ArgumentException("The current implementation supports XGraphicsUnit.Point only.", "unit"); XGraphicsContainer xContainer = null; -#if CORE - if (TargetContext == XGraphicTargetContext.CORE) - xContainer = new XGraphicsContainer(); -#endif -#if GDI - // _gfx can be null if drawing applies to PDF page only. - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - xContainer = new XGraphicsContainer(_gfx != null ? _gfx.Save() : null); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - xContainer = new XGraphicsContainer(); -#endif - -#if __ANDROID__ || __IOS__ || PORTABLE xContainer = new XGraphicsContainer(); -#endif InternalGraphicsState iState = new InternalGraphicsState(this, xContainer); iState.Transform = _transform; @@ -4514,23 +1517,6 @@ public void EndContainer(XGraphicsContainer container) throw new ArgumentNullException("container"); _gsStack.Restore(container.InternalState); -#if CORE - // nothing to do -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI && _gfx != null) - { - try - { - Lock.EnterGdiPlus(); - _gfx.Restore(container.GdiState); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - // nothing to do -#endif _transform = container.InternalState.Transform; if (_renderer != null) @@ -4560,68 +1546,15 @@ public XSmoothingMode SmoothingMode { get { -#if CORE - // nothing to do -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - return (XSmoothingMode)_gfx.SmoothingMode; - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - // nothing to do -#endif return _smoothingMode; } set { _smoothingMode = value; -#if CORE - // nothing to do -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.SmoothingMode = (SmoothingMode)value; - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - // nothing to do -#endif } } XSmoothingMode _smoothingMode; - //public Region Clip { get; set; } - //public GdiRectF ClipBounds { get; } - //public CompositingMode CompositingMode { get; set; } - //public CompositingQuality CompositingQuality { get; set; } - //public float DpiX { get; } - //public float DpiY { get; } - //public InterpolationMode InterpolationMode { get; set; } - //public bool IsClipEmpty { get; } - //public bool IsVisibleClipEmpty { get; } - //public float PageScale { get; set; } - //public GraphicsUnit PageUnit { get; set; } - //public PixelOffsetMode PixelOffsetMode { get; set; } - //public Point RenderingOrigin { get; set; } - //public SmoothingMode SmoothingMode { get; set; } - //public int TextContrast { get; set; } - //public TextRenderingHint TextRenderingHint { get; set; } - //public Matrix Transform { get; set; } - //public GdiRectF VisibleClipBounds { get; } - #endregion // -------------------------------------------------------------------------------------------- @@ -4828,85 +1761,16 @@ void AddTransform(XMatrix transform, XMatrixOrder order) _transform = matrix; matrix = DefaultViewMatrix; matrix.Multiply(_transform, XMatrixOrder.Prepend); -#if CORE - if (TargetContext == XGraphicTargetContext.CORE) - { - GetType(); - // TODO: _gsStack... - } -#endif -#if GDI - if (TargetContext == XGraphicTargetContext.GDI) - { - if (_gfx != null) - { - try - { - Lock.EnterGdiPlus(); - _gfx.Transform = (GdiMatrix)matrix; - } - finally { Lock.ExitGdiPlus(); } - } - } -#endif -#if WPF - if (TargetContext == XGraphicTargetContext.WPF) - { -#if !SILVERLIGHT - MatrixTransform mt = new MatrixTransform(transform.ToWpfMatrix()); -#else - MatrixTransform mt = new MatrixTransform(); - mt.Matrix = transform.ToWpfMatrix(); -#endif - if (order == XMatrixOrder.Append) - mt = (MatrixTransform)mt.Inverse; - _gsStack.Current.PushTransform(mt); - } -#endif if (_renderer != null) _renderer.AddTransform(transform, XMatrixOrder.Prepend); } - //public void TransformPoints(CoordinateSpace destSpace, CoordinateSpace srcSpace, Point[] points) - //{ - //} - // - //public void TransformPoints(CoordinateSpace destSpace, CoordinateSpace srcSpace, GdiPointF[] points) - //{ - //} - #endregion // -------------------------------------------------------------------------------------------- #region Clipping -#if GDI - /// - /// Updates the clip region of this XGraphics to the intersection of the - /// current clip region and the specified rectangle. - /// - public void IntersectClip(Rectangle rect) - { - XGraphicsPath path = new XGraphicsPath(); - path.AddRectangle(rect); - IntersectClip(path); - } -#endif - -#if GDI - /// - /// Updates the clip region of this XGraphics to the intersection of the - /// current clip region and the specified rectangle. - /// - public void IntersectClip(GdiRectF rect) - { - XGraphicsPath path = new XGraphicsPath(); - path.AddRectangle(rect); - IntersectClip(path); - } -#endif - /// /// Updates the clip region of this XGraphics to the intersection of the /// current clip region and the specified rectangle. @@ -4927,40 +1791,6 @@ public void IntersectClip(XGraphicsPath path) if (path == null) throw new ArgumentNullException("path"); - if (_drawGraphics) - { -#if GDI && !WPF - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.SetClip(path._gdipPath, CombineMode.Intersect); - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF && !GDI - if (TargetContext == XGraphicTargetContext.WPF) - _gsStack.Current.PushClip(path._pathGeometry); -#endif -#if GDI && WPF - if (TargetContext == XGraphicTargetContext.GDI) - { - try - { - Lock.EnterGdiPlus(); - _gfx.SetClip(path._gdipPath, CombineMode.Intersect); - } - finally { Lock.ExitGdiPlus(); } - } - else - { - _gsStack.Current.PushClip(path._pathGeometry); - } -#endif - } - if (_renderer != null) _renderer.SetClip(path, XCombineMode.Intersect); } @@ -5020,167 +1850,6 @@ public SpaceTransformer Transformer // -------------------------------------------------------------------------------------------- - #region Internal Helper Functions - -#if GDI - /// - /// Converts a GdiPoint[] into a GdiPointF[]. - /// - internal static GdiPointF[] MakePointFArray(GdiPoint[] points, int offset, int count) - { - if (points == null) - return null; - - //int length = points.Length; - GdiPointF[] result = new GdiPointF[count]; - for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++) - { - result[idx].X = points[srcIdx].X; - result[idx].Y = points[srcIdx].Y; - } - return result; - } -#endif - -#if GDI - /// - /// Converts a XPoint[] into a GdiPointF[]. - /// - internal static GdiPointF[] MakePointFArray(XPoint[] points) - { - if (points == null) - return null; - - int count = points.Length; - GdiPointF[] result = new GdiPointF[count]; - for (int idx = 0; idx < count; idx++) - { - result[idx].X = (float)points[idx].X; - result[idx].Y = (float)points[idx].Y; - } - return result; - } -#endif - -#if GDI - /// - /// Converts a Point[] into a XPoint[]. - /// - internal static XPoint[] MakeXPointArray(GdiPoint[] points, int offset, int count) - { - if (points == null) - return null; - - //int lengh = points.Length; - XPoint[] result = new XPoint[count]; - for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++) - { - result[idx].X = points[srcIdx].X; - result[idx].Y = points[srcIdx].Y; - } - return result; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Converts a Point[] into a XPoint[]. - /// - internal static XPoint[] MakeXPointArray(SysPoint[] points, int offset, int count) - { - if (points == null) - return null; - - //int length = points.Length; - XPoint[] result = new XPoint[count]; - for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++) - { - result[idx].X = points[srcIdx].X; - result[idx].Y = points[srcIdx].Y; - } - return result; - } -#endif - -#if GDI - /// - /// Converts a GdiPointF[] into a XPoint[]. - /// - internal static XPoint[] MakeXPointArray(GdiPointF[] points, int offset, int count) - { - if (points == null) - return null; - - //int length = points.Length; - XPoint[] result = new XPoint[count]; - for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++) - { - result[idx].X = points[srcIdx].X; - result[idx].Y = points[srcIdx].Y; - } - return result; - } -#endif - -#if GDI - /// - /// Converts a XRect[] into a GdiRectF[]. - /// - internal static GdiRectF[] MakeRectangleFArray(XRect[] rects, int offset, int count) - { - if (rects == null) - return null; - - //int length = rects.Length; - GdiRectF[] result = new GdiRectF[count]; - for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++) - { - XRect rect = rects[srcIdx]; - result[idx] = new GdiRectF((float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); - } - return result; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Converts an XPoint[] into a Point[]. - /// - internal static SysPoint[] MakePointArray(XPoint[] points) - { - if (points == null) - return null; - - int count = points.Length; - SysPoint[] result = new SysPoint[count]; - for (int idx = 0; idx < count; idx++) - { - result[idx].X = points[idx].X; - result[idx].Y = points[idx].Y; - } - return result; - } -#endif - - #endregion - - ///// - ///// Testcode - ///// - //public void TestXObject(PdfDocument thisDoc, PdfPage thisPage, int page, - // PdfDocument externalDoc, ImportedObjectTable impDoc) - //{ - // PdfPage impPage = externalDoc.Pages[page]; - // // impDoc.ImportPage(impPage); - // PdfFormXObject form = new PdfFormXObject(thisDoc, impDoc, impPage); - // thisDoc.xrefTable.Add(form); - - // PdfDictionary xobjects = new PdfDictionary(); - // xobjects.Elements["/X42"] = form.XRef; - // thisPage.Resources.Elements[PdfResources.Keys.XObject] = xobjects; - // ((XGraphicsPdfRenderer)renderer).DrawXObject("/X42"); - //} - internal void DisassociateImage() { if (_associatedImage == null) @@ -5203,29 +1872,6 @@ internal XImage AssociatedImage } XImage _associatedImage; -#if GDI - /// - /// Always defined System.Drawing.Graphics object. Used as 'query context' for PDF pages. - /// - internal Graphics _gfx; -#endif - -#if WPF - /// - /// Always defined System.Drawing.Graphics object. Used as 'query context' for PDF pages. - /// -#if !SILVERLIGHT - DrawingVisual _dv; - internal DrawingContext _dc; -#else - internal AgDrawingContext _dc; -#endif -#endif - -#if UWP - CanvasDrawingSession _cds; -#endif - /// /// The transformation matrix from the XGraphics page space to the Graphics world space. /// (The name 'default view matrix' comes from Microsoft OS/2 Presentation Manager. I choose @@ -5240,10 +1886,6 @@ internal XImage AssociatedImage readonly XForm _form; -#if GDI - internal Metafile Metafile; -#endif - /// /// Interface to an (optional) renderer. Currently it is the XGraphicsPdfRenderer, if defined. /// @@ -5272,25 +1914,6 @@ public PdfPage PdfPage } } -#if GDI - /// - /// Gets the System.Drawing.Graphics objects that serves as drawing surface if no PDF is rendered, - /// or null, if no such object exists. - /// - public Graphics Graphics - { - get { return _gfx; } - } -#endif - - //#if CORE || GDI - // /// - // /// Critical section used to serialize access to GDI+. - // /// This may be necessary to use PDFsharp savely in a Web application. - // /// - // internal static readonly object GdiPlus = new object(); - //#endif - /// /// Provides access to internal data structures of the XGraphics class. /// @@ -5301,16 +1924,6 @@ internal XGraphicsInternals(XGraphics gfx) _gfx = gfx; } readonly XGraphics _gfx; - -#if GDI - /// - /// Gets the underlying Graphics object. - /// - public Graphics Graphics - { - get { return _gfx._gfx; } - } -#endif } /// diff --git a/PdfSharpCore/Drawing/XGraphicsContainer.cs b/PdfSharpCore/Drawing/XGraphicsContainer.cs index fa053fea..a7fb2a90 100644 --- a/PdfSharpCore/Drawing/XGraphicsContainer.cs +++ b/PdfSharpCore/Drawing/XGraphicsContainer.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// @@ -42,17 +34,6 @@ namespace PdfSharpCore.Drawing /// public sealed class XGraphicsContainer { -#if GDI - internal XGraphicsContainer(GraphicsState state) - { - GdiState = state; - } - internal GraphicsState GdiState; -#endif -#if WPF - internal XGraphicsContainer() - { } -#endif internal InternalGraphicsState InternalState; } } diff --git a/PdfSharpCore/Drawing/XGraphicsPath.cs b/PdfSharpCore/Drawing/XGraphicsPath.cs index 4d6a7d13..aa3af3a7 100644 --- a/PdfSharpCore/Drawing/XGraphicsPath.cs +++ b/PdfSharpCore/Drawing/XGraphicsPath.cs @@ -28,27 +28,6 @@ #endregion using System; -using System.Diagnostics; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -#if !SILVERLIGHT -using WpfBrushes = System.Windows.Media.Brushes; -#endif -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -using SysRect = Windows.Foundation.Rect; -#endif using PdfSharpCore.Internal; namespace PdfSharpCore.Drawing @@ -63,155 +42,21 @@ public sealed class XGraphicsPath /// public XGraphicsPath() { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath = new CoreGraphicsPath(); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath = new GraphicsPath(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE - _pathGeometry = new PathGeometry(); -#endif - } - -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XGraphicsPath(PointF[] points, byte[] types, XFillMode fillMode) - { -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath = new GraphicsPath(points, types, (FillMode)fillMode); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF // Is true only in Hybrid build. - _pathGeometry = new PathGeometry(); - _pathGeometry.FillRule = FillRule.EvenOdd; -#endif - } -#endif - -#if WPF || NETFX_CORE - /// - /// Gets the current path figure. - /// - PathFigure CurrentPathFigure - { - get - { - int count = _pathGeometry.Figures.Count; - if (count == 0) - { - // Create new figure if there is none. - _pathGeometry.Figures.Add(new PathFigure()); - count++; - } - else - { - PathFigure lastFigure = _pathGeometry.Figures[count - 1]; - if (lastFigure.IsClosed) - { - if (lastFigure.Segments.Count > 0) - { - // Create new figure if previous one was closed. - _pathGeometry.Figures.Add(new PathFigure()); - count++; - } - else - { - Debug.Assert(false); - } - } - } - // Return last figure in collection. - return _pathGeometry.Figures[count - 1]; - } } - /// - /// Gets the current path figure, but never created a new one. - /// - PathFigure PeekCurrentFigure - { - get - { - int count = _pathGeometry.Figures.Count; - return count == 0 ? null : _pathGeometry.Figures[count - 1]; - } - } -#endif - /// /// Clones this instance. /// public XGraphicsPath Clone() { XGraphicsPath path = (XGraphicsPath)MemberwiseClone(); -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath = new CoreGraphicsPath(_corePath); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - path._gdipPath = _gdipPath.Clone() as GraphicsPath; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - path._pathGeometry = _pathGeometry.Clone(); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight cannot clone geometry objects."); - // TODO: make it manually... -#pragma warning disable 0162 -#endif -#endif return path; } // ----- AddLine ------------------------------------------------------------------------------ -#if GDI - /// - /// Adds a line segment to current figure. - /// - public void AddLine(System.Drawing.Point pt1, System.Drawing.Point pt2) - { - AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y); - } -#endif - -#if WPF - /// - /// Adds a line segment to current figure. - /// - public void AddLine(SysPoint pt1, SysPoint pt2) - { - AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y); - } -#endif - -#if GDI - /// - /// Adds a line segment to current figure. - /// - public void AddLine(PointF pt1, PointF pt2) - { - AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y); - } -#endif - /// /// Adds a line segment to current figure. /// @@ -228,77 +73,12 @@ public void AddMove(double x1, double y1) /// public void AddLine(double x1, double y1, double x2, double y2) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.MoveOrLineTo(x1, y1); _corePath.LineTo(x2, y2, false); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddLine((float)x1, (float)y1, (float)x2, (float)y2); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - { - figure.StartPoint = new SysPoint(x1, y1); -#if !SILVERLIGHT - var lineSegment = new LineSegment(new SysPoint(x2, y2), true); -#else - var lineSegment = new LineSegment { Point = new Point(x2, y2) }; -#endif - figure.Segments.Add(lineSegment); - } - else - { -#if !SILVERLIGHT - var lineSegment1 = new LineSegment(new SysPoint(x1, y1), true); - var lineSegment2 = new LineSegment(new SysPoint(x2, y2), true); -#else - var lineSegment1 = new LineSegment { Point = new Point(x1, y1) }; - var lineSegment2 = new LineSegment { Point = new Point(x2, y2) }; -#endif - figure.Segments.Add(lineSegment1); - figure.Segments.Add(lineSegment2); - } -#endif } // ----- AddLines ----------------------------------------------------------------------------- -#if GDI - /// - /// Adds a series of connected line segments to current figure. - /// - public void AddLines(System.Drawing.Point[] points) - { - AddLines(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if WPF - /// - /// Adds a series of connected line segments to current figure. - /// - public void AddLines(SysPoint[] points) - { - AddLines(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Adds a series of connected line segments to current figure. - /// - public void AddLines(PointF[] points) - { - AddLines(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - /// /// Adds a series of connected line segments to current figure. /// @@ -310,84 +90,13 @@ public void AddLines(XPoint[] points) int count = points.Length; if (count == 0) return; -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.MoveOrLineTo(points[0].X, points[0].Y); for (int idx = 1; idx < count; idx++) _corePath.LineTo(points[idx].X, points[idx].Y, false); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddLines(XGraphics.MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - { - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - for (int idx = 1; idx < count; idx++) - { -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(new SysPoint(points[idx].X, points[idx].Y), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = new Point(points[idx].X, points[idx].Y); // ,true? -#endif - figure.Segments.Add(lineSegment); - } - } - else - { - for (int idx = 0; idx < count; idx++) - { - // figure.Segments.Add(new LineSegment(new SysPoint(points[idx].x, points[idx].y), true)); -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(new SysPoint(points[idx].X, points[idx].Y), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = new Point(points[idx].X, points[idx].Y); // ,true? -#endif - figure.Segments.Add(lineSegment); - } - } -#endif } // ----- AddBezier ---------------------------------------------------------------------------- -#if GDI - /// - /// Adds a cubic Bézier curve to the current figure. - /// - public void AddBezier(System.Drawing.Point pt1, System.Drawing.Point pt2, System.Drawing.Point pt3, System.Drawing.Point pt4) - { - AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); - } -#endif - -#if WPF - /// - /// Adds a cubic Bézier curve to the current figure. - /// - public void AddBezier(SysPoint pt1, SysPoint pt2, SysPoint pt3, SysPoint pt4) - { - AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); - } -#endif - -#if GDI - /// - /// Adds a cubic Bézier curve to the current figure. - /// - public void AddBezier(PointF pt1, PointF pt2, PointF pt3, PointF pt4) - { - AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); - } -#endif - /// /// Adds a cubic Bézier curve to the current figure. /// @@ -401,84 +110,12 @@ public void AddBezier(XPoint pt1, XPoint pt2, XPoint pt3, XPoint pt4) /// public void AddBezier(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.MoveOrLineTo(x1, y1); _corePath.BezierTo(x2, y2, x3, y3, x4, y4, false); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddBezier((float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3, (float)x4, (float)y4); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - figure.StartPoint = new SysPoint(x1, y1); - else - { - // figure.Segments.Add(new LineSegment(new SysPoint(x1, y1), true)); -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(new SysPoint(x1, y1), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = new Point(x1, y1); -#endif - figure.Segments.Add(lineSegment); - } - //figure.Segments.Add(new BezierSegment( - // new SysPoint(x2, y2), - // new SysPoint(x3, y3), - // new SysPoint(x4, y4), true)); -#if !SILVERLIGHT - BezierSegment bezierSegment = new BezierSegment( - new SysPoint(x2, y2), - new SysPoint(x3, y3), - new SysPoint(x4, y4), true); -#else - BezierSegment bezierSegment = new BezierSegment(); - bezierSegment.Point1 = new Point(x2, y2); - bezierSegment.Point2 = new Point(x3, y3); - bezierSegment.Point3 = new Point(x4, y4); -#endif - figure.Segments.Add(bezierSegment); -#endif } // ----- AddBeziers --------------------------------------------------------------------------- -#if GDI - /// - /// Adds a sequence of connected cubic Bézier curves to the current figure. - /// - public void AddBeziers(System.Drawing.Point[] points) - { - AddBeziers(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if WPF - /// - /// Adds a sequence of connected cubic Bézier curves to the current figure. - /// - public void AddBeziers(SysPoint[] points) - { - AddBeziers(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Adds a sequence of connected cubic Bézier curves to the current figure. - /// - public void AddBeziers(PointF[] points) - { - AddBeziers(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - /// /// Adds a sequence of connected cubic Bézier curves to the current figure. /// @@ -495,91 +132,16 @@ public void AddBeziers(XPoint[] points) throw new ArgumentException("Invalid number of points for bezier curve. Number must fulfil 4+3n.", "points"); -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.MoveOrLineTo(points[0].X, points[0].Y); for (int idx = 1; idx < count; idx += 3) { _corePath.BezierTo(points[idx].X, points[idx].Y, points[idx + 1].X, points[idx + 1].Y, points[idx + 2].X, points[idx + 2].Y, false); } -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddBeziers(XGraphics.MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - else - { - // figure.Segments.Add(new LineSegment(new SysPoint(points[0].x, points[0].y), true)); -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(new SysPoint(points[0].X, points[0].Y), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = new Point(points[0].X, points[0].Y); -#endif - figure.Segments.Add(lineSegment); - } - for (int idx = 1; idx < count; idx += 3) - { - //figure.Segments.Add(new BezierSegment( - // new SysPoint(points[idx].x, points[idx].y), - // new SysPoint(points[idx + 1].x, points[idx + 1].y), - // new SysPoint(points[idx + 2].x, points[idx + 2].y), true)); -#if !SILVERLIGHT - BezierSegment bezierSegment = new BezierSegment( - new SysPoint(points[idx].X, points[idx].Y), - new SysPoint(points[idx + 1].X, points[idx + 1].Y), - new SysPoint(points[idx + 2].X, points[idx + 2].Y), true); -#else - BezierSegment bezierSegment = new BezierSegment(); - bezierSegment.Point1 = new Point(points[idx].X, points[idx].Y); - bezierSegment.Point2 = new Point(points[idx + 1].X, points[idx + 1].Y); - bezierSegment.Point3 = new Point(points[idx + 2].X, points[idx + 2].Y); -#endif - figure.Segments.Add(bezierSegment); - } -#endif } // ----- AddCurve ----------------------------------------------------------------------- -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(System.Drawing.Point[] points) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if WPF - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(SysPoint[] points) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(PointF[] points) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length)); - } -#endif - /// /// Adds a spline curve to the current figure. /// @@ -588,36 +150,6 @@ public void AddCurve(XPoint[] points) AddCurve(points, 0.5); } -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(System.Drawing.Point[] points, double tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - -#if WPF - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(SysPoint[] points, double tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(PointF[] points, double tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - /// /// Adds a spline curve to the current figure. /// @@ -626,122 +158,19 @@ public void AddCurve(XPoint[] points, double tension) int count = points.Length; if (count < 2) throw new ArgumentException("AddCurve requires two or more points.", "points"); -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.AddCurve(points, tension); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddCurve(XGraphics.MakePointFArray(points), (float)tension); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - tension /= 3; - - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - else - { - // figure.Segments.Add(new LineSegment(new SysPoint(points[0].x, points[0].y), true)); -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(new SysPoint(points[0].X, points[0].Y), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = new Point(points[0].X, points[0].Y); -#endif - figure.Segments.Add(lineSegment); - } - - if (count == 2) - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension)); - } - else - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[2], tension)); - for (int idx = 1; idx < count - 2; idx++) - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[count - 1], tension)); - } -#endif - } - -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(System.Drawing.Point[] points, int offset, int numberOfSegments, float tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), offset, numberOfSegments, tension); } -#endif - -#if WPF - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(SysPoint[] points, int offset, int numberOfSegments, float tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), offset, numberOfSegments, tension); - } -#endif - -#if GDI - /// - /// Adds a spline curve to the current figure. - /// - public void AddCurve(PointF[] points, int offset, int numberOfSegments, float tension) - { - AddCurve(XGraphics.MakeXPointArray(points, 0, points.Length), offset, numberOfSegments, tension); - } -#endif /// /// Adds a spline curve to the current figure. /// public void AddCurve(XPoint[] points, int offset, int numberOfSegments, double tension) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE - throw new NotImplementedException("AddCurve not yet implemented."); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddCurve(XGraphics.MakePointFArray(points), offset, numberOfSegments, (float)tension); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF throw new NotImplementedException("AddCurve not yet implemented."); -#endif } // ----- AddArc ------------------------------------------------------------------------------- -#if GDI - /// - /// Adds an elliptical arc to the current figure. - /// - public void AddArc(Rectangle rect, double startAngle, double sweepAngle) - { - AddArc(rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - -#if GDI - /// - /// Adds an elliptical arc to the current figure. - /// - public void AddArc(RectangleF rect, double startAngle, double sweepAngle) - { - AddArc(rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif - /// /// Adds an elliptical arc to the current figure. /// @@ -755,48 +184,7 @@ public void AddArc(XRect rect, double startAngle, double sweepAngle) /// public void AddArc(double x, double y, double width, double height, double startAngle, double sweepAngle) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.AddArc(x, y, width, height, startAngle, sweepAngle); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddArc((float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - SysPoint startPoint; - ArcSegment seg = GeometryHelper.CreateArcSegment(x, y, width, height, startAngle, sweepAngle, out startPoint); - if (figure.Segments.Count == 0) - figure.StartPoint = startPoint; - else - { - //#if !SILVERLIGHT - // LineSegment lineSegment = new LineSegment(startPoint, true); - //#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = startPoint; - //#endif - figure.Segments.Add(lineSegment); - } - - figure.Segments.Add(seg); - - //figure.Segments.Add( - //if (figure.Segments.Count == 0) - // figure.StartPoint = new SysPoint(points[0].x, points[0].y); - //else - // figure.Segments.Add(new LineSegment(new SysPoint(points[0].x, points[0].y), true)); - - //for (int idx = 1; idx < 5555; idx += 3) - // figure.Segments.Add(new BezierSegment( - // new SysPoint(points[idx].x, points[idx].y), - // new SysPoint(points[idx + 1].x, points[idx + 1].y), - // new SysPoint(points[idx + 2].x, points[idx + 2].y), true)); -#endif } /// @@ -804,268 +192,54 @@ public void AddArc(double x, double y, double width, double height, double start /// public void AddArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArg, XSweepDirection sweepDirection) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.AddArc(point1, point2, size, rotationAngle, isLargeArg, sweepDirection); -#endif -#if GDI - DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddArc"); -#endif -#if WPF - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count == 0) - figure.StartPoint = point1.ToPoint(); - else - { - // figure.Segments.Add(new LineSegment(point1.ToPoint(), true)); -#if !SILVERLIGHT - LineSegment lineSegment = new LineSegment(point1.ToPoint(), true); -#else - LineSegment lineSegment = new LineSegment(); - lineSegment.Point = point1.ToPoint(); -#endif - figure.Segments.Add(lineSegment); - } - - // figure.Segments.Add(new ArcSegment(point2.ToPoint(), size.ToSize(), rotationAngle, isLargeArg, sweepDirection, true)); -#if !SILVERLIGHT - ArcSegment arcSegment = new ArcSegment(point2.ToPoint(), size.ToSize(), rotationAngle, isLargeArg, (SweepDirection)sweepDirection, true); -#else - ArcSegment arcSegment = new ArcSegment(); - arcSegment.Point = point2.ToPoint(); - arcSegment.Size = size.ToSize(); - arcSegment.RotationAngle = rotationAngle; - arcSegment.IsLargeArc = isLargeArg; - arcSegment.SweepDirection = (SweepDirection)sweepDirection; -#endif - figure.Segments.Add(arcSegment); -#endif } // ----- AddRectangle ------------------------------------------------------------------------- -#if GDI - /// - /// Adds a rectangle to this path. - /// - public void AddRectangle(Rectangle rect) - { - AddRectangle(new XRect(rect)); - } -#endif - -#if GDI - /// - /// Adds a rectangle to this path. - /// - public void AddRectangle(RectangleF rect) - { - AddRectangle(new XRect(rect)); - } -#endif - - /// - /// Adds a rectangle to this path. - /// - public void AddRectangle(XRect rect) - { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE - _corePath.MoveTo(rect.X, rect.Y); - _corePath.LineTo(rect.X + rect.Width, rect.Y, false); - _corePath.LineTo(rect.X + rect.Width, rect.Y + rect.Height, false); - _corePath.LineTo(rect.X, rect.Y + rect.Height, true); - _corePath.CloseSubpath(); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - // If rect is empty GDI+ removes the rect from the path. - // This is not intended if the path is used for clipping. - // See http://forum.PdfSharp.net/viewtopic.php?p=9433#p9433 - // _gdipPath.AddRectangle(rect.ToRectangleF()); - - // Draw the rectangle manually. - _gdipPath.StartFigure(); - _gdipPath.AddLines(new PointF[] { rect.TopLeft.ToPointF(), rect.TopRight.ToPointF(), rect.BottomRight.ToPointF(), rect.BottomLeft.ToPointF() }); - _gdipPath.CloseFigure(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - StartFigure(); - PathFigure figure = CurrentPathFigure; - figure.StartPoint = new SysPoint(rect.X, rect.Y); - - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x + rect.width, rect.y), true)); - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x + rect.width, rect.y + rect.height), true)); - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x, rect.y + rect.height), true)); -#if !SILVERLIGHT - LineSegment lineSegment1 = new LineSegment(new SysPoint(rect.X + rect.Width, rect.Y), true); - LineSegment lineSegment2 = new LineSegment(new SysPoint(rect.X + rect.Width, rect.Y + rect.Height), true); - LineSegment lineSegment3 = new LineSegment(new SysPoint(rect.X, rect.Y + rect.Height), true); -#else - LineSegment lineSegment1 = new LineSegment(); - lineSegment1.Point = new Point(rect.X + rect.Width, rect.Y); - LineSegment lineSegment2 = new LineSegment(); - lineSegment2.Point = new Point(rect.X + rect.Width, rect.Y + rect.Height); - LineSegment lineSegment3 = new LineSegment(); - lineSegment3.Point = new Point(rect.X, rect.Y + rect.Height); -#endif - figure.Segments.Add(lineSegment1); - figure.Segments.Add(lineSegment2); - figure.Segments.Add(lineSegment3); - CloseFigure(); -#endif - } - /// - /// Adds a rectangle to this path. - /// - public void AddRectangle(double x, double y, double width, double height) - { - AddRectangle(new XRect(x, y, width, height)); - } - - // ----- AddRectangles ------------------------------------------------------------------------ - -#if GDI - /// - /// Adds a series of rectangles to this path. - /// - public void AddRectangles(Rectangle[] rects) - { - int count = rects.Length; - for (int idx = 0; idx < count; idx++) - AddRectangle(rects[idx]); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddRectangles(rects); - } - finally { Lock.ExitGdiPlus(); } - } -#endif - -#if GDI - /// - /// Adds a series of rectangles to this path. - /// - public void AddRectangles(RectangleF[] rects) - { - int count = rects.Length; - for (int idx = 0; idx < count; idx++) - AddRectangle(rects[idx]); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddRectangles(rects); - } - finally { Lock.ExitGdiPlus(); } - } -#endif - - /// - /// Adds a series of rectangles to this path. - /// - public void AddRectangles(XRect[] rects) - { - int count = rects.Length; - for (int idx = 0; idx < count; idx++) - { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE - AddRectangle(rects[idx]); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddRectangle(rects[idx].ToRectangleF()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - StartFigure(); - PathFigure figure = CurrentPathFigure; - XRect rect = rects[idx]; - figure.StartPoint = new SysPoint(rect.X, rect.Y); - - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x + rect.width, rect.y), true)); - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x + rect.width, rect.y + rect.height), true)); - // figure.Segments.Add(new LineSegment(new SysPoint(rect.x, rect.y + rect.height), true)); -#if !SILVERLIGHT - LineSegment lineSegment1 = new LineSegment(new SysPoint(rect.X + rect.Width, rect.Y), true); - LineSegment lineSegment2 = new LineSegment(new SysPoint(rect.X + rect.Width, rect.Y + rect.Height), true); - LineSegment lineSegment3 = new LineSegment(new SysPoint(rect.X, rect.Y + rect.Height), true); -#else - LineSegment lineSegment1 = new LineSegment(); - lineSegment1.Point = new Point(rect.X + rect.Width, rect.Y); - LineSegment lineSegment2 = new LineSegment(); - lineSegment2.Point = new Point(rect.X + rect.Width, rect.Y + rect.Height); - LineSegment lineSegment3 = new LineSegment(); - lineSegment3.Point = new Point(rect.X, rect.Y + rect.Height); -#endif - figure.Segments.Add(lineSegment1); - figure.Segments.Add(lineSegment2); - figure.Segments.Add(lineSegment3); - CloseFigure(); -#endif - } - } - - // ----- AddRoundedRectangle ------------------------------------------------------------------ - -#if GDI - /// - /// Adds a rectangle with rounded corners to this path. - /// - public void AddRoundedRectangle(Rectangle rect, System.Drawing.Size ellipseSize) - { - AddRoundedRectangle(rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Adds a rectangle with rounded corners to this path. + /// Adds a rectangle to this path. /// - public void AddRoundedRectangle(SysRect rect, SysSize ellipseSize) + public void AddRectangle(XRect rect) { - AddRoundedRectangle(rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); + _corePath.MoveTo(rect.X, rect.Y); + _corePath.LineTo(rect.X + rect.Width, rect.Y, false); + _corePath.LineTo(rect.X + rect.Width, rect.Y + rect.Height, false); + _corePath.LineTo(rect.X, rect.Y + rect.Height, true); + _corePath.CloseSubpath(); } -#endif -#if GDI /// - /// Adds a rectangle with rounded corners to this path. + /// Adds a rectangle to this path. /// - public void AddRoundedRectangle(RectangleF rect, SizeF ellipseSize) + public void AddRectangle(double x, double y, double width, double height) { - AddRoundedRectangle(rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); + AddRectangle(new XRect(x, y, width, height)); } -#endif -#if GDI + // ----- AddRectangles ------------------------------------------------------------------------ + /// - /// Adds a rectangle with rounded corners to this path. + /// Adds a series of rectangles to this path. /// - public void AddRoundedRectangle(XRect rect, SizeF ellipseSize) + public void AddRectangles(XRect[] rects) { - AddRoundedRectangle(rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height); + int count = rects.Length; + for (int idx = 0; idx < count; idx++) + { + AddRectangle(rects[idx]); + } } -#endif + + // ----- AddRoundedRectangle ------------------------------------------------------------------ /// /// Adds a rectangle with rounded corners to this path. /// public void AddRoundedRectangle(double x, double y, double width, double height, double ellipseWidth, double ellipseHeight) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE -#if true double arcWidth = ellipseWidth / 2; double arcHeight = ellipseHeight / 2; -#if true // Clockwise _corePath.MoveTo(x + width - arcWidth, y); _corePath.QuadrantArcTo(x + width - arcWidth, y + arcHeight, arcWidth, arcHeight, 1, true); @@ -1079,182 +253,11 @@ public void AddRoundedRectangle(double x, double y, double width, double height, _corePath.QuadrantArcTo(x + arcWidth, y + arcHeight, arcWidth, arcHeight, 2, true); _corePath.CloseSubpath(); -#else // Counterclockwise - _corePath.MoveTo(x + arcWidth, y); - _corePath.QuadrantArcTo(x + arcWidth, y + arcHeight, arcWidth, arcHeight, 2, false); - - _corePath.LineTo(x, y + height - arcHeight, false); - _corePath.QuadrantArcTo(x + arcWidth, y + height - arcHeight, arcWidth, arcHeight, 3, false); - _corePath.LineTo(x + width - arcWidth, y + height, false); - _corePath.QuadrantArcTo(x + width - arcWidth, y + height - arcHeight, arcWidth, arcHeight, 4, false); - - _corePath.LineTo(x + width, y + arcHeight, false); - _corePath.QuadrantArcTo(x + width - arcWidth, y + arcHeight, arcWidth, arcHeight, 1, false); - - _corePath.CloseSubpath(); -#endif -#else - // AddArc not yet implemented - AddArc((float)(x + width - ellipseWidth), (float)y, (float)ellipseWidth, (float)ellipseHeight, -90, 90); - AddArc((float)(x + width - ellipseWidth), (float)(y + height - ellipseHeight), (float)ellipseWidth, - (float)ellipseHeight, 0, 90); - AddArc((float)x, (float)(y + height - ellipseHeight), (float)ellipseWidth, (float)ellipseHeight, 90, 90); - AddArc((float)x, (float)y, (float)ellipseWidth, (float)ellipseHeight, 180, 90); - CloseFigure(); -#endif -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.StartFigure(); - _gdipPath.AddArc((float)(x + width - ellipseWidth), (float)y, (float)ellipseWidth, (float)ellipseHeight, -90, 90); - _gdipPath.AddArc((float)(x + width - ellipseWidth), (float)(y + height - ellipseHeight), (float)ellipseWidth, (float)ellipseHeight, 0, 90); - _gdipPath.AddArc((float)x, (float)(y + height - ellipseHeight), (float)ellipseWidth, (float)ellipseHeight, 90, 90); - _gdipPath.AddArc((float)x, (float)y, (float)ellipseWidth, (float)ellipseHeight, 180, 90); - _gdipPath.CloseFigure(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE - double ex = ellipseWidth / 2; - double ey = ellipseHeight / 2; - StartFigure(); - PathFigure figure = CurrentPathFigure; - figure.StartPoint = new SysPoint(x + ex, y); - - //#if !SILVERLIGHT - // figure.Segments.Add(new LineSegment(new SysPoint(x + width - ex, y), true)); - // // TODOWPF XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx - // figure.Segments.Add(new ArcSegment(new SysPoint(x + width, y + ey), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - // //figure.Segments.Add(new LineSegment(new SysPoint(x + width, y + ey), true)); - - // figure.Segments.Add(new LineSegment(new SysPoint(x + width, y + height - ey), true)); - // // TODOWPF - // figure.Segments.Add(new ArcSegment(new SysPoint(x + width - ex, y + height), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - // //figure.Segments.Add(new LineSegment(new SysPoint(x + width - ex, y + height), true)); - - // figure.Segments.Add(new LineSegment(new SysPoint(x + ex, y + height), true)); - // // TODOWPF - // figure.Segments.Add(new ArcSegment(new SysPoint(x, y + height - ey), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - // //figure.Segments.Add(new LineSegment(new SysPoint(x, y + height - ey), true)); - - // figure.Segments.Add(new LineSegment(new SysPoint(x, y + ey), true)); - // // TODOWPF - // figure.Segments.Add(new ArcSegment(new SysPoint(x + ex, y), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - // //figure.Segments.Add(new LineSegment(new SysPoint(x + ex, y), true)); - //#else - -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new LineSegment(new SysPoint(x + width - ex, y), true)); -#else - figure.Segments.Add(new LineSegment { Point = new SysPoint(x + width - ex, y) }); -#endif - - // TODOWPF XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new ArcSegment(new SysPoint(x + width, y + ey), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - //figure.Segments.Add(new LineSegment(new SysPoint(x + width, y + ey), true)); -#else - figure.Segments.Add(new ArcSegment - { - Point = new SysPoint(x + width, y + ey), - Size = new SysSize(ex, ey), - //RotationAngle = 0, - //IsLargeArc = false, - SweepDirection = SweepDirection.Clockwise - }); -#endif - -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new LineSegment(new SysPoint(x + width, y + height - ey), true)); -#else - figure.Segments.Add(new LineSegment { Point = new SysPoint(x + width, y + height - ey) }); -#endif - - // TODOWPF -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new ArcSegment(new SysPoint(x + width - ex, y + height), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - //figure.Segments.Add(new LineSegment(new SysPoint(x + width - ex, y + height), true)); -#else - figure.Segments.Add(new ArcSegment - { - Point = new SysPoint(x + width - ex, y + height), - Size = new SysSize(ex, ey), - //RotationAngle = 0, - //IsLargeArc = false, - SweepDirection = SweepDirection.Clockwise - }); -#endif - -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new LineSegment(new SysPoint(x + ex, y + height), true)); -#else - figure.Segments.Add(new LineSegment { Point = new SysPoint(x + ex, y + height) }); -#endif - - // TODOWPF -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new ArcSegment(new SysPoint(x, y + height - ey), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - //figure.Segments.Add(new LineSegment(new SysPoint(x, y + height - ey), true)); -#else - figure.Segments.Add(new ArcSegment - { - Point = new SysPoint(x, y + height - ey), - Size = new SysSize(ex, ey), - //RotationAngle = 0, - //IsLargeArc = false, - SweepDirection = SweepDirection.Clockwise - }); -#endif - -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new LineSegment(new SysPoint(x, y + ey), true)); -#else - figure.Segments.Add(new LineSegment { Point = new SysPoint(x, y + ey) }); -#endif - - // TODOWPF -#if !SILVERLIGHT && !NETFX_CORE - figure.Segments.Add(new ArcSegment(new SysPoint(x + ex, y), new SysSize(ex, ey), 0, false, SweepDirection.Clockwise, true)); - //figure.Segments.Add(new LineSegment(new SysPoint(x + ex, y), true)); -#else - figure.Segments.Add(new ArcSegment - { - Point = new SysPoint(x + ex, y), - Size = new SysSize(ex, ey), - //RotationAngle = 0, - //IsLargeArc = false, - SweepDirection = SweepDirection.Clockwise - }); -#endif - CloseFigure(); -#endif } // ----- AddEllipse --------------------------------------------------------------------------- -#if GDI - /// - /// Adds an ellipse to the current path. - /// - public void AddEllipse(Rectangle rect) - { - AddEllipse(rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - -#if GDI - /// - /// Adds an ellipse to the current path. - /// - public void AddEllipse(RectangleF rect) - { - AddEllipse(rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - /// /// Adds an ellipse to the current path. /// @@ -1268,7 +271,6 @@ public void AddEllipse(XRect rect) /// public void AddEllipse(double x, double y, double width, double height) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE double w = width / 2; double h = height / 2; double xc = x + w; @@ -1279,101 +281,15 @@ public void AddEllipse(double x, double y, double width, double height) _corePath.QuadrantArcTo(xc, yc, w, h, 3, true); _corePath.QuadrantArcTo(xc, yc, w, h, 2, true); _corePath.CloseSubpath(); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddEllipse((float)x, (float)y, (float)width, (float)height); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry.AddGeometry(new EllipseGeometry(new Rect(x, y, width, height))); -#else - var figure = new PathFigure(); - figure.StartPoint = new SysPoint(x, y + height / 2); - var segment = new ArcSegment - { - Point = new SysPoint(x + width, y + height / 2), - Size = new SysSize(width / 2, height / 2), - IsLargeArc = true, - RotationAngle = 180, - SweepDirection = SweepDirection.Clockwise, - }; - figure.Segments.Add(segment); - segment = new ArcSegment - { - Point = figure.StartPoint, - Size = new SysSize(width / 2, height / 2), - IsLargeArc = true, - RotationAngle = 180, - SweepDirection = SweepDirection.Clockwise, - }; - figure.Segments.Add(segment); - _pathGeometry.Figures.Add(figure); -#endif - // StartFigure() isn't needed because AddGeometry() implicitly starts a new figure, - // but CloseFigure() is needed for the next adding not to continue this figure. - CloseFigure(); -#endif } // ----- AddPolygon --------------------------------------------------------------------------- -#if GDI - /// - /// Adds a polygon to this path. - /// - public void AddPolygon(System.Drawing.Point[] points) - { - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPolygon(points); - } - finally { Lock.ExitGdiPlus(); } - } -#endif - -#if WPF || NETFX_CORE - /// - /// Adds a polygon to this path. - /// - public void AddPolygon(SysPoint[] points) - { - // TODO: fill mode unclear here -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry.AddGeometry(GeometryHelper.CreatePolygonGeometry(points, XFillMode.Alternate, true)); - CloseFigure(); // StartFigure() isn't needed because AddGeometry() implicitly starts a new figure, but CloseFigure() is needed for the next adding not to continue this figure. -#else - AddPolygon(XGraphics.MakeXPointArray(points, 0, points.Length)); -#endif - } -#endif - -#if GDI - /// - /// Adds a polygon to this path. - /// - public void AddPolygon(PointF[] points) - { - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPolygon(points); - } - finally { Lock.ExitGdiPlus(); } - } -#endif - /// /// Adds a polygon to this path. /// public void AddPolygon(XPoint[] points) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE int count = points.Length; if (count == 0) return; @@ -1383,65 +299,10 @@ public void AddPolygon(XPoint[] points) _corePath.LineTo(points[idx].X, points[idx].Y, false); _corePath.LineTo(points[count - 1].X, points[count - 1].Y, true); _corePath.CloseSubpath(); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPolygon(XGraphics.MakePointFArray(points)); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry.AddGeometry(GeometryHelper.CreatePolygonGeometry(XGraphics.MakePointArray(points), XFillMode.Alternate, true)); -#else - var figure = new PathFigure(); - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - figure.IsClosed = true; - - PolyLineSegment segment = new PolyLineSegment(); - int count = points.Length; - // For correct drawing the start point of the segment must not be the same as the first point. - for (int idx = 1; idx < count; idx++) - segment.Points.Add(new SysPoint(points[idx].X, points[idx].Y)); -#if !SILVERLIGHT && !NETFX_CORE - seg.IsStroked = true; -#endif - figure.Segments.Add(segment); - _pathGeometry.Figures.Add(figure); -#endif - // TODO: NOT NEEDED - //CloseFigure(); // StartFigure() isn't needed because AddGeometry() implicitly starts a new figure, but CloseFigure() is needed for the next adding not to continue this figure. -#endif - } - - // ----- AddPie ------------------------------------------------------------------------------- -#if GDI - /// - /// Adds the outline of a pie shape to this path. - /// - public void AddPie(Rectangle rect, double startAngle, double sweepAngle) - { - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPie(rect, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } } -#endif -#if GDI - /// - /// Adds the outline of a pie shape to this path. - /// - public void AddPie(RectangleF rect, double startAngle, double sweepAngle) - { - AddPie(rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle); - } -#endif + // ----- AddPie ------------------------------------------------------------------------------- /// /// Adds the outline of a pie shape to this path. @@ -1456,54 +317,11 @@ public void AddPie(XRect rect, double startAngle, double sweepAngle) /// public void AddPie(double x, double y, double width, double height, double startAngle, double sweepAngle) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE - DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddPie"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPie((float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddPie"); -#endif } // ----- AddClosedCurve ------------------------------------------------------------------------ -#if GDI - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(System.Drawing.Point[] points) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), 0.5); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(SysPoint[] points) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), 0.5); - } -#endif - -#if GDI - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(PointF[] points) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), 0.5); - } -#endif - /// /// Adds a closed curve to this path. /// @@ -1512,36 +330,6 @@ public void AddClosedCurve(XPoint[] points) AddClosedCurve(points, 0.5); } -#if GDI - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(System.Drawing.Point[] points, double tension) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(SysPoint[] points, double tension) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - -#if GDI - /// - /// Adds a closed curve to this path. - /// - public void AddClosedCurve(PointF[] points, double tension) - { - AddClosedCurve(XGraphics.MakeXPointArray(points, 0, points.Length), tension); - } -#endif - /// /// Adds a closed curve to this path. /// @@ -1554,38 +342,7 @@ public void AddClosedCurve(XPoint[] points, double tension) return; if (count < 2) throw new ArgumentException("Not enough points.", "points"); - -#if CORE || __IOS__ || __ANDROID__ || PORTABLE DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddClosedCurve"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddClosedCurve(XGraphics.MakePointFArray(points), (float)tension); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF ||NETFX_CORE - tension /= 3; - - StartFigure(); - PathFigure figure = CurrentPathFigure; - figure.StartPoint = new SysPoint(points[0].X, points[0].Y); - - if (count == 2) - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension)); - } - else - { - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 1], points[0], points[1], points[2], tension)); - for (int idx = 1; idx < count - 2; idx++) - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[0], tension)); - figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 2], points[count - 1], points[0], points[1], tension)); - } -#endif } // ----- AddPath ------------------------------------------------------------------------------ @@ -1595,60 +352,11 @@ public void AddClosedCurve(XPoint[] points, double tension) /// public void AddPath(XGraphicsPath path, bool connect) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddPath"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddPath(path._gdipPath, connect); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry.AddGeometry(path._pathGeometry); -#else - // AG-HACK: No AddGeometry in Silverlight version of PathGeometry - throw new InvalidOperationException("Silverlight/WinRT cannot merge geometry objects."); - // TODO: make it manually by using a GeometryGroup -#endif -#endif } // ----- AddString ---------------------------------------------------------------------------- -#if GDI - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, System.Drawing.Point origin, XStringFormat format) - { - AddString(s, family, style, emSize, new XRect(origin.X, origin.Y, 0, 0), format); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, SysPoint origin, XStringFormat format) - { - AddString(s, family, style, emSize, new XPoint(origin), format); - } -#endif - -#if GDI - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, PointF origin, XStringFormat format) - { - AddString(s, family, style, emSize, new XRect(origin.X, origin.Y, 0, 0), format); - } -#endif - /// /// Adds a text string to this path. /// @@ -1657,82 +365,7 @@ public void AddString(string s, XFontFamily family, XFontStyle style, double emS { try { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddString"); -#endif -#if GDI - if (family.GdiFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); - - PointF p = origin.ToPointF(); - p.Y += SimulateBaselineOffset(family, style, emSize, format); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, p, format.RealizeGdiStringFormat()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF - if (family.WpfFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); -#if !SILVERLIGHT - XFont font = new XFont(family.Name, emSize, style); - - double x = origin.X; - double y = origin.Y; - - double lineSpace = font.GetHeight(); - double cyAscent = lineSpace * font.CellAscent / font.CellSpace; - double cyDescent = lineSpace * font.CellDescent / font.CellSpace; - - Typeface typeface = FontHelper.CreateTypeface(family.WpfFamily, style); - FormattedText formattedText = FontHelper.CreateFormattedText(s, typeface, emSize, WpfBrushes.Black); - - switch (format.Alignment) - { - case XStringAlignment.Near: - // nothing to do, this is the default - //formattedText.TextAlignment = TextAlignment.Left; - break; - - case XStringAlignment.Center: - formattedText.TextAlignment = TextAlignment.Center; - break; - - case XStringAlignment.Far: - formattedText.TextAlignment = TextAlignment.Right; - break; - } - switch (format.LineAlignment) - { - case XLineAlignment.Near: - //y += cyAscent; - break; - - case XLineAlignment.Center: - // TODO use CapHeight. PDFlib also uses 3/4 of ascent - y += -lineSpace / 2; //-formattedText.Baseline + (cyAscent * 2 / 4); - break; - - case XLineAlignment.Far: - y += -formattedText.Baseline - cyDescent; - break; - - case XLineAlignment.BaseLine: - y -= formattedText.Baseline; - break; - } - - Geometry geo = formattedText.BuildGeometry(new XPoint(x, y)); - _pathGeometry.AddGeometry(geo); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight cannot create geometry of glyphs."); - // TODO: Get the outline directly from the font. -#endif -#endif } catch { @@ -1740,86 +373,6 @@ public void AddString(string s, XFontFamily family, XFontStyle style, double emS } } -#if GDI - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, Rectangle layoutRect, XStringFormat format) - { - if (family.GdiFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); - - Rectangle rect = new Rectangle(layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height); - rect.Offset(new System.Drawing.Point(0, (int)SimulateBaselineOffset(family, style, emSize, format))); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, rect, format.RealizeGdiStringFormat()); - } - finally { Lock.ExitGdiPlus(); } - } - - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, RectangleF layoutRect, XStringFormat format) - { - if (family.GdiFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); - - RectangleF rect = new RectangleF(layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height); - rect.Offset(new PointF(0, SimulateBaselineOffset(family, style, emSize, format))); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, layoutRect, format.RealizeGdiStringFormat()); - } - finally { Lock.ExitGdiPlus(); } - } - - /// - /// Calculates the offset for BaseLine positioning simulation: - /// In GDI we have only Near, Center and Far as LineAlignment and no BaseLine. For XLineAlignment.BaseLine StringAlignment.Near is returned. - /// We now return the negative drawed ascender height. - /// This has to be added to the LayoutRect/Origin before each _gdipPath.AddString(). - /// - /// - /// - /// - /// - /// - private float SimulateBaselineOffset(XFontFamily family, XFontStyle style, double emSize, XStringFormat format) - { - XFont font = new XFont(family.Name, emSize, style); - - if (format.LineAlignment == XLineAlignment.BaseLine) - { - double lineSpace = font.GetHeight(); - int cellSpace = font.FontFamily.GetLineSpacing(font.Style); - int cellAscent = font.FontFamily.GetCellAscent(font.Style); - int cellDescent = font.FontFamily.GetCellDescent(font.Style); - double cyAscent = lineSpace * cellAscent / cellSpace; - cyAscent = lineSpace * font.CellAscent / font.CellSpace; - return (float)-cyAscent; - } - return 0; - } - -#endif - -#if WPF - /// - /// Adds a text string to this path. - /// - public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, Rect rect, XStringFormat format) - { - //gdip Path.AddString(s, family.gdiFamily, (int)style, (float)emSize, layoutRect, format.RealizeGdiStringFormat()); - AddString(s, family, style, emSize, new XRect(rect), format); - } -#endif - /// /// Adds a text string to this path. /// @@ -1843,155 +396,7 @@ public void AddString(string s, XFontFamily family, XFontStyle style, double emS return; XFont font = new XFont(family.Name, emSize, style); -#if CORE || __IOS__ || __ANDROID__ || PORTABLE DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddString"); -#endif -#if (GDI || CORE_) && !WPF - //Gfx.DrawString(text, font.Realize_GdiFont(), brush.RealizeGdiBrush(), rect, - // format != null ? format.RealizeGdiStringFormat() : null); - - if (family.GdiFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); - - RectangleF rect = layoutRect.ToRectangleF(); - rect.Offset(new PointF(0, SimulateBaselineOffset(family, style, emSize, format))); - - try - { - Lock.EnterGdiPlus(); - _gdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, rect, format.RealizeGdiStringFormat()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF && !GDI - if (family.WpfFamily == null) - throw new NotFiniteNumberException(PSSR.NotImplementedForFontsRetrievedWithFontResolver(family.Name)); -#if !SILVERLIGHT - // Just a first sketch, but currently we do not need it and there is enough to do... - double x = layoutRect.X; - double y = layoutRect.Y; - - //double lineSpace = font.GetHeight(this); - //double cyAscent = lineSpace * font.cellAscent / font.cellSpace; - //double cyDescent = lineSpace * font.cellDescent / font.cellSpace; - - //double cyAscent = family.GetCellAscent(style) * family.GetLineSpacing(style) / family.getl; //fontlineSpace * font.cellAscent / font.cellSpace; - //double cyDescent =family.GetCellDescent(style); // lineSpace * font.cellDescent / font.cellSpace; - double lineSpace = font.GetHeight(); - double cyAscent = lineSpace * font.CellAscent / font.CellSpace; - double cyDescent = lineSpace * font.CellDescent / font.CellSpace; - - bool bold = (style & XFontStyle.Bold) != 0; - bool italic = (style & XFontStyle.Italic) != 0; - bool strikeout = (style & XFontStyle.Strikeout) != 0; - bool underline = (style & XFontStyle.Underline) != 0; - - Typeface typeface = FontHelper.CreateTypeface(family.WpfFamily, style); - //FormattedText formattedText = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, emSize, WpfBrushes.Black); - FormattedText formattedText = FontHelper.CreateFormattedText(s, typeface, emSize, WpfBrushes.Black); - - switch (format.Alignment) - { - case XStringAlignment.Near: - // nothing to do, this is the default - //formattedText.TextAlignment = TextAlignment.Left; - break; - - case XStringAlignment.Center: - x += layoutRect.Width / 2; - formattedText.TextAlignment = TextAlignment.Center; - break; - - case XStringAlignment.Far: - x += layoutRect.Width; - formattedText.TextAlignment = TextAlignment.Right; - break; - } - //if (PageDirection == XPageDirection.Downwards) - //{ - switch (format.LineAlignment) - { - case XLineAlignment.Near: - //y += cyAscent; - break; - - case XLineAlignment.Center: - // TO/DO use CapHeight. PDFlib also uses 3/4 of ascent - //y += -formattedText.Baseline + (cyAscent * 2 / 4) + layoutRect.Height / 2; - - // GDI seems to make it this simple: - // TODO: Check WPF's vertical alignment and make all implementations fit. $MaOs - y += layoutRect.Height / 2 - lineSpace / 2; - break; - - case XLineAlignment.Far: - y += -formattedText.Baseline - cyDescent + layoutRect.Height; - break; - - case XLineAlignment.BaseLine: - y -= formattedText.Baseline; - break; - } - //} - //else - //{ - // // TODOWPF - // switch (format.LineAlignment) - // { - // case XLineAlignment.Near: - // //y += cyDescent; - // break; - - // case XLineAlignment.Center: - // // TODO use CapHeight. PDFlib also uses 3/4 of ascent - // //y += -(cyAscent * 3 / 4) / 2 + rect.Height / 2; - // break; - - // case XLineAlignment.Far: - // //y += -cyAscent + rect.Height; - // break; - - // case XLineAlignment.BaseLine: - // // nothing to do - // break; - // } - //} - - //if (bold && !descriptor.IsBoldFace) - //{ - // // TODO: emulate bold by thicker outline - //} - - //if (italic && !descriptor.IsItalicFace) - //{ - // // TODO: emulate italic by shearing transformation - //} - - if (underline) - { - //double underlinePosition = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlinePosition / font.cellSpace; - //double underlineThickness = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlineThickness / font.cellSpace; - //DrawRectangle(null, brush, x, y - underlinePosition, width, underlineThickness); - } - - if (strikeout) - { - //double strikeoutPosition = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutPosition / font.cellSpace; - //double strikeoutSize = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutSize / font.cellSpace; - //DrawRectangle(null, brush, x, y - strikeoutPosition - strikeoutSize, width, strikeoutSize); - } - - //dc.DrawText(formattedText, layoutRectangle.Location.ToPoint()); - //dc.DrawText(formattedText, new SysPoint(x, y)); - - Geometry geo = formattedText.BuildGeometry(new Point(x, y)); - _pathGeometry.AddGeometry(geo); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight cannot create geometry of glyphs."); - // TODO: no, yagni -#endif -#endif } // -------------------------------------------------------------------------------------------- @@ -2001,22 +406,7 @@ public void AddString(string s, XFontFamily family, XFontStyle style, double emS /// public void CloseFigure() { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE _corePath.CloseSubpath(); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.CloseFigure(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE - PathFigure figure = PeekCurrentFigure; - if (figure != null && figure.Segments.Count != 0) - figure.IsClosed = true; -#endif } /// @@ -2024,25 +414,7 @@ public void CloseFigure() /// public void StartFigure() { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // TODO: ??? -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.StartFigure(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE - PathFigure figure = CurrentPathFigure; - if (figure.Segments.Count != 0) - { - figure = new PathFigure(); - _pathGeometry.Figures.Add(figure); - } -#endif } // -------------------------------------------------------------------------------------------- @@ -2056,20 +428,7 @@ public XFillMode FillMode set { _fillMode = value; -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Nothing to do. -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.FillMode = (FillMode)value; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE - _pathGeometry.FillRule = value == XFillMode.Winding ? FillRule.Nonzero : FillRule.EvenOdd; -#endif } } @@ -2082,26 +441,7 @@ public XFillMode FillMode /// public void Flatten() { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Flatten(); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetFlattenedPathGeometry(); -#else - // AGHACK - throw new InvalidOperationException("Silverlight/WinrRT cannot flatten a geometry."); - // TODO: no, yagni -#endif -#endif } /// @@ -2109,27 +449,7 @@ public void Flatten() /// public void Flatten(XMatrix matrix) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Flatten(matrix.ToGdiMatrix()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetFlattenedPathGeometry(); - _pathGeometry.Transform = new MatrixTransform(matrix.ToWpfMatrix()); -#else - // AGHACK - throw new InvalidOperationException("Silverlight/WinRT cannot flatten a geometry."); - // TODO: no, yagni -#endif -#endif } /// @@ -2137,32 +457,7 @@ public void Flatten(XMatrix matrix) /// public void Flatten(XMatrix matrix, double flatness) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if CORE___ - throw new NotImplementedException("XGraphicsPath.Flatten"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Flatten(matrix.ToGdiMatrix(), (float)flatness); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetFlattenedPathGeometry(); - // TODO: matrix handling not yet tested - if (!matrix.IsIdentity) - _pathGeometry.Transform = new MatrixTransform(matrix.ToWpfMatrix()); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight/WinRT cannot flatten a geometry."); - // TODO: no, yagni -#endif -#endif } // -------------------------------------------------------------------------------------------- @@ -2173,29 +468,7 @@ public void Flatten(XMatrix matrix, double flatness) /// public void Widen(XPen pen) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if CORE___ - throw new NotImplementedException("XGraphicsPath.Widen"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Widen(pen.RealizeGdiPen()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight/WinRT cannot widen a geometry."); - // TODO: no, yagni -#endif -#endif } /// @@ -2204,29 +477,7 @@ public void Widen(XPen pen) /// public void Widen(XPen pen, XMatrix matrix) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if CORE - throw new NotImplementedException("XGraphicsPath.Widen"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Widen(pen.RealizeGdiPen(), matrix.ToGdiMatrix()); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight/WinRT cannot widen a geometry."); - // TODO: no, yagni -#endif -#endif } /// @@ -2235,29 +486,7 @@ public void Widen(XPen pen, XMatrix matrix) /// public void Widen(XPen pen, XMatrix matrix, double flatness) { -#if CORE || __IOS__ || __ANDROID__ || PORTABLE // Just do nothing. -#endif -#if CORE__ - throw new NotImplementedException("XGraphicsPath.Widen"); -#endif -#if GDI - try - { - Lock.EnterGdiPlus(); - _gdipPath.Widen(pen.RealizeGdiPen(), matrix.ToGdiMatrix(), (float)flatness); - } - finally { Lock.ExitGdiPlus(); } -#endif -#if WPF || NETFX_CORE -#if !SILVERLIGHT && !NETFX_CORE - _pathGeometry = _pathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); -#else - // AG-HACK - throw new InvalidOperationException("Silverlight/WinRT cannot widen a geometry."); - // TODO: no, yagni -#endif -#endif } /// @@ -2268,25 +497,9 @@ public XGraphicsPathInternals Internals get { return new XGraphicsPathInternals(this); } } -#if CORE || __IOS__ || __ANDROID__ || PORTABLE /// /// Gets access to underlying Core graphics path. /// internal CoreGraphicsPath _corePath; -#endif - -#if GDI - /// - /// Gets access to underlying GDI+ graphics path. - /// - internal GraphicsPath _gdipPath; -#endif - -#if WPF || NETFX_CORE - /// - /// Gets access to underlying WPF/WinRT path geometry. - /// - internal PathGeometry _pathGeometry; -#endif } } \ No newline at end of file diff --git a/PdfSharpCore/Drawing/XGraphicsPathInternals.cs b/PdfSharpCore/Drawing/XGraphicsPathInternals.cs index 2aebddea..7ebff46d 100644 --- a/PdfSharpCore/Drawing/XGraphicsPathInternals.cs +++ b/PdfSharpCore/Drawing/XGraphicsPathInternals.cs @@ -52,25 +52,5 @@ internal XGraphicsPathInternals(XGraphicsPath path) _path = path; } XGraphicsPath _path; - -#if GDI - /// - /// Gets the underlying GDI+ path object. - /// - public GraphicsPath GdiPath - { - get { return _path._gdipPath; } - } -#endif - -#if WPF || NETFX_CORE - /// - /// Gets the underlying WPF path geometry object. - /// - public PathGeometry WpfPath - { - get { return _path._pathGeometry; } - } -#endif } } \ No newline at end of file diff --git a/PdfSharpCore/Drawing/XGraphicsPathItem.cs b/PdfSharpCore/Drawing/XGraphicsPathItem.cs deleted file mode 100644 index 6e6289fe..00000000 --- a/PdfSharpCore/Drawing/XGraphicsPathItem.cs +++ /dev/null @@ -1,77 +0,0 @@ -#region PDFsharp - A .NET library for processing PDF -// -// Authors: -// Stefan Lange -// -// Copyright (c) 2005-2016 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 - -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - -namespace PdfSharpCore.Drawing -{ -#if true_ // unused - /// - /// Represents a segment of a path defined by a type and a set of points. - /// - internal sealed class XGraphicsPathItem - { - public XGraphicsPathItem(XGraphicsPathItemType type) - { - Type = type; - Points = null; - } - -#if GDI - public XGraphicsPathItem(XGraphicsPathItemType type, params PointF[] points) - { - Type = type; - Points = XGraphics.MakeXPointArray(points, 0, points.Length); - } -#endif - - public XGraphicsPathItem(XGraphicsPathItemType type, params XPoint[] points) - { - Type = type; - Points = (XPoint[])points.Clone(); - } - - public XGraphicsPathItem Clone() - { - XGraphicsPathItem item = (XGraphicsPathItem)MemberwiseClone(); - item.Points = (XPoint[])Points.Clone(); - return item; - } - - public XGraphicsPathItemType Type; - public XPoint[] Points; - } -#endif -} \ No newline at end of file diff --git a/PdfSharpCore/Drawing/XGraphicsState.cs b/PdfSharpCore/Drawing/XGraphicsState.cs index 1e315824..15d67ede 100644 --- a/PdfSharpCore/Drawing/XGraphicsState.cs +++ b/PdfSharpCore/Drawing/XGraphicsState.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// @@ -44,22 +36,6 @@ namespace PdfSharpCore.Drawing public sealed class XGraphicsState { // This class is simply a wrapper of InternalGraphicsState. -#if CORE - internal XGraphicsState() - { } -#endif -#if GDI - internal XGraphicsState(GraphicsState state) - { - GdiState = state; - } - - internal GraphicsState GdiState; -#endif -#if WPF - internal XGraphicsState() - { } -#endif internal InternalGraphicsState InternalState; } } diff --git a/PdfSharpCore/Drawing/XImage.cs b/PdfSharpCore/Drawing/XImage.cs index 013668f0..9a9eaecf 100644 --- a/PdfSharpCore/Drawing/XImage.cs +++ b/PdfSharpCore/Drawing/XImage.cs @@ -33,6 +33,7 @@ using PdfSharpCore.Pdf.IO; using PdfSharpCore.Pdf.Advanced; using MigraDocCore.DocumentObjectModel.MigraDoc.DocumentObjectModel.Shapes; +using PdfSharpCore.Pdf.IO.enums; using static MigraDocCore.DocumentObjectModel.MigraDoc.DocumentObjectModel.Shapes.ImageSource; using PdfSharpCore.Utils; using SixLabors.ImageSharp.PixelFormats; @@ -78,9 +79,7 @@ protected XImage() // Useful stuff here: http://stackoverflow.com/questions/350027/setting-wpf-image-source-in-code XImage(string path) { -#if NETCOREAPP1_1 if (ImageSource.ImageSourceImpl == null) ImageSource.ImageSourceImpl = new ImageSharpImageSource(); -#endif _source = ImageSource.FromFile(path); Initialize(); } @@ -96,9 +95,8 @@ protected XImage() { // Create a dummy unique path. _path = "*" + Guid.NewGuid().ToString("B"); -#if NETCOREAPP1_1 - if (ImageSource.ImageSourceImpl == null) ImageSource.ImageSourceImpl = new ImageSharpImageSource(); -#endif + if (ImageSource.ImageSourceImpl == null) + ImageSource.ImageSourceImpl = new ImageSharpImageSource(); _source = ImageSource.FromStream(_path, stream); Initialize(); } @@ -118,9 +116,21 @@ protected XImage() /// /// The path to a BMP, PNG, GIF, JPEG, TIFF, or PDF file. public static XImage FromFile(string path) + { + return FromFile(path, PdfReadAccuracy.Strict); + } + + /// + /// Creates an image from the specified file. + /// For non-pdf files, this requires that an instance of an implementation of be set on the `ImageSource.ImageSourceImpl` property. + /// For .NetCore apps, if this property is null at this point, then with Pixel Type is used + /// + /// The path to a BMP, PNG, GIF, JPEG, TIFF, or PDF file. + /// Moderate allows for broken references when using a PDF file. + public static XImage FromFile(string path, PdfReadAccuracy accuracy) { if (PdfReader.TestPdfFile(path) > 0) - return new XPdfForm(path); + return new XPdfForm(path, accuracy); return new XImage(path); } @@ -159,11 +169,7 @@ public static bool ExistsFile(string path) if (PdfReader.TestPdfFile(path) > 0) return true; -#if !NETFX_CORE && !UWP && !PORTABLE - return File.Exists(path); -#else return false; -#endif } internal XImageState XImageState @@ -182,20 +188,6 @@ internal void Initialize() } } -#if __IOS__ - public MemoryStream AsJpeg() - { - var ms = new MemoryStream(); - - using (var stream = _iosImage.AsJPEG(0.7f).AsStream()) - { - stream.CopyTo(ms); - } - - return ms; - } -#endif - public MemoryStream AsJpeg() { var ms = new MemoryStream(); @@ -212,193 +204,6 @@ public MemoryStream AsBitmap() return ms; } -#if WPF - /// - /// Gets the image filename. - /// - /// The bitmap source. - internal static string GetImageFilename(BitmapSource bitmapSource) - { - string filename = bitmapSource.ToString(); - filename = UrlDecodeStringFromStringInternal(filename); - if (filename.StartsWith("file:///")) - filename = filename.Substring(8); // Remove all 3 slashes! - else if (filename.StartsWith("file://")) - filename = filename.Substring(5); // Keep 2 slashes (UNC path) - return filename; - } - - private static string UrlDecodeStringFromStringInternal(string s/*, Encoding e*/) - { - int length = s.Length; - string result = ""; - for (int i = 0; i < length; i++) - { - char ch = s[i]; - if (ch == '+') - { - ch = ' '; - } - else if ((ch == '%') && (i < (length - 2))) - { - if ((s[i + 1] == 'u') && (i < (length - 5))) - { - int num3 = HexToInt(s[i + 2]); - int num4 = HexToInt(s[i + 3]); - int num5 = HexToInt(s[i + 4]); - int num6 = HexToInt(s[i + 5]); - if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0))) - { - goto AddByte; - } - ch = (char)((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6); - i += 5; - result += ch; - continue; - } - int num7 = HexToInt(s[i + 1]); - int num8 = HexToInt(s[i + 2]); - if ((num7 >= 0) && (num8 >= 0)) - { - byte b = (byte)((num7 << 4) | num8); - i += 2; - result += (char)b; - continue; - } - } - AddByte: - if ((ch & 0xff80) == 0) - { - result += ch; - } - else - { - result += ch; - } - } - return result; - } - - private static int HexToInt(char h) - { - if (h >= '0' && h <= '9') - return (h - '0'); - if (h >= 'a' && h <= 'f') - return ((h - 'a') + 10); - if (h >= 'A' && h <= 'F') - return (h - 'A') + 10; - return -1; - } -#endif - -#if WPF - /// - /// Tests if a file is a JPEG. - /// - /// The filename. - internal static bool TestJpeg(string filename) - { - byte[] imageBits = null; - return ReadJpegFile(filename, 16, ref imageBits); - } - - /// - /// Tests if a file is a JPEG. - /// - /// The filename. - internal static bool TestJpeg(Stream stream) - { - byte[] imageBits = null; - return ReadJpegFile(stream, 16, ref imageBits) == true; - } - - /// - /// Reads the JPEG file. - /// - /// The filename. - /// The maximum count of bytes to be read. - /// The bytes read from the file. - /// False, if file could not be read or is not a JPEG file. - internal static bool ReadJpegFile(string filename, int maxRead, ref byte[] imageBits) - { - if (File.Exists(filename)) - { - FileStream fs = null; - try - { - fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - } - catch - { - return false; - } - - bool? test = ReadJpegFile(fs, maxRead, ref imageBits); - // Treat test result as definite. - if (test == false || test == true) - { - fs.Close(); - return test.Value; - } - // Test result is maybe. - // Hack: store the file in PDF if extension matches ... - string str = filename.ToLower(); - if (str.EndsWith(".jpg") || str.EndsWith(".jpeg")) - return true; - } - return false; - } - - /// - /// Reads the JPEG file. - /// - /// The stream. - /// The maximum count of bytes to be read. - /// The bytes read from the file. - /// False, if file could not be read or is not a JPEG file. - internal static bool? ReadJpegFile(Stream stream, int maxRead, ref byte[] imageBits) - { - if (!stream.CanSeek) - return false; - stream.Seek(0, SeekOrigin.Begin); - - if (stream.Length < 16) - { - return false; - } - int len = maxRead == -1 ? (int)stream.Length : maxRead; - imageBits = new byte[len]; - stream.Read(imageBits, 0, len); - if (imageBits[0] == 0xff && - imageBits[1] == 0xd8 && - imageBits[2] == 0xff && - imageBits[3] == 0xe0 && - imageBits[6] == 0x4a && - imageBits[7] == 0x46 && - imageBits[8] == 0x49 && - imageBits[9] == 0x46 && - imageBits[10] == 0x0) - { - return true; - } - // TODO: Exif: find JFIF header - if (imageBits[0] == 0xff && - imageBits[1] == 0xd8 && - imageBits[2] == 0xff && - imageBits[3] == 0xe1 /*&& - imageBits[6] == 0x4a && - imageBits[7] == 0x46 && - imageBits[8] == 0x49 && - imageBits[9] == 0x46 && - imageBits[10] == 0x0*/) - { - // Hack: store the file in PDF if extension matches ... - return null; - } - return false; - } -#endif - /// /// Under construction /// @@ -415,46 +220,9 @@ protected virtual void Dispose(bool disposing) { if (!_disposed) _disposed = true; - -#if CORE || GDI || WPF - //if (_importedImage != null) - { - _importedImage = null; - } -#endif - -#if CORE_WITH_GDI || GDI - if (_gdiImage != null) - { - try - { - Lock.EnterGdiPlus(); - _gdiImage.Dispose(); - _gdiImage = null; - } - finally { Lock.ExitGdiPlus(); } - } -#endif -#if WPF - _wpfImage = null; -#endif } bool _disposed; -#if CORE || GDI || WPF - /// - /// The factor for conversion from DPM to PointWidth or PointHeight. - /// 72 points per inch, 1000 mm per meter, 25.4 mm per inch => 72 * 1000 / 25.4. - /// - private const decimal FactorDPM72 = 72000 / 25.4m; - - /// - /// The factor for conversion from DPM to PointWidth or PointHeight. - /// 1000 mm per meter, 25.4 mm per inch => 1000 / 25.4. - /// - private const decimal FactorDPM = 1000 / 25.4m; -#endif - /// /// Gets the width of the image in point. /// @@ -462,59 +230,7 @@ public virtual double PointWidth { get { -#if CORE || GDI || WPF - if (_importedImage != null) - { - if (_importedImage.Information.HorizontalDPM > 0) - return (double)(_importedImage.Information.Width * FactorDPM72 / _importedImage.Information.HorizontalDPM); - if (_importedImage.Information.HorizontalDPI > 0) - return (double)(_importedImage.Information.Width * 72 / _importedImage.Information.HorizontalDPI); - // Assume 72 DPI if information not available. - return _importedImage.Information.Width; - } -#endif - -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Width * 72 / _gdiImage.HorizontalResolution; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - double gdiWidth = _gdiImage.Width * 72 / _gdiImage.HorizontalResolution; - double wpfWidth = _wpfImage.Width * 72.0 / 96.0; - //Debug.Assert(gdiWidth == wpfWidth); - Debug.Assert(DoubleUtil.AreRoughlyEqual(gdiWidth, wpfWidth, 5)); - return wpfWidth; -#endif - //#if GDI && !WPF - // return _gdiImage.Width * 72 / _gdiImage.HorizontalResolution; - //#endif -#if WPF && !GDI -#if !SILVERLIGHT - Debug.Assert(Math.Abs(_wpfImage.PixelWidth * 72 / _wpfImage.DpiX - _wpfImage.Width * 72.0 / 96.0) < 0.001); - return _wpfImage.Width * 72.0 / 96.0; -#else - // AGHACK - return _wpfImage.PixelWidth * 72 / 96.0; -#endif -#endif -#if NETFX_CORE || UWP - //var wb = new WriteableBitmap(); - //GetImagePropertiesAsync - return 100; -#endif -#if __IOS__ - return _iosImage.CGImage.Width * 72.0 / 96.0; -#endif -#if __ANDROID__ - return _androidImage.Width * 72 / 96.0; -#endif -#if PORTABLE return _source.Width * 72 / 96.0; -#endif } } @@ -525,56 +241,7 @@ public virtual double PointHeight { get { -#if CORE || GDI || WPF - if (_importedImage != null) - { - if (_importedImage.Information.VerticalDPM > 0) - return (double)(_importedImage.Information.Height * FactorDPM72 / _importedImage.Information.VerticalDPM); - if (_importedImage.Information.VerticalDPI > 0) - return (double)(_importedImage.Information.Height * 72 / _importedImage.Information.VerticalDPI); - // Assume 72 DPI if information not available. - return _importedImage.Information.Width; - } -#endif - -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Height * 72 / _gdiImage.HorizontalResolution; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - double gdiHeight = _gdiImage.Height * 72 / _gdiImage.HorizontalResolution; - double wpfHeight = _wpfImage.Height * 72.0 / 96.0; - Debug.Assert(DoubleUtil.AreRoughlyEqual(gdiHeight, wpfHeight, 5)); - return wpfHeight; -#endif - //#if GDI && !WPF - // return _gdiImage.Height * 72 / _gdiImage.HorizontalResolution; - //#endif -#if WPF && !GDI -#if !SILVERLIGHT - Debug.Assert(Math.Abs(_wpfImage.PixelHeight * 72 / _wpfImage.DpiY - _wpfImage.Height * 72.0 / 96.0) < 0.001); - return _wpfImage.Height * 72.0 / 96.0; -#else - // AGHACK - return _wpfImage.PixelHeight * 72 / 96.0; -#endif -#endif -#if NETFX_CORE || UWP - return _wrtImage.PixelHeight; //_gdi Image.Width * 72 / _gdiImage.HorizontalResolution; -#endif -#if __IOS__ - return _iosImage.CGImage.Height * 72.0 / 96.0; -#endif -#if __ANDROID__ - return _androidImage.Height * 72 / 96.0; -#endif -#if PORTABLE return _source.Height * 72 / 96.0; -#endif } } @@ -585,51 +252,7 @@ public virtual int PixelWidth { get { -#if CORE || GDI || WPF - if (_importedImage != null) - return (int)_importedImage.Information.Width; -#endif - -#if CORE_WITH_GDI - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Width; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Width; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - int gdiWidth = _gdiImage.Width; - int wpfWidth = _wpfImage.PixelWidth; - Debug.Assert(gdiWidth == wpfWidth); - return wpfWidth; -#endif - //#if GDI && !WPF - // return _gdiImage.Width; - //#endif -#if WPF && !GDI - return _wpfImage.PixelWidth; -#endif -#if NETFX_CORE || UWP - return _wrtImage.PixelWidth; -#endif -#if __IOS__ - return (int) _iosImage.CGImage.Width; -#endif -#if __ANDROID__ - return _androidImage.Width; -#endif -#if PORTABLE return _source.Width; -#endif } } @@ -640,51 +263,7 @@ public virtual int PixelHeight { get { -#if CORE || GDI || WPF - if (_importedImage != null) - return (int)_importedImage.Information.Height; -#endif - -#if CORE_WITH_GDI - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Height; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.Height; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - int gdiHeight = _gdiImage.Height; - int wpfHeight = _wpfImage.PixelHeight; - Debug.Assert(gdiHeight == wpfHeight); - return wpfHeight; -#endif - //#if GDI && !WPF - // return _gdiImage.Height; - //#endif -#if WPF && !GDI - return _wpfImage.PixelHeight; -#endif -#if NETFX_CORE || UWP - return _wrtImage.PixelHeight; -#endif -#if __IOS__ - return (int)_iosImage.CGImage.Height; -#endif -#if __ANDROID__ - return _androidImage.Height; -#endif -#if PORTABLE return _source.Height; -#endif } } @@ -703,51 +282,7 @@ public virtual double HorizontalResolution { get { -#if CORE || GDI || WPF - if (_importedImage != null) - { - if (_importedImage.Information.HorizontalDPI > 0) - return (double)_importedImage.Information.HorizontalDPI; - if (_importedImage.Information.HorizontalDPM > 0) - return (double)(_importedImage.Information.HorizontalDPM / FactorDPM); - return 72; - } -#endif - -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.HorizontalResolution; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - double gdiResolution = _gdiImage.HorizontalResolution; - double wpfResolution = _wpfImage.PixelWidth * 96.0 / _wpfImage.Width; - Debug.Assert(gdiResolution == wpfResolution); - return wpfResolution; -#endif - //#if GDI && !WPF - // return _gdiImage.HorizontalResolution; - //#endif -#if WPF && !GDI -#if !SILVERLIGHT - return _wpfImage.DpiX; //.PixelWidth * 96.0 / _wpfImage.Width; -#else - // AGHACK - return 96; -#endif -#endif -#if NETFX_CORE || UWP - return 96; -#endif -#if __IOS__ || __ANDROID__ return 96; -#endif -#if PORTABLE - return 96; -#endif } } @@ -758,51 +293,7 @@ public virtual double VerticalResolution { get { -#if CORE || GDI || WPF - if (_importedImage != null) - { - if (_importedImage.Information.VerticalDPI > 0) - return (double)_importedImage.Information.VerticalDPI; - if (_importedImage.Information.VerticalDPM > 0) - return (double)(_importedImage.Information.VerticalDPM / FactorDPM); - return 72; - } -#endif - -#if (CORE_WITH_GDI || GDI) && !WPF - try - { - Lock.EnterGdiPlus(); - return _gdiImage.VerticalResolution; - } - finally { Lock.ExitGdiPlus(); } -#endif -#if GDI && WPF - double gdiResolution = _gdiImage.VerticalResolution; - double wpfResolution = _wpfImage.PixelHeight * 96.0 / _wpfImage.Height; - Debug.Assert(gdiResolution == wpfResolution); - return wpfResolution; -#endif - //#if GDI && !WPF - // return _gdiImage.VerticalResolution; - //#endif -#if WPF && !GDI -#if !SILVERLIGHT - return _wpfImage.DpiY; //.PixelHeight * 96.0 / _wpfImage.Height; -#else - // AGHACK - return 96; -#endif -#endif -#if NETFX_CORE || UWP - return 96; -#endif -#if __IOS__ || __ANDROID__ - return 96; -#endif -#if PORTABLE return 96; -#endif } } @@ -825,160 +316,6 @@ public XImageFormat Format } XImageFormat _format; -#if WPF - /// - /// Gets a value indicating whether this image is JPEG. - /// - internal virtual bool IsJpeg - { -#if !SILVERLIGHT - //get { if (!isJpeg.HasValue) InitializeGdiHelper(); return isJpeg.HasValue ? isJpeg.Value : false; } - get - { - if (!_isJpeg.HasValue) - InitializeJpegQuickTest(); - return _isJpeg.HasValue ? _isJpeg.Value : false; - } - //set { isJpeg = value; } -#else - // AGHACK - get { return true; } -#endif - } - private bool? _isJpeg; - - /// - /// Gets a value indicating whether this image is cmyk. - /// - internal virtual bool IsCmyk - { -#if !SILVERLIGHT - get { if (!_isCmyk.HasValue) InitializeGdiHelper(); return _isCmyk.HasValue ? _isCmyk.Value : false; } - //set { isCmyk = value; } -#else - get { return false; } // AGHACK -#endif - } - private bool? _isCmyk; - -#if !SILVERLIGHT - /// - /// Gets the JPEG memory stream (if IsJpeg returns true). - /// - public virtual MemoryStream Memory - { - get - { - if (!_isCmyk.HasValue) InitializeGdiHelper(); - return _memory; - } - //set { memory = value; } - } - MemoryStream _memory; - - /// - /// Determines if an image is JPEG w/o creating an Image object. - /// - private void InitializeJpegQuickTest() - { - if (_stream != null) - _isJpeg = TestJpeg(_stream); - else - _isJpeg = TestJpeg(GetImageFilename(_wpfImage)); - } - - /// - /// Initializes the GDI helper. - /// We use GDI+ to detect if image is JPEG. - /// If so, we also determine if it's CMYK and we read the image bytes. - /// - private void InitializeGdiHelper() - { - if (!_isCmyk.HasValue) - { - try - { - string imageFilename = GetImageFilename(_wpfImage); - // To reduce exceptions, check if file exists. - if (!string.IsNullOrEmpty(imageFilename) && File.Exists(imageFilename)) - { - MemoryStream memory = new MemoryStream(); - using (FileStream file = new FileStream(imageFilename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - byte[] bytes = new byte[file.Length]; - file.Read(bytes, 0, (int)file.Length); - memory.Write(bytes, 0, (int)file.Length); - memory.Seek(0, SeekOrigin.Begin); - } - InitializeJpegHelper(memory); - } - else if (_stream != null) - { - MemoryStream memory = new MemoryStream(); - // If we have a stream, copy data from the stream. - if (_stream != null && _stream.CanSeek) - { - _stream.Seek(0, SeekOrigin.Begin); - byte[] buffer = new byte[32 * 1024]; // 32K buffer. - int bytesRead; - while ((bytesRead = _stream.Read(buffer, 0, buffer.Length)) > 0) - { - memory.Write(buffer, 0, bytesRead); - } - InitializeJpegHelper(memory); - } - } - } - catch { } - } - } - - private void InitializeJpegHelper(MemoryStream memory) - { - using (System.Drawing.Image image = new System.Drawing.Bitmap(memory)) - { - string guid = image.RawFormat.Guid.ToString("B").ToUpper(); - _isJpeg = guid == "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}"; - _isCmyk = (image.Flags & - ((int)System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk | (int)System.Drawing.Imaging.ImageFlags.ColorSpaceYcck)) != 0; - if (_isJpeg.Value) - { - //_memory = new MemoryStream(); - //image.Save(_memory, System.Drawing.Imaging.ImageFormat.Jpeg); - if ((int)memory.Length != 0) - { - _memory = memory; - } - else - { - _memory = null; - } - } - } - } -#endif -#endif - -#if DEBUG_ - // TEST - internal void CreateAllImages(string name) - { - if (image != null) - { - image.Save(name + ".bmp", ImageFormat.Bmp); - image.Save(name + ".emf", ImageFormat.Emf); - image.Save(name + ".exif", ImageFormat.Exif); - image.Save(name + ".gif", ImageFormat.Gif); - image.Save(name + ".ico", ImageFormat.Icon); - image.Save(name + ".jpg", ImageFormat.Jpeg); - image.Save(name + ".png", ImageFormat.Png); - image.Save(name + ".tif", ImageFormat.Tiff); - image.Save(name + ".wmf", ImageFormat.Wmf); - image.Save(name + "2.bmp", ImageFormat.MemoryBmp); - } - } -#endif - internal void AssociateWithGraphics(XGraphics gfx) { if (_associatedGraphics != null) @@ -1009,29 +346,6 @@ internal XGraphics AssociatedGraphics } XGraphics _associatedGraphics; -#if CORE || GDI || WPF - internal ImportedImage _importedImage; -#endif - -#if CORE_WITH_GDI || GDI - internal Image _gdiImage; -#endif -#if WPF - internal BitmapSource _wpfImage; -#if SILVERLIGHT - //internal byte[] _bytes; -#endif -#endif -#if NETFX_CORE || UWP - internal BitmapSource _wrtImage; -#endif -#if __IOS__ - internal UIImage _iosImage; -#endif -#if __ANDROID__ - internal Android.Graphics.Bitmap _androidImage; -#endif - /// /// If path starts with '*' the image is created from a stream and the path is a GUID. /// diff --git a/PdfSharpCore/Drawing/XKnownColorTable.cs b/PdfSharpCore/Drawing/XKnownColorTable.cs index 276c2d3c..e6c93dbf 100644 --- a/PdfSharpCore/Drawing/XKnownColorTable.cs +++ b/PdfSharpCore/Drawing/XKnownColorTable.cs @@ -27,13 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { internal class XKnownColorTable diff --git a/PdfSharpCore/Drawing/XLinearGradientBrush.cs b/PdfSharpCore/Drawing/XLinearGradientBrush.cs index 4f074016..28856f4f 100644 --- a/PdfSharpCore/Drawing/XLinearGradientBrush.cs +++ b/PdfSharpCore/Drawing/XLinearGradientBrush.cs @@ -30,26 +30,6 @@ using System; using System.ComponentModel; using PdfSharpCore.Internal; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiLinearGradientBrush =System.Drawing.Drawing2D.LinearGradientBrush; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -using WpfBrush = System.Windows.Media.Brush; -#endif -#if UWP -using Windows.UI; -using Windows.UI.Xaml.Media; -using Microsoft.Graphics.Canvas; -using Microsoft.Graphics.Canvas.Brushes; -#endif - // ReSharper disable RedundantNameQualifier because it is required for hybrid build namespace PdfSharpCore.Drawing @@ -61,33 +41,6 @@ public sealed class XLinearGradientBrush : XBaseGradientBrush { //internal XLinearGradientBrush(); -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(System.Drawing.Point point1, System.Drawing.Point point2, XColor color1, XColor color2) - : this(new XPoint(point1), new XPoint(point2), color1, color2) - { } -#endif - -#if WPF - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(SysPoint point1, SysPoint point2, XColor color1, XColor color2) - : this(new XPoint(point1), new XPoint(point2), color1, color2) - { } -#endif - -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(PointF point1, PointF point2, XColor color1, XColor color2) - : this(new XPoint(point1), new XPoint(point2), color1, color2) - { } -#endif - /// /// Initializes a new instance of the class. /// @@ -97,30 +50,6 @@ public XLinearGradientBrush(XPoint point1, XPoint point2, XColor color1, XColor _point2 = point2; } -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(Rectangle rect, XColor color1, XColor color2, XLinearGradientMode linearGradientMode) - : this(new XRect(rect), color1, color2, linearGradientMode) - { } - - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(RectangleF rect, XColor color1, XColor color2, XLinearGradientMode linearGradientMode) - : this(new XRect(rect), color1, color2, linearGradientMode) - { } -#endif - -#if WPF - /// - /// Initializes a new instance of the class. - /// - public XLinearGradientBrush(Rect rect, XColor color1, XColor color2, XLinearGradientMode linearGradientMode) - : this(new XRect(rect), color1, color2, linearGradientMode) - { } -#endif /// /// Initializes a new instance of the class. @@ -145,137 +74,6 @@ public XLinearGradientBrush(XRect rect, XColor color1, XColor color2, XLinearGra //public XLinearGradientBrush(RectangleF rect, XColor color1, XColor color2, double angle, bool isAngleScaleable); //public XLinearGradientBrush(RectangleF rect, XColor color1, XColor color2, double angle, bool isAngleScaleable); - -#if GDI - internal override System.Drawing.Brush RealizeGdiBrush() - { - //if (dirty) - //{ - // if (brush == null) - // brush = new SolidBrush(color.ToGdiColor()); - // else - // { - // brush.Color = color.ToGdiColor(); - // } - // dirty = false; - //} - - // TODO: use dirty to optimize code - GdiLinearGradientBrush brush; - try - { - Lock.EnterGdiPlus(); - if (_useRect) - { - brush = new GdiLinearGradientBrush(_rect.ToRectangleF(), - _color1.ToGdiColor(), _color2.ToGdiColor(), (LinearGradientMode)_linearGradientMode); - } - else - { - brush = new GdiLinearGradientBrush( - _point1.ToPointF(), _point2.ToPointF(), - _color1.ToGdiColor(), _color2.ToGdiColor()); - } - if (!_matrix.IsIdentity) - brush.Transform = _matrix.ToGdiMatrix(); - //brush.WrapMode = WrapMode.Clamp; - } - finally { Lock.ExitGdiPlus(); } - return brush; - } -#endif - -#if WPF - internal override WpfBrush RealizeWpfBrush() - { - //if (dirty) - //{ - // if (brush == null) - // brush = new SolidBrush(color.ToGdiColor()); - // else - // { - // brush.Color = color.ToGdiColor(); - // } - // dirty = false; - //} - - System.Windows.Media.LinearGradientBrush brush; - if (_useRect) - { -#if !SILVERLIGHT - brush = new System.Windows.Media.LinearGradientBrush(_color1.ToWpfColor(), _color2.ToWpfColor(), new SysPoint(0, 0), new SysPoint(1, 1));// rect.TopLeft, this.rect.BottomRight); - //brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect.ToRectangleF(), - // color1.ToGdiColor(), color2.ToGdiColor(), (LinearGradientMode)linearGradientMode); -#else - GradientStop gs1 = new GradientStop(); - gs1.Color = _color1.ToWpfColor(); - gs1.Offset = 0; - - GradientStop gs2 = new GradientStop(); - gs2.Color = _color2.ToWpfColor(); - gs2.Offset = 1; - - GradientStopCollection gsc = new GradientStopCollection(); - gsc.Add(gs1); - gsc.Add(gs2); - - brush = new LinearGradientBrush(gsc, 0); - brush.StartPoint = new Point(0, 0); - brush.EndPoint = new Point(1, 1); -#endif - - } - else - { -#if !SILVERLIGHT - brush = new System.Windows.Media.LinearGradientBrush(_color1.ToWpfColor(), _color2.ToWpfColor(), _point1, _point2); - //brush = new System.Drawing.Drawing2D.LinearGradientBrush( - // point1.ToPointF(), point2.ToPointF(), - // color1.ToGdiColor(), color2.ToGdiColor()); -#else - GradientStop gs1 = new GradientStop(); - gs1.Color = _color1.ToWpfColor(); - gs1.Offset = 0; - - GradientStop gs2 = new GradientStop(); - gs2.Color = _color2.ToWpfColor(); - gs2.Offset = 1; - - GradientStopCollection gsc = new GradientStopCollection(); - gsc.Add(gs1); - gsc.Add(gs2); - - brush = new LinearGradientBrush(gsc, 0); - brush.StartPoint = _point1; - brush.EndPoint = _point2; -#endif - } - if (!_matrix.IsIdentity) - { -#if !SILVERLIGHT - brush.Transform = new MatrixTransform(_matrix.ToWpfMatrix()); -#else - MatrixTransform transform = new MatrixTransform(); - transform.Matrix = _matrix.ToWpfMatrix(); - brush.Transform = transform; -#endif - } - return brush; - } -#endif - -#if UWP - internal override ICanvasBrush RealizeCanvasBrush() - { - ICanvasBrush brush; - - brush = new CanvasSolidColorBrush(CanvasDevice.GetSharedDevice(), Colors.RoyalBlue); - - return brush; - } -#endif - - internal bool _useRect; internal XPoint _point1, _point2; internal XRect _rect; diff --git a/PdfSharpCore/Drawing/XMatrix.cs b/PdfSharpCore/Drawing/XMatrix.cs index 617631b3..4605e9eb 100644 --- a/PdfSharpCore/Drawing/XMatrix.cs +++ b/PdfSharpCore/Drawing/XMatrix.cs @@ -31,26 +31,11 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif -#if !EDF_CORE using PdfSharpCore.Internal; -#else -using PdfSharpCore.Internal; -#endif + // ReSharper disable RedundantNameQualifier -#if !EDF_CORE namespace PdfSharpCore.Drawing -#else -namespace Edf.Drawing -#endif { /// /// Represents a 3-by-3 matrix that represents an affine 2D transformation. @@ -693,52 +678,6 @@ public void TransformPoints(XPoint[] points) } } -#if GDI - /// - /// Multiplies all points of the specified array with the this matrix. - /// - public void TransformPoints(System.Drawing.Point[] points) - { - if (points == null) - throw new ArgumentNullException("points"); - - if (IsIdentity) - return; - - int count = points.Length; - for (int idx = 0; idx < count; idx++) - { - double x = points[idx].X; - double y = points[idx].Y; - points[idx].X = (int)(x * _m11 + y * _m21 + _offsetX); - points[idx].Y = (int)(x * _m12 + y * _m22 + _offsetY); - } - } -#endif - -#if WPF - /// - /// Transforms an array of points. - /// - public void TransformPoints(System.Windows.Point[] points) - { - if (points == null) - throw new ArgumentNullException("points"); - - if (IsIdentity) - return; - - int count = points.Length; - for (int idx = 0; idx < count; idx++) - { - double x = points[idx].X; - double y = points[idx].Y; - points[idx].X = (int)(x * _m11 + y * _m21 + _offsetX); - points[idx].Y = (int)(x * _m12 + y * _m22 + _offsetY); - } - } -#endif - /// /// Transforms the specified vector by this Matrix and returns the result. /// @@ -769,30 +708,6 @@ public void Transform(XVector[] vectors) } } -#if GDI - /// - /// Multiplies all vectors of the specified array with the this matrix. The translation elements - /// of this matrix (third row) are ignored. - /// - public void TransformVectors(PointF[] points) - { - if (points == null) - throw new ArgumentNullException("points"); - - if (IsIdentity) - return; - - int count = points.Length; - for (int idx = 0; idx < count; idx++) - { - double x = points[idx].X; - double y = points[idx].Y; - points[idx].X = (float)(x * _m11 + y * _m21 + _offsetX); - points[idx].Y = (float)(x * _m12 + y * _m22 + _offsetY); - } - } -#endif - /// /// Gets the determinant of this matrix. /// @@ -1004,86 +919,6 @@ public double OffsetY } } -#if GDI -//#if UseGdiObjects - /// - /// Converts this matrix to a System.Drawing.Drawing2D.Matrix object. - /// - public System.Drawing.Drawing2D.Matrix ToGdiMatrix() - { - if (IsIdentity) - return new System.Drawing.Drawing2D.Matrix(); - - return new System.Drawing.Drawing2D.Matrix((float)_m11, (float)_m12, (float)_m21, (float)_m22, - (float)_offsetX, (float)_offsetY); - } -//#endif -#endif - -#if WPF - /// Converts this matrix to a System.Windows.Media.Matrix object. - /// - /// - public System.Windows.Media.Matrix ToWpfMatrix() - { - return (System.Windows.Media.Matrix)this; - //return new System.Windows.Media.Matrix(_m11, _m12, _m21, _m22, _offsetX, _offsetY); - } -#endif - -#if GDI - /// - /// Explicitly converts a XMatrix to a Matrix. - /// - public static explicit operator System.Drawing.Drawing2D.Matrix(XMatrix matrix) - { - if (matrix.IsIdentity) - return new System.Drawing.Drawing2D.Matrix(); - - return new System.Drawing.Drawing2D.Matrix( - (float)matrix._m11, (float)matrix._m12, - (float)matrix._m21, (float)matrix._m22, - (float)matrix._offsetX, (float)matrix._offsetY); - } -#endif - -#if WPF - /// - /// Explicitly converts an XMatrix to a Matrix. - /// - public static explicit operator System.Windows.Media.Matrix(XMatrix matrix) - { - if (matrix.IsIdentity) - return new System.Windows.Media.Matrix(); - - return new System.Windows.Media.Matrix( - matrix._m11, matrix._m12, - matrix._m21, matrix._m22, - matrix._offsetX, matrix._offsetY); - } -#endif - -#if GDI - /// - /// Implicitly converts a Matrix to an XMatrix. - /// - public static implicit operator XMatrix(System.Drawing.Drawing2D.Matrix matrix) - { - float[] elements = matrix.Elements; - return new XMatrix(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]); - } -#endif - -#if WPF - /// - /// Implicitly converts a Matrix to an XMatrix. - /// - public static implicit operator XMatrix(System.Windows.Media.Matrix matrix) - { - return new XMatrix(matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.OffsetX, matrix.OffsetY); - } -#endif - /// /// Determines whether the two matrices are equal. /// diff --git a/PdfSharpCore/Drawing/XPdfForm.cs b/PdfSharpCore/Drawing/XPdfForm.cs index 790eb190..f4042d3f 100644 --- a/PdfSharpCore/Drawing/XPdfForm.cs +++ b/PdfSharpCore/Drawing/XPdfForm.cs @@ -29,17 +29,10 @@ using System; using System.IO; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Internal; using PdfSharpCore.Pdf; using PdfSharpCore.Pdf.IO; +using PdfSharpCore.Pdf.IO.enums; namespace PdfSharpCore.Drawing { @@ -59,21 +52,20 @@ public class XPdfForm : XForm /// document. Furthermore, because XPdfForm can occupy very much memory, it is recommended to /// dispose XPdfForm objects if not needed anymore. /// - internal XPdfForm(string path) + internal XPdfForm(string path, PdfReadAccuracy accuracy) { int pageNumber; path = ExtractPageNumber(path, out pageNumber); -#if true // !NETFX_CORE && !PORTABLE path = Path.GetFullPath(path); if (!File.Exists(path)) throw new FileNotFoundException(PSSR.FileNotFound(path)); -#endif if (PdfReader.TestPdfFile(path) == 0) throw new ArgumentException("The specified file has no valid PDF file header.", "path"); _path = path; + _pathReadAccuracy = accuracy; if (pageNumber != 0) PageNumber = pageNumber; } @@ -82,7 +74,8 @@ internal XPdfForm(string path) /// Initializes a new instance of the class from a stream. /// /// The stream. - internal XPdfForm(Stream stream) + /// Moderate allows for broken references. + internal XPdfForm(Stream stream, PdfReadAccuracy accuracy) { // Create a dummy unique path _path = "*" + Guid.NewGuid().ToString("B"); @@ -90,7 +83,7 @@ internal XPdfForm(Stream stream) if (PdfReader.TestPdfFile(stream) == 0) throw new ArgumentException("The specified stream has no valid PDF file header.", "stream"); - _externalDocument = PdfReader.Open(stream); + _externalDocument = PdfReader.Open(stream, accuracy); } /// @@ -98,23 +91,32 @@ internal XPdfForm(Stream stream) /// /// The stream. /// The password. - internal XPdfForm(Stream stream, string password) { + /// Moderate allows for broken references. + internal XPdfForm(Stream stream, string password, PdfReadAccuracy accuracy) { // Create a dummy unique path _path = "*" + Guid.NewGuid().ToString("B"); if (PdfReader.TestPdfFile(stream) == 0) throw new ArgumentException("The specified stream has no valid PDF file header.", "stream"); - _externalDocument = PdfReader.Open(stream, password, PdfDocumentOpenMode.ReadOnly); + _externalDocument = PdfReader.Open(stream, password, PdfDocumentOpenMode.ReadOnly, accuracy); } /// /// Creates an XPdfForm from a file. /// public static new XPdfForm FromFile(string path) + { + return FromFile(path, PdfReadAccuracy.Strict); + } + + /// + /// Creates an XPdfForm from a file. + /// + public static new XPdfForm FromFile(string path, PdfReadAccuracy accuracy) { // TODO: Same file should return same object (that's why the function is static). - return new XPdfForm(path); + return new XPdfForm(path, accuracy); } /// @@ -122,14 +124,29 @@ internal XPdfForm(Stream stream, string password) { /// public static XPdfForm FromStream(Stream stream) { - return new XPdfForm(stream); + return FromStream(stream, PdfReadAccuracy.Strict); + } + + /// + /// Creates an XPdfForm from a stream. + /// + public static XPdfForm FromStream(Stream stream, PdfReadAccuracy accuracy) + { + return new XPdfForm(stream, accuracy); } /// /// Creates an XPdfForm from a stream and a password. /// public static XPdfForm FromStream(Stream stream, string password) { - return new XPdfForm(stream, password); + return FromStream(stream, password, PdfReadAccuracy.Strict); + } + + /// + /// Creates an XPdfForm from a stream and a password. + /// + public static XPdfForm FromStream(Stream stream, string password, PdfReadAccuracy accuracy) { + return new XPdfForm(stream, password, accuracy); } /* @@ -370,12 +387,14 @@ internal PdfDocument ExternalDocument throw new InvalidOperationException("This XPdfForm is a template and not an imported PDF page; therefore it has no external document."); if (_externalDocument == null) - _externalDocument = PdfDocument.Tls.GetDocument(_path); + _externalDocument = PdfDocument.Tls.GetDocument(_path, _pathReadAccuracy); return _externalDocument; } } internal PdfDocument _externalDocument; + private PdfReadAccuracy _pathReadAccuracy; + /// /// Extracts the page number if the path has the form 'MyFile.pdf#123' and returns /// the actual path without the number sign and the following digits. diff --git a/PdfSharpCore/Drawing/XPen.cs b/PdfSharpCore/Drawing/XPen.cs index 1d5101f4..eef2a954 100644 --- a/PdfSharpCore/Drawing/XPen.cs +++ b/PdfSharpCore/Drawing/XPen.cs @@ -29,19 +29,6 @@ using System; using PdfSharpCore.Internal; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiPen = System.Drawing.Pen; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using WpfPen =System.Windows.Media.Pen; -using WpfBrush =System.Windows.Media.Brush; -#endif -#if UWP -#endif namespace PdfSharpCore.Drawing { @@ -300,144 +287,7 @@ public bool Overprint } internal bool _overprint; -#if GDI -#if UseGdiObjects - /// - /// Implicit conversion from Pen to XPen - /// - public static implicit operator XPen(Pen pen) - { - XPen xpen; - try - { - Lock.EnterGdiPlus(); - switch (pen.PenType) - { - case PenType.SolidColor: - xpen = new XPen(pen.Color, pen.Width); - xpen.LineJoin = (XLineJoin)pen.LineJoin; - xpen.DashStyle = (XDashStyle)pen.DashStyle; - xpen._miterLimit = pen.MiterLimit; - break; - - default: - throw new NotImplementedException("Pen type not supported by PdfSharpCore."); - } - // Bug fixed by drice2@ageone.de - if (pen.DashStyle == System.Drawing.Drawing2D.DashStyle.Custom) - { - int length = pen.DashPattern.Length; - double[] pattern = new double[length]; - for (int idx = 0; idx < length; idx++) - pattern[idx] = pen.DashPattern[idx]; - xpen.DashPattern = pattern; - xpen._dashOffset = pen.DashOffset; - } - } - finally { Lock.ExitGdiPlus(); } - return xpen; - } -#endif - - internal System.Drawing.Pen RealizeGdiPen() - { - if (_dirty) - { - if (_gdiPen == null) - _gdiPen = new System.Drawing.Pen(_color.ToGdiColor(), (float)_width); - else - { - _gdiPen.Color = _color.ToGdiColor(); - _gdiPen.Width = (float)_width; - } - LineCap lineCap = XConvert.ToLineCap(_lineCap); - _gdiPen.StartCap = lineCap; - _gdiPen.EndCap = lineCap; - _gdiPen.LineJoin = XConvert.ToLineJoin(_lineJoin); - _gdiPen.DashOffset = (float)_dashOffset; - if (_dashStyle == XDashStyle.Custom) - { - int len = _dashPattern == null ? 0 : _dashPattern.Length; - float[] pattern = new float[len]; - for (int idx = 0; idx < len; idx++) - pattern[idx] = (float)_dashPattern[idx]; - _gdiPen.DashPattern = pattern; - } - else - _gdiPen.DashStyle = (System.Drawing.Drawing2D.DashStyle)_dashStyle; - } - return _gdiPen; - } -#endif - -#if WPF - internal WpfPen RealizeWpfPen() - { -#if !SILVERLIGHT - if (_dirty || !_dirty) // TODOWPF: XPen is frozen by design, WPF Pen can change - { - //if (_wpfPen == null) - _wpfPen = new WpfPen(new SolidColorBrush(_color.ToWpfColor()), _width); - //else - //{ - // _wpfPen.Brush = new SolidColorBrush(_color.ToWpfColor()); - // _wpfPen.Thickness = _width; - //} - PenLineCap lineCap = XConvert.ToPenLineCap(_lineCap); - _wpfPen.StartLineCap = lineCap; - _wpfPen.EndLineCap = lineCap; - _wpfPen.LineJoin = XConvert.ToPenLineJoin(_lineJoin); - if (_dashStyle == XDashStyle.Custom) - { - // TODOWPF: does not work in all cases - _wpfPen.DashStyle = new System.Windows.Media.DashStyle(_dashPattern, _dashOffset); - } - else - { - switch (_dashStyle) - { - case XDashStyle.Solid: - _wpfPen.DashStyle = DashStyles.Solid; - break; - - case XDashStyle.Dash: - //_wpfPen.DashStyle = DashStyles.Dash; - _wpfPen.DashStyle = new System.Windows.Media.DashStyle(new double[] { 2, 2 }, 0); - break; - - case XDashStyle.Dot: - //_wpfPen.DashStyle = DashStyles.Dot; - _wpfPen.DashStyle = new System.Windows.Media.DashStyle(new double[] { 0, 2 }, 1.5); - break; - - case XDashStyle.DashDot: - //_wpfPen.DashStyle = DashStyles.DashDot; - _wpfPen.DashStyle = new System.Windows.Media.DashStyle(new double[] { 2, 2, 0, 2 }, 0); - break; - - case XDashStyle.DashDotDot: - //_wpfPen.DashStyle = DashStyles.DashDotDot; - _wpfPen.DashStyle = new System.Windows.Media.DashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 0); - break; - } - } - } -#else - _wpfPen = new System.Windows.Media.Pen(); - _wpfPen.Brush = new SolidColorBrush(_color.ToWpfColor()); - _wpfPen.Thickness = _width; -#endif - return _wpfPen; - } -#endif - bool _dirty = true; readonly bool _immutable; -#if GDI - GdiPen _gdiPen; -#endif -#if WPF - WpfPen _wpfPen; -#endif } } \ No newline at end of file diff --git a/PdfSharpCore/Drawing/XPoint.cs b/PdfSharpCore/Drawing/XPoint.cs index 6d03c4f0..78417a68 100644 --- a/PdfSharpCore/Drawing/XPoint.cs +++ b/PdfSharpCore/Drawing/XPoint.cs @@ -31,32 +31,9 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; -#if CORE -#endif -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -#endif -#if !EDF_CORE -using PdfSharpCore.Internal; -#else using PdfSharpCore.Internal; -#endif -#if !EDF_CORE namespace PdfSharpCore.Drawing -#else -namespace Edf.Drawing -#endif { /// /// Represents a pair of floating point x- and y-coordinates that defines a point @@ -76,39 +53,6 @@ public XPoint(double x, double y) _y = y; } -#if GDI - /// - /// Initializes a new instance of the XPoint class with the specified point. - /// - public XPoint(System.Drawing.Point point) - { - _x = point.X; - _y = point.Y; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Initializes a new instance of the XPoint class with the specified point. - /// - public XPoint(SysPoint point) - { - _x = point.X; - _y = point.Y; - } -#endif - -#if GDI - /// - /// Initializes a new instance of the XPoint class with the specified point. - /// - public XPoint(PointF point) - { - _x = point.X; - _y = point.Y; - } -#endif - /// /// Determines whether two points are equal. /// @@ -211,38 +155,6 @@ public double Y } double _y; -#if CORE -#if UseGdiObjects - /// - /// Converts this XPoint to a System.Drawing.Point. - /// - public PointF ToPointF() - { - return new PointF((float)_x, (float)_y); - } -#endif -#endif - -#if GDI - /// - /// Converts this XPoint to a System.Drawing.Point. - /// - public PointF ToPointF() - { - return new PointF((float)_x, (float)_y); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Converts this XPoint to a System.Windows.Point. - /// - public SysPoint ToPoint() - { - return new SysPoint(_x, _y); - } -#endif - /// /// Converts this XPoint to a human readable string. /// diff --git a/PdfSharpCore/Drawing/XPrivateFontCollection.cs b/PdfSharpCore/Drawing/XPrivateFontCollection.cs index 4116b9d3..cea85631 100644 --- a/PdfSharpCore/Drawing/XPrivateFontCollection.cs +++ b/PdfSharpCore/Drawing/XPrivateFontCollection.cs @@ -27,31 +27,10 @@ // DEALINGS IN THE SOFTWARE. #endregion -using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using PdfSharpCore.Fonts; -#if CORE || GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -using GdiPrivateFontCollection = System.Drawing.Text.PrivateFontCollection; -#endif -#if WPF -using System.Windows.Markup; -using WpfFonts = System.Windows.Media.Fonts; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -#endif namespace PdfSharpCore.Drawing { -#if true /// /// Makes fonts that are not installed on the system available within the current application domain.
/// In Silverlight required for all fonts used in PDF documents. @@ -68,25 +47,6 @@ public sealed class XPrivateFontCollection // HACK: Use one global PrivateFontCollection in GDI+ } -#if GDI - //internal PrivateFontCollection PrivateFontCollection - //{ - // get { return privateFontCollection; } - // set { privateFontCollection = value; } - //} - - GdiPrivateFontCollection GetPrivateFontCollection() - { - // Create only if really needed. - if (_privateFontCollection == null) - _privateFontCollection = new GdiPrivateFontCollection(); - return _privateFontCollection; - } - - // PrivateFontCollection of GDI+ - private GdiPrivateFontCollection _privateFontCollection; -#endif - /// /// Gets the global font collection. /// @@ -96,296 +56,6 @@ internal static XPrivateFontCollection Singleton } internal static XPrivateFontCollection _singleton = new XPrivateFontCollection(); -#if GDI - /// - /// Adds the font data to the font collections. - /// - [Obsolete("Use Add(Stream stream)")] - public void AddFont(byte[] data, string familyName) - { - if (String.IsNullOrEmpty(familyName)) - throw new ArgumentNullException("familyName"); - - //if (glyphTypeface == null) - // throw new ArgumentNullException("glyphTypeface"); - - // Add to GDI+ PrivateFontCollection - int length = data.Length; - - // Copy data without unsafe code - IntPtr ip = Marshal.AllocCoTaskMem(length); - Marshal.Copy(data, 0, ip, length); - GetPrivateFontCollection().AddMemoryFont(ip, length); - // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! - //Marshal.FreeCoTaskMem(ip); - //privateFonts.Add(glyphTypeface); - } -#endif - -#if GDI - /// - /// Adds the specified font data to the global PrivateFontCollection. - /// Family name and style are automatically retrieved from the font. - /// - [Obsolete("Use Add(stream).")] - public static void AddFont(Stream stream) - { - Add(stream); - } - - /// - /// Adds the specified font data to the global PrivateFontCollection. - /// Family name and style are automatically retrieved from the font. - /// - public static void Add(Stream stream) - { - int length = (int)stream.Length; - byte[] bytes = new byte[length]; - stream.Read(bytes, 0, length); - Add(bytes); - } - - /// - /// Adds the specified font data to the global PrivateFontCollection. - /// Family name and style are automatically retrieved from the font. - /// - public static void Add(byte[] font) - { - IntPtr unmanagedPointer = Marshal.AllocCoTaskMem(font.Length); - Marshal.Copy(font, 0, unmanagedPointer, font.Length); - Singleton.GetPrivateFontCollection().AddMemoryFont(unmanagedPointer, font.Length); - // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! - //Marshal.FreeCoTaskMem(ip); - - XFontSource fontSource = XFontSource.GetOrCreateFrom(font); - - string familyName = fontSource.FontName; - - if (familyName.EndsWith(" Regular", StringComparison.OrdinalIgnoreCase)) - familyName = familyName.Substring(0, familyName.Length - 8); - - bool bold = fontSource.Fontface.os2.IsBold; - bool italic = fontSource.Fontface.os2.IsItalic; - IncompetentlyMakeAHackToFixAProblemYouWoldNeverHaveIfYouUseAFontResolver(fontSource, ref familyName, ref bold, ref italic); - string key = MakeKey(familyName, bold, italic); - Singleton._fontSources.Add(key, fontSource); - - string typefaceKey = XGlyphTypeface.ComputeKey(familyName, bold, italic); - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - - static void IncompetentlyMakeAHackToFixAProblemYouWoldNeverHaveIfYouUseAFontResolver(XFontSource fontSource, - ref string familyName, ref bool bold, ref bool italic) - { - const string regularSuffix = " Regular"; - const string boldSuffix = " Bold"; - const string italicSuffix = " Italic"; - const string boldItalicSuffix = " Bold Italic"; - const string italicBoldSuffix = " Italic Bold"; - - if (familyName.EndsWith(regularSuffix, StringComparison.OrdinalIgnoreCase)) - { - familyName = familyName.Substring(0, familyName.Length - regularSuffix.Length); - Debug.Assert(!bold && !italic); - bold = italic = false; - } - else if (familyName.EndsWith(boldItalicSuffix, StringComparison.OrdinalIgnoreCase) || familyName.EndsWith(italicBoldSuffix, StringComparison.OrdinalIgnoreCase)) - { - familyName = familyName.Substring(0, familyName.Length - boldItalicSuffix.Length); - Debug.Assert(bold && italic); - bold = italic = true; - } - else if (familyName.EndsWith(boldSuffix, StringComparison.OrdinalIgnoreCase)) - { - familyName = familyName.Substring(0, familyName.Length - boldSuffix.Length); - Debug.Assert(bold && !italic); - bold = true; - italic = false; - } - else if (familyName.EndsWith(italicSuffix, StringComparison.OrdinalIgnoreCase)) - { - familyName = familyName.Substring(0, familyName.Length - italicSuffix.Length); - Debug.Assert(!bold && italic); - bold = false; - italic = true; - } - else - { - Debug.Assert(!bold && !italic); - bold = false; - italic = false; - } - } -#endif - - // /// - // /// Adds XGlyphTypeface to internal collection. - // /// Family name and style are automatically retrieved from the font. - // /// - // void AddGlyphTypeface(XGlyphTypeface glyphTypeface) - // { - // string name = MakeName(glyphTypeface); - // if (_typefaces.ContainsKey(name)) - // throw new InvalidOperationException(PSSR.FontAlreadyAdded(glyphTypeface.DisplayName)); - - // _typefaces.Add(name, glyphTypeface); - // //Debug.WriteLine("Font added: " + name); - - //#if GDI - // // Add to GDI+ PrivateFontCollection singleton. - // byte[] data = glyphTypeface.Fontface.FontSource.Bytes; - // int length = data.Length; - - // IntPtr ip = Marshal.AllocCoTaskMem(length); - // Marshal.Copy(data, 0, ip, length); - // _privateFontCollection.AddMemoryFont(ip, length); - // // Do not free the memory here, AddMemoryFont stores a pointer, not a copy! - // // Marshal.FreeCoTaskMem(ip); - //#endif - - //#if WPF - //#endif - // } - -#if WPF - /// - /// Initializes a new instance of the FontFamily class from the specified font family name and an optional base uniform resource identifier (URI) value. - /// Sample: Add(new Uri("pack://application:,,,/"), "./myFonts/#FontFamilyName");) - /// - /// Specifies the base URI that is used to resolve familyName. - /// The family name or names that comprise the new FontFamily. Multiple family names should be separated by commas. - public static void Add(Uri baseUri, string familyName) - { - Uri uri = new Uri("pack://application:,,,/"); - - // TODO: What means 'Multiple family names should be separated by commas.'? - // does not work - - - if (String.IsNullOrEmpty(familyName)) - throw new ArgumentNullException("familyName"); - - if (familyName.Contains(",")) - throw new NotImplementedException("Only one family name is supported."); - - // Family name starts right of '#'. - int idxHash = familyName.IndexOf('#'); - if (idxHash < 0) - throw new ArgumentException("Family name must contain a '#'. Example './#MyFontFamilyName'", "familyName"); - - string key = familyName.Substring(idxHash + 1); - if (String.IsNullOrEmpty(key)) - throw new ArgumentException("familyName has invalid format."); - - if (Singleton._fontFamilies.ContainsKey(key)) - throw new ArgumentException("An entry with the specified family name already exists."); - -#if !SILVERLIGHT -#if DEBUG_ - foreach (WpfFontFamily fontFamily1 in WpfFonts.GetFontFamilies(baseUri, familyName)) - { - ICollection wpfTypefaces = fontFamily1.GetTypefaces(); - wpfTypefaces.GetType(); - } -#endif - // Create WPF font family. - WpfFontFamily fontFamily = new WpfFontFamily(baseUri, familyName); - //System.Windows.Media.FontFamily x; - // Required for new Uri("pack://application:,,,/") - // ReSharper disable once ObjectCreationAsStatement - // new System.Windows.Application(); - -#else - System.Windows.Media.FontFamily fontFamily = new System.Windows.Media.FontFamily(familyName); -#endif - - // Check whether font data really exists -#if DEBUG && !SILVERLIGHT - ICollection list = fontFamily.GetTypefaces(); - foreach (WpfTypeface typeFace in list) - { - Debug.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}", familyName, typeFace.FaceNames[FontHelper.XmlLanguageEnUs], typeFace.Style, typeFace.Weight, typeFace.Stretch)); - WpfGlyphTypeface glyphTypeface; - if (!typeFace.TryGetGlyphTypeface(out glyphTypeface)) - { - Debug.WriteLine(" Glyph typeface does not exists."); - //throw new ArgumentException("Font with the specified family name does not exist."); - } - } -#endif - - Singleton._fontFamilies.Add(key, fontFamily); - } -#endif - - //internal static XGlyphTypeface TryGetXGlyphTypeface(string familyName, XFontStyle style) - //{ - // string name = MakeName(familyName, style); - - // XGlyphTypeface typeface; - // _global._typefaces.TryGetValue(name, out typeface); - // return typeface; - //} - -#if GDI - internal static GdiFont TryCreateFont(string name, double size, GdiFontStyle style, out XFontSource fontSource) - { - fontSource = null; - try - { - GdiPrivateFontCollection pfc = Singleton._privateFontCollection; - if (pfc == null) - return null; -#if true - string key = MakeKey(name, (XFontStyle)style); - if (Singleton._fontSources.TryGetValue(key, out fontSource)) - { - GdiFont font = new GdiFont(name, (float)size, style, GraphicsUnit.World); -#if DEBUG_ - Debug.Assert(StringComparer.OrdinalIgnoreCase.Compare(name, font.Name) == 0); - Debug.Assert(font.Bold == ((style & GdiFontStyle.Bold) != 0)); - Debug.Assert(font.Italic == ((style & GdiFontStyle.Italic) != 0)); -#endif - return font; - } - return null; -#else - foreach (GdiFontFamily family in pfc.Families) - { - if (string.Compare(family.Name, name, StringComparison.OrdinalIgnoreCase) == 0) - { - GdiFont font = new GdiFont(family, (float)size, style, GraphicsUnit.World); - if (string.Compare(font.Name, name, StringComparison.OrdinalIgnoreCase) != 0) - { - // Style simulation is not implemented in GDI+. - // Use WPF build. - } - return font; - } - } -#endif - } - catch (Exception ex) - { - // Ignore exception and return null. - Debug.WriteLine(ex.ToString()); - } - return null; - } -#endif - -#if WPF && !SILVERLIGHT - internal static WpfTypeface TryCreateTypeface(string name, XFontStyle style, out WpfFontFamily fontFamily) - { - if (Singleton._fontFamilies.TryGetValue(name, out fontFamily)) - { - WpfTypeface typeface = FontHelper.CreateTypeface(fontFamily, style); - return typeface; - } - return null; - } -#endif - static string MakeKey(string familyName, XFontStyle style) { return MakeKey(familyName, (style & XFontStyle.Bold) != 0, (style & XFontStyle.Italic) != 0); @@ -397,13 +67,5 @@ static string MakeKey(string familyName, bool bold, bool italic) } readonly Dictionary _typefaces = new Dictionary(); -#if GDI - //List privateFonts = new List(); - readonly Dictionary _fontSources = new Dictionary(StringComparer.OrdinalIgnoreCase); -#endif -#if WPF - readonly Dictionary _fontFamilies = new Dictionary(StringComparer.OrdinalIgnoreCase); -#endif } -#endif } diff --git a/PdfSharpCore/Drawing/XRadialGradientBrush.cs b/PdfSharpCore/Drawing/XRadialGradientBrush.cs index e8a7a972..168ba7ea 100644 --- a/PdfSharpCore/Drawing/XRadialGradientBrush.cs +++ b/PdfSharpCore/Drawing/XRadialGradientBrush.cs @@ -30,26 +30,6 @@ using System; using System.ComponentModel; using PdfSharpCore.Internal; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -//using GdiLinearGradientBrush = System.Drawing.Drawing2D.LinearGradientBrush; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -using WpfBrush = System.Windows.Media.Brush; -#endif -#if UWP -using Windows.UI; -using Windows.UI.Xaml.Media; -using Microsoft.Graphics.Canvas; -using Microsoft.Graphics.Canvas.Brushes; -#endif - // ReSharper disable RedundantNameQualifier because it is required for hybrid build namespace PdfSharpCore.Drawing @@ -61,33 +41,6 @@ public sealed class XRadialGradientBrush : XBaseGradientBrush { //internal XRadialGradientBrush(); -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XRadialGradientBrush(System.Drawing.Point center1, System.Drawing.Point center2, double r1, double r2, XColor color1, XColor color2) - : this(new XPoint(center1), new XPoint(center2), r1, r2, color1, color2) - { } -#endif - -#if WPF - /// - /// Initializes a new instance of the class. - /// - public XRadialGradientBrush(SysPoint center1, SysPoint center2, double r1, double r2, XColor color1, XColor color2) - : this(new XPoint(center1), mew XPoint(center2), r1, r2, color1, color2) - { } -#endif - -#if GDI - /// - /// Initializes a new instance of the class. - /// - public XRadialGradientBrush(PointF center1, PointF center2, double r1, double r2, XColor color1, XColor color2) - : this(new XPoint(center1), new XPoint(center2), r1, r2, color1, color2) - { } -#endif - /// /// Initializes a new instance of the class. /// @@ -110,151 +63,6 @@ public XRadialGradientBrush(XPoint center, double r1, double r2, XColor color1, _r2 = r2; } - -#if GDI - internal override System.Drawing.Brush RealizeGdiBrush() - { - //if (dirty) - //{ - // if (brush == null) - // brush = new SolidBrush(color.ToGdiColor()); - // else - // { - // brush.Color = color.ToGdiColor(); - // } - // dirty = false; - //} - - // TODO: use dirty to optimize code - PathGradientBrush brush; - try - { - Lock.EnterGdiPlus(); - - GraphicsPath gp = new GraphicsPath(); - - - - gp.AddEllipse(); - - PathGradientBrush pgb = new PathGradientBrush(gp); - - pgb.CenterPoint = new PointF(label1.ClientRectangle.Width / 2, - label1.ClientRectangle.Height / 2); - pgb.CenterColor = Color.White; - pgb.SurroundingColors = new Color[] { Color.Red }; - - - if (_useRect) - { - brush = new PathGradientBrush(_rect.ToRectangleF(), - _color1.ToGdiColor(), _color2.ToGdiColor(), (LinearGradientMode)_linearGradientMode); - } - else - { - brush = new GdiLinearGradientBrush( - _center.ToPointF(), _point2.ToPointF(), - _color1.ToGdiColor(), _color2.ToGdiColor()); - } - if (!_matrix.IsIdentity) - brush.Transform = _matrix.ToGdiMatrix(); - //brush.WrapMode = WrapMode.Clamp; - } - finally { Lock.ExitGdiPlus(); } - return brush; - } -#endif - -#if WPF - internal override WpfBrush RealizeWpfBrush() - { - //if (dirty) - //{ - // if (brush == null) - // brush = new SolidBrush(color.ToGdiColor()); - // else - // { - // brush.Color = color.ToGdiColor(); - // } - // dirty = false; - //} - - System.Windows.Media.LinearGradientBrush brush; - if (_useRect) - { -#if !SILVERLIGHT - brush = new System.Windows.Media.LinearGradientBrush(_color1.ToWpfColor(), _color2.ToWpfColor(), new SysPoint(0, 0), new SysPoint(1, 1));// rect.TopLeft, this.rect.BottomRight); - //brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect.ToRectangleF(), - // color1.ToGdiColor(), color2.ToGdiColor(), (LinearGradientMode)linearGradientMode); -#else - GradientStop gs1 = new GradientStop(); - gs1.Color = _color1.ToWpfColor(); - gs1.Offset = 0; - - GradientStop gs2 = new GradientStop(); - gs2.Color = _color2.ToWpfColor(); - gs2.Offset = 1; - - GradientStopCollection gsc = new GradientStopCollection(); - gsc.Add(gs1); - gsc.Add(gs2); - - brush = new LinearGradientBrush(gsc, 0); - brush.StartPoint = new Point(0, 0); - brush.EndPoint = new Point(1, 1); -#endif - - } - else - { -#if !SILVERLIGHT - brush = new System.Windows.Media.LinearGradientBrush(_color1.ToWpfColor(), _color2.ToWpfColor(), _center, _point2); - //brush = new System.Drawing.Drawing2D.LinearGradientBrush( - // center.ToPointF(), point2.ToPointF(), - // color1.ToGdiColor(), color2.ToGdiColor()); -#else - GradientStop gs1 = new GradientStop(); - gs1.Color = _color1.ToWpfColor(); - gs1.Offset = 0; - - GradientStop gs2 = new GradientStop(); - gs2.Color = _color2.ToWpfColor(); - gs2.Offset = 1; - - GradientStopCollection gsc = new GradientStopCollection(); - gsc.Add(gs1); - gsc.Add(gs2); - - brush = new LinearGradientBrush(gsc, 0); - brush.StartPoint = _center; - brush.EndPoint = _point2; -#endif - } - if (!_matrix.IsIdentity) - { -#if !SILVERLIGHT - brush.Transform = new MatrixTransform(_matrix.ToWpfMatrix()); -#else - MatrixTransform transform = new MatrixTransform(); - transform.Matrix = _matrix.ToWpfMatrix(); - brush.Transform = transform; -#endif - } - return brush; - } -#endif - -#if UWP - internal override ICanvasBrush RealizeCanvasBrush() - { - ICanvasBrush brush; - - brush = new CanvasSolidColorBrush(CanvasDevice.GetSharedDevice(), Colors.RoyalBlue); - - return brush; - } -#endif - internal XPoint _center1, _center2; internal double _r1, _r2; } diff --git a/PdfSharpCore/Drawing/XRect.cs b/PdfSharpCore/Drawing/XRect.cs index ccc45922..2559f7ae 100644 --- a/PdfSharpCore/Drawing/XRect.cs +++ b/PdfSharpCore/Drawing/XRect.cs @@ -31,30 +31,7 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; -#if CORE -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -using SysRect = System.Windows.Rect; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -using SysRect = Windows.Foundation.Rect; -#endif -#if !EDF_CORE using PdfSharpCore.Internal; -#else -using PdfSharpCore.Internal; -#endif namespace PdfSharpCore.Drawing { @@ -127,45 +104,6 @@ public XRect(XSize size) } } -#if GDI - /// - /// Initializes a new instance of the XRect class. - /// - public XRect(PointF location, SizeF size) - { - _x = location.X; - _y = location.Y; - _width = size.Width; - _height = size.Height; - } -#endif - -#if GDI - /// - /// Initializes a new instance of the XRect class. - /// - public XRect(RectangleF rect) - { - _x = rect.X; - _y = rect.Y; - _width = rect.Width; - _height = rect.Height; - } -#endif - -#if WPF || NETFX_CORE - /// - /// Initializes a new instance of the XRect class. - /// - public XRect(SysRect rect) - { - _x = rect.X; - _y = rect.Y; - _width = rect.Width; - _height = rect.Height; - } -#endif - /// /// Creates a rectangle from for straight lines. /// @@ -755,56 +693,6 @@ public void Scale(double scaleX, double scaleY) } } -#if CORE // Internal version in CORE build. -#if UseGdiObjects - /// - /// Converts this instance to a System.Drawing.RectangleF. - /// - internal RectangleF ToRectangleF() - { - return new RectangleF((float)_x, (float)_y, (float)_width, (float)_height); - } -#endif -#endif - -#if GDI - /// - /// Converts this instance to a System.Drawing.RectangleF. - /// - public RectangleF ToRectangleF() - { - return new RectangleF((float)_x, (float)_y, (float)_width, (float)_height); - } -#endif - -#if GDI - /// - /// Performs an implicit conversion from a System.Drawing.Rectangle to an XRect. - /// - public static implicit operator XRect(Rectangle rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// - /// Performs an implicit conversion from a System.Drawing.RectangleF to an XRect. - /// - public static implicit operator XRect(RectangleF rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Performs an implicit conversion from System.Windows.Rect to XRect. - /// - public static implicit operator XRect(SysRect rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } -#endif - bool ContainsInternal(double x, double y) { return x >= _x && x - _width <= _x && y >= _y && y - _height <= _y; diff --git a/PdfSharpCore/Drawing/XSize.cs b/PdfSharpCore/Drawing/XSize.cs index 4e3090bb..2897b08a 100644 --- a/PdfSharpCore/Drawing/XSize.cs +++ b/PdfSharpCore/Drawing/XSize.cs @@ -31,24 +31,7 @@ using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -using SysPoint = System.Windows.Point; -using SysSize = System.Windows.Size; -#endif -#if NETFX_CORE -using Windows.UI.Xaml.Media; -using SysPoint = Windows.Foundation.Point; -using SysSize = Windows.Foundation.Size; -#endif -#if !EDF_CORE using PdfSharpCore.Internal; -#else -using PdfSharpCore.Internal; -#endif namespace PdfSharpCore.Drawing { @@ -145,16 +128,6 @@ public static XSize Parse(string source) return empty; } -#if GDI - /// - /// Converts this XSize to a PointF. - /// - public PointF ToPointF() - { - return new PointF((float)_width, (float)_height); - } -#endif - /// /// Converts this XSize to an XPoint. /// @@ -171,65 +144,6 @@ public XVector ToXVector() return new XVector(_width, _height); } -#if GDI - /// - /// Converts this XSize to a SizeF. - /// - public SizeF ToSizeF() - { - return new SizeF((float)_width, (float)_height); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Converts this XSize to a System.Windows.Size. - /// - public SysSize ToSize() - { - return new SysSize(_width, _height); - } -#endif - -#if GDI - /// - /// Creates an XSize from a System.Drawing.Size. - /// - public static XSize FromSize(System.Drawing.Size size) - { - return new XSize(size.Width, size.Height); - } - - /// - /// Implicit conversion from XSize to System.Drawing.Size. The conversion must be implicit because the - /// WinForms designer uses it. - /// - public static implicit operator XSize(System.Drawing.Size size) - { - return new XSize(size.Width, size.Height); - } -#endif - -#if WPF || NETFX_CORE - /// - /// Creates an XSize from a System.Drawing.Size. - /// - public static XSize FromSize(SysSize size) - { - return new XSize(size.Width, size.Height); - } -#endif - -#if GDI - /// - /// Creates an XSize from a System.Drawing.Size. - /// - public static XSize FromSizeF(SizeF size) - { - return new XSize(size.Width, size.Height); - } -#endif - /// /// Converts this XSize to a human readable string. /// @@ -333,16 +247,6 @@ public static explicit operator XPoint(XSize size) return new XPoint(size._width, size._height); } -#if WPF || NETFX_CORE - /// - /// Performs an explicit conversion from Size to XSize. - /// - public static explicit operator XSize(SysSize size) - { - return new XSize(size.Width, size.Height); - } -#endif - private static XSize CreateEmptySize() { XSize size = new XSize(); diff --git a/PdfSharpCore/Drawing/XSolidBrush.cs b/PdfSharpCore/Drawing/XSolidBrush.cs index ae9e1e9a..ebeec182 100644 --- a/PdfSharpCore/Drawing/XSolidBrush.cs +++ b/PdfSharpCore/Drawing/XSolidBrush.cs @@ -28,19 +28,6 @@ #endregion using System; -using System.Diagnostics; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif -#if UWP -using Microsoft.Graphics.Canvas; -using Microsoft.Graphics.Canvas.Brushes; -using UwpBrush = Windows.UI.Xaml.Media.Brush; -#endif namespace PdfSharpCore.Drawing { @@ -86,15 +73,6 @@ public XColor Color { if (_immutable) throw new ArgumentException(PSSR.CannotChangeImmutableObject("XSolidBrush")); -#if GDI - _gdiDirty = _gdiDirty || _color != value; -#endif -#if WPF - _wpfDirty = _wpfDirty || _color != value; -#endif -#if GDI && WPF - _gdiDirty = _wpfDirty = true; -#endif _color = value; } } @@ -115,64 +93,6 @@ public bool Overprint } } internal bool _overprint; - -#if GDI - internal override System.Drawing.Brush RealizeGdiBrush() - { - if (_gdiDirty) - { - if (_gdiBrush == null) - _gdiBrush = new SolidBrush(_color.ToGdiColor()); - else - _gdiBrush.Color = _color.ToGdiColor(); - _gdiDirty = false; - } - -#if DEBUG - System.Drawing.Color clr = _color.ToGdiColor(); - SolidBrush brush1 = new SolidBrush(clr); - Debug.Assert(_gdiBrush.Color == brush1.Color); -#endif - return _gdiBrush; - } -#endif - -#if WPF - internal override System.Windows.Media.Brush RealizeWpfBrush() - { - if (_wpfDirty) - { - if (_wpfBrush == null) - _wpfBrush = new SolidColorBrush(_color.ToWpfColor()); - else - _wpfBrush.Color = _color.ToWpfColor(); - _wpfDirty = false; - } - -#if DEBUG_ - System.Windows.Media.Color clr = _color.ToWpfColor(); - System.Windows.Media.SolidColorBrush brush1 = new System.Windows.Media.SolidColorBrush(clr); //System.Drawing.Color.FromArgb(128, 128, 0, 0)); - Debug.Assert(_wpfBrush.Color == brush1.Color); // Crashes during unit testing -#endif - return _wpfBrush; - } -#endif - -#if UWP - internal override ICanvasBrush RealizeCanvasBrush() - { - return new CanvasSolidColorBrush(CanvasDevice.GetSharedDevice(), _color.ToUwpColor()); - } -#endif - -#if GDI - bool _gdiDirty = true; - SolidBrush _gdiBrush; -#endif -#if WPF - bool _wpfDirty = true; - SolidColorBrush _wpfBrush; -#endif readonly bool _immutable; } } diff --git a/PdfSharpCore/Drawing/XStringFormat.cs b/PdfSharpCore/Drawing/XStringFormat.cs index f2406b28..4373498f 100644 --- a/PdfSharpCore/Drawing/XStringFormat.cs +++ b/PdfSharpCore/Drawing/XStringFormat.cs @@ -28,40 +28,9 @@ #endregion using System; -#if CORE -#endif -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif namespace PdfSharpCore.Drawing { -#if true_ - /// - /// Not used in this implementation. - /// - [Flags] - public enum XStringFormatFlags - { - //DirectionRightToLeft = 0x0001, - //DirectionVertical = 0x0002, - //FitBlackBox = 0x0004, - //DisplayFormatControl = 0x0020, - //NoFontFallback = 0x0400, - /// - /// The default value. - /// - MeasureTrailingSpaces = 0x0800, - //NoWrap = 0x1000, - //LineLimit = 0x2000, - //NoClip = 0x4000, - } -#endif - /// /// Represents the text layout information. /// @@ -72,9 +41,6 @@ public class XStringFormat ///
public XStringFormat() { -#if WPF - GetType(); // Make ReSharper happy. -#endif } //TODO public StringFormat(StringFormat format); @@ -99,15 +65,6 @@ public XStringAlignment Alignment set { _alignment = value; -#if CORE || GDI -#if UseGdiObjects - // Update StringFormat only if it exists. - if (_stringFormat != null) - { - _stringFormat.Alignment = (StringAlignment)value; - } -#endif -#endif } } XStringAlignment _alignment; @@ -128,48 +85,9 @@ public XLineAlignment LineAlignment set { _lineAlignment = value; -#if CORE || GDI -#if UseGdiObjects - // Update StringFormat only if it exists. - if (_stringFormat != null) - { - // BaseLine is specific to PdfSharpCore. - if (value == XLineAlignment.BaseLine) - _stringFormat.LineAlignment = StringAlignment.Near; - else - _stringFormat.LineAlignment = (StringAlignment)value; - } -#endif -#endif - } - } - XLineAlignment _lineAlignment; - -#if GDI - //#if UseGdiObjects - internal StringFormat RealizeGdiStringFormat() - { - if (_stringFormat == null) - { - _stringFormat = StringFormat.GenericTypographic; - _stringFormat.Alignment = (StringAlignment)_alignment; - - // BaseLine is specific to PdfSharpCore. - if (_lineAlignment == XLineAlignment.BaseLine) - _stringFormat.LineAlignment = StringAlignment.Near; - else - _stringFormat.LineAlignment = (StringAlignment)_lineAlignment; - //_stringFormat.FormatFlags = (StringFormatFlags)_formatFlags; - - // Bugfix: Set MeasureTrailingSpaces to get the correct width with Graphics.MeasureString(). - // Before, MeasureString() didn't include blanks in width calculation, which could result in text overflowing table or page border before wrapping. $MaOs - _stringFormat.FormatFlags = _stringFormat.FormatFlags | StringFormatFlags.MeasureTrailingSpaces; } - return _stringFormat; } - StringFormat _stringFormat; - //#endif -#endif + XLineAlignment _lineAlignment; } } diff --git a/PdfSharpCore/Drawing/XStringFormats.cs b/PdfSharpCore/Drawing/XStringFormats.cs index e2d3d167..4bf943f3 100644 --- a/PdfSharpCore/Drawing/XStringFormats.cs +++ b/PdfSharpCore/Drawing/XStringFormats.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { /// diff --git a/PdfSharpCore/Drawing/XTypeface.cs b/PdfSharpCore/Drawing/XTypeface.cs index 1361073a..272023c8 100644 --- a/PdfSharpCore/Drawing/XTypeface.cs +++ b/PdfSharpCore/Drawing/XTypeface.cs @@ -27,16 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Documents; -using System.Windows.Media; -#endif - namespace PdfSharpCore.Drawing { #if true_ // Not yet used diff --git a/PdfSharpCore/Drawing/XUnit.cs b/PdfSharpCore/Drawing/XUnit.cs index 0f714bd7..92628a2f 100644 --- a/PdfSharpCore/Drawing/XUnit.cs +++ b/PdfSharpCore/Drawing/XUnit.cs @@ -67,11 +67,7 @@ public XUnit(double point) public XUnit(double value, XGraphicsUnit type) { if (!Enum.IsDefined(typeof(XGraphicsUnit), type)) -#if !SILVERLIGHT && !NETFX_CORE && !UWP && !PORTABLE - throw new System.ComponentModel.InvalidEnumArgumentException("type"); -#else throw new ArgumentException("type"); -#endif _value = value; _type = type; } diff --git a/PdfSharpCore/Drawing/XVector.cs b/PdfSharpCore/Drawing/XVector.cs index 546cf564..5e1dfab8 100644 --- a/PdfSharpCore/Drawing/XVector.cs +++ b/PdfSharpCore/Drawing/XVector.cs @@ -32,20 +32,7 @@ using System.Globalization; using System.Runtime.InteropServices; using PdfSharpCore.Internal; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif - -#pragma warning disable 1591 - -#if !EDF_CORE namespace PdfSharpCore.Drawing -#else -namespace Edf.Drawing -#endif { /// /// Represents a two-dimensional vector specified by x- and y-coordinates. diff --git a/PdfSharpCore/Fonts.OpenType/FontDescriptor.cs b/PdfSharpCore/Fonts.OpenType/FontDescriptor.cs index 68e5acb9..bfaf9a5a 100644 --- a/PdfSharpCore/Fonts.OpenType/FontDescriptor.cs +++ b/PdfSharpCore/Fonts.OpenType/FontDescriptor.cs @@ -27,21 +27,7 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif -using PdfSharpCore.Pdf.Internal; -using PdfSharpCore.Fonts; -#if !EDF_CORE using PdfSharpCore.Drawing; -#endif - -#pragma warning disable 0649 namespace PdfSharpCore.Fonts.OpenType { diff --git a/PdfSharpCore/Fonts.OpenType/GlyphDataTable.cs b/PdfSharpCore/Fonts.OpenType/GlyphDataTable.cs index a95a50e1..28b22c5e 100644 Binary files a/PdfSharpCore/Fonts.OpenType/GlyphDataTable.cs and b/PdfSharpCore/Fonts.OpenType/GlyphDataTable.cs differ diff --git a/PdfSharpCore/Fonts.OpenType/GlyphTypefaceCache.cs b/PdfSharpCore/Fonts.OpenType/GlyphTypefaceCache.cs index 5985d261..46d5a62e 100644 --- a/PdfSharpCore/Fonts.OpenType/GlyphTypefaceCache.cs +++ b/PdfSharpCore/Fonts.OpenType/GlyphTypefaceCache.cs @@ -63,7 +63,6 @@ public static void AddGlyphTypeface(XGlyphTypeface glyphTypeface) { Lock.EnterFontFactory(); GlyphTypefaceCache cache = Singleton; - Debug.Assert(!cache._glyphTypefacesByKey.ContainsKey(glyphTypeface.Key)); cache._glyphTypefacesByKey.TryAdd(glyphTypeface.Key, glyphTypeface); } finally { Lock.ExitFontFactory(); } diff --git a/PdfSharpCore/Fonts.OpenType/OpenTypeDescriptor.cs b/PdfSharpCore/Fonts.OpenType/OpenTypeDescriptor.cs index b8edbbf9..93ee9370 100644 --- a/PdfSharpCore/Fonts.OpenType/OpenTypeDescriptor.cs +++ b/PdfSharpCore/Fonts.OpenType/OpenTypeDescriptor.cs @@ -30,18 +30,8 @@ using System; using System.Diagnostics; using System.Text; -#if GDI -using System.Drawing; -using System.Drawing.Drawing2D; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -#endif using PdfSharpCore.Pdf.Internal; -#if !EDF_CORE using PdfSharpCore.Drawing; -#endif namespace PdfSharpCore.Fonts.OpenType { @@ -220,13 +210,7 @@ void Initialize() XHeight = (int)(0.66 * Ascender); //flags = image. - -#if !EDF_CORE Encoding ansi = PdfEncoders.WinAnsiEncoding; // System.Text.Encoding.Default; -#else - Encoding ansi = null; //$$$ PdfEncoders.WinAnsiEncoding; // System.Text.Encoding.Default; -#endif - Encoding unicode = Encoding.Unicode; byte[] bytes = new byte[256]; diff --git a/PdfSharpCore/Fonts.OpenType/OpenTypeFontTable.cs b/PdfSharpCore/Fonts.OpenType/OpenTypeFontTable.cs index d173c31c..48bcc656 100644 --- a/PdfSharpCore/Fonts.OpenType/OpenTypeFontTable.cs +++ b/PdfSharpCore/Fonts.OpenType/OpenTypeFontTable.cs @@ -30,13 +30,6 @@ using System; using System.Diagnostics; -//using Fixed = System.Int32; -//using FWord = System.Int16; -//using UFWord = System.UInt16; -#if SILVERLIGHT -using PdfSharpCore; -#endif - namespace PdfSharpCore.Fonts.OpenType { // TODO: Create a font driver for reading and writing OpenType font files. diff --git a/PdfSharpCore/Fonts.OpenType/OpenTypeFontface.cs b/PdfSharpCore/Fonts.OpenType/OpenTypeFontface.cs index 212aaf49..33778b32 100644 Binary files a/PdfSharpCore/Fonts.OpenType/OpenTypeFontface.cs and b/PdfSharpCore/Fonts.OpenType/OpenTypeFontface.cs differ diff --git a/PdfSharpCore/Fonts/CMapInfo.cs b/PdfSharpCore/Fonts/CMapInfo.cs index 2b2bc724..896fb007 100644 --- a/PdfSharpCore/Fonts/CMapInfo.cs +++ b/PdfSharpCore/Fonts/CMapInfo.cs @@ -101,11 +101,7 @@ internal void AddAnsiChars() byte[] ansi = new byte[256 - 32]; for (int idx = 0; idx < 256 - 32; idx++) ansi[idx] = (byte)(idx + 32); -#if EDF_CORE - string text = null; // PdfEncoders.WinAnsiEncoding.GetString(ansi, 0, ansi.Length); -#else string text = PdfEncoders.WinAnsiEncoding.GetString(ansi, 0, ansi.Length); -#endif AddChars(text); } diff --git a/PdfSharpCore/Fonts/FontFactory.cs b/PdfSharpCore/Fonts/FontFactory.cs index 44d26712..396ad698 100644 --- a/PdfSharpCore/Fonts/FontFactory.cs +++ b/PdfSharpCore/Fonts/FontFactory.cs @@ -31,19 +31,6 @@ using System.Diagnostics; using System.Collections.Generic; using System.Text; -#if CORE || GDI -using System.Drawing; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -#endif -#if WPF -using System.Windows; -using System.Windows.Media; -using System.Windows.Resources; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -using WpfTypeface = System.Windows.Media.Typeface; -#endif using PdfSharpCore.Drawing; using PdfSharpCore.Fonts.OpenType; using PdfSharpCore.Internal; @@ -155,38 +142,6 @@ public static FontResolverInfo ResolveTypeface(string familyName, FontResolvingO finally { Lock.ExitFontFactory(); } } -#if GDI - /// - /// Registers the font face. - /// - public static XFontSource RegisterFontFace(byte[] fontBytes) - { - try - { - Lock.EnterFontFactory(); - ulong key = FontHelper.CalcChecksum(fontBytes); - XFontSource fontSource; - if (FontSourcesByKey.TryGetValue(key, out fontSource)) - { - throw new InvalidOperationException("Font face already registered."); - } - fontSource = XFontSource.GetOrCreateFrom(fontBytes); - Debug.Assert(FontSourcesByKey.ContainsKey(key)); - Debug.Assert(fontSource.Fontface != null); - - //fontSource.Fontface = new OpenTypeFontface(fontSource); - //FontSourcesByKey.Add(checksum, fontSource); - //FontSourcesByFontName.Add(fontSource.FontName, fontSource); - - XGlyphTypeface glyphTypeface = new XGlyphTypeface(fontSource); - FontSourcesByName.Add(glyphTypeface.Key, fontSource); - GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); - return fontSource; - } - finally { Lock.ExitFontFactory(); } - } -#endif - /// /// Gets the bytes of a physical font with specified face name. /// diff --git a/PdfSharpCore/Fonts/FontResolverInfo.cs b/PdfSharpCore/Fonts/FontResolverInfo.cs index 9d9350df..f4117f9b 100644 --- a/PdfSharpCore/Fonts/FontResolverInfo.cs +++ b/PdfSharpCore/Fonts/FontResolverInfo.cs @@ -31,15 +31,6 @@ using System.Diagnostics; using System.Globalization; using PdfSharpCore.Drawing; -#if CORE -using System.Drawing; -#endif -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif namespace PdfSharpCore.Fonts { diff --git a/PdfSharpCore/Fonts/FontResolvingOptions.cs b/PdfSharpCore/Fonts/FontResolvingOptions.cs index 3874ee29..fe110d73 100644 --- a/PdfSharpCore/Fonts/FontResolvingOptions.cs +++ b/PdfSharpCore/Fonts/FontResolvingOptions.cs @@ -27,13 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Text; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; namespace PdfSharpCore.Fonts diff --git a/PdfSharpCore/Fonts/FontWriter.cs b/PdfSharpCore/Fonts/FontWriter.cs index f740adbf..6aacc7e5 100644 --- a/PdfSharpCore/Fonts/FontWriter.cs +++ b/PdfSharpCore/Fonts/FontWriter.cs @@ -52,9 +52,6 @@ public void Close(bool closeUnderlyingStream) { if (_stream != null && closeUnderlyingStream) { -#if !UWP && !PORTABLE - _stream.Close(); -#endif _stream.Dispose(); } _stream = null; diff --git a/PdfSharpCore/Fonts/GlobalFontSettings.cs b/PdfSharpCore/Fonts/GlobalFontSettings.cs index 447df31a..f223842c 100644 --- a/PdfSharpCore/Fonts/GlobalFontSettings.cs +++ b/PdfSharpCore/Fonts/GlobalFontSettings.cs @@ -57,10 +57,13 @@ public static IFontResolver FontResolver { get { -#if NETCOREAPP1_1 - if (_fontResolver == null) FontResolver = new FontResolver(); -#endif - return _fontResolver; + try + { + Lock.EnterFontFactory(); + if (_fontResolver == null) FontResolver = new FontResolver(); + return _fontResolver; + } + finally { Lock.ExitFontFactory(); } } set { diff --git a/PdfSharpCore/Fonts/PlatformFontResolver.cs b/PdfSharpCore/Fonts/PlatformFontResolver.cs index 955e076c..3ff645a0 100644 --- a/PdfSharpCore/Fonts/PlatformFontResolver.cs +++ b/PdfSharpCore/Fonts/PlatformFontResolver.cs @@ -34,29 +34,6 @@ using System.IO; using System.Linq; using System.Xml; - -#if __IOS__ -using ObjCRuntime; -using UIKit; -using CoreGraphics; -#endif - -#if CORE || GDI -using System.Drawing; -using System.Drawing.Drawing2D; -using GdiFontFamily = System.Drawing.FontFamily; -using GdiFont = System.Drawing.Font; -using GdiFontStyle = System.Drawing.FontStyle; -#endif -#if WPF -using System.Windows; -using System.Windows.Documents; -using System.Windows.Media; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -using WpfStyleSimulations = System.Windows.Media.StyleSimulations; -#endif using PdfSharpCore.Drawing; #pragma warning disable 1591 @@ -100,33 +77,7 @@ internal static FontResolverInfo ResolveTypeface(string familyName, FontResolvin // It is possible that we already have the correct font source. E.g. we already have the regular typeface in cache // and looking now for the italic typeface, but no such font exists. In this case we get the regular font source // and cache again it with the italic typeface key. Furthermore in glyph typeface style simulation for italic is set. -#if (CORE || GDI) && !WPF - GdiFont gdiFont; - XFontSource fontSource = CreateFontSource(familyName, fontResolvingOptions, out gdiFont, typefaceKey); -#endif -#if WPF && !SILVERLIGHT - WpfFontFamily wpfFontFamily; - WpfTypeface wpfTypeface; - WpfGlyphTypeface wpfGlyphTypeface; - XFontSource fontSource = CreateFontSource(familyName, fontResolvingOptions, out wpfFontFamily, out wpfTypeface, out wpfGlyphTypeface, typefaceKey); -#endif -#if SILVERLIGHT - //GlyphTypeface wpfGlyphTypeface; - XFontSource fontSource = null;//CreateFontSource(familyName, isBold, isItalic, out wpfGlyphTypeface, typefaceKey); -#endif -#if NETFX_CORE || UWP - //GlyphTypeface wpfGlyphTypeface; - XFontSource fontSource = null;//CreateFontSource(familyName, isBold, isItalic, out wpfGlyphTypeface, typefaceKey); -#endif -#if __IOS__ - XFontSource fontSource = CreateFontSource(familyName, fontResolvingOptions, typefaceKey); -#endif -#if __ANDROID__ - XFontSource fontSource = CreateFontSource(familyName, fontResolvingOptions, typefaceKey); -#endif -#if PORTABLE XFontSource fontSource = null; -#endif // If no such font exists return null. PDFsharp will fail. if (fontSource == null) return null; @@ -137,71 +88,10 @@ internal static FontResolverInfo ResolveTypeface(string familyName, FontResolvin //#endif if (fontResolvingOptions.OverrideStyleSimulations) { -#if (CORE || GDI) && !WPF - // TODO: Support style simulation for GDI+ platform fonts. - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, fontResolvingOptions.MustSimulateBold, fontResolvingOptions.MustSimulateItalic, gdiFont); -#endif -#if WPF && !SILVERLIGHT - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, fontResolvingOptions.MustSimulateBold, fontResolvingOptions.MustSimulateItalic, - wpfFontFamily, wpfTypeface, wpfGlyphTypeface); -#endif } else { -#if (CORE || GDI) && !WPF - bool mustSimulateBold = gdiFont.Bold && !fontSource.Fontface.os2.IsBold; - bool mustSimulateItalic = gdiFont.Italic && !fontSource.Fontface.os2.IsItalic; - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, mustSimulateBold, mustSimulateItalic, gdiFont); -#endif -#if WPF && !SILVERLIGHT - // WPF knows what styles have to be simulated. - bool mustSimulateBold = (wpfGlyphTypeface.StyleSimulations & WpfStyleSimulations.BoldSimulation) == WpfStyleSimulations.BoldSimulation; - bool mustSimulateItalic = (wpfGlyphTypeface.StyleSimulations & WpfStyleSimulations.ItalicSimulation) == WpfStyleSimulations.ItalicSimulation; - - // Weird behavior of WPF is fixed here in case we request a bold italic typeface. - // If only italic is available, bold is simulated based on italic. - // If only bold is available, italic is simulated based on bold. - // But if both bold and italic is available, italic face is used and bold is simulated. - // The latter case is reversed here, i.e. bold face is used and italic is simulated. - if (fontResolvingOptions.IsBoldItalic && mustSimulateBold && !mustSimulateItalic) - { - // Try to get the bold typeface. - string typefaceKeyBold = XGlyphTypeface.ComputeKey(familyName, true, false); - FontResolverInfo infoBold = ResolveTypeface(familyName, - new FontResolvingOptions(FontHelper.CreateStyle(true, false)), typefaceKeyBold); - // Use it if it does not base on simulateion. - if (infoBold != null && infoBold.StyleSimulations == XStyleSimulations.None) - { - // Use existing bold typeface and simualte italic. - fontResolverInfo = new PlatformFontResolverInfo(typefaceKeyBold, false, true, - wpfFontFamily, wpfTypeface, wpfGlyphTypeface); - } - else - { - // Simulate both. - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, true, true, - wpfFontFamily, wpfTypeface, wpfGlyphTypeface); - } - } - else - { - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, mustSimulateBold, mustSimulateItalic, - wpfFontFamily, wpfTypeface, wpfGlyphTypeface); - } -#endif } - -#if SILVERLIGHT - fontResolverInfo = null; //new PlattformResolverInfo(typefaceKey, false, false, wpfGlyphTypeface); -#endif - -#if __IOS__ - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, false, false); -#endif - -#if __ANDROID__ - fontResolverInfo = new PlatformFontResolverInfo(typefaceKey, false, false); -#endif FontFactory.CacheFontResolverInfo(typefaceKey, fontResolverInfo); // Register font data under the platform specific face name. @@ -210,392 +100,5 @@ internal static FontResolverInfo ResolveTypeface(string familyName, FontResolvin return fontResolverInfo; } - -#if (CORE_WITH_GDI || GDI) && !WPF - /// - /// Create a GDI+ font and use its handle to retrieve font data using native calls. - /// - internal static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, out GdiFont font, string typefaceKey) - { - if (string.IsNullOrEmpty(typefaceKey)) - typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); -#if true_ - if (familyName == "Cambria") - Debug-Break.Break(); -#endif - GdiFontStyle gdiStyle = (GdiFontStyle)(fontResolvingOptions.FontStyle & XFontStyle.BoldItalic); - - // Create a 10 point GDI+ font as an exemplar. - XFontSource fontSource; - font = FontHelper.CreateFont(familyName, 10, gdiStyle, out fontSource); - - if (fontSource != null) - { - Debug.Assert(font != null); - // Case: Font was created by a GDI+ private font collection. -#if true -#if DEBUG - XFontSource existingFontSource; - Debug.Assert(FontFactory.TryGetFontSourceByTypefaceKey(typefaceKey, out existingFontSource) && - ReferenceEquals(fontSource, existingFontSource)); -#endif -#else - // Win32 API cannot get font data from fonts created by private font collection, - // because this is handled internally in GDI+. - // Therefore the font source was created when the private font is added to the private font collection. - if (!FontFactory.TryGetFontSourceByTypefaceKey(typefaceKey, out fontSource)) - { - // Simplify styles. - // (The code is written for clarity - do not rearrange for optimization) - if (font.Bold && font.Italic) - { - if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, true, false), out fontSource)) - { - // Use bold font. - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - else if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, true), out fontSource)) - { - // Use italic font. - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - else if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) - { - // Use regular font. - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - } - else if (font.Bold || font.Italic) - { - // Use regular font. - if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) - { - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - } - else - { - if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) - { - // Should never come here... - FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); - } - } - } -#endif - } - else - { - // Get or create the font source and cache it unter the specified typeface key. - fontSource = XFontSource.GetOrCreateFromGdi(typefaceKey, font); - } - return fontSource; - } -#endif - -#if WPF && !SILVERLIGHT - /// - /// Create a WPF GlyphTypeface and retrieve font data from it. - /// - internal static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, - out WpfFontFamily wpfFontFamily, out WpfTypeface wpfTypeface, out WpfGlyphTypeface wpfGlyphTypeface, string typefaceKey) - { - if (string.IsNullOrEmpty(typefaceKey)) - typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); - XFontStyle style = fontResolvingOptions.FontStyle; - -#if DEBUG - if (StringComparer.OrdinalIgnoreCase.Compare(familyName, "Segoe UI Semilight") == 0 - && (style & XFontStyle.BoldItalic) == XFontStyle.Italic) - familyName.GetType(); -#endif - - // Use WPF technique to create font data. - wpfTypeface = XPrivateFontCollection.TryCreateTypeface(familyName, style, out wpfFontFamily); -#if DEBUG__ - if (wpfTypeface != null) - { - WpfGlyphTypeface glyphTypeface; - ICollection list = wpfFontFamily.GetTypefaces(); - foreach (WpfTypeface tf in list) - { - if (!tf.TryGetGlyphTypeface(out glyphTypeface)) - Debug-Break.Break(); - } - - //if (!WpfTypeface.TryGetGlyphTypeface(out glyphTypeface)) - // throw new InvalidOperationException(PSSR.CannotGetGlyphTypeface(familyName)); - } -#endif - if (wpfFontFamily == null) - wpfFontFamily = new WpfFontFamily(familyName); - - if (wpfTypeface == null) - wpfTypeface = FontHelper.CreateTypeface(wpfFontFamily, style); - - // Let WPF choose the right glyph typeface. - if (!wpfTypeface.TryGetGlyphTypeface(out wpfGlyphTypeface)) - throw new InvalidOperationException(PSSR.CannotGetGlyphTypeface(familyName)); - - // Get or create the font source and cache it unter the specified typeface key. - XFontSource fontSource = XFontSource.GetOrCreateFromWpf(typefaceKey, wpfGlyphTypeface); - return fontSource; - } -#endif - -#if SILVERLIGHT - /// - /// Silverlight has no access to the bytes of its fonts and threrefore return null. - /// - internal static XFontSource CreateFontSource(string familyName, bool isBold, bool isItalic) - { - // PDFsharp does not provide a default font because this would blow up the assembly - // unneccessarily if the font is not needed. Provide your own font resolver to generate - // PDF files containing text. - return null; - } -#endif - -#if NETFX_CORE - internal static XFontSource CreateFontSource(string familyName, bool isBold, bool isItalic, string typefaceKey) - { - throw new NotImplementedException(); - } -#endif - -#if __IOS__ - - [StructLayout(LayoutKind.Sequential)] - public struct FontHeader - { - public Int32 fVersion; - public UInt16 fNumTables; - public UInt16 fSearchRange; - public UInt16 fEntrySelector; - public UInt16 fRangeShift; - }; - - [StructLayout(LayoutKind.Sequential)] - public struct TableEntry - { - public UInt32 fTag; - public UInt32 fCheckSum; - public UInt32 fOffset; - public UInt32 fLength; - }; - - [DllImport(Constants.CoreGraphicsLibrary)] - extern static IntPtr CGFontCopyTableTags(IntPtr font); - - [DllImport(Constants.CoreGraphicsLibrary)] - extern static IntPtr CGFontCopyTableForTag(IntPtr font, int tag); - - [DllImport(Constants.CoreFoundationLibrary)] - extern static nint CFArrayGetCount(IntPtr theArray); - - [DllImport(Constants.CoreFoundationLibrary)] - extern static IntPtr CFArrayGetValueAtIndex(IntPtr theArray, nint idx); - - [DllImport(Constants.CoreFoundationLibrary)] - extern static nint CFDataGetLength(IntPtr theData); - - [DllImport(Constants.CoreFoundationLibrary)] - internal extern static IntPtr CFRelease(IntPtr handle); - - [DllImport(Constants.CoreFoundationLibrary)] - extern static IntPtr CFDataGetBytePtr(IntPtr theData); - - public static ushort SwapBytes(ushort x) - { - return (ushort)((ushort)((x & 0xff) << 8) | ((x >> 8) & 0xff)); - } - - public static uint SwapBytes(uint x) - { - return ((x & 0x000000ff) << 24) + - ((x & 0x0000ff00) << 8) + - ((x & 0x00ff0000) >> 8) + - ((x & 0xff000000) >> 24); - } - - private unsafe static UInt32 CalcTableCheckSum(UInt32* table, nint numberOfBytesInTable) - { - UInt32 sum = 0; - nint nLongs = (numberOfBytesInTable + 3) / 4; - while (nLongs-- > 0) - { - sum += SwapBytes(*table++); - } - return sum; - } - - internal unsafe static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, string typefaceKey) - { - if (string.IsNullOrEmpty(typefaceKey)) - typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); - - var descriptor = UIFont.FromName(familyName, 20.0f).FontDescriptor; - - UIFontDescriptorSymbolicTraits traits = 0; - - if (fontResolvingOptions.IsItalic) - { - traits |= UIFontDescriptorSymbolicTraits.Italic; - } - - if (fontResolvingOptions.IsBold) - { - traits |= UIFontDescriptorSymbolicTraits.Bold; - } - - var uifont = UIFont.FromDescriptor(descriptor.CreateWithTraits(traits), 20.0f); - var cgFont = CGFont.CreateWithFontName(uifont.Name); - - IntPtr tags = CGFontCopyTableTags(cgFont.Handle); - nint tableCount = CFArrayGetCount(tags); - nint totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount; - - for (int index = 0; index < tableCount; ++index) - { - nint tableSize = 0; - - int aTag = (int)CFArrayGetValueAtIndex(tags, index); - - IntPtr tableDataRef = CGFontCopyTableForTag(cgFont.Handle, aTag); - - if (tableDataRef != IntPtr.Zero) - { - tableSize = CFDataGetLength(tableDataRef); - CFRelease(tableDataRef); - } - - totalSize += (tableSize + 3) & ~3; - } - - var data = new byte[totalSize]; - - fixed (byte* dataStart = data) - { - byte* dataPtr = dataStart; - - UInt16 entrySelector = 0; - UInt16 searchRange = 1; - - while (searchRange < tableCount >> 1) - { - entrySelector++; - searchRange <<= 1; - } - searchRange <<= 4; - - UInt16 rangeShift = (UInt16)((tableCount << 4) - searchRange); - - FontHeader* offsetTable = (FontHeader*)dataPtr; - offsetTable->fVersion = (Int32)SwapBytes((UInt16)1); - offsetTable->fNumTables = SwapBytes((UInt16)tableCount); - offsetTable->fSearchRange = SwapBytes((UInt16)searchRange); - offsetTable->fEntrySelector = SwapBytes((UInt16)entrySelector); - offsetTable->fRangeShift = SwapBytes((UInt16)rangeShift); - dataPtr += sizeof(FontHeader); - - TableEntry* entry = (TableEntry*) dataPtr; - dataPtr += sizeof(TableEntry) * tableCount; - - for (int index = 0; index < tableCount; ++index) - { - int aTag = (int)CFArrayGetValueAtIndex(tags, index); - - IntPtr tableDataRef = CGFontCopyTableForTag(cgFont.Handle, aTag); - - nint tableSize = 0; - - if (tableDataRef != IntPtr.Zero) - { - tableSize = CFDataGetLength(tableDataRef); - Buffer.MemoryCopy((byte*)CFDataGetBytePtr(tableDataRef), dataPtr, tableSize, tableSize); - entry->fTag = SwapBytes((UInt32)aTag); - entry->fCheckSum = SwapBytes(CalcTableCheckSum((UInt32*)dataPtr, tableSize)); - UInt32 offset = (UInt32)(dataPtr - dataStart); - entry->fOffset = SwapBytes((UInt32)offset); - entry->fLength = SwapBytes((UInt32)tableSize); - CFRelease(tableDataRef); - } - - dataPtr += (tableSize + 3) & ~3; - ++entry; - } - } - - var fontSource = XFontSource.GetOrCreateFrom(typefaceKey, data); - - return fontSource; - } -#endif - -#if __ANDROID__ - - public struct AndroidFontInfo - { - public string FamilyName; - public bool Italic; - public bool Bold; - } - - private static Dictionary fonts = null; - - internal static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, string typefaceKey) - { - if (string.IsNullOrEmpty(typefaceKey)) - typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); - - if (fonts == null) - { - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.Load("/system/etc/fonts.xml"); - - fonts = new Dictionary(); - - var familyset = xmlDoc.DocumentElement; - foreach (XmlNode family in familyset.ChildNodes) - { - if (family.Attributes != null && family.Attributes["name"] != null) - { - foreach (XmlNode font in family.ChildNodes) - { - if (font.Attributes["style"] != null && font.Attributes["weight"] != null) - { - var id = new AndroidFontInfo - { - FamilyName = family.Attributes["name"].Value, - Italic = font.Attributes["style"].Value == "italic", - Bold = int.Parse(font.Attributes["weight"].Value) > 500, - }; - - fonts[id] = font.ChildNodes[0].Value; - } - } - } - } - } - - XFontSource fontSource = null; - - string path; - - var searchId = new AndroidFontInfo - { - FamilyName = familyName, - Italic = fontResolvingOptions.IsItalic, - Bold = fontResolvingOptions.IsBold, - }; - - if (fonts.TryGetValue(searchId, out path)) - { - fontSource = XFontSource.GetOrCreateFrom(typefaceKey, File.ReadAllBytes(Path.Combine("/system/fonts/", path))); - } - - return fontSource; - } -#endif } } diff --git a/PdfSharpCore/Fonts/PlatformFontResolverInfo.cs b/PdfSharpCore/Fonts/PlatformFontResolverInfo.cs index c63d9d38..4bf1d858 100644 --- a/PdfSharpCore/Fonts/PlatformFontResolverInfo.cs +++ b/PdfSharpCore/Fonts/PlatformFontResolverInfo.cs @@ -27,18 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if CORE || GDI -using System.Drawing; -using GdiFont = System.Drawing.Font; - -#endif -#if WPF -using System.Windows.Media; -using WpfFontFamily = System.Windows.Media.FontFamily; -using WpfTypeface = System.Windows.Media.Typeface; -using WpfGlyphTypeface = System.Windows.Media.GlyphTypeface; -#endif - namespace PdfSharpCore.Fonts { /// @@ -46,72 +34,11 @@ namespace PdfSharpCore.Fonts /// internal class PlatformFontResolverInfo : FontResolverInfo { -#if CORE || GDI - public PlatformFontResolverInfo(string faceName, bool mustSimulateBold, bool mustSimulateItalic, GdiFont gdiFont) - : base(faceName, mustSimulateBold, mustSimulateItalic) - { - _gdiFont = gdiFont; - } -#endif -#if WPF - public PlatformFontResolverInfo(string faceName, bool mustSimulateBold, bool mustSimulateItalic, WpfFontFamily wpfFontFamily, - WpfTypeface wpfTypeface, WpfGlyphTypeface wpfGlyphTypeface) - : base(faceName, mustSimulateBold, mustSimulateItalic) - { - _wpfFontFamily = wpfFontFamily; - _wpfTypeface = wpfTypeface; - _wpfGlyphTypeface = wpfGlyphTypeface; - } -#endif - -#if CORE || GDI - public Font GdiFont - { - get { return _gdiFont; } - } - readonly Font _gdiFont; -#endif -#if WPF - public WpfFontFamily WpfFontFamily - { - get { return _wpfFontFamily; } - } - readonly WpfFontFamily _wpfFontFamily; - - public WpfTypeface WpfTypeface - { - get { return _wpfTypeface; } - } - readonly WpfTypeface _wpfTypeface; - public WpfGlyphTypeface WpfGlyphTypeface - { - get { return _wpfGlyphTypeface; } - } - readonly WpfGlyphTypeface _wpfGlyphTypeface; -#endif -#if NETFX_CORE || UWP || PORTABLE - public PlatformFontResolverInfo(string faceName, bool mustSimulateBold, bool mustSimulateItalic) - : base(faceName, mustSimulateBold, mustSimulateItalic) - { - //_gdiFont = gdiFont; - } -#endif -#if __IOS__ public PlatformFontResolverInfo(string faceName, bool mustSimulateBold, bool mustSimulateItalic) : base(faceName, mustSimulateBold, mustSimulateItalic) { //_gdiFont = gdiFont; } -#endif -#if __ANDROID__ - public PlatformFontResolverInfo(string faceName, bool mustSimulateBold, bool mustSimulateItalic) - : base(faceName, mustSimulateBold, mustSimulateItalic) - { - //_gdiFont = gdiFont; - } -#endif - - } } diff --git a/PdfSharpCore/Internal/Calc.cs b/PdfSharpCore/Internal/Calc.cs index 50ac0c96..37f70fac 100644 --- a/PdfSharpCore/Internal/Calc.cs +++ b/PdfSharpCore/Internal/Calc.cs @@ -28,12 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -#endif using PdfSharpCore.Drawing; namespace PdfSharpCore.Internal diff --git a/PdfSharpCore/Internal/ColorHelper.cs b/PdfSharpCore/Internal/ColorHelper.cs index b115c4db..f15a0fbe 100644 --- a/PdfSharpCore/Internal/ColorHelper.cs +++ b/PdfSharpCore/Internal/ColorHelper.cs @@ -28,13 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -#endif - #pragma warning disable 649 namespace PdfSharpCore.Internal diff --git a/PdfSharpCore/Internal/Diagnostics.cs b/PdfSharpCore/Internal/Diagnostics.cs index 5adae30b..3f7ff614 100644 --- a/PdfSharpCore/Internal/Diagnostics.cs +++ b/PdfSharpCore/Internal/Diagnostics.cs @@ -32,13 +32,6 @@ using PdfSharpCore.Pdf.Content; using PdfSharpCore.Pdf.IO; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -#endif - namespace PdfSharpCore.Internal { enum NotImplementedBehaviour diff --git a/PdfSharpCore/Internal/DiagnosticsHelper.cs b/PdfSharpCore/Internal/DiagnosticsHelper.cs index 3f9f3243..81930eb2 100644 --- a/PdfSharpCore/Internal/DiagnosticsHelper.cs +++ b/PdfSharpCore/Internal/DiagnosticsHelper.cs @@ -28,12 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -#endif using System.Diagnostics; using PdfSharpCore.Drawing; using PdfSharpCore.Fonts; diff --git a/PdfSharpCore/Internal/DoubleUtil.cs b/PdfSharpCore/Internal/DoubleUtil.cs index 983952c8..ed961b38 100644 --- a/PdfSharpCore/Internal/DoubleUtil.cs +++ b/PdfSharpCore/Internal/DoubleUtil.cs @@ -29,17 +29,8 @@ using System; using System.Runtime.InteropServices; -#if !EDF_CORE using PdfSharpCore.Drawing; -#else -using PdfSharpCore.Drawing; -#endif - -#if !EDF_CORE namespace PdfSharpCore.Internal -#else -namespace Edf.Internal -#endif { /// /// Some floating point utilities. Partially reflected from WPF, later equalized with original source code. diff --git a/PdfSharpCore/Internal/NativeMethods.cs b/PdfSharpCore/Internal/NativeMethods.cs deleted file mode 100644 index a8fae34f..00000000 --- a/PdfSharpCore/Internal/NativeMethods.cs +++ /dev/null @@ -1,155 +0,0 @@ -#region PDFsharp - A .NET library for processing PDF -// -// Authors: -// Stefan Lange -// -// Copyright (c) 2005-2016 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.Runtime.InteropServices; - -// ReSharper disable InconsistentNaming - -namespace PdfSharpCore.Internal -{ -#if CORE || GDI || WPF - /// - /// Required native Win32 calls. - /// - static class NativeMethods - { - public const int GDI_ERROR = -1; - - /// - /// Reflected from System.Drawing.SafeNativeMethods+LOGFONT - /// - //[SuppressUnmanagedCodeSecurity] - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public class LOGFONT - { - // Preserve us for warning CS0649... - LOGFONT(int dummy) - { - lfHeight = 0; - lfWidth = 0; - lfEscapement = 0; - lfOrientation = 0; - lfWeight = 0; - lfItalic = 0; - lfUnderline = 0; - lfStrikeOut = 0; - lfCharSet = 0; - lfOutPrecision = 0; - lfClipPrecision = 0; - lfQuality = 0; - lfPitchAndFamily = 0; - lfFaceName = ""; - } - public int lfHeight; - public int lfWidth; - public int lfEscapement; - public int lfOrientation; - public int lfWeight; - public byte lfItalic; - public byte lfUnderline; - public byte lfStrikeOut; - public byte lfCharSet; - public byte lfOutPrecision; - public byte lfClipPrecision; - public byte lfQuality; - public byte lfPitchAndFamily; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string lfFaceName; - public override string ToString() - { - object[] objArray1 = new object[0x1c] - { - "lfHeight=", lfHeight, - ", lfWidth=", lfWidth, - ", lfEscapement=", lfEscapement, - ", lfOrientation=", lfOrientation, - ", lfWeight=", lfWeight, - ", lfItalic=", lfItalic, - ", lfUnderline=", lfUnderline, - ", lfStrikeOut=", lfStrikeOut, - ", lfCharSet=", lfCharSet, - ", lfOutPrecision=", lfOutPrecision, - ", lfClipPrecision=", lfClipPrecision, - ", lfQuality=", lfQuality, - ", lfPitchAndFamily=", lfPitchAndFamily, - ", lfFaceName=", lfFaceName - }; - return string.Concat(objArray1); - } - public LOGFONT() { } - } - - [DllImport("user32.dll")] - public static extern IntPtr GetDC(IntPtr hwnd); - - [DllImport("user32.dll")] - public static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc); - - [DllImport("gdi32.dll", SetLastError = true)] - public static extern int GetFontData( - IntPtr hdc, // handle to DC - uint dwTable, // metric table name - uint dwOffset, // offset into table - byte[] lpvBuffer, // buffer for returned data - int cbData // length of data - ); - - // CreateDCA(__in_opt LPCSTR pwszDriver, __in_opt LPCSTR pwszDevice, __in_opt LPCSTR pszPort, __in_opt CONST DEVMODEA* pdm); - [DllImport("gdi32.dll", SetLastError = true)] - public static extern IntPtr CreateDC( - string driver, - string device, - string port, - IntPtr data - ); - - [DllImport("gdi32.dll", SetLastError = true)] - public static extern IntPtr CreateCompatibleDC(IntPtr hdc); - - [DllImport("gdi32.dll", EntryPoint = "CreateFontIndirectW")] - public static extern IntPtr CreateFontIndirect(LOGFONT lpLogFont); - - [DllImport("gdi32.dll")] - public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); - - [DllImport("gdi32.dll")] - public static extern bool DeleteObject(IntPtr hgdiobj); - - public const int HORZSIZE = 4; // Horizontal size in millimeters - public const int VERTSIZE = 6; // Vertical size in millimeters - public const int HORZRES = 8; // Horizontal width in pixels - public const int VERTRES = 10; // Vertical height in pixels - public const int LOGPIXELSX = 88; // Logical pixels/inch in X - public const int LOGPIXELSY = 90; // Logical pixels/inch in Y - [DllImport("gdi32.dll")] - public static extern int GetDeviceCaps(IntPtr hdc, int nIndex); - } -#endif -} \ No newline at end of file diff --git a/PdfSharpCore/Internal/TokenizerHelper.cs b/PdfSharpCore/Internal/TokenizerHelper.cs index 903c248b..35f3b63d 100644 --- a/PdfSharpCore/Internal/TokenizerHelper.cs +++ b/PdfSharpCore/Internal/TokenizerHelper.cs @@ -30,11 +30,7 @@ using System; using System.Globalization; -#if !EDF_CORE namespace PdfSharpCore.Internal -#else -namespace Edf.Internal -#endif { // Reflected from WPF to ensure compatibility // Use netmassdownloader -d "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0" -output g:\cachetest -v diff --git a/PdfSharpCore/Pdf.AcroForms/PdfAcroField.cs b/PdfSharpCore/Pdf.AcroForms/PdfAcroField.cs index 522415dd..ad8f1843 100644 --- a/PdfSharpCore/Pdf.AcroForms/PdfAcroField.cs +++ b/PdfSharpCore/Pdf.AcroForms/PdfAcroField.cs @@ -300,6 +300,11 @@ public sealed class PdfAcroFieldCollection : PdfArray : base(array) { } + PdfAcroFieldCollection(PdfDocument document) + : base(document) + { } + + /// /// Gets the names of all fields in the collection. /// @@ -553,6 +558,30 @@ public class Keys : KeysBase [KeyInfo(KeyType.Integer | KeyType.Optional)] public const string Q = "/Q"; + /// + /// (Optional) The type of PDF object that this dictionary describes; if present, + /// must be Sig for a signature dictionary. + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string Type = "/Type"; + + /// + /// + /// + [KeyInfo(KeyType.Name | KeyType.Required)] + public const string Subtype = "/Subtype"; + + + /// + /// + /// + [KeyInfo(KeyType.Rectangle | KeyType.Required)] + public const string Rect = "/Rect"; + + + [KeyInfo(KeyType.Rectangle | KeyType.Required)] + public const string P = "/P"; + // ReSharper restore InconsistentNaming } } diff --git a/PdfSharpCore/Pdf.AcroForms/PdfSignatureField.cs b/PdfSharpCore/Pdf.AcroForms/PdfSignatureField.cs index b7f6a87a..3ce237f1 100644 --- a/PdfSharpCore/Pdf.AcroForms/PdfSignatureField.cs +++ b/PdfSharpCore/Pdf.AcroForms/PdfSignatureField.cs @@ -56,7 +56,7 @@ internal PdfSignatureField(PdfDictionary dict) /// must be Sig for a signature dictionary. /// [KeyInfo(KeyType.Name | KeyType.Optional)] - public const string Type = "/Type"; + public new const string Type = "/Type"; /// /// (Required; inheritable) The name of the signature handler to be used for diff --git a/PdfSharpCore/Pdf.Advanced/PdfCatalog.cs b/PdfSharpCore/Pdf.Advanced/PdfCatalog.cs index b34c661d..ab489c62 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfCatalog.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfCatalog.cs @@ -160,14 +160,15 @@ internal PdfOutlineCollection Outlines /// public PdfAcroForm AcroForm { - get + get { return (PdfAcroForm)Elements.GetValue(Keys.AcroForm); } + set { - if (_acroForm == null) - _acroForm = (PdfAcroForm)Elements.GetValue(Keys.AcroForm); - return _acroForm; + if (Elements.ContainsKey(Keys.AcroForm)) + Elements[Keys.AcroForm] = value; + else + Elements.Add(Keys.AcroForm, value); } } - PdfAcroForm _acroForm; /// /// Gets or sets the language identifier specifying the natural language for all text in the document. diff --git a/PdfSharpCore/Pdf.Advanced/PdfContent.cs b/PdfSharpCore/Pdf.Advanced/PdfContent.cs index e6eae90f..16349459 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfContent.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfContent.cs @@ -78,13 +78,13 @@ public bool Compressed { if (value) { - PdfItem filter = Elements["/Filter"]; + PdfItem filter = Elements[PdfStream.Keys.Filter]; if (filter == null) { byte[] bytes = Filtering.FlateDecode.Encode(Stream.Value, _document.Options.FlateEncodeMode); Stream.Value = bytes; - Elements.SetInteger("/Length", Stream.Length); - Elements.SetName("/Filter", "/FlateDecode"); + Elements.SetInteger(PdfStream.Keys.Length, Stream.Length); + Elements.SetName(PdfStream.Keys.Filter, "/FlateDecode"); } } } @@ -97,15 +97,17 @@ void Decode() { if (Stream != null && Stream.Value != null) { - PdfItem item = Elements["/Filter"]; + PdfItem item = Elements[PdfStream.Keys.Filter]; if (item != null) { - byte[] bytes = Filtering.Decode(Stream.Value, item); + var decodeParms = Elements[PdfStream.Keys.DecodeParms]; + byte[] bytes = Filtering.Decode(Stream.Value, item, decodeParms); if (bytes != null) { Stream.Value = bytes; - Elements.Remove("/Filter"); - Elements.SetInteger("/Length", Stream.Length); + Elements.Remove(PdfStream.Keys.Filter); + Elements.Remove(PdfStream.Keys.DecodeParms); + Elements.SetInteger(PdfStream.Keys.Length, Stream.Length); } } } diff --git a/PdfSharpCore/Pdf.Advanced/PdfCrossReferenceStream.cs b/PdfSharpCore/Pdf.Advanced/PdfCrossReferenceStream.cs index 219994a2..13cb745b 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfCrossReferenceStream.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfCrossReferenceStream.cs @@ -43,19 +43,14 @@ internal sealed class PdfCrossReferenceStream : PdfTrailer // Reference: 3.4.7 public PdfCrossReferenceStream(PdfDocument document) : base(document) { -#if DEBUG && CORE - if (Internal.PdfDiagnostics.TraceXrefStreams) - { - Debug.WriteLine("PdfCrossReferenceStream created."); - } -#endif } public readonly List Entries = new List(); + [DebuggerDisplay("{Type} {Field2} {Field3}")] public struct CrossReferenceStreamEntry { - // Reference: TABLE 3.16 Entries in a cross-refernece stream / Page 109 + // Reference: TABLE 3.16 Entries in a cross-reference stream / Page 109 public uint Type; // 0, 1, or 2. diff --git a/PdfSharpCore/Pdf.Advanced/PdfDictionaryWithContentStream.cs b/PdfSharpCore/Pdf.Advanced/PdfDictionaryWithContentStream.cs index 9278697f..01e5aab7 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfDictionaryWithContentStream.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfDictionaryWithContentStream.cs @@ -29,13 +29,6 @@ using System; using System.Diagnostics; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; namespace PdfSharpCore.Pdf.Advanced diff --git a/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs b/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs new file mode 100644 index 00000000..20dcb243 --- /dev/null +++ b/PdfSharpCore/Pdf.Advanced/PdfEmbeddedFile.cs @@ -0,0 +1,132 @@ +namespace PdfSharpCore.Pdf.Advanced +{ + /// + /// Represent a file stream embedded in the PDF document + /// + public class PdfEmbeddedFile : PdfDictionary + { + private readonly PdfDictionary paramsDictionary; + + public PdfEmbeddedFile(PdfDocument document) + : base(document) + { + this.paramsDictionary = new PdfDictionary(); + + Elements.SetName(Keys.Type, "/EmbeddedFile"); + Elements.SetObject(Keys.Params, paramsDictionary); + } + + public PdfEmbeddedFile(PdfDocument document, byte[] bytes, string checksum = null) + : this(document) + { + this.CreateStreamAndSetProperties(bytes, checksum); + } + + public void CreateStreamAndSetProperties(byte[] bytes, string checksum = null) + { + this.CreateStream(bytes); + + this.paramsDictionary.Elements.SetInteger(Keys.Size, bytes.Length); + + if (string.IsNullOrEmpty(checksum)) + this.paramsDictionary.Elements.Remove(Keys.CheckSum); + else + this.paramsDictionary.Elements.SetString(Keys.CheckSum, checksum); + } + + public string MimeType + { + get { return Elements.GetName(Keys.Subtype); } + set { Elements.SetName(Keys.Subtype, value); } + } + + // TODO : Add properties for the subdictionnary Params and the subsubdictionnary Mac + + /// + /// Predefined keys of this embedded file. + /// + public class Keys : PdfDictionary.PdfStream.Keys + { + /// + /// (Optional) The type of PDF object that this dictionary describes; if present, + /// must be EmbeddedFile for an embedded file stream. + /// + [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "EmbeddedFile")] + public const string Type = "/Type"; + + /// + /// (Optional) The subtype of the embedded file. The value of this entry must be a + /// first-class name, as defined in Appendix E. Names without a registered prefix + /// must conform to the MIME media type names defined in Internet RFC 2046, + /// Multipurpose Internet Mail Extensions (MIME), Part Two: Media Types(see the + /// Bibliography), with the provision that characters not allowed in names must + /// use the 2-character hexadecimal code format described in Section 3.2.4, + /// “Name Objects.” + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string Subtype = "/Subtype"; + + /// + /// (Optional) An embedded file parameter dictionary containing additional, + /// file-specific information (see Table 3.43). + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string Params = "/Params"; + + /// + /// (Optional) The size of the embedded file, in bytes. + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string Size = "/Size"; + + /// + /// (Optional) The date and time when the embedded file was created. + /// + [KeyInfo(KeyType.Date | KeyType.Optional)] + public const string CreationDate = "/CreationDate"; + + /// + /// (Optional) The date and time when the embedded file was last modified. + /// + [KeyInfo(KeyType.Date | KeyType.Optional)] + public const string ModDate = "/ModDate"; + + /// + /// (Optional) A subdictionary containing additional information specific to Mac OS files (see Table 3.44). + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string Mac = "/Mac"; + + /// + /// (Optional) A 16-byte string that is the checksum of the bytes of the uncompressed + /// embedded file. The checksum is calculated by applying the standard MD5 message-digest + /// algorithm (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see the + /// Bibliography) to the bytes of the embedded file stream. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string CheckSum = "/CheckSum"; + + /// + /// Gets the KeysMeta for these keys. + /// + internal static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +} diff --git a/PdfSharpCore/Pdf.Advanced/PdfExtGState.cs b/PdfSharpCore/Pdf.Advanced/PdfExtGState.cs index 930a7aa7..5ca96ee2 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfExtGState.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfExtGState.cs @@ -29,13 +29,6 @@ using System.Globalization; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -#endif - namespace PdfSharpCore.Pdf.Advanced { /// diff --git a/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs b/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs new file mode 100644 index 00000000..056aa399 --- /dev/null +++ b/PdfSharpCore/Pdf.Advanced/PdfFileSpecification.cs @@ -0,0 +1,120 @@ +namespace PdfSharpCore.Pdf.Advanced +{ + /// + /// Represent a file stream embedded in the PDF document + /// + public class PdfFileSpecification : PdfDictionary + { + private readonly PdfDictionary embeddedFileDictionary; + + public PdfFileSpecification(PdfDocument document) + : base(document) + { + this.embeddedFileDictionary = new PdfDictionary(); + + Elements.SetName(Keys.Type, "/Filespec"); + Elements.SetObject(Keys.EF, embeddedFileDictionary); + } + + public PdfFileSpecification(PdfDocument document, string fileName, PdfEmbeddedFile embeddedFile) + : this(document) + { + this.FileName = fileName; + this.EmbeddedFile = embeddedFile; + } + + public string FileName + { + get { return Elements.GetString(Keys.F); } + set { Elements.SetString(Keys.F, value); } + } + + public PdfEmbeddedFile EmbeddedFile + { + get + { + var reference = embeddedFileDictionary.Elements.GetReference(Keys.F); + + return reference?.Value as PdfEmbeddedFile; + } + set + { + if (value == null) + { + embeddedFileDictionary.Elements.Remove(Keys.F); + } + else + { + if (!value.IsIndirect) + Owner._irefTable.Add(value); + + embeddedFileDictionary.Elements.SetReference(Keys.F, value); + } + } + } + + /// + /// Predefined keys of this embedded file. + /// + public class Keys : KeysBase + { + /// + /// (Required if an EF or RF entry is present; recommended always) + /// The type of PDF object that this dictionary describes; must be Filespec + /// for a file specification dictionary (see implementation note 45 in Appendix H). + /// + [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "Filespec")] + public const string Type = "/Type"; + + /// + /// (Required if the DOS, Mac, and Unix entries are all absent; amended with the UF + /// entry for PDF 1.7) A file specification string of the form described in Section + /// 3.10.1, “File Specification Strings,” or (if the file system is URL) a uniform + /// resource locator, as described in Section 3.10.4, “URL Specifications.” + /// + /// Note: It is recommended that the UF entry be used in addition to the F entry. + /// The UF entry provides cross-platform and cross-language compatibility and the F + /// entry provides backwards compatibility + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string F = "/F"; + + /// + /// (Required if RF is present; PDF 1.3; amended to include the UF key in PDF 1.7) + /// A dictionary containing a subset of the keys F, UF, DOS, Mac, and Unix, + /// corresponding to the entries by those names in the file specification dictionary. + /// The value of each such key is an embedded file stream (see Section 3.10.3, + /// “Embedded File Streams”) containing the corresponding file. If this entry is + /// present, the Type entry is required and the file specification dictionary must + /// be indirectly referenced. (See implementation note 46in Appendix H.) + /// + /// Note: It is recommended that the F and UF entries be used in place of the DOS, + /// Mac, or Unix entries. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Optional)] + public const string EF = "/EF"; + + /// + /// Gets the KeysMeta for these keys. + /// + internal static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +} diff --git a/PdfSharpCore/Pdf.Advanced/PdfFormXObject.cs b/PdfSharpCore/Pdf.Advanced/PdfFormXObject.cs index cec3b48a..3e18d762 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfFormXObject.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfFormXObject.cs @@ -29,13 +29,6 @@ using System; using System.Diagnostics; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; namespace PdfSharpCore.Pdf.Advanced @@ -219,9 +212,9 @@ internal PdfFormXObject(PdfDocument thisDocument, PdfImportedObjectTable importe // Translate the image such that its center lies on the center of the rotated bounding box double offset = (height - width) / 2; - if (height > width) + if (rotate == 90) matrix.TranslatePrepend(offset, offset); - else + else if (rotate == -90) matrix.TranslatePrepend(-offset, -offset); //string item = "[" + PdfEncoders.ToString(matrix) + "]"; diff --git a/PdfSharpCore/Pdf.Advanced/PdfGroupAttributes.cs b/PdfSharpCore/Pdf.Advanced/PdfGroupAttributes.cs index d42df3bd..c2c5aaa3 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfGroupAttributes.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfGroupAttributes.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Pdf.Advanced { /// diff --git a/PdfSharpCore/Pdf.Advanced/PdfImage.cs b/PdfSharpCore/Pdf.Advanced/PdfImage.cs index 461d6851..a45397d0 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfImage.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfImage.cs @@ -31,15 +31,6 @@ using System; using System.Diagnostics; using System.IO; -#if CORE -using System.Drawing.Imaging; -#endif -#if GDI -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media.Imaging; -#endif using PdfSharpCore.Drawing; using PdfSharpCore.Drawing.Internal; using PdfSharpCore.Pdf.Filters; @@ -62,7 +53,6 @@ public PdfImage(PdfDocument document, XImage image) _image = image; -#if !SILVERLIGHT ////// TODO: identify multiple used images. If the image already exists use the same XRef. ////_defaultName = PdfImageTable.NextImageName; @@ -91,147 +81,8 @@ public PdfImage(PdfDocument document, XImage image) Debug.Assert(false, "Unexpected image type."); break; } -#else - InitializeAg(); -#endif } -#if SILVERLIGHT - private void InitializeAg() - { - ReadTrueColorMemoryBitmapAg(3, 8, true); - } - - private void ReadTrueColorMemoryBitmapAg(int components, int bits, bool hasAlpha) - { - int pdfVersion = Owner.Version; - MemoryStream memory = new MemoryStream(); - - WriteableBitmap bitmap = null; - if (_image._wpfImage is WriteableBitmap) - bitmap = (WriteableBitmap)_image._wpfImage; - else if (_image._wpfImage is BitmapImage) - bitmap = new WriteableBitmap(_image._wpfImage); - - if (bitmap != null) - { - int height = _image.PixelHeight; - int width = _image.PixelWidth; - - int logicalComponents = components; - if (components == 4) - logicalComponents = 3; - - byte[] imageData = new byte[components * width * height]; - - bool hasMask = false; - bool hasAlphaMask = false; - byte[] alphaMask = hasAlpha ? new byte[width * height] : null; - MonochromeMask mask = hasAlpha ? new MonochromeMask(width, height) : null; - - int nOffsetRead = 0; - if (logicalComponents == 3) - { - for (int y = 0; y < height; ++y) - { - int nOffsetWrite = 3 * y * width; // 3*(height - 1 - y)*width; - int nOffsetWriteAlpha = 0; - if (hasAlpha) - { - mask.StartLine(y); - nOffsetWriteAlpha = y * width; // (height - 1 - y) * width; - } - - for (int x = 0; x < width; ++x) - { - uint pixel = (uint)bitmap.Pixels[nOffsetRead]; - imageData[nOffsetWrite] = (byte)(pixel >> 16); - imageData[nOffsetWrite + 1] = (byte)(pixel >> 8); - imageData[nOffsetWrite + 2] = (byte)(pixel); - if (hasAlpha) - { - byte pel = (byte)(pixel >> 24); - mask.AddPel(pel); - alphaMask[nOffsetWriteAlpha] = pel; - if (!hasMask || !hasAlphaMask) - { - if (pel != 255) - { - hasMask = true; - if (pel != 0) - hasAlphaMask = true; - } - } - ++nOffsetWriteAlpha; - } - //nOffsetRead += hasAlpha ? 4 : components; - ++nOffsetRead; - nOffsetWrite += 3; - } - //nOffsetRead = 4*((nOffsetRead + 3)/4); // Align to 32 bit boundary - } - } - else if (components == 1) - { - // Grayscale - throw new NotImplementedException("Image format not supported (grayscales)."); - } - - FlateDecode fd = new FlateDecode(); - if (hasMask) - { - // monochrome mask is either sufficient or - // provided for compatibility with older reader versions - byte[] maskDataCompressed = fd.Encode(mask.MaskData, _document.Options.FlateEncodeMode); - PdfDictionary pdfMask = new PdfDictionary(_document); - pdfMask.Elements.SetName(Keys.Type, "/XObject"); - pdfMask.Elements.SetName(Keys.Subtype, "/Image"); - - Owner._irefTable.Add(pdfMask); - pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask); - pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length); - pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode"); - pdfMask.Elements[Keys.Width] = new PdfInteger(width); - pdfMask.Elements[Keys.Height] = new PdfInteger(height); - pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1); - pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true); - Elements[Keys.Mask] = pdfMask.Reference; - } - if (hasMask && hasAlphaMask && pdfVersion >= 14) - { - // The image provides an alpha mask (requires Arcrobat 5.0 or higher) - byte[] alphaMaskCompressed = fd.Encode(alphaMask, _document.Options.FlateEncodeMode); - PdfDictionary smask = new PdfDictionary(_document); - smask.Elements.SetName(Keys.Type, "/XObject"); - smask.Elements.SetName(Keys.Subtype, "/Image"); - - Owner._irefTable.Add(smask); - smask.Stream = new PdfStream(alphaMaskCompressed, smask); - smask.Elements[Keys.Length] = new PdfInteger(alphaMaskCompressed.Length); - smask.Elements[Keys.Filter] = new PdfName("/FlateDecode"); - smask.Elements[Keys.Width] = new PdfInteger(width); - smask.Elements[Keys.Height] = new PdfInteger(height); - smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8); - smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - Elements[Keys.SMask] = smask.Reference; - } - - byte[] imageDataCompressed = fd.Encode(imageData, _document.Options.FlateEncodeMode); - - Stream = new PdfStream(imageDataCompressed, this); - Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length); - Elements[Keys.Filter] = new PdfName("/FlateDecode"); - Elements[Keys.Width] = new PdfInteger(width); - Elements[Keys.Height] = new PdfInteger(height); - Elements[Keys.BitsPerComponent] = new PdfInteger(8); - // TODO: CMYK - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - if (_image.Interpolate) - Elements[Keys.Interpolate] = PdfBoolean.True; - } - } -#endif - /// /// Gets the underlying XImage object. /// @@ -287,97 +138,7 @@ void InitializeJpeg() Elements[Keys.Width] = new PdfInteger(_image.PixelWidth); Elements[Keys.Height] = new PdfInteger(_image.PixelHeight); Elements[Keys.BitsPerComponent] = new PdfInteger(8); - -#if CORE || GDI || WPF - if (_image._importedImage != null) - { - if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGCMYK || - _image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGRGBW) - { - // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...) - Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); - if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGRGBW) - Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors from RGBW to CMYK. - } - else if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGGRAY) - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - } - else - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - } - } -#endif -#if CORE_WITH_GDI - if (_image._importedImage == null) - { - if ((_image._gdiImage.Flags & ((int)ImageFlags.ColorSpaceCmyk | (int)ImageFlags.ColorSpaceYcck)) != 0) - { - // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...) - Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); - if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceYcck) != 0) - Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors? Why?? - } - else if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceGray) != 0) - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - } - else - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - } - } -#endif -#if GDI - if (_image._importedImage == null) - { - if ((_image._gdiImage.Flags & ((int)ImageFlags.ColorSpaceCmyk | (int)ImageFlags.ColorSpaceYcck)) != 0) - { - // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...) - Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); - if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceYcck) != 0) - Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors? Why?? - } - else if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceGray) != 0) - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - } - else - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - } - } -#endif -#if WPF - // TODOSILVERLIGHT -#if !SILVERLIGHT - string pixelFormat = _image._wpfImage.Format.ToString(); -#else - string pixelFormat = "xxx"; -#endif - - bool isCmyk = _image.IsCmyk; - bool isGrey = pixelFormat == "Gray8"; - if (isCmyk) - { - // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...) - Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK"); - Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors? Why?? - } - else if (isGrey) - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - } - else - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - } -#endif - -#if __IOS__ || __ANDROID__ || PORTABLE Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); -#endif } /// @@ -385,344 +146,9 @@ void InitializeJpeg() /// void InitializeNonJpeg() { -#if CORE || GDI || WPF - if (_image._importedImage != null) - { - switch (_image._importedImage.Information.ImageFormat) - { - case ImageInformation.ImageFormats.RGB24: - CreateTrueColorMemoryBitmap(3, 8, false); - break; - - case ImageInformation.ImageFormats.Palette8: - CreateIndexedMemoryBitmap(8); - break; - - case ImageInformation.ImageFormats.Palette4: - CreateIndexedMemoryBitmap(4); - break; - - case ImageInformation.ImageFormats.Palette1: - CreateIndexedMemoryBitmap(1); - break; - - default: - throw new NotImplementedException("Image format not supported."); - } - return; - } -#endif -#if NETCOREAPP1_1 ReadTrueColorMemoryBitmap(3, 8, true); -#endif -#if (CORE_WITH_GDI || GDI) && !WPF - //bool hasMask = false; - switch (_image._gdiImage.PixelFormat) - { - case PixelFormat.Format24bppRgb: - ReadTrueColorMemoryBitmap(3, 8, false); - break; - - case PixelFormat.Format32bppRgb: - ReadTrueColorMemoryBitmap(4, 8, false); - break; - - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - //hasMask = true; - ReadTrueColorMemoryBitmap(3, 8, true); - break; - - case PixelFormat.Format8bppIndexed: - ReadIndexedMemoryBitmap(8/*, ref hasMask*/); - break; - - case PixelFormat.Format4bppIndexed: - ReadIndexedMemoryBitmap(4/*, ref hasMask*/); - break; - - case PixelFormat.Format1bppIndexed: - ReadIndexedMemoryBitmap(1/*, ref hasMask*/); - break; - - default: -#if DEBUGxxx - image.image.Save("$$$.bmp", ImageFormat.Bmp); -#endif - throw new NotImplementedException("Image format not supported."); - } -#endif -#if WPF // && !GDI -#if !SILVERLIGHT - string format = _image._wpfImage.Format.ToString(); -#else - string format = "Bgr24"; -#endif - switch (format) - { - case "Bgr24": //Format24bppRgb: - ReadTrueColorMemoryBitmap(3, 8, false); - break; - - //case .PixelFormat.Format32bppRgb: - // ReadTrueColorMemoryBitmap(4, 8, false); - // break; - - case "Bgra32": //PixelFormat.Format32bppArgb: - //case PixelFormat.Format32bppPArgb: - ReadTrueColorMemoryBitmap(3, 8, true); - break; - - case "Bgr32": - ReadTrueColorMemoryBitmap(4, 8, false); - break; - - case "Pbgra32": - ReadTrueColorMemoryBitmap(3, 8, true); - break; - - case "Indexed8": //Format8bppIndexed: - case "Gray8": - ReadIndexedMemoryBitmap(8/*, ref hasMask*/); - break; - - case "Indexed4": //Format4bppIndexed: - case "Gray4": - ReadIndexedMemoryBitmap(4/*, ref hasMask*/); - break; - - case "Indexed2": - ReadIndexedMemoryBitmap(2/*, ref hasMask*/); - break; - - case "Indexed1": //Format1bppIndexed: - case "BlackWhite": //Format1bppIndexed: - ReadIndexedMemoryBitmap(1/*, ref hasMask*/); - break; - - default: -#if DEBUGxxx - image.image.Save("$$$.bmp", ImageFormat.Bmp); -#endif - throw new NotImplementedException("Image format \"" + format + "\" not supported."); - } -#endif } -#if CORE || GDI || WPF - private void CreateIndexedMemoryBitmap(int bits) - { - ImageDataBitmap idb = (ImageDataBitmap)_image._importedImage.ImageData; - ImageInformation ii = _image._importedImage.Information; - - int pdfVersion = Owner.Version; - int firstMaskColor = -1, lastMaskColor = -1; - bool segmentedColorMask = idb.SegmentedColorMask; - - { - - FlateDecode fd = new FlateDecode(); - if (firstMaskColor != -1 && - lastMaskColor != -1) - { - // Color mask requires Reader 4.0 or higher: - //if (!segmentedColorMask && pdfVersion >= 13) - if (!segmentedColorMask && pdfVersion >= 13 && !idb.IsGray) - { - PdfArray array = new PdfArray(_document); - array.Elements.Add(new PdfInteger(firstMaskColor)); - array.Elements.Add(new PdfInteger(lastMaskColor)); - Elements[Keys.Mask] = array; - } - else - { - // Monochrome mask - byte[] maskDataCompressed = fd.Encode(idb.BitmapMask, _document.Options.FlateEncodeMode); - PdfDictionary pdfMask = new PdfDictionary(_document); - pdfMask.Elements.SetName(Keys.Type, "/XObject"); - pdfMask.Elements.SetName(Keys.Subtype, "/Image"); - - Owner._irefTable.Add(pdfMask); - pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask); - pdfMask.Elements[PdfStream.Keys.Length] = new PdfInteger(maskDataCompressed.Length); - pdfMask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - pdfMask.Elements[Keys.Width] = new PdfInteger((int)ii.Width); - pdfMask.Elements[Keys.Height] = new PdfInteger((int)ii.Height); - pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1); - pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true); - Elements[Keys.Mask] = pdfMask.Reference; - } - } - - byte[] imageDataCompressed = fd.Encode(idb.Data, _document.Options.FlateEncodeMode); - byte[] imageDataFaxCompressed = idb.DataFax != null ? fd.Encode(idb.DataFax, _document.Options.FlateEncodeMode) : null; - - bool usesCcittEncoding = false; - if (idb.DataFax != null && - (idb.LengthFax < imageDataCompressed.Length || - imageDataFaxCompressed.Length < imageDataCompressed.Length)) - { - // /CCITTFaxDecode creates the smaller file (with or without /FlateDecode): - usesCcittEncoding = true; - - if (idb.LengthFax < imageDataCompressed.Length) - { - Stream = new PdfStream(idb.DataFax, this); - Elements[PdfStream.Keys.Length] = new PdfInteger(idb.LengthFax); - Elements[PdfStream.Keys.Filter] = new PdfName("/CCITTFaxDecode"); - //PdfArray array2 = new PdfArray(_document); - PdfDictionary dictionary = new PdfDictionary(); - if (idb.K != 0) - dictionary.Elements.Add("/K", new PdfInteger(idb.K)); - if (idb.IsBitonal < 0) - dictionary.Elements.Add("/BlackIs1", new PdfBoolean(true)); - dictionary.Elements.Add("/EndOfBlock", new PdfBoolean(false)); - dictionary.Elements.Add("/Columns", new PdfInteger((int)ii.Width)); - dictionary.Elements.Add("/Rows", new PdfInteger((int)ii.Height)); - //array2.Elements.Add(dictionary); - Elements[PdfStream.Keys.DecodeParms] = dictionary; // array2; - } - else - { - Stream = new PdfStream(imageDataFaxCompressed, this); - Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataFaxCompressed.Length); - PdfArray arrayFilters = new PdfArray(_document); - arrayFilters.Elements.Add(new PdfName("/FlateDecode")); - arrayFilters.Elements.Add(new PdfName("/CCITTFaxDecode")); - Elements[PdfStream.Keys.Filter] = arrayFilters; - PdfArray arrayDecodeParms = new PdfArray(_document); - - PdfDictionary dictFlateDecodeParms = new PdfDictionary(); - //dictFlateDecodeParms.Elements.Add("/Columns", new PdfInteger(1)); - - PdfDictionary dictCcittFaxDecodeParms = new PdfDictionary(); - if (idb.K != 0) - dictCcittFaxDecodeParms.Elements.Add("/K", new PdfInteger(idb.K)); - if (idb.IsBitonal < 0) - dictCcittFaxDecodeParms.Elements.Add("/BlackIs1", new PdfBoolean(true)); - dictCcittFaxDecodeParms.Elements.Add("/EndOfBlock", new PdfBoolean(false)); - dictCcittFaxDecodeParms.Elements.Add("/Columns", new PdfInteger((int)ii.Width)); - dictCcittFaxDecodeParms.Elements.Add("/Rows", new PdfInteger((int)ii.Height)); - - arrayDecodeParms.Elements.Add(dictFlateDecodeParms); // How to add the "null object"? - arrayDecodeParms.Elements.Add(dictCcittFaxDecodeParms); - Elements[PdfStream.Keys.DecodeParms] = arrayDecodeParms; - } - } - else - { - // /FlateDecode creates the smaller file (or no monochrome bitmap): - Stream = new PdfStream(imageDataCompressed, this); - Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataCompressed.Length); - Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - } - - Elements[Keys.Width] = new PdfInteger((int)ii.Width); - Elements[Keys.Height] = new PdfInteger((int)ii.Height); - Elements[Keys.BitsPerComponent] = new PdfInteger(bits); - // TODO: CMYK - - // CCITT encoding: we need color palette for isBitonal == 0 - // FlateDecode: we need color palette for isBitonal <= 0 unless we have grayscales - if ((usesCcittEncoding && idb.IsBitonal == 0) || - (!usesCcittEncoding && idb.IsBitonal <= 0 && !idb.IsGray)) - { - PdfDictionary colorPalette = null; - colorPalette = new PdfDictionary(_document); - byte[] packedPaletteData = idb.PaletteDataLength >= 48 ? fd.Encode(idb.PaletteData, _document.Options.FlateEncodeMode) : null; // don't compress small palettes - if (packedPaletteData != null && packedPaletteData.Length + 20 < idb.PaletteDataLength) // +20: compensate for the overhead (estimated value) - { - // Create compressed color palette: - colorPalette.CreateStream(packedPaletteData); - colorPalette.Elements[PdfStream.Keys.Length] = new PdfInteger(packedPaletteData.Length); - colorPalette.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - } - else - { - // Create uncompressed color palette: - colorPalette.CreateStream(idb.PaletteData); - colorPalette.Elements[PdfStream.Keys.Length] = new PdfInteger(idb.PaletteDataLength); - } - Owner._irefTable.Add(colorPalette); - - PdfArray arrayColorSpace = new PdfArray(_document); - arrayColorSpace.Elements.Add(new PdfName("/Indexed")); - arrayColorSpace.Elements.Add(new PdfName("/DeviceRGB")); - arrayColorSpace.Elements.Add(new PdfInteger((int)ii.ColorsUsed - 1)); - arrayColorSpace.Elements.Add(colorPalette.Reference); - Elements[Keys.ColorSpace] = arrayColorSpace; - } - else - { - Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - } - if (_image.Interpolate) - Elements[Keys.Interpolate] = PdfBoolean.True; - } - } - - private void CreateTrueColorMemoryBitmap(int components, int bits, bool hasAlpha) - { - int pdfVersion = Owner.Version; - FlateDecode fd = new FlateDecode(); - ImageDataBitmap idb = (ImageDataBitmap)_image._importedImage.ImageData; - ImageInformation ii = _image._importedImage.Information; - bool hasMask = idb.AlphaMaskLength > 0 || idb.BitmapMaskLength > 0; - bool hasAlphaMask = idb.AlphaMaskLength > 0; - - if (hasMask) - { - // monochrome mask is either sufficient or - // provided for compatibility with older reader versions - byte[] maskDataCompressed = fd.Encode(idb.BitmapMask, _document.Options.FlateEncodeMode); - PdfDictionary pdfMask = new PdfDictionary(_document); - pdfMask.Elements.SetName(Keys.Type, "/XObject"); - pdfMask.Elements.SetName(Keys.Subtype, "/Image"); - - Owner._irefTable.Add(pdfMask); - pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask); - pdfMask.Elements[PdfStream.Keys.Length] = new PdfInteger(maskDataCompressed.Length); - pdfMask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - pdfMask.Elements[Keys.Width] = new PdfInteger((int)ii.Width); - pdfMask.Elements[Keys.Height] = new PdfInteger((int)ii.Height); - pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1); - pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true); - Elements[Keys.Mask] = pdfMask.Reference; - } - if (hasMask && hasAlphaMask && pdfVersion >= 14) - { - // The image provides an alpha mask (requires Arcrobat 5.0 or higher) - byte[] alphaMaskCompressed = fd.Encode(idb.AlphaMask, _document.Options.FlateEncodeMode); - PdfDictionary smask = new PdfDictionary(_document); - smask.Elements.SetName(Keys.Type, "/XObject"); - smask.Elements.SetName(Keys.Subtype, "/Image"); - - Owner._irefTable.Add(smask); - smask.Stream = new PdfStream(alphaMaskCompressed, smask); - smask.Elements[PdfStream.Keys.Length] = new PdfInteger(alphaMaskCompressed.Length); - smask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - smask.Elements[Keys.Width] = new PdfInteger((int)ii.Width); - smask.Elements[Keys.Height] = new PdfInteger((int)ii.Height); - smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8); - smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray"); - Elements[Keys.SMask] = smask.Reference; - } - - byte[] imageDataCompressed = fd.Encode(idb.Data, _document.Options.FlateEncodeMode); - - Stream = new PdfStream(imageDataCompressed, this); - Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataCompressed.Length); - Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode"); - Elements[Keys.Width] = new PdfInteger((int)ii.Width); - Elements[Keys.Height] = new PdfInteger((int)ii.Height); - Elements[Keys.BitsPerComponent] = new PdfInteger(8); - // TODO: CMYK - Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); - if (_image.Interpolate) - Elements[Keys.Interpolate] = PdfBoolean.True; - } -#endif - private static int ReadWord(byte[] ab, int offset) { return ab[offset] + 256 * ab[offset + 1]; @@ -741,56 +167,19 @@ private static int ReadDWord(byte[] ab, int offset) /// true (ARGB), false (RGB) private void ReadTrueColorMemoryBitmap(int components, int bits, bool hasAlpha) { -#if DEBUG_ - image.image.Save("$$$.bmp", ImageFormat.Bmp); -#endif int pdfVersion = Owner.Version; MemoryStream memory = new MemoryStream(); -#if CORE_WITH_GDI - _image._gdiImage.Save(memory, ImageFormat.Bmp); -#endif -#if GDI - _image._gdiImage.Save(memory, ImageFormat.Bmp); -#endif -#if WPF -#if !SILVERLIGHT - BmpBitmapEncoder encoder = new BmpBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(_image._wpfImage)); - encoder.Save(memory); -#else - // AGHACK - GetType(); -#endif -#endif -#if NETCOREAPP1_1 memory = _image.AsBitmap(); -#endif // THHO4THHO Use ImageImporterBMP here to avoid redundant code. int streamLength = (int)memory.Length; Debug.Assert(streamLength > 0, "Bitmap image encoding failed."); if (streamLength > 0) { -#if !NETFX_CORE && !UWP && !PORTABLE - // THHO4STLA: available with wrt, but not with wrt81. - // Note: imageBits.Length can be larger than streamLength. Do not use these extra bytes! - byte[] imageBits = memory.GetBuffer(); -#elif NETFX_CORE - byte[] imageBits = new byte[streamLength]; - memory.Seek(0, SeekOrigin.Begin); - memory.Read(imageBits, 0, streamLength); - memory.Close(); -#elif UWP - byte[] imageBits = new byte[streamLength]; - memory.Seek(0, SeekOrigin.Begin); - memory.Read(imageBits, 0, streamLength); - memory.Dispose(); -#elif PORTABLE byte[] imageBits = new byte[streamLength]; memory.Seek(0, SeekOrigin.Begin); memory.Read(imageBits, 0, streamLength); memory.Dispose(); -#endif int height = _image.PixelHeight; int width = _image.PixelWidth; @@ -958,25 +347,6 @@ private void ReadIndexedMemoryBitmap(int bits/*, ref bool hasAlpha*/) bool segmentedColorMask = false; MemoryStream memory = new MemoryStream(); -#if CORE_WITH_GDI - _image._gdiImage.Save(memory, ImageFormat.Bmp); -#endif -#if GDI - _image._gdiImage.Save(memory, ImageFormat.Bmp); -#endif -#if WPF -#if !SILVERLIGHT - BmpBitmapEncoder encoder = new BmpBitmapEncoder(); - //if (!_image._path.StartsWith("*")) - // encoder.Frames.Add(BitmapFrame.Create(new Uri(_image._path), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)); - //else - encoder.Frames.Add(BitmapFrame.Create(_image._wpfImage)); - encoder.Save(memory); -#else - // AGHACK - GetType(); -#endif -#endif // THHO4THHO Use ImageImporterBMP here to avoid redundant code. int streamLength = (int)memory.Length; @@ -986,11 +356,7 @@ private void ReadIndexedMemoryBitmap(int bits/*, ref bool hasAlpha*/) byte[] imageBits = new byte[streamLength]; memory.Seek(0, SeekOrigin.Begin); memory.Read(imageBits, 0, streamLength); -#if !UWP && !PORTABLE - memory.Close(); -#else memory.Dispose(); -#endif int height = _image.PixelHeight; int width = _image.PixelWidth; @@ -998,22 +364,11 @@ private void ReadIndexedMemoryBitmap(int bits/*, ref bool hasAlpha*/) if (ReadWord(imageBits, 0) != 0x4d42 || // "BM" ReadDWord(imageBits, 2) != streamLength || ReadDWord(imageBits, 14) != 40 || // sizeof BITMAPINFOHEADER -#if WPF - // TODOWPF: bug with height and width??? With which files??? ReadDWord(imageBits, 18) != width || ReadDWord(imageBits, 22) != height) -#else - ReadDWord(imageBits, 18) != width || - ReadDWord(imageBits, 22) != height) -#endif { throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format"); } -#if WPF - // TODOWPF: bug with height and width - width = ReadDWord(imageBits, 18); - height = ReadDWord(imageBits, 22); -#endif int fileBits = ReadWord(imageBits, 28); if (fileBits != bits) { @@ -1098,7 +453,6 @@ private void ReadIndexedMemoryBitmap(int bits/*, ref bool hasAlpha*/) byte[] imageDataFax = null; int k = 0; - if (bits == 1) { // TODO: flag/option? diff --git a/PdfSharpCore/Pdf.Advanced/PdfInternals.cs b/PdfSharpCore/Pdf.Advanced/PdfInternals.cs index e1d9b5b8..b921ccbd 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfInternals.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfInternals.cs @@ -191,12 +191,7 @@ public PdfObject[] GetAllObjects() public T CreateIndirectObject() where T : PdfObject { T result = null; -#if !NETFX_CORE && !UWP && !PORTABLE - ConstructorInfo ctorInfo = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.ExactBinding, - null, new Type[] { typeof(PdfDocument) }, null); -#else ConstructorInfo ctorInfo = null; // TODO -#endif if (ctorInfo != null) { result = (T)ctorInfo.Invoke(new object[] { _document }); diff --git a/PdfSharpCore/Pdf.Advanced/PdfObjectStream.cs b/PdfSharpCore/Pdf.Advanced/PdfObjectStream.cs index 12bfe132..97cfb1d7 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfObjectStream.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfObjectStream.cs @@ -48,12 +48,6 @@ public class PdfObjectStream : PdfDictionary public PdfObjectStream(PdfDocument document) : base(document) { -#if DEBUG && CORE - if (Internal.PdfDiagnostics.TraceObjectStreams) - { - Debug.WriteLine("PdfObjectStream(document) created."); - } -#endif } /// @@ -62,19 +56,18 @@ public PdfObjectStream(PdfDocument document) internal PdfObjectStream(PdfDictionary dict) : base(dict) { + // while objects inside an object-stream are not encrypted, the object-streams themself ARE ! + // 7.5.7, Page 47: In an encrypted file (i.e., entire object stream is encrypted), + // strings occurring anywhere in an object stream shall not be separately encrypted. + if (_document._trailer.Elements[PdfTrailer.Keys.Encrypt] is PdfReference) + _document.SecurityHandler.EncryptObject(dict); + int n = Elements.GetInteger(Keys.N); int first = Elements.GetInteger(Keys.First); Stream.TryUnfilter(); Parser parser = new Parser(null, new MemoryStream(Stream.Value)); _header = parser.ReadObjectStreamHeader(n, first); - -#if DEBUG && CORE - if (Internal.PdfDiagnostics.TraceObjectStreams) - { - Debug.WriteLine(String.Format("PdfObjectStream(document) created. Header item count: {0}", _header.GetLength(0))); - } -#endif } /// @@ -162,12 +155,4 @@ public class Keys : PdfStream.Keys public const string Extends = "/Extends"; } } - -#if DEBUG && CORE - static class ObjectStreamDiagnostics - { - public static void AddObjectStreamXRef() - { } - } -#endif } diff --git a/PdfSharpCore/Pdf.Advanced/PdfReference.cs b/PdfSharpCore/Pdf.Advanced/PdfReference.cs index 36897edf..68823433 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfReference.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfReference.cs @@ -79,7 +79,7 @@ public PdfReference(PdfObject pdfObject) /// /// Initializes a new PdfReference instance from the specified object identifier and file position. /// - public PdfReference(PdfObjectID objectID, int position) + public PdfReference(PdfObjectID objectID, long position) { _objectID = objectID; _position = position; @@ -152,12 +152,12 @@ public int GenerationNumber /// /// Gets or sets the file position of the related PdfObject. /// - public int Position + public long Position { get { return _position; } set { _position = value; } } - int _position; // I know it should be long, but I have never seen a 2GB PDF file. + long _position; //public bool InUse //{ diff --git a/PdfSharpCore/Pdf.Advanced/PdfShading.cs b/PdfSharpCore/Pdf.Advanced/PdfShading.cs index 9e98d2ac..c880e102 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfShading.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfShading.cs @@ -28,13 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; using PdfSharpCore.Drawing.Pdf; using PdfSharpCore.Pdf.Internal; diff --git a/PdfSharpCore/Pdf.Advanced/PdfShadingPattern.cs b/PdfSharpCore/Pdf.Advanced/PdfShadingPattern.cs index 25170ded..4bc597b8 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfShadingPattern.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfShadingPattern.cs @@ -28,13 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; using PdfSharpCore.Drawing.Pdf; diff --git a/PdfSharpCore/Pdf.Advanced/PdfSoftMask.cs b/PdfSharpCore/Pdf.Advanced/PdfSoftMask.cs index 6bd2863d..d8f66c2e 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfSoftMask.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfSoftMask.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Pdf.Advanced { /// diff --git a/PdfSharpCore/Pdf.Advanced/PdfTilingPattern.cs b/PdfSharpCore/Pdf.Advanced/PdfTilingPattern.cs index 21945877..0d72d915 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfTilingPattern.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfTilingPattern.cs @@ -27,14 +27,6 @@ // DEALINGS IN THE SOFTWARE. #endregion -#if GDI -using System.Drawing; -using System.Drawing.Imaging; -#endif -#if WPF -using System.Windows.Media; -#endif - namespace PdfSharpCore.Pdf.Advanced { /// diff --git a/PdfSharpCore/Pdf.Advanced/PdfToUnicodeMap.cs b/PdfSharpCore/Pdf.Advanced/PdfToUnicodeMap.cs index e5a1776e..0447f03e 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfToUnicodeMap.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfToUnicodeMap.cs @@ -89,11 +89,7 @@ internal override void PrepareForSave() } MemoryStream ms = new MemoryStream(); -#if !SILVERLIGHT && !NETFX_CORE && !PORTABLE - StreamWriter wrt = new StreamWriter(ms, Encoding.ASCII); -#else StreamWriter wrt = new StreamWriter(ms, Encoding.UTF8); -#endif wrt.Write(prefix); wrt.WriteLine("1 begincodespacerange"); @@ -107,19 +103,11 @@ internal override void PrepareForSave() wrt.WriteLine("endbfrange"); wrt.Write(suffix); -#if !UWP && !PORTABLE - wrt.Close(); -#else wrt.Dispose(); -#endif // Compress like content streams byte[] bytes = ms.ToArray(); -#if !UWP && !PORTABLE - ms.Close(); -#else ms.Dispose(); -#endif if (Owner.Options.CompressContentStreams) { Elements.SetName("/Filter", "/FlateDecode"); diff --git a/PdfSharpCore/Pdf.Advanced/PdfTrailer.cs b/PdfSharpCore/Pdf.Advanced/PdfTrailer.cs index f8576c63..aef89783 100644 --- a/PdfSharpCore/Pdf.Advanced/PdfTrailer.cs +++ b/PdfSharpCore/Pdf.Advanced/PdfTrailer.cs @@ -201,15 +201,9 @@ internal void Finish() iref = _document._trailer.Elements[Keys.Encrypt] as PdfReference; if (iref != null) { - iref = _document._irefTable[iref.ObjectID]; - Debug.Assert(iref.Value != null); - _document._trailer.Elements[Keys.Encrypt] = iref; - - // The encryption dictionary (security handler) was read in before the XRefTable construction - // was completed. The next lines fix that state (it took several hours to find these bugs...). - iref.Value = _document._trailer._securityHandler; - _document._trailer._securityHandler.Reference = iref; - iref.Value.Reference = iref; + _document._irefTable.Remove(_document._irefTable[iref.ObjectID]); + _document._irefTable.Add(_document._trailer._securityHandler); + _document._trailer.Elements[Keys.Encrypt] = _document._trailer._securityHandler; } Elements.Remove(Keys.Prev); diff --git a/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs b/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs new file mode 100644 index 00000000..34c995e2 --- /dev/null +++ b/PdfSharpCore/Pdf.Annotations/PdfFileAttachmentAnnotation.cs @@ -0,0 +1,129 @@ +using PdfSharpCore.Pdf.Advanced; +using System; + +namespace PdfSharpCore.Pdf.Annotations +{ + /// + /// Represent a file that is attached to the PDF + /// + public class PdfFileAttachmentAnnotation : PdfAnnotation + { + /// + /// Name of icons used in displaying the annotation. + /// + public enum IconType + { + Graph, + PushPin, + Paperclip, + Tag + } + + /// + /// Initializes a new instance of the class. + /// + public PdfFileAttachmentAnnotation() + { + Elements.SetName(Keys.Subtype, "/FileAttachment"); + } + + /// + /// Initializes a new instance of the class. + /// + public PdfFileAttachmentAnnotation(PdfDocument document) + : base(document) + { + Elements.SetName(Keys.Subtype, "/FileAttachment"); + Flags = PdfAnnotationFlags.Locked; + } + + public IconType Icon + { + get + { + var iconName = Elements.GetName(Keys.Name); + + if (iconName == null) + return IconType.PushPin; + + return (IconType)(Enum.Parse(typeof(IconType), iconName)); + } + set { Elements.SetName(Keys.Name, value.ToString()); } + } + + public PdfFileSpecification File + { + get + { + var reference = Elements.GetReference(Keys.FS); + + return reference?.Value as PdfFileSpecification; + } + set + { + if (value == null) + { + Elements.Remove(Keys.FS); + } + else + { + if (!value.IsIndirect) + Owner._irefTable.Add(value); + + Elements.SetReference(Keys.FS, value); + } + } + } + + /// + /// Predefined keys of this dictionary. + /// + internal new class Keys : PdfAnnotation.Keys + { + /// + /// (Required) The file associated with this annotation. + /// + [KeyInfo(KeyType.Dictionary | KeyType.Required)] + public const string FS = "/FS"; + + /// + /// (Optional) The name of an icon to be used in displaying the annotation. + /// Viewer applications should provide predefined icon appearances for at least + /// the following standard names: + /// + /// Graph + /// PushPin + /// Paperclip + /// Tag + /// + /// Additional names may be supported as well. Default value: PushPin. + /// Note: The annotation dictionary’s AP entry, if present, takes precedence over + /// the Name entry; see Table 8.15 on page 606 and Section 8.4.4, “Appearance Streams.” + /// + [KeyInfo(KeyType.Name | KeyType.Optional)] + public const string Name = "/Name"; + + /// + /// Gets the KeysMeta for these keys. + /// + public static DictionaryMeta Meta + { + get + { + if (Keys.meta == null) + Keys.meta = CreateMeta(typeof(Keys)); + return Keys.meta; + } + } + static DictionaryMeta meta; + } + + /// + /// Gets the KeysMeta of this dictionary type. + /// + internal override DictionaryMeta Meta + { + get { return Keys.Meta; } + } + } +} diff --git a/PdfSharpCore/Pdf.Content.Objects/CObjects.cs b/PdfSharpCore/Pdf.Content.Objects/CObjects.cs index 6a2d6082..af440074 100644 --- a/PdfSharpCore/Pdf.Content.Objects/CObjects.cs +++ b/PdfSharpCore/Pdf.Content.Objects/CObjects.cs @@ -1,4 +1,5 @@ #region PDFsharp - A .NET library for processing PDF + // // Authors: // Stefan Lange @@ -25,6 +26,7 @@ // 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; @@ -35,7 +37,7 @@ using System.IO; using System.Text; -namespace PdfSharpCore.Pdf.Content.Objects // TODO: split into single files +namespace PdfSharpCore.Pdf.Content.Objects // TODO: split into single files { /// /// Base class for all PDF content stream objects. @@ -46,7 +48,8 @@ public abstract class CObject : ICloneable /// Initializes a new instance of the class. /// protected CObject() - { } + { + } /// /// Creates a new object that is a copy of the current instance. @@ -109,6 +112,7 @@ public string Text get { return _text; } set { _text = value; } } + string _text; /// @@ -129,7 +133,7 @@ internal override void WriteObject(ContentWriter writer) /// Represents a sequence of objects in a PDF content stream. /// [DebuggerDisplay("(count={Count})")] - public class CSequence : CObject, IList // , ICollection, IEnumerable + public class CSequence : CObject, IList // , ICollection, IEnumerable { /// /// Creates a new object that is a copy of the current instance. @@ -250,6 +254,7 @@ public CObject this[int index] get { return (CObject)_items[index]; } set { _items[index] = value; } } + #endregion #region ICollection Members @@ -315,11 +320,7 @@ public byte[] ToContent() int count = (int)stream.Length; byte[] bytes = new byte[count]; stream.Read(bytes, 0, count); -#if !UWP && !PORTABLE - stream.Close(); -#else stream.Dispose(); -#endif return bytes; } @@ -366,14 +367,8 @@ void IList.RemoveAt(int index) CObject IList.this[int index] { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } } #endregion @@ -488,6 +483,7 @@ public int Value get { return _value; } set { _value = value; } } + int _value; /// @@ -535,6 +531,7 @@ public double Value get { return _value; } set { _value = value; } } + double _value; /// @@ -615,6 +612,7 @@ public string Value get { return _value; } set { _value = value; } } + string _value; /// @@ -625,6 +623,7 @@ public CStringType CStringType get { return _cStringType; } set { _cStringType = value; } } + CStringType _cStringType; /// @@ -691,6 +690,7 @@ public override string ToString() break; } } + s.Append(')'); break; @@ -714,6 +714,7 @@ public override string ToString() default: throw new ArgumentOutOfRangeException(); } + return s.ToString(); } @@ -729,12 +730,14 @@ internal override void WriteObject(ContentWriter writer) [DebuggerDisplay("({Name})")] public class CName : CObject { + private const string NamePrefix = "/"; + /// /// Initializes a new instance of the class. /// public CName() { - _name = "/"; + _name = NamePrefix; } /// @@ -764,21 +767,24 @@ protected override CObject Copy() } /// - /// Gets or sets the name. Names must start with a slash. + /// Gets or sets the content stream name. Names must start with a slash. /// + /// + /// If does not start with a forward slash public string Name { - get { return _name; } + get => _name; set { - if (String.IsNullOrEmpty(_name)) - throw new ArgumentNullException("name"); - if (_name[0] != '/') - throw new ArgumentException(PSSR.NameMustStartWithSlash); + if (string.IsNullOrEmpty(value)) + throw new ArgumentNullException(nameof(value)); + if (!value.StartsWith(NamePrefix)) + throw new ArgumentException(PSSR.NameMustStartWithSlash, nameof(value)); _name = value; } } - string _name; + + private string _name; /// /// Returns a string that represents the current value. @@ -841,7 +847,8 @@ public class COperator : CObject /// Initializes a new instance of the class. /// protected COperator() - { } + { + } internal COperator(OpCode opcode) { @@ -882,6 +889,7 @@ public CSequence Operands { get { return _seqence ?? (_seqence = new CSequence()); } } + CSequence _seqence; /// @@ -891,6 +899,7 @@ public OpCode OpCode { get { return _opcode; } } + readonly OpCode _opcode; @@ -907,13 +916,14 @@ public override string ToString() internal override void WriteObject(ContentWriter writer) { - int count = _seqence != null ? _seqence.Count : 0; + int count = _seqence?.Count ?? 0; for (int idx = 0; idx < count; idx++) { // ReSharper disable once PossibleNullReferenceException because the loop is not entered if _sequence is null _seqence[idx].WriteObject(writer); } + writer.WriteLineRaw(ToString()); } } -} +} \ No newline at end of file diff --git a/PdfSharpCore/Pdf.Content/CLexer.cs b/PdfSharpCore/Pdf.Content/CLexer.cs index 1bc6148b..b6e92f1f 100644 Binary files a/PdfSharpCore/Pdf.Content/CLexer.cs and b/PdfSharpCore/Pdf.Content/CLexer.cs differ diff --git a/PdfSharpCore/Pdf.Content/ContentWriter.cs b/PdfSharpCore/Pdf.Content/ContentWriter.cs index 3af98935..93ca0c35 100644 --- a/PdfSharpCore/Pdf.Content/ContentWriter.cs +++ b/PdfSharpCore/Pdf.Content/ContentWriter.cs @@ -51,11 +51,7 @@ public void Close(bool closeUnderlyingStream) { if (_stream != null && closeUnderlyingStream) { -#if UWP || PORTABLE _stream.Dispose(); -#else - _stream.Close(); -#endif _stream = null; } } diff --git a/PdfSharpCore/Pdf.Filters/Filter.cs b/PdfSharpCore/Pdf.Filters/Filter.cs index 3f9562d5..158abfbb 100644 --- a/PdfSharpCore/Pdf.Filters/Filter.cs +++ b/PdfSharpCore/Pdf.Filters/Filter.cs @@ -37,7 +37,15 @@ namespace PdfSharpCore.Pdf.Filters /// public class FilterParms { - // not yet used + /// + /// Gets the decoding-parameters for a filter. May be null + /// + public PdfDictionary DecodeParms { get; private set; } + + public FilterParms(PdfDictionary decodeParms) + { + DecodeParms = decodeParms; + } } /// @@ -68,9 +76,9 @@ public virtual byte[] Encode(string rawString) /// /// Decodes the specified data. /// - public byte[] Decode(byte[] data) + public byte[] Decode(byte[] data, PdfDictionary decodeParms) { - return Decode(data, null); + return Decode(data, new FilterParms(decodeParms)); } /// diff --git a/PdfSharpCore/Pdf.Filters/Filtering.cs b/PdfSharpCore/Pdf.Filters/Filtering.cs index faaf6fb8..4b153b37 100644 --- a/PdfSharpCore/Pdf.Filters/Filtering.cs +++ b/PdfSharpCore/Pdf.Filters/Filtering.cs @@ -191,27 +191,34 @@ public static byte[] Decode(byte[] data, string filterName) { Filter filter = GetFilter(filterName); if (filter != null) - return filter.Decode(data, null); + return filter.Decode(data, (PdfDictionary)null); return null; } /// /// Decodes the data with the specified filter. /// - public static byte[] Decode(byte[] data, PdfItem filterItem) + public static byte[] Decode(byte[] data, PdfItem filterItem, PdfItem decodeParms) { byte[] result = null; - if (filterItem is PdfName) + if (filterItem is PdfName && (decodeParms == null || decodeParms is PdfDictionary)) { Filter filter = GetFilter(filterItem.ToString()); if (filter != null) - result = filter.Decode(data); + result = filter.Decode(data, decodeParms as PdfDictionary); } - else if (filterItem is PdfArray) + else if (filterItem is PdfArray itemArray && (decodeParms == null || decodeParms is PdfArray)) { - PdfArray array = (PdfArray)filterItem; - foreach (PdfItem item in array) - data = Decode(data, item); + var decodeArray = decodeParms as PdfArray; + // array length of filter and decode parms should match. if they dont, return data unmodified + if (decodeArray != null && decodeArray.Elements.Count != itemArray.Elements.Count) + return data; + for (var i = 0; i < itemArray.Elements.Count; i++) + { + var item = itemArray.Elements[i]; + var parms = decodeArray != null ? decodeArray.Elements[i] : null; + data = Decode(data, item, parms); + } result = data; } return result; diff --git a/PdfSharpCore/Pdf.Filters/FlateDecode.cs b/PdfSharpCore/Pdf.Filters/FlateDecode.cs index 35dae66c..47c16ff4 100644 --- a/PdfSharpCore/Pdf.Filters/FlateDecode.cs +++ b/PdfSharpCore/Pdf.Filters/FlateDecode.cs @@ -30,12 +30,8 @@ using System; using System.IO; using PdfSharpCore.Internal; -#if NET_ZIP -using System.IO.Compression; -#else -using PdfSharpCore.SharpZipLib.Zip.Compression; -using PdfSharpCore.SharpZipLib.Zip.Compression.Streams; -#endif +using ICSharpCode.SharpZipLib.Zip.Compression; +using ICSharpCode.SharpZipLib.Zip.Compression.Streams; namespace PdfSharpCore.Pdf.Filters { @@ -63,75 +59,7 @@ public byte[] Encode(byte[] data, PdfFlateEncodeMode mode) // DeflateStream/GZipStream does not work immediately and I have not the leisure to work it out. // So I keep on using SharpZipLib even with .NET 2.0. -#if NET_ZIP - // See http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97064 - // - // Excerpt from the RFC 1950 specs for first byte: - // - // CMF (Compression Method and flags) - // This byte is divided into a 4-bit compression method and a 4- - // bit information field depending on the compression method. - // - // bits 0 to 3 CM Compression method - // bits 4 to 7 CINFO Compression info - // - // CM (Compression method) - // This identifies the compression method used in the file. CM = 8 - // denotes the "deflate" compression method with a window size up - // to 32K. This is the method used by gzip and PNG (see - // references [1] and [2] in Chapter 3, below, for the reference - // documents). CM = 15 is reserved. It might be used in a future - // version of this specification to indicate the presence of an - // extra field before the compressed data. - // - // CINFO (Compression info) - // For CM = 8, CINFO is the base-2 logarithm of the LZ77 window - // size, minus eight (CINFO=7 indicates a 32K window size). Values - // of CINFO above 7 are not allowed in this version of the - // specification. CINFO is not defined in this specification for - // CM not equal to 8. - ms.WriteByte(0x78); - // Excerpt from the RFC 1950 specs for second byte: - // - // FLG (FLaGs) - // This flag byte is divided as follows: - // - // bits 0 to 4 FCHECK (check bits for CMF and FLG) - // bit 5 FDICT (preset dictionary) - // bits 6 to 7 FLEVEL (compression level) - // - // The FCHECK value must be such that CMF and FLG, when viewed as - // a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), - // is a multiple of 31. - // - // FDICT (Preset dictionary) - // If FDICT is set, a DICT dictionary identifier is present - // immediately after the FLG byte. The dictionary is a sequence of - // bytes which are initially fed to the compressor without - // producing any compressed output. DICT is the Adler-32 checksum - // of this sequence of bytes (see the definition of ADLER32 - // below). The decompressor can use this identifier to determine - // which dictionary has been used by the compressor. - // - // FLEVEL (Compression level) - // These flags are available for use by specific compression - // methods. The "deflate" method (CM = 8) sets these flags as - // follows: - // - // 0 - compressor used fastest algorithm - // 1 - compressor used fast algorithm - // 2 - compressor used default algorithm - // 3 - compressor used maximum compression, slowest algorithm - // - // The information in FLEVEL is not needed for decompression; it - // is there to indicate if recompression might be worthwhile. - ms.WriteByte(0x49); - - DeflateStream zip = new DeflateStream(ms, CompressionMode.Compress, true); - zip.Write(data, 0, data.Length); - zip.Close(); -#else int level = Deflater.DEFAULT_COMPRESSION; switch (mode) { @@ -145,13 +73,7 @@ public byte[] Encode(byte[] data, PdfFlateEncodeMode mode) DeflaterOutputStream zip = new DeflaterOutputStream(ms, new Deflater(level, false)); zip.Write(data, 0, data.Length); zip.Finish(); -#endif -#if !NETFX_CORE && !UWP && !PORTABLE - ms.Capacity = (int)ms.Length; - return ms.GetBuffer(); -#else return ms.ToArray(); -#endif } /// @@ -159,35 +81,11 @@ public byte[] Encode(byte[] data, PdfFlateEncodeMode mode) /// public override byte[] Decode(byte[] data, FilterParms parms) { + if (data.Length == 0) return data; + MemoryStream msInput = new MemoryStream(data); MemoryStream msOutput = new MemoryStream(); -#if NET_ZIP - // See http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97064 - // It seems to work when skipping the first two bytes. - byte header; // 0x30 0x59 - header = (byte)msInput.ReadByte(); - //Debug.Assert(header == 48); - header = (byte)msInput.ReadByte(); - //Debug.Assert(header == 89); - DeflateStream zip = new DeflateStream(msInput, CompressionMode.Decompress, true); - int cbRead; - byte[] abResult = new byte[1024]; - do - { - cbRead = zip.Read(abResult, 0, abResult.Length); - if (cbRead > 0) - msOutput.Write(abResult, 0, cbRead); - } - while (cbRead > 0); - zip.Close(); - msOutput.Flush(); - if (msOutput.Length >= 0) - { - msOutput.Capacity = (int)msOutput.Length; - return msOutput.GetBuffer(); - } - return null; -#else + InflaterInputStream iis = new InflaterInputStream(msInput, new Inflater(false)); int cbRead; byte[] abResult = new byte[32768]; @@ -198,23 +96,15 @@ public override byte[] Decode(byte[] data, FilterParms parms) msOutput.Write(abResult, 0, cbRead); } while (cbRead > 0); -#if UWP - iis.Dispose(); -#else iis.Close(); -#endif msOutput.Flush(); if (msOutput.Length >= 0) { -#if NETFX_CORE || UWP || PORTABLE + if (parms.DecodeParms != null) + return StreamDecoder.Decode(msOutput.ToArray(), parms.DecodeParms); return msOutput.ToArray(); -#else - msOutput.Capacity = (int)msOutput.Length; - return msOutput.GetBuffer(); -#endif } return null; -#endif } } } diff --git a/PdfSharpCore/Pdf.Filters/LzwDecode.cs b/PdfSharpCore/Pdf.Filters/LzwDecode.cs index 8c6f726d..21f8e4e1 100644 --- a/PdfSharpCore/Pdf.Filters/LzwDecode.cs +++ b/PdfSharpCore/Pdf.Filters/LzwDecode.cs @@ -101,12 +101,9 @@ public override byte[] Decode(byte[] data, FilterParms parms) if (outputStream.Length >= 0) { -#if !NETFX_CORE && !UWP && !PORTABLE - outputStream.Capacity = (int)outputStream.Length; - return outputStream.GetBuffer(); -#else + if (parms.DecodeParms != null) + return StreamDecoder.Decode(outputStream.ToArray(), parms.DecodeParms); return outputStream.ToArray(); -#endif } return null; } diff --git a/PdfSharpCore/Pdf.Filters/PngFilter.cs b/PdfSharpCore/Pdf.Filters/PngFilter.cs new file mode 100644 index 00000000..7900c354 --- /dev/null +++ b/PdfSharpCore/Pdf.Filters/PngFilter.cs @@ -0,0 +1,83 @@ +using PdfSharpCore.Pdf.IO; +using System; + +namespace PdfSharpCore.Pdf.Filters +{ + internal static class PngFilter + { + /// + /// Implements PNG-Filtering according to the PNG-specification

+ /// see: https://datatracker.ietf.org/doc/html/rfc2083#section-6 + ///
+ /// The width of a scanline in bytes + /// Bytes per pixel + /// The input data + /// The target array where the unfiltered data is stored + /// + internal static void Unfilter(int stride, int bpp, byte[] inData, byte[] outData) + { + var prevRow = new byte[stride]; + var row = new byte[stride]; + var pos = 0; + var outIndex = 0; + while (pos < inData.Length) + { + Array.Copy(inData, pos + 1, row, 0, stride); + var filterType = inData[pos]; + if (filterType > 4) + throw new PdfReaderException(string.Format("Unexpected Png-Predictor {0} in Xref Stream. Expected 0 to 4.", filterType)); + switch (filterType) + { + case 0: // None + for (var i = 0; i < row.Length; i++) + outData[outIndex++] = row[i]; + break; + case 1: // Sub + for (var i = 0; i < row.Length; i++) + { + var left = i < bpp ? 0 : outData[outIndex - bpp]; + outData[outIndex++] = (byte)(row[i] + left); + } + break; + case 2: // Up + for (var i = 0; i < row.Length; i++) + outData[outIndex++] = (byte)(row[i] + prevRow[i]); + break; + case 3: // Average + for (var i = 0; i < row.Length; i++) + { + var left = i < bpp ? 0 : outData[outIndex - bpp]; + outData[outIndex++] = (byte)(row[i] + (byte)((left + prevRow[i]) / 2)); + } + break; + case 4: // Paeth + for (var i = 0; i < row.Length; i++) + { + var left = i < bpp ? (byte)0 : outData[outIndex - bpp]; + var above = prevRow[i]; + var aboveLeft = i < bpp ? (byte)0 : prevRow[i - bpp]; + outData[outIndex++] = (byte)(row[i] + PaethPredictor(left, above, aboveLeft)); + } + break; + } + // remember current scanline + Array.Copy(outData, outIndex - stride, prevRow, 0, stride); + pos += stride + 1; // each scanline is preceded by a predictor-byte + } + } + + // https://datatracker.ietf.org/doc/html/rfc2083#page-36 + private static byte PaethPredictor(byte a, byte b, byte c) + { + var p = a + b - c; + var pa = Math.Abs(p - a); + var pb = Math.Abs(p - b); + var pc = Math.Abs(p - c); + if (pa <= pb && pa <= pc) + return a; + else if (pb <= pc) + return b; + return c; + } + } +} diff --git a/PdfSharpCore/Pdf.Filters/StreamDecoder.cs b/PdfSharpCore/Pdf.Filters/StreamDecoder.cs new file mode 100644 index 00000000..3740d74c --- /dev/null +++ b/PdfSharpCore/Pdf.Filters/StreamDecoder.cs @@ -0,0 +1,60 @@ +using PdfSharpCore.Pdf.IO; +using System; + +namespace PdfSharpCore.Pdf.Filters +{ + internal static class StreamDecoder + { + // PdfReference, chapter 7.4.4.3 + + /// + /// Further decodes a stream of bytes that were processed by the Flate- or LZW-decoder. + /// + /// The data to decode + /// Parameters for the decoder. If this is null, is returned unchanged + /// The decoded data as a byte-array + /// + /// + public static byte[] Decode(byte[] data, PdfDictionary decodeParms) + { + if (decodeParms == null) + return data; + + var predictor = decodeParms.Elements.GetInteger("/Predictor"); + var colors = decodeParms.Elements.GetInteger("/Colors"); + var bpc = decodeParms.Elements.GetInteger("/BitsPerComponent"); + var columns = decodeParms.Elements.GetInteger("/Columns"); + + // set up defaults according to the spec + if (predictor < 1) + predictor = 1; + if (colors < 1) + colors = 1; + if (bpc < 1) + bpc = 8; + if (columns < 1) + columns = 1; + + if (predictor == 1) // no prediction, return data as is + return data; + + // TIFF predictor. TODO: implement + if (predictor == 2) + throw new NotImplementedException("TIFF predictor is not implemented"); + + // PNG predictors + if (predictor >= 10 && predictor <= 15) + { + if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16) + throw new PdfReaderException("Invalid number of bits per component"); + var stride = (bpc * colors * columns + 7) / 8; + var rows = data.Length / (stride + 1); + var unfilteredData = new byte[rows * stride]; + PngFilter.Unfilter(stride, (bpc * colors + 7) / 8, data, unfilteredData); + return unfilteredData; + } + + throw new PdfReaderException("Invalid predictor " + predictor); + } + } +} diff --git a/PdfSharpCore/Pdf.IO/Lexer.cs b/PdfSharpCore/Pdf.IO/Lexer.cs index da923e1f..c669b1c1 100644 --- a/PdfSharpCore/Pdf.IO/Lexer.cs +++ b/PdfSharpCore/Pdf.IO/Lexer.cs @@ -34,8 +34,8 @@ using System.IO; using PdfSharpCore.Internal; using PdfSharpCore.Pdf.Internal; - -#pragma warning disable 1591 +using System.Collections.Generic; +using System.Linq; namespace PdfSharpCore.Pdf.IO { @@ -54,7 +54,7 @@ public class Lexer public Lexer(Stream pdfInputStream) { _pdfSteam = pdfInputStream; - _pdfLength = (int)_pdfSteam.Length; + _pdfLength = _pdfSteam.Length; _idxChar = 0; Position = 0; } @@ -62,7 +62,7 @@ public Lexer(Stream pdfInputStream) /// /// Gets or sets the position within the PDF stream. /// - public int Position + public long Position { get { return _idxChar; } set @@ -173,7 +173,20 @@ public Symbol ScanNextToken() ///
public byte[] ReadStream(int length) { - int pos; + var pos = MoveToStartOfStream(); + _pdfSteam.Position = pos; + byte[] bytes = new byte[length]; + int read = _pdfSteam.Read(bytes, 0, length); + Debug.Assert(read == length); + + // Synchronize idxChar etc. + Position = pos + length; + return bytes; + } + + internal long MoveToStartOfStream() + { + long pos; // Skip illegal blanks behind stream. while (_currChar == Chars.SP) @@ -189,21 +202,51 @@ public byte[] ReadStream(int length) } else pos = _idxChar + 1; + return pos; + } - _pdfSteam.Position = pos; - byte[] bytes = new byte[length]; - int read = _pdfSteam.Read(bytes, 0, length); - Debug.Assert(read == length); + /// + /// Scans the input stream for the specified marker.

+ /// Returns the bytes from the current position up to the start of the marker or the end of the stream.

+ /// The position of the input-stream is the byte right after the marker (if found) or the end of the stream. + ///
+ /// The marker to scan for + /// Receives a boolean that indicates whether the marker was found + /// + internal byte[] ScanUntilMarker(byte[] marker, out bool markerFound) + { + markerFound = false; + var result = new List(); + while (true) + { + var markerIndex = 0; + while (_currChar != Chars.EOF && _currChar != marker[markerIndex]) + { + result.Add((byte)_currChar); + ScanNextChar(false); + } + while (_currChar != Chars.EOF && markerIndex < marker.Length && _currChar == marker[markerIndex]) + { + markerIndex++; + ScanNextChar(false); + } + if (_currChar == Chars.EOF || markerIndex == marker.Length) + { + if (markerIndex == marker.Length) + markerFound = true; + break; + } + // only part of the marker was found, add to result and continue + result.AddRange(marker.Take(markerIndex)); + } - // Synchronize idxChar etc. - Position = pos + length; - return bytes; + return result.ToArray(); } /// /// Reads a string in raw encoding. /// - public String ReadRawString(int position, int length) + public string ReadRawString(long position, int length) { _pdfSteam.Position = position; byte[] bytes = new byte[length]; @@ -303,23 +346,17 @@ public Symbol ScanNumber() long l = Int64.Parse(_token.ToString(), CultureInfo.InvariantCulture); if (l >= Int32.MinValue && l <= Int32.MaxValue) return Symbol.Integer; - if (l > 0 && l <= UInt32.MaxValue) - return Symbol.UInteger; + if (l >= Int64.MinValue && l <= Int64.MaxValue) + return Symbol.Long; // Got an AutoCAD PDF file that contains this: /C 264584027963392 // Best we can do is to convert it to real value. return Symbol.Real; - //thr ow new PdfReaderException("Number exceeds integer range."); } public Symbol ScanNumberOrReference() { Symbol result = ScanNumber(); - if (result == Symbol.Integer) - { - int pos = Position; - string objectNumber = Token; - } return result; } @@ -463,7 +500,8 @@ public Symbol ScanLiteralString() { // Octal character code. if (ch >= '8') - ParserDiagnostics.HandleUnexpectedCharacter(ch); + break; // Since the first possible octal character is not valid, + // the backslash is ignored. int n = ch - '0'; if (char.IsDigit(_nextChar)) // Second octal character. @@ -484,12 +522,6 @@ public Symbol ScanLiteralString() } ch = (char)n; } - else - { - //TODO - // Debug.As sert(false, "Not implemented; unknown escape character."); - ParserDiagnostics.HandleUnexpectedCharacter(ch); - } break; } break; @@ -562,15 +594,19 @@ public Symbol ScanHexadecimalString() ScanNextChar(true); break; } - if (char.IsLetterOrDigit(_currChar)) + if (IsHexChar(_currChar)) { - hex[0] = char.ToUpper(_currChar); - hex[1] = char.ToUpper(_nextChar); - int ch = int.Parse(new string(hex), NumberStyles.AllowHexSpecifier); + hex[0] = _currChar; + hex[1] = IsHexChar(_nextChar) ? _nextChar : ' '; + int ch = int.Parse(new string(hex), NumberStyles.HexNumber); _token.Append(Convert.ToChar(ch)); ScanNextChar(true); - ScanNextChar(true); + if (_currChar != '>') + ScanNextChar(true); } + else + // prevent endless loop in case _currChar is neither '>' nor a hex-char nor whitespace + ScanNextChar(true); } string chars = _token.ToString(); int count = chars.Length; @@ -585,6 +621,13 @@ public Symbol ScanHexadecimalString() return _symbol = Symbol.HexString; } + internal static bool IsHexChar(char c) + { + return char.IsDigit(c) || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); + } + /// /// Move current position one character further in PDF stream. /// @@ -632,7 +675,7 @@ bool PeekReference() // A Reference has the form "nnn mmm R". The implementation of the the parser used a // reduce/shift algorithm in the first place. But this case is the only one we need to // look ahead 3 tokens. - int positon = Position; + var positon = Position; // Skip digits. while (char.IsDigit(_currChar)) @@ -719,33 +762,32 @@ public char MoveToNonWhiteSpace() } return _currChar; } - -#if DEBUG - public string SurroundingsOfCurrentPosition(bool hex) - { - const int range = 20; - int start = Math.Max(Position - range, 0); - int length = Math.Min(2 * range, PdfLength - start); - long posOld = _pdfSteam.Position; - _pdfSteam.Position = start; - byte[] bytes = new byte[length]; - _pdfSteam.Read(bytes, 0, length); - _pdfSteam.Position = posOld; - string result = ""; - if (hex) - { - for (int idx = 0; idx < length; idx++) - result += ((int)bytes[idx]).ToString("x2"); - //result += string.Format("{0:", (int) bytes[idx]); - } - else - { - for (int idx = 0; idx < length; idx++) - result += (char)bytes[idx]; - } - return result; - } -#endif +// #if DEBUG +// public string SurroundingsOfCurrentPosition(bool hex) +// { +// const int range = 20; +// int start = Math.Max(Position - range, 0); +// int length = Math.Min(2 * range, PdfLength - start); +// long posOld = _pdfSteam.Position; +// _pdfSteam.Position = start; +// byte[] bytes = new byte[length]; +// _pdfSteam.Read(bytes, 0, length); +// _pdfSteam.Position = posOld; +// string result = ""; +// if (hex) +// { +// for (int idx = 0; idx < length; idx++) +// result += ((int)bytes[idx]).ToString("x2"); +// //result += string.Format("{0:", (int) bytes[idx]); +// } +// else +// { +// for (int idx = 0; idx < length; idx++) +// result += (char)bytes[idx]; +// } +// return result; +// } +// #endif /// /// Gets the current symbol. @@ -799,6 +841,7 @@ public uint TokenToUInteger return uint.Parse(_token.ToString(), CultureInfo.InvariantCulture); } } + public long TokenToLong => long.Parse(_token.ToString(), CultureInfo.InvariantCulture); /// /// Interprets current token as real or integer literal. @@ -865,13 +908,13 @@ internal static bool IsDelimiter(char ch) /// /// Gets the length of the PDF output. /// - public int PdfLength + public long PdfLength { get { return _pdfLength; } } - readonly int _pdfLength; - int _idxChar; + readonly long _pdfLength; + long _idxChar; char _currChar; char _nextChar; StringBuilder _token; diff --git a/PdfSharpCore/Pdf.IO/Parser.cs b/PdfSharpCore/Pdf.IO/Parser.cs index f1c589d6..e39a162f 100644 --- a/PdfSharpCore/Pdf.IO/Parser.cs +++ b/PdfSharpCore/Pdf.IO/Parser.cs @@ -41,7 +41,7 @@ namespace PdfSharpCore.Pdf.IO { /* - Direct and indireckt objects + Direct and indirect objects * If a simple object (boolean, integer, number, date, string, rectangle etc.) is referenced indirect, the parser reads this objects immediatly and consumes the indirection. @@ -52,7 +52,7 @@ is returned. * If a composite object is a direct object, no PdfReference is created and the object is parsed immediatly. - * A refernece to a non existing object is specified as legal, therefore null is returned. + * A reference to a non existing object is specified as legal, therefore null is returned. */ /// @@ -77,9 +77,9 @@ public Parser(PdfDocument document) /// /// Sets PDF input stream position to the specified object. /// - public int MoveToObject(PdfObjectID objectID) + public long MoveToObject(PdfObjectID objectID) { - int position = _document._irefTable[objectID].Position; + var position = _document._irefTable[objectID].Position; if (position < 0) throw new PositionNotFoundException(objectID); @@ -97,10 +97,6 @@ public PdfObjectID ReadObjectNumber(int position) _lexer.Position = position; int objectNumber = ReadInteger(); int generationNumber = ReadInteger(); -#if DEBUG && CORE - if (objectNumber == 1074) - GetType(); -#endif return new PdfObjectID(objectNumber, generationNumber); } @@ -228,6 +224,13 @@ public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool incl ReadSymbol(Symbol.EndObj); return pdfObject; + case Symbol.Long: + pdfObject = new PdfLongObject(_document, _lexer.TokenToLong); + pdfObject.SetObjectID(objectNumber, generationNumber); + if (!fromObjecStream) + ReadSymbol(Symbol.EndObj); + return pdfObject; + case Symbol.Real: pdfObject = new PdfRealObject(_document, _lexer.TokenToReal); pdfObject.SetObjectID(objectNumber, generationNumber); @@ -257,6 +260,11 @@ public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool incl ParserDiagnostics.HandleUnexpectedToken(_lexer.Token); break; + case Symbol.EndObj: + pdfObject = new PdfNullObject(_document); + pdfObject.SetObjectID(objectNumber, generationNumber); + return pdfObject; + default: // Should not come here anymore. ParserDiagnostics.HandleUnexpectedToken(_lexer.Token); @@ -270,6 +278,7 @@ public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool incl #if true_ ReadStream(dict); #else + var startOfStream = _lexer.Position; int length = GetStreamLength(dict); byte[] bytes = _lexer.ReadStream(length); #if true_ @@ -299,7 +308,21 @@ public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool incl #endif PdfDictionary.PdfStream stream = new PdfDictionary.PdfStream(bytes, dict); dict.Stream = stream; - ReadSymbol(Symbol.EndStream); + try + { + ReadSymbol(Symbol.EndStream); + } + catch (PdfReaderException) + { + // stream length may be incorrect, scan byte by byte up to the "endstream" keyword + _lexer.Position = startOfStream; + _lexer.Position = _lexer.MoveToStartOfStream(); + bytes = _lexer.ScanUntilMarker(PdfEncoders.RawEncoding.GetBytes("\nendstream"), out var markerFound); + if (!markerFound) + throw; + stream = new PdfDictionary.PdfStream(bytes, dict); + dict.Stream = stream; + } symbol = ScanNextToken(); #endif if (symbol == Symbol.Eof) @@ -465,6 +488,10 @@ private void ParseObject(Symbol stop) _stack.Shift(new PdfUInteger(_lexer.TokenToUInteger)); break; + case Symbol.Long: + _stack.Shift(new PdfLong(_lexer.TokenToLong)); + break; + case Symbol.Real: _stack.Shift(new PdfReal(_lexer.TokenToReal)); break; @@ -752,7 +779,7 @@ private int ReadInteger(bool canBeIndirect) if (symbol == Symbol.R) { - int position = _lexer.Position; + var position = _lexer.Position; // MoveToObject(lexer.Token); ReadObjectID(null); int n = ReadInteger(); @@ -769,6 +796,36 @@ private int ReadInteger() return ReadInteger(false); } + private long ReadLong() + { + return ReadLong(false); + } + + /// + /// Reads an integer value directly from the PDF data stream. + /// + private long ReadLong(bool canBeIndirect) + { + Symbol symbol = _lexer.ScanNextToken(); + if (symbol == Symbol.Long) + return _lexer.TokenToLong; + + if (symbol == Symbol.Integer) + return _lexer.TokenToLong; + + if (symbol == Symbol.R) + { + var position = _lexer.Position; + ReadObjectID(null); + int n = ReadInteger(); + ReadSymbol(Symbol.EndObj); + _lexer.Position = position; + return n; + } + ParserDiagnostics.HandleUnexpectedToken(_lexer.Token); + return 0; + } + // /// // /// Reads a real value directly or (optionally) indirectly from the PDF data stream. // /// @@ -1007,7 +1064,7 @@ internal int[][] ReadObjectStreamHeader(int n, int first) /// internal PdfTrailer ReadTrailer(PdfReadAccuracy accuracy) { - int length = _lexer.PdfLength; + var length = _lexer.PdfLength; // Implementation note 18 Appendix H: // Acrobat viewers require only that the %%EOF marker appear somewhere within the last 1024 bytes of the file. @@ -1031,7 +1088,10 @@ internal PdfTrailer ReadTrailer(PdfReadAccuracy accuracy) if (idx == -1) { // If "startxref" was still not found yet, read the file completely. - string trail = _lexer.ReadRawString(0, length); + if (length > int.MaxValue) + //TODO: Implement chunking to read long files. + throw new NotImplementedException("Reading >2GB files with a 'startxref' in the middle not implemented."); + var trail = _lexer.ReadRawString(0, (int)length); idx = trail.LastIndexOf("startxref", StringComparison.Ordinal); _lexer.Position = idx; } @@ -1039,7 +1099,7 @@ internal PdfTrailer ReadTrailer(PdfReadAccuracy accuracy) throw new Exception("The StartXRef table could not be found, the file cannot be opened."); ReadSymbol(Symbol.StartXRef); - _lexer.Position = ReadInteger(); + _lexer.Position = ReadLong(); // Read all trailers. while (true) @@ -1082,7 +1142,7 @@ private PdfTrailer ReadXRefTableAndTrailer(PdfCrossReferenceTable xrefTable, Pdf int length = ReadInteger(); for (int id = start; id < start + length; id++) { - int position = ReadInteger(); + var position = ReadLong(); int generation = ReadInteger(); ReadSymbol(Symbol.Keyword); string token = _lexer.Token; @@ -1154,9 +1214,9 @@ private PdfTrailer ReadXRefTableAndTrailer(PdfCrossReferenceTable xrefTable, Pdf /// The identifier found in the PDF file. /// The generation found in the PDF file. /// - private bool CheckXRefTableEntry(int position, int id, int generation, out int idChecked, out int generationChecked) + private bool CheckXRefTableEntry(long position, int id, int generation, out int idChecked, out int generationChecked) { - int origin = _lexer.Position; + var origin = _lexer.Position; idChecked = -1; generationChecked = -1; try @@ -1211,25 +1271,31 @@ private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) ReadSymbol(Symbol.BeginStream); ReadStream(xrefStream); - //xrefTable.Add(new PdfReference(objectID, position)); - PdfReference iref = new PdfReference(xrefStream); - iref.ObjectID = objectID; - iref.Value = xrefStream; - xrefTable.Add(iref); + // An additional cross-reference (/Prev) could have been referenced in the first cross-reference by position. + // That goes into item.Type == 1 below and adds its objectID into the xrefTable with just a position and no value. + // Then we can't just do `xrefTable.Add(iref)` because that is a no-op when the objectID is already present in the ObjectTable. + // Making sure that the iref.Value is set here correctly ensure that the mechanisms in PdfReader will work correctly: + // 1. It needs to find a PdfCrossReferenceStream in iref.Value in order to resolve compressed objects. + // 2. If we leave null in iref.Value it would do redundant parsing to resolve the value again. + if (xrefTable.ObjectTable.TryGetValue(objectID, out PdfReference iref)) + { + if (iref.Value == null) + { + iref.Value = xrefStream; + } + } + else + { + iref = new PdfReference(xrefStream); + iref.ObjectID = objectID; + iref.Value = xrefStream; + xrefTable.Add(iref); + } Debug.Assert(xrefStream.Stream != null); //string sValue = new RawEncoding().GetString(xrefStream.Stream.UnfilteredValue,); //sValue.GetType(); - byte[] bytesRaw = xrefStream.Stream.UnfilteredValue; - byte[] bytes = bytesRaw; - - // HACK: Should be done in UnfilteredValue. - if (xrefStream.Stream.HasDecodeParams) - { - int predictor = xrefStream.Stream.DecodePredictor; - int columns = xrefStream.Stream.DecodeColumns; - bytes = DecodeCrossReferenceStream(bytesRaw, columns, predictor); - } + var bytes = xrefStream.Stream.UnfilteredValue; #if DEBUG_ for (int idx = 0; idx < bytes.Length; idx++) @@ -1286,37 +1352,6 @@ private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) Debug.Assert(wsum * subsectionEntryCount == bytes.Length, "Check implementation here."); int testcount = subsections[0][1]; int[] currentSubsection = subsections[0]; -#if DEBUG && CORE - if (PdfDiagnostics.TraceXrefStreams) - { - for (int idx = 0; idx < testcount; idx++) - { - uint field1 = StreamHelper.ReadBytes(bytes, idx * wsum, wsize[0]); - uint field2 = StreamHelper.ReadBytes(bytes, idx * wsum + wsize[0], wsize[1]); - uint field3 = StreamHelper.ReadBytes(bytes, idx * wsum + wsize[0] + wsize[1], wsize[2]); - string res = String.Format("{0,2:00}: {1} {2,5} {3} // ", idx, field1, field2, field3); - switch (field1) - { - case 0: - res += "Fee list: object number, generation number"; - break; - - case 1: - res += "Not compresed: offset, generation number"; - break; - - case 2: - res += "Compressed: object stream object number, index in stream"; - break; - - default: - res += "??? Type undefined"; - break; - } - Debug.WriteLine(res); - } - } -#endif int index2 = -1; for (int ssc = 0; ssc < subsectionCount; ssc++) @@ -1346,7 +1381,7 @@ private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) //// (PDF Reference Implementation Notes 15). int position = (int)item.Field2; - objectID = ReadObjectNumber(position); + objectID = ReadObjectNumber(position); #if DEBUG if (objectID.ObjectNumber == 1074) GetType(); @@ -1359,7 +1394,7 @@ private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) #if DEBUG GetType(); #endif - // Add iref for all uncrompressed objects. + // Add iref for all uncompressed objects. xrefTable.Add(new PdfReference(objectID, position)); } @@ -1377,6 +1412,16 @@ private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) /// /// Parses a PDF date string. /// + /// + /// Format is + /// YYYY Year MM month DD day (01-31) HH hour (00-23) mm minute (00-59) ss second (00.59) + /// O is the relationship of local time to Universal Time (UT), denoted by one of the characters +, -, or Z (see below) + /// HH followed by ' is the absolute value of the offset from UT in hours (00-23) + /// mm followed by ' is the absolute value of the offset from UT in minutes (00-59) + /// For example, December 23, 1998, at 7:52 PM, U.S.Pacific Standard Time, is represented by the string, + /// D:19981223195200-08'00' + /// + internal static DateTime ParseDateTime(string date, DateTime errorValue) // TODO: TryParseDateTime { DateTime datetime = errorValue; @@ -1384,7 +1429,6 @@ internal static DateTime ParseDateTime(string date, DateTime errorValue) // TOD { if (date.StartsWith("D:")) { - // Format is // D:YYYYMMDDHHmmSSOHH'mm' // ^2 ^10 ^16 ^20 int length = date.Length; @@ -1392,20 +1436,20 @@ internal static DateTime ParseDateTime(string date, DateTime errorValue) // TOD char o = 'Z'; if (length >= 10) { - year = Int32.Parse(date.Substring(2, 4)); - month = Int32.Parse(date.Substring(6, 2)); - day = Int32.Parse(date.Substring(8, 2)); + year = int.Parse(date.Substring(2, 4)); + month = int.Parse(date.Substring(6, 2)); + day = int.Parse(date.Substring(8, 2)); if (length >= 16) { - hour = Int32.Parse(date.Substring(10, 2)); - minute = Int32.Parse(date.Substring(12, 2)); - second = Int32.Parse(date.Substring(14, 2)); + hour = int.Parse(date.Substring(10, 2)); + minute = int.Parse(date.Substring(12, 2)); + second = int.Parse(date.Substring(14, 2)); if (length >= 23) { if ((o = date[16]) != 'Z') { - hh = Int32.Parse(date.Substring(17, 2)); - mm = Int32.Parse(date.Substring(20, 2)); + hh = int.Parse(date.Substring(17, 2)); + mm = int.Parse(date.Substring(20, 2)); } } } @@ -1422,7 +1466,7 @@ internal static DateTime ParseDateTime(string date, DateTime errorValue) // TOD datetime = datetime.Subtract(ts); } // Now that we converted datetime to UTC, mark it as UTC. - DateTime.SpecifyKind(datetime, DateTimeKind.Utc); + datetime = DateTime.SpecifyKind(datetime, DateTimeKind.Utc); } else { @@ -1747,10 +1791,11 @@ public static object Read(PdfObject o, string key) private ParserState SaveState() { - ParserState state = new ParserState(); - state.Position = _lexer.Position; - state.Symbol = _lexer.Symbol; - return state; + return new ParserState + { + Position = _lexer.Position, + Symbol = _lexer.Symbol + }; } private void RestoreState(ParserState state) @@ -1761,48 +1806,10 @@ private void RestoreState(ParserState state) private class ParserState { - public int Position; + public long Position; public Symbol Symbol; } - private byte[] DecodeCrossReferenceStream(byte[] bytes, int columns, int predictor) - { - int size = bytes.Length; - if (predictor < 10 || predictor > 15) - throw new ArgumentException("Invalid predictor.", "predictor"); - - int rowSizeRaw = columns + 1; - - if (size % rowSizeRaw != 0) - throw new ArgumentException("Columns and size of array do not match."); - - int rows = size / rowSizeRaw; - - byte[] result = new byte[rows * columns]; -#if DEBUG - for (int i = 0; i < result.Length; ++i) - result[i] = 88; -#endif - - for (int row = 0; row < rows; ++row) - { - if (bytes[row * rowSizeRaw] != 2) - throw new ArgumentException("Invalid predictor in array."); - - for (int col = 0; col < columns; ++col) - { - // Copy data for first row. - if (row == 0) - result[row * columns + col] = bytes[row * rowSizeRaw + col + 1]; - else - { - // For other rows, add previous row. - result[row * columns + col] = (byte)(result[row * columns - columns + col] + bytes[row * rowSizeRaw + col + 1]); - } - } - } - return result; - } private readonly PdfDocument _document; private readonly Lexer _lexer; diff --git a/PdfSharpCore/Pdf.IO/PdfReader.cs b/PdfSharpCore/Pdf.IO/PdfReader.cs index 08806c60..2cdb0b90 100644 --- a/PdfSharpCore/Pdf.IO/PdfReader.cs +++ b/PdfSharpCore/Pdf.IO/PdfReader.cs @@ -74,7 +74,6 @@ public static class PdfReader /// public static int TestPdfFile(string path) { -#if NETCOREAPP1_1 || (!NETFX_CORE && !PORTABLE) FileStream stream = null; try { @@ -96,11 +95,7 @@ public static int TestPdfFile(string path) { if (stream != null) { -#if NETCOREAPP1_1 || UWP stream.Dispose(); -#else - stream.Close(); -#endif } } // ReSharper disable once EmptyGeneralCatchClause @@ -108,7 +103,6 @@ public static int TestPdfFile(string path) { } } -#endif return 0; } @@ -264,7 +258,6 @@ public static PdfDocument Open(string path, string password, PdfDocumentOpenMode /// public static PdfDocument Open(string path, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider provider, PdfReadAccuracy accuracy) { -#if NETCOREAPP1_1 || (!NETFX_CORE && !PORTABLE) PdfDocument document; Stream stream = null; try @@ -279,16 +272,10 @@ public static PdfDocument Open(string path, string password, PdfDocumentOpenMode finally { if (stream != null) -#if NETCOREAPP1_1 || UWP stream.Dispose(); -#else - stream.Close(); -#endif + } return document; -#else - return null; -#endif } /// diff --git a/PdfSharpCore/Pdf.IO/PdfWriter.cs b/PdfSharpCore/Pdf.IO/PdfWriter.cs index dff47b53..d24e1532 100644 --- a/PdfSharpCore/Pdf.IO/PdfWriter.cs +++ b/PdfSharpCore/Pdf.IO/PdfWriter.cs @@ -57,11 +57,7 @@ public PdfWriter(Stream pdfStream, PdfStandardSecurityHandler securityHandler) public void Close(bool closeUnderlyingStream) { if (_stream != null && closeUnderlyingStream) -#if UWP || PORTABLE - _stream.Dispose(); -#else - _stream.Close(); -#endif + _stream.Dispose(); _stream = null; } @@ -70,9 +66,9 @@ public void Close() Close(true); } - public int Position + public long Position { - get { return (int)_stream.Position; } + get { return _stream.Position; } } /// @@ -124,6 +120,16 @@ public void Write(int value) _lastCat = CharCat.Character; } + /// + /// Writes the specified value to the PDF stream. + /// + public void Write(long value) + { + WriteSeparator(CharCat.Character); + WriteRaw(value.ToString(CultureInfo.InvariantCulture)); + _lastCat = CharCat.Character; + } + /// /// Writes the specified value to the PDF stream. /// @@ -144,6 +150,16 @@ public void Write(PdfInteger value) WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); } + /// + /// Writes the specified value to the PDF stream. + /// + public void Write(PdfLong value) + { + WriteSeparator(CharCat.Character); + _lastCat = CharCat.Character; + WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); + } + /// /// Writes the specified value to the PDF stream. /// @@ -180,40 +196,12 @@ public void Write(PdfReal value) public void Write(PdfString value) { WriteSeparator(CharCat.Delimiter); -#if true PdfStringEncoding encoding = (PdfStringEncoding)(value.Flags & PdfStringFlags.EncodingMask); string pdf = (value.Flags & PdfStringFlags.HexLiteral) == 0 ? - PdfEncoders.ToStringLiteral(value.Value, encoding, SecurityHandler) : - PdfEncoders.ToHexStringLiteral(value.Value, encoding, SecurityHandler); + PdfEncoders.ToStringLiteral(value.EncryptionValue, encoding == PdfStringEncoding.Unicode, SecurityHandler) : + PdfEncoders.ToHexStringLiteral(value.EncryptionValue, encoding == PdfStringEncoding.Unicode, SecurityHandler); WriteRaw(pdf); -#else - switch (value.Flags & PdfStringFlags.EncodingMask) - { - case PdfStringFlags.Undefined: - case PdfStringFlags.PDFDocEncoding: - if ((value.Flags & PdfStringFlags.HexLiteral) == 0) - WriteRaw(PdfEncoders.DocEncode(value.Value, false)); - else - WriteRaw(PdfEncoders.DocEncodeHex(value.Value, false)); - break; - case PdfStringFlags.WinAnsiEncoding: - throw new NotImplementedException("Unexpected encoding: WinAnsiEncoding"); - - case PdfStringFlags.Unicode: - if ((value.Flags & PdfStringFlags.HexLiteral) == 0) - WriteRaw(PdfEncoders.DocEncode(value.Value, true)); - else - WriteRaw(PdfEncoders.DocEncodeHex(value.Value, true)); - break; - - case PdfStringFlags.StandardEncoding: - case PdfStringFlags.MacRomanEncoding: - case PdfStringFlags.MacExpertEncoding: - default: - throw new NotImplementedException("Unexpected encoding"); - } -#endif _lastCat = CharCat.Delimiter; } @@ -495,12 +483,12 @@ public void WriteFileHeader(PdfDocument document) } } - public void WriteEof(PdfDocument document, int startxref) + public void WriteEof(PdfDocument document, long startxref) { WriteRaw("startxref\n"); WriteRaw(startxref.ToString(CultureInfo.InvariantCulture)); WriteRaw("\n%%EOF\n"); - int fileSize = (int)_stream.Position; + var fileSize = _stream.Position; if (_layout == PdfWriterLayout.Verbose) { TimeSpan duration = DateTime.Now - document._creation; @@ -589,8 +577,8 @@ void WriteSeparator(CharCat cat, char ch) } else { - if (cat == CharCat.Character) - _stream.WriteByte((byte)' '); + //if (cat == CharCat.Character) + _stream.WriteByte((byte)' '); } break; } diff --git a/PdfSharpCore/Pdf.IO/enums/Symbol.cs b/PdfSharpCore/Pdf.IO/enums/Symbol.cs index b91eb151..f4fc83f3 100644 --- a/PdfSharpCore/Pdf.IO/enums/Symbol.cs +++ b/PdfSharpCore/Pdf.IO/enums/Symbol.cs @@ -41,7 +41,7 @@ public enum Symbol BeginStream, EndStream, BeginArray, EndArray, BeginDictionary, EndDictionary, - Obj, EndObj, R, XRef, Trailer, StartXRef, Eof, + Obj, EndObj, R, XRef, Trailer, StartXRef, Eof, Long #pragma warning restore 1591 } } diff --git a/PdfSharpCore/Pdf.Internal/AnsiEncoding.cs b/PdfSharpCore/Pdf.Internal/AnsiEncoding.cs index 73dde8de..b38632a2 100644 --- a/PdfSharpCore/Pdf.Internal/AnsiEncoding.cs +++ b/PdfSharpCore/Pdf.Internal/AnsiEncoding.cs @@ -36,49 +36,6 @@ namespace PdfSharpCore.Pdf.Internal /// public sealed class AnsiEncoding : Encoding { -#if DEBUG_ && !(SILVERLIGHT || NETFX_CORE) - public static void ProofImplementation() - { - // Implementation was verified with .NET Ansi encoding. - Encoding dotnetImplementation = Encoding.GetEncoding(1252); - Encoding thisImplementation = new AnsiEncoding(); - - // Check ANSI chars. - for (int i = 0; i <= 255; i++) - { - byte[] b = { (byte) i }; - char[] ch1 = dotnetImplementation.GetChars(b, 0, 1); - char[] ch2 = thisImplementation.GetChars(b, 0, 1); - if (ch1[0] != ch2[0]) - Debug.Print("Error"); - byte[] b1 = dotnetImplementation.GetBytes(ch1, 0, 1); - byte[] b2 = thisImplementation.GetBytes(ch1, 0, 1); - if (b1.Length != b2.Length || b1.Length > 1 || b1[0] != b2[0]) - Debug.Print("Error"); - } - - // Check Unicode chars. - for (int i = 0; i <= 65535; i++) - { - if (i >= 256) - break; - if (i == 0x80) - Debug.Print(""); - char[] ch = new char[] { (char)i }; - byte[] b1 = dotnetImplementation.GetBytes(ch, 0, 1); - byte[] b2 = thisImplementation.GetBytes(ch, 0, 1); - if (b1.Length != b2.Length || b1.Length > 1 || b1[0] != b2[0]) - Debug.Print("Error"); - //byte[] b = new byte[] { (byte)i }; - //char ch = (char)i; - char[] ch1 = dotnetImplementation.GetChars(b1, 0, 1); - char[] ch2 = thisImplementation.GetChars(b2, 0, 1); - if (ch1[0] != ch2[0]) - Debug.Print("Error"); - } - } -#endif - /// /// Gets the byte count. /// diff --git a/PdfSharpCore/Pdf.Internal/ColorSpaceHelper.cs b/PdfSharpCore/Pdf.Internal/ColorSpaceHelper.cs index 39d76ea0..dfe92d19 100644 --- a/PdfSharpCore/Pdf.Internal/ColorSpaceHelper.cs +++ b/PdfSharpCore/Pdf.Internal/ColorSpaceHelper.cs @@ -42,7 +42,6 @@ static class ColorSpaceHelper /// public static XColor EnsureColorMode(PdfColorMode colorMode, XColor color) { -#if true if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) return XColor.FromArgb((int)(color.A * 255), color.R, color.G, color.B); @@ -50,13 +49,6 @@ public static XColor EnsureColorMode(PdfColorMode colorMode, XColor color) return XColor.FromCmyk(color.A, color.C, color.M, color.Y, color.K); return color; -#else - if (colorMode == PdfColorMode.Rgb && color.ColorSpace != XColorSpace.Rgb) - throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); - - if (colorMode == PdfColorMode.Cmyk && color.ColorSpace != XColorSpace.Cmyk) - throw new InvalidOperationException(PSSR.InappropriateColorSpace(colorMode, color.ColorSpace)); -#endif } /// diff --git a/PdfSharpCore/Pdf.Internal/PdfEncoders.cs b/PdfSharpCore/Pdf.Internal/PdfEncoders.cs index 6dd9b1aa..7c050919 100644 --- a/PdfSharpCore/Pdf.Internal/PdfEncoders.cs +++ b/PdfSharpCore/Pdf.Internal/PdfEncoders.cs @@ -68,13 +68,8 @@ public static Encoding WinAnsiEncoding { if (_winAnsiEncoding == null) { -#if !SILVERLIGHT && !NETFX_CORE && !UWP && !__IOS__ && !__ANDROID__ && !PORTABLE - // Use .net encoder if available. - _winAnsiEncoding = Encoding.GetEncoding(1252); -#else // Use own implementation in Silverlight and WinRT _winAnsiEncoding = new AnsiEncoding(); -#endif } return _winAnsiEncoding; } diff --git a/PdfSharpCore/Pdf.Internal/RawEncoding.cs b/PdfSharpCore/Pdf.Internal/RawEncoding.cs index a65e3f1d..96293b31 100644 --- a/PdfSharpCore/Pdf.Internal/RawEncoding.cs +++ b/PdfSharpCore/Pdf.Internal/RawEncoding.cs @@ -147,19 +147,5 @@ public override int GetMaxCharCount(int byteCount) { return byteCount; } - -#if SILVERLIGHT - /// - /// When overridden in a derived class, decodes all the bytes in the specified byte array into a string. - /// - /// The byte array containing the sequence of bytes to decode. - /// - /// A containing the results of decoding the specified sequence of bytes. - /// - public string GetString(byte[] bytes) - { - return GetString(bytes, 0, bytes.Length); - } -#endif } } diff --git a/PdfSharpCore/Pdf.Internal/RawUnicodeEncoding.cs b/PdfSharpCore/Pdf.Internal/RawUnicodeEncoding.cs index 68fbfe1f..c3503254 100644 --- a/PdfSharpCore/Pdf.Internal/RawUnicodeEncoding.cs +++ b/PdfSharpCore/Pdf.Internal/RawUnicodeEncoding.cs @@ -64,9 +64,9 @@ public override int GetCharCount(byte[] bytes, int index, int count) public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - for (int count = byteCount; count > 0; byteIndex += 2, charIndex++, count--) + for (int count = byteCount; count > 0; byteIndex += 2, charIndex++, count -= 2) { - chars[charIndex] = (char)((int)bytes[byteIndex] << 8 + (int)bytes[byteIndex + 1]); + chars[charIndex] = (char)((int)(bytes[byteIndex] << 8) + (int)bytes[byteIndex + 1]); } return byteCount; } diff --git a/PdfSharpCore/Pdf.Internal/ThreadLocalStorage.cs b/PdfSharpCore/Pdf.Internal/ThreadLocalStorage.cs index f8acb338..c5ac5550 100644 --- a/PdfSharpCore/Pdf.Internal/ThreadLocalStorage.cs +++ b/PdfSharpCore/Pdf.Internal/ThreadLocalStorage.cs @@ -32,6 +32,7 @@ using System.Diagnostics; using System.IO; using PdfSharpCore.Pdf.IO; +using PdfSharpCore.Pdf.IO.enums; namespace PdfSharpCore.Pdf.Internal { @@ -55,7 +56,7 @@ public void RemoveDocument(string path) _importedDocuments.Remove(path); } - public PdfDocument GetDocument(string path) + public PdfDocument GetDocument(string path, PdfReadAccuracy accuracy) { Debug.Assert(path.StartsWith("*") || Path.IsPathRooted(path), "Path must be full qualified."); @@ -69,7 +70,7 @@ public PdfDocument GetDocument(string path) } if (document == null) { - document = PdfReader.Open(path, PdfDocumentOpenMode.Import); + document = PdfReader.Open(path, PdfDocumentOpenMode.Import, accuracy); _importedDocuments.Add(path, document.Handle); } return document; diff --git a/PdfSharpCore/Pdf.Security/AESEncryptor.cs b/PdfSharpCore/Pdf.Security/AESEncryptor.cs new file mode 100644 index 00000000..aec5c2d4 --- /dev/null +++ b/PdfSharpCore/Pdf.Security/AESEncryptor.cs @@ -0,0 +1,323 @@ +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace PdfSharpCore.Pdf.Security +{ + internal class AESEncryptor : RC4Encryptor + { + public override void InitEncryptionKey(string password) + { + if (rValue == 5) + { + InitVersion5(password); + return; + } + if (rValue == 6) + { + // http://esec-lab.sogeti.com/post/The-undocumented-password-validation-algorithm-of-Adobe-Reader-X + InitVersion6(password); + return; + } + base.InitEncryptionKey(password); + } + + /// + /// Pdf Reference 1.7 Extension Level 3, Chapter 3.5.2, Algorithm 3.2a + /// + /// + protected void InitVersion5(string password) + { + var pwdBytes = Encoding.UTF8.GetBytes(password); + if (pwdBytes.Length > 127) + pwdBytes = pwdBytes.Take(127).ToArray(); + // split O and U into their components + var oHash = new byte[32]; + var oValidation = new byte[8]; + var oSalt = new byte[8]; + var uHash = new byte[32]; + var uValidation = new byte[8]; + var uSalt = new byte[8]; + + Array.Copy(ownerValue, oHash, 32); + Array.Copy(ownerValue, 32, oValidation, 0, 8); + Array.Copy(ownerValue, 40, oSalt, 0, 8); + Array.Copy(userValue, uHash, 32); + Array.Copy(userValue, 32, uValidation, 0, 8); + Array.Copy(userValue, 40, uSalt, 0, 8); + + computedOwnerValue = new byte[32]; + computedUserValue = new byte[32]; + + var oKeyBytes = new byte[pwdBytes.Length + 8 + 48]; + Array.Copy(pwdBytes, oKeyBytes, pwdBytes.Length); + Array.Copy(oValidation, 0, oKeyBytes, pwdBytes.Length, 8); + Array.Copy(userValue, 0, oKeyBytes, pwdBytes.Length + 8, 48); + + HaveOwnerPermission = PasswordMatchR5(oKeyBytes, ownerValue); + if (HaveOwnerPermission) + { + PasswordValid = true; + Array.Copy(ownerValue, computedOwnerValue, 32); + CreateEncryptionKeyR5(oeValue, pwdBytes, oSalt, userValue); + } + else + { + oKeyBytes = new byte[pwdBytes.Length + 8]; + Array.Copy(pwdBytes, oKeyBytes, pwdBytes.Length); + Array.Copy(uValidation, 0, oKeyBytes, pwdBytes.Length, 8); + + // if the result matches the first 32 bytes of userValue, we have the user password + PasswordValid = PasswordMatchR5(oKeyBytes, userValue); + if (PasswordValid) + { + Array.Copy(userValue, computedUserValue, 32); + CreateEncryptionKeyR5(ueValue, pwdBytes, uSalt, null); + } + } + } + + private void CreateEncryptionKeyR5(byte[] encryptedValue, byte[] password, byte[] salt, byte[] uservalue) + { + var sha = SHA256.Create(); + var aes256Cbc = Aes.Create(); + aes256Cbc.KeySize = 256; + aes256Cbc.Mode = CipherMode.CBC; + aes256Cbc.Padding = PaddingMode.None; + var bufLen = password.Length + salt.Length + (uservalue != null ? 48 : 0); + var buf = new byte[bufLen]; + Array.Copy(password, buf, password.Length); + Array.Copy(salt, 0, buf, password.Length, salt.Length); + if (uservalue != null) + Array.Copy(uservalue, 0, buf, password.Length + salt.Length, 48); + var shaKey = sha.ComputeHash(buf); + using (var decryptor = aes256Cbc.CreateDecryptor(shaKey, new byte[16])) + { + using (var ms = new MemoryStream(encryptedValue)) + { + using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) + { + encryptionKey = new byte[32]; + cs.Read(encryptionKey, 0, 32); + } + } + } + aes256Cbc.Clear(); + } + + private void InitVersion6(string password) + { + // split O and U into their components + var oSalt = new byte[8]; + var uSalt = new byte[8]; + var uKeySalt = new byte[8]; + var oKeySalt = new byte[8]; + var oKey = new byte[48]; + Array.Copy(ownerValue, 32, oSalt, 0, 8); + Array.Copy(userValue, 32, uSalt, 0, 8); + Array.Copy(userValue, 40, uKeySalt, 0, 8); + Array.Copy(ownerValue, 40, oKeySalt, 0, 8); + Array.Copy(userValue, oKey, 48); + + computedUserValue = new byte[32]; + computedOwnerValue = new byte[32]; + ValidateVersion6(password, uSalt, null, computedUserValue); + ValidateVersion6(password, oSalt, oKey, computedOwnerValue); + + byte[] keyToDecrypt = null; + byte[] salt = null; + byte[] hashKey = null; + if (CompareArrays(computedOwnerValue, ownerValue, 32)) + { + keyToDecrypt = oeValue; + salt = oKeySalt; + hashKey = oKey; + PasswordValid = true; + HaveOwnerPermission = true; + } + else if (CompareArrays(computedUserValue, userValue, 32)) + { + keyToDecrypt = ueValue; + salt = uKeySalt; + PasswordValid = true; + } + + if (keyToDecrypt != null) + { + encryptionKey = new byte[32]; + var hash = new byte[32]; + var iv = new byte[16]; + ValidateVersion6(password, salt, hashKey, hash); + using (var aes256 = Aes.Create()) + { + aes256.KeySize = 256; + aes256.Mode = CipherMode.CBC; + aes256.Padding = PaddingMode.None; + using (var decryptor = aes256.CreateDecryptor(hash, iv)) + { + decryptor.TransformBlock(keyToDecrypt, 0, 32, encryptionKey, 0); + } + } + } + } + + private static void ValidateVersion6(string password, byte[] salt, byte[] ownerKey, byte[] hash) + { + var data = new byte[(128 + 64 + 48) * 64]; + var block = new byte[64]; + var blockSize = 32; + var dataLen = 0; + int i, j, sum; + + using (var aes128 = Aes.Create()) + { + aes128.BlockSize = 16 * 8; + aes128.Mode = CipherMode.CBC; + var pwdBytes = Encoding.UTF8.GetBytes(password); + var iv = new byte[16]; + var aesKey = new byte[16]; + + /* Step 1: calculate initial data block */ + using (var sha256 = SHA256.Create()) + { + sha256.TransformBlock(pwdBytes, 0, pwdBytes.Length, pwdBytes, 0); + sha256.TransformBlock(salt, 0, salt.Length, salt, 0); + if (ownerKey != null) + sha256.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0); + sha256.TransformFinalBlock(salt, 0, 0); + Array.Copy(sha256.Hash, block, sha256.HashSize / 8); + } + for (i = 0; i < 64 || i < data[dataLen * 64 - 1] + 32; i++) + { + /* Step 2: repeat password and data block 64 times */ + Array.Copy(pwdBytes, data, pwdBytes.Length); + Array.Copy(block, 0, data, pwdBytes.Length, blockSize); + if (ownerKey != null) + Array.Copy(ownerKey, 0, data, pwdBytes.Length + blockSize, 48); + dataLen = pwdBytes.Length + blockSize + (ownerKey != null ? 48 : 0); + for (j = 1; j < 64; j++) + Array.Copy(data, 0, data, j * dataLen, dataLen); + + /* Step 3: encrypt data using data block as key and iv */ + Array.Copy(block, 16, iv, 0, 16); + Array.Copy(block, 0, aesKey, 0, 16); + using (var aesEnc = aes128.CreateEncryptor(aesKey, iv)) + { + aesEnc.TransformBlock(data, 0, dataLen * 64, data, 0); + + /* Step 4: determine SHA-2 hash size for this round */ + for (j = 0, sum = 0; j < 16; j++) + sum += data[j]; + + /* Step 5: calculate data block for next round */ + blockSize = 32 + sum % 3 * 16; + HashAlgorithm hashAlg = null; + switch (blockSize) + { + case 32: + hashAlg = SHA256.Create(); + break; + case 48: + hashAlg = SHA384.Create(); + break; + case 64: + hashAlg = SHA512.Create(); + break; + } + hashAlg.TransformBlock(data, 0, dataLen * 64, data, 0); + hashAlg.TransformFinalBlock(data, 0, 0); + Array.Copy(hashAlg.Hash, block, hashAlg.HashSize / 8); + hashAlg.Dispose(); + } + } + } + Array.Copy(block, hash, 32); + } + + private static bool PasswordMatchR5(byte[] key, byte[] comparand) + { + var sha = SHA256.Create(); + var hash = sha.ComputeHash(key); + for (var i = 0; i < 32; i++) + { + if (hash[i] != comparand[i]) + return false; + } + return true; + } + + /// + /// Pdf Reference 1.7, Chapter 7.6.2, Algorithm #1 + /// + /// + public override void CreateHashKey(PdfObjectID id) + { + if (rValue >= 5) + { + if (key == null || key.Length != encryptionKey.Length) + key = new byte[encryptionKey.Length]; + Array.Copy(encryptionKey, key, encryptionKey.Length); + return; + } + var objectId = new byte[5]; + md5.Initialize(); + // Split the object number and generation + objectId[0] = (byte)id.ObjectNumber; + objectId[1] = (byte)(id.ObjectNumber >> 8); + objectId[2] = (byte)(id.ObjectNumber >> 16); + objectId[3] = (byte)id.GenerationNumber; + objectId[4] = (byte)(id.GenerationNumber >> 8); + var salt = new byte[] { 0x73, 0x41, 0x6C, 0x54 }; + var k = new byte[encryptionKey.Length + 9]; + Array.Copy(encryptionKey, k, encryptionKey.Length); + Array.Copy(objectId, 0, k, encryptionKey.Length, objectId.Length); + Array.Copy(salt, 0, k, encryptionKey.Length + objectId.Length, salt.Length); + key = md5.ComputeHash(k); + md5.Initialize(); + keySize = encryptionKey.Length + 5; + if (keySize > 16) + keySize = 16; + } + + /// + /// Decrypts a block of data + /// + /// Bytes to decrypt + /// + public override byte[] Encrypt(byte[] bytes) + { + // first 16 bytes should be an initialization vector for the encryption + if (bytes.Length <= 16) + return bytes; + + var iv = new byte[16]; + Array.Copy(bytes, iv, 16); + // Pdf Reference 1.7, Section 7.6.2 : + // "Strings and streams encrypted with AES shall use a padding scheme that is described in Internet RFC 2898, PKCS #5" + var output = new byte[bytes.Length - 16]; + int dataLength; + using (var aes = Aes.Create()) + { + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + var decryptor = aes.CreateDecryptor(key, iv); + try + { + var offset = decryptor.TransformBlock(bytes, 16, bytes.Length - 16, output, 0); + var suffix = decryptor.TransformFinalBlock(bytes, 0, 0); + Array.Copy(suffix, 0, output, offset, suffix.Length); + dataLength = offset + suffix.Length; + } + catch + { + // return unmodified + // (encountered documents that were "partly" encrypted, i.e. everything was encrypted except object-streams) + return bytes; + } + } + return output.Take(dataLength).ToArray(); + } + } +} diff --git a/PdfSharpCore/Pdf.Security/EncryptorBase.cs b/PdfSharpCore/Pdf.Security/EncryptorBase.cs new file mode 100644 index 00000000..96ef3385 --- /dev/null +++ b/PdfSharpCore/Pdf.Security/EncryptorBase.cs @@ -0,0 +1,150 @@ +using PdfSharpCore.Pdf.Internal; +using System; +using System.Security.Cryptography; + +namespace PdfSharpCore.Pdf.Security +{ + internal abstract class EncryptorBase + { + protected readonly MD5 md5 = MD5.Create(); + + /// + /// The encryption key for the owner. + /// + protected byte[] ownerKey = new byte[32]; + + /// + /// The encryption key for the user. + /// + protected byte[] userKey = new byte[32]; + + /// + /// The encryption key for a particular object/generation. + /// + protected byte[] key; + + /// + /// The global encryption key. + /// + protected byte[] encryptionKey; + + /// + /// The /O value as read from the input document + /// + protected byte[] ownerValue; + + /// + /// The /U value as read from the input document + /// + protected byte[] userValue; + + protected byte[] computedOwnerValue; + + protected byte[] computedUserValue; + + protected byte[] documentId; + + protected byte[] oeValue; + + protected byte[] ueValue; + + protected byte[] permsValue; + + protected int pValue; + + protected int rValue; + + protected int vValue; + + protected bool encryptMetadata; + + protected PdfDictionary cf; + + protected string stmF; + + protected string strF; + + protected int keyLength; + + protected static readonly byte[] passwordPadding = new byte[] // 32 bytes password padding defined by Adobe + { + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A, + }; + + /// + /// The encryption key length for a particular object/generation. + /// + protected int keySize; + + protected PdfDocument doc; + + protected PdfDictionary encryptionDict; + + public bool PasswordValid { get; protected set; } + + public bool HaveOwnerPermission { get; protected set; } + + public void Initialize(PdfDocument document, PdfDictionary encryptionDictionary) + { + doc = document; + encryptionDict = encryptionDictionary; + + documentId = PdfEncoders.RawEncoding.GetBytes(doc.Internals.FirstDocumentID); + ownerValue = PdfEncoders.RawEncoding.GetBytes(encryptionDict.Elements.GetString(PdfStandardSecurityHandler.Keys.O)); + userValue = PdfEncoders.RawEncoding.GetBytes(encryptionDict.Elements.GetString(PdfStandardSecurityHandler.Keys.U)); + oeValue = PdfEncoders.RawEncoding.GetBytes(encryptionDict.Elements.GetString(PdfStandardSecurityHandler.Keys.OE)); + ueValue = PdfEncoders.RawEncoding.GetBytes(encryptionDict.Elements.GetString(PdfStandardSecurityHandler.Keys.UE)); + permsValue = PdfEncoders.RawEncoding.GetBytes(encryptionDict.Elements.GetString(PdfStandardSecurityHandler.Keys.Perms)); + pValue = encryptionDict.Elements.GetInteger(PdfStandardSecurityHandler.Keys.P); + rValue = encryptionDict.Elements.GetInteger(PdfStandardSecurityHandler.Keys.R); + vValue = encryptionDict.Elements.GetInteger(PdfSecurityHandler.Keys.V); + encryptMetadata = !encryptionDict.Elements.ContainsKey(PdfStandardSecurityHandler.Keys.EncryptMetadata) || encryptionDict.Elements.GetBoolean(PdfStandardSecurityHandler.Keys.EncryptMetadata); + cf = encryptionDict.Elements.GetDictionary(PdfSecurityHandler.Keys.CF); + stmF = encryptionDict.Elements.GetString(PdfSecurityHandler.Keys.StmF); + strF = encryptionDict.Elements.GetString(PdfSecurityHandler.Keys.StrF); + keyLength = encryptionDict.Elements.GetInteger(PdfSecurityHandler.Keys.Length) / 8; // specified in Bits + // Length may be absent, use default of 40 bits (see 7.6.1 Table 20, "V" entry) + if (keyLength <= 0) + keyLength = 5; + keySize = keyLength; + } + + public void SetEncryptionKey(byte[] encKey) + { + encryptionKey = encKey; + } + + /// + /// Pads a password to a 32 byte array. + /// + protected static byte[] PadPassword(string password) + { + var padded = new byte[32]; + if (password == null) + Array.Copy(passwordPadding, 0, padded, 0, 32); + else + { + int length = password.Length; + Array.Copy(PdfEncoders.RawEncoding.GetBytes(password), 0, padded, 0, Math.Min(length, 32)); + if (length < 32) + Array.Copy(passwordPadding, 0, padded, length, 32 - length); + } + return padded; + } + + /// + /// Compares the first 'length' bytes of two byte-arrays + /// + /// + protected static bool CompareArrays(byte[] left, byte[] right, int length) + { + for (var i = 0; i < length; i++) + { + if (left[i] != right[i]) + return false; + } + return true; + } + } +} diff --git a/PdfSharpCore/Pdf.Security/EncryptorFactory.cs b/PdfSharpCore/Pdf.Security/EncryptorFactory.cs new file mode 100644 index 00000000..f0e8ab33 --- /dev/null +++ b/PdfSharpCore/Pdf.Security/EncryptorFactory.cs @@ -0,0 +1,63 @@ +using PdfSharpCore.Pdf.IO; + +namespace PdfSharpCore.Pdf.Security +{ + internal class EncryptorFactory + { + public static void Create(PdfDocument doc, PdfDictionary dict, out IEncryptor stringEncryptor, out IEncryptor streamEncryptor) + { + stringEncryptor = streamEncryptor = null; + + var filter = dict.Elements.GetName(PdfSecurityHandler.Keys.Filter); + var v = dict.Elements.GetInteger(PdfSecurityHandler.Keys.V); + var maxSupportedVersion = 5; + if (filter != "/Standard" || !(v >= 1 && v <= maxSupportedVersion)) + throw new PdfReaderException(PSSR.UnknownEncryption); + foreach (var keyName in new []{"/StrF", "/StmF"}) + { + IEncryptor encryptor = null; + if (v >= 4) + { + var cf = dict.Elements.GetDictionary(PdfSecurityHandler.Keys.CF); + if (cf != null) + { + var filterName = dict.Elements.GetName(keyName); + if (!string.IsNullOrEmpty(filterName)) + { + /* + * Pdf Reference 1.7 Chapter 7.6.5 (Crypt Filters) + * + * None: The application shall not decrypt data but shall direct the input stream to the security handler for decryption. + * V2: The application shall ask the security handler for the encryption key and shall implicitly decrypt data with + * "Algorithm 1: Encryption of data using the RC4 or AES algorithms", using the RC4 algorithm. + * AESV2: (PDF 1.6)The application shall ask the security handler for the encryption key and shall implicitly decrypt data with + * "Algorithm 1: Encryption of data using the RC4 or AES algorithms", using the AES algorithm in Cipher Block + * Chaining (CBC) mode with a 16-byte block size and an initialization vector that shall be randomly generated and + * placed as the first 16 bytes in the stream or string. + * AESV3: (PDF 1.7, ExtensionLevel 3) The application asks the security handler for the encryption key and implicitly decrypts data with + * Algorithm 3.1a, using the AES-256 algorithm in Cipher Block Chaining (CBC) with padding mode with a 16-byte block size and an + * initialization vector that is randomly generated and placed as the first 16 bytes in the stream or string. + * The key size (Length) shall be 256 bits. + */ + var filterDict = cf.Elements.GetDictionary(filterName); + if (filterDict != null) + { + var cfm = filterDict.Elements.GetName(PdfSecurityHandler.Keys.CFM); + if (!string.IsNullOrEmpty(cfm) && cfm.StartsWith("/AESV")) // AESV2(PDF 1.6), AESV3(PDF 1.7, ExtensionLevel 3) + encryptor = new AESEncryptor(); + } + } + } + } + // default to RC4 encryption + if (encryptor == null) + encryptor = new RC4Encryptor(); + encryptor.Initialize(doc, dict); + if (keyName == "/StrF") + stringEncryptor = encryptor; + else + streamEncryptor = encryptor; + } + } + } +} diff --git a/PdfSharpCore/Pdf.Security/IEncryptor.cs b/PdfSharpCore/Pdf.Security/IEncryptor.cs new file mode 100644 index 00000000..005c59b8 --- /dev/null +++ b/PdfSharpCore/Pdf.Security/IEncryptor.cs @@ -0,0 +1,21 @@ +namespace PdfSharpCore.Pdf.Security +{ + internal interface IEncryptor + { + bool PasswordValid { get; } + + bool HaveOwnerPermission { get; } + + void Initialize(PdfDocument document, PdfDictionary encryptionDict); + + void InitEncryptionKey(string password); + + bool ValidatePassword(string password); + + void SetEncryptionKey(byte[] key); + + void CreateHashKey(PdfObjectID objectId); + + byte[] Encrypt(byte[] bytes); + } +} \ No newline at end of file diff --git a/PdfSharpCore/Pdf.Security/MD5Managed.cs b/PdfSharpCore/Pdf.Security/MD5Managed.cs deleted file mode 100644 index 34efe070..00000000 --- a/PdfSharpCore/Pdf.Security/MD5Managed.cs +++ /dev/null @@ -1,499 +0,0 @@ -#region PDFsharp - A .NET library for processing PDF -// -// Authors: -// Stefan Lange -// -// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany) -// -// http://www.PdfSharpCore.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 - -// Based on code from here: -// http://archive.msdn.microsoft.com/SilverlightMD5/Release/ProjectReleases.aspx?ReleaseId=2206 -// -// ************************************************************** -// * Raw implementation of the MD5 hash algorithm -// * from RFC 1321. -// * -// * Written By: Reid Borsuk and Jenny Zheng -// * Copyright (c) Microsoft Corporation. All rights reserved. -// ************************************************************** - -using System; -using System.Diagnostics; -#if !NETFX_CORE && !UWP && !PORTABLE -using System.Security.Cryptography; -#endif - -// ReSharper disable InconsistentNaming - -#if SILVERLIGHT || WINDOWS_PHONE || UWP || (GDI && DEBUG) || PORTABLE -namespace PdfSharpCore.Pdf.Security -{ - -#if false && (UWP || PORTABLE) - class HashAlgorithm - { - public int HashSizeValue { get; set; } - - public virtual void Initialize() - { } - - protected virtual void HashCore(byte[] array, int ibStart, int cbSize) - { } - - protected virtual byte[] HashFinal() - { - return null; - } - - public byte[] HashValue { get; set; } - - public void TransformBlock(byte[] a, int b, int c, byte[] d, int e) - { } - - public void TransformFinalBlock(byte[] a, int b, int c) - { } - - public byte[] ComputeHash(byte[] a) - { - return null; - } - - public byte[] Hash - { - get { return null; } - } - } -#endif - /// - /// A managed implementation of the MD5 algorithm. - /// Necessary because MD5 is not part of the framework in Silverlight and WP. - /// - class MD5Managed - //#if !UWP - : System.Security.Cryptography.HashAlgorithm // TODO: WinRT has not even a HashAlgorithm base class. - //#endif - { - // Intitial values as defined in RFC 1321. - const uint A = 0x67452301; - const uint B = 0xefcdab89; - const uint C = 0x98badcfe; - const uint D = 0x10325476; - - public override int HashSize { get; } = 128; - - - public MD5Managed() - { - Initialize(); - } - - public sealed override void Initialize() - { - _data = new byte[64]; - _dataSize = 0; - _totalLength = 0; - _abcd = new MD5Core.ABCDStruct(); - - // Intitial values as defined in RFC 1321. - _abcd.A = A; - _abcd.B = B; - _abcd.C = C; - _abcd.D = D; - } - - - public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - // Do some validation, we let BlockCopy do the destination array validation - if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); - - if (inputOffset < 0) - throw new ArgumentOutOfRangeException("inputOffset", "Argument out of range - need non-negative number"); - - if (inputCount < 0 || (inputCount > inputBuffer.Length)) - throw new ArgumentException("Invalid Value"); - - if ((inputBuffer.Length - inputCount) < inputOffset) - throw new ArgumentException("Invalid Offset Length"); - - this.HashCore(inputBuffer, inputOffset, inputCount); - - if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))) - Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); - - return inputCount; - } - - - private byte[] m_hashValue; - - - public byte[] Hash - { - get { - return this.m_hashValue; - } - } - - - public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) - { - // Do some validation - if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); - - if (inputOffset < 0) - throw new ArgumentOutOfRangeException("inputOffset", "Argument out of range - need non-negative number"); - - if (inputCount < 0 || (inputCount > inputBuffer.Length)) - throw new ArgumentException("Invalid Value"); - - if ((inputBuffer.Length - inputCount) < inputOffset) - throw new ArgumentException("Invalid Offset Length"); - - this.HashCore(inputBuffer, inputOffset, inputCount); - this.m_hashValue = this.HashFinal(); - - - byte[] outputBytes; - if (inputCount != 0) - { - outputBytes = new byte[inputCount]; - System.Array.Copy(inputBuffer, inputOffset, outputBytes, 0, inputCount); - } - else - { - outputBytes = System.Array.Empty(); - } - - return outputBytes; - } - - - protected override void HashCore(byte[] array, int ibStart, int cbSize) - { - int startIndex = ibStart; - int totalArrayLength = _dataSize + cbSize; - if (totalArrayLength >= 64) - { - Array.Copy(array, startIndex, _data, _dataSize, 64 - _dataSize); - // Process message of 64 bytes (512 bits) - MD5Core.GetHashBlock(_data, ref _abcd, 0); - startIndex += 64 - _dataSize; - totalArrayLength -= 64; - while (totalArrayLength >= 64) - { - Array.Copy(array, startIndex, _data, 0, 64); - MD5Core.GetHashBlock(array, ref _abcd, startIndex); - totalArrayLength -= 64; - startIndex += 64; - } - _dataSize = totalArrayLength; - Array.Copy(array, startIndex, _data, 0, totalArrayLength); - } - else - { - Array.Copy(array, startIndex, _data, _dataSize, cbSize); - _dataSize = totalArrayLength; - } - _totalLength += cbSize; - } - - protected override byte[] HashFinal() - { - this.m_hashValue = MD5Core.GetHashFinalBlock(_data, 0, _dataSize, _abcd, _totalLength * 8); - return this.m_hashValue; - } - - byte[] _data; - MD5Core.ABCDStruct _abcd; - Int64 _totalLength; - int _dataSize; - - static class MD5Core - { -#if true - public static byte[] GetHash(byte[] input) - { - if (null == input) - throw new ArgumentNullException("input"); - - // Intitial values defined in RFC 1321. - ABCDStruct abcd = new ABCDStruct(); - abcd.A = A; - abcd.B = B; - abcd.C = C; - abcd.D = D; - - // We pass in the input array by block, the final block of data must be handled specially for padding & length embeding. - int startIndex = 0; - while (startIndex <= input.Length - 64) - { - GetHashBlock(input, ref abcd, startIndex); - startIndex += 64; - } - // The final data block. - return GetHashFinalBlock(input, startIndex, input.Length - startIndex, abcd, (Int64)input.Length * 8); - } -#endif - - internal static byte[] GetHashFinalBlock(byte[] input, int ibStart, int cbSize, ABCDStruct abcd, Int64 len) - { - byte[] working = new byte[64]; - byte[] length = BitConverter.GetBytes(len); - - // Padding is a single bit 1, followed by the number of 0s required to make size congruent to 448 modulo 512. Step 1 of RFC 1321 - // The CLR ensures that our buffer is 0-assigned, we don't need to explicitly set it. This is why it ends up being quicker to just - // use a temporary array rather then doing in-place assignment (5% for small inputs) - Array.Copy(input, ibStart, working, 0, cbSize); - working[cbSize] = 0x80; - - // We have enough room to store the length in this chunk. - if (cbSize <= 56) - { - Array.Copy(length, 0, working, 56, 8); - GetHashBlock(working, ref abcd, 0); - } - else // We need an aditional chunk to store the length. - { - GetHashBlock(working, ref abcd, 0); - // Create an entirely new chunk due to the 0-assigned trick mentioned above, to avoid an extra function call clearing the array. - working = new byte[64]; - Array.Copy(length, 0, working, 56, 8); - GetHashBlock(working, ref abcd, 0); - } - byte[] output = new byte[16]; - Array.Copy(BitConverter.GetBytes(abcd.A), 0, output, 0, 4); - Array.Copy(BitConverter.GetBytes(abcd.B), 0, output, 4, 4); - Array.Copy(BitConverter.GetBytes(abcd.C), 0, output, 8, 4); - Array.Copy(BitConverter.GetBytes(abcd.D), 0, output, 12, 4); - return output; - } - - internal static void GetHashBlock(byte[] input, ref ABCDStruct ABCDValue, int ibStart) - { - uint[] temp = Converter(input, ibStart); - uint a = ABCDValue.A; - uint b = ABCDValue.B; - uint c = ABCDValue.C; - uint d = ABCDValue.D; - - a = r1(a, b, c, d, temp[0], 7, 0xd76aa478); - d = r1(d, a, b, c, temp[1], 12, 0xe8c7b756); - c = r1(c, d, a, b, temp[2], 17, 0x242070db); - b = r1(b, c, d, a, temp[3], 22, 0xc1bdceee); - a = r1(a, b, c, d, temp[4], 7, 0xf57c0faf); - d = r1(d, a, b, c, temp[5], 12, 0x4787c62a); - c = r1(c, d, a, b, temp[6], 17, 0xa8304613); - b = r1(b, c, d, a, temp[7], 22, 0xfd469501); - a = r1(a, b, c, d, temp[8], 7, 0x698098d8); - d = r1(d, a, b, c, temp[9], 12, 0x8b44f7af); - c = r1(c, d, a, b, temp[10], 17, 0xffff5bb1); - b = r1(b, c, d, a, temp[11], 22, 0x895cd7be); - a = r1(a, b, c, d, temp[12], 7, 0x6b901122); - d = r1(d, a, b, c, temp[13], 12, 0xfd987193); - c = r1(c, d, a, b, temp[14], 17, 0xa679438e); - b = r1(b, c, d, a, temp[15], 22, 0x49b40821); - - a = r2(a, b, c, d, temp[1], 5, 0xf61e2562); - d = r2(d, a, b, c, temp[6], 9, 0xc040b340); - c = r2(c, d, a, b, temp[11], 14, 0x265e5a51); - b = r2(b, c, d, a, temp[0], 20, 0xe9b6c7aa); - a = r2(a, b, c, d, temp[5], 5, 0xd62f105d); - d = r2(d, a, b, c, temp[10], 9, 0x02441453); - c = r2(c, d, a, b, temp[15], 14, 0xd8a1e681); - b = r2(b, c, d, a, temp[4], 20, 0xe7d3fbc8); - a = r2(a, b, c, d, temp[9], 5, 0x21e1cde6); - d = r2(d, a, b, c, temp[14], 9, 0xc33707d6); - c = r2(c, d, a, b, temp[3], 14, 0xf4d50d87); - b = r2(b, c, d, a, temp[8], 20, 0x455a14ed); - a = r2(a, b, c, d, temp[13], 5, 0xa9e3e905); - d = r2(d, a, b, c, temp[2], 9, 0xfcefa3f8); - c = r2(c, d, a, b, temp[7], 14, 0x676f02d9); - b = r2(b, c, d, a, temp[12], 20, 0x8d2a4c8a); - - a = r3(a, b, c, d, temp[5], 4, 0xfffa3942); - d = r3(d, a, b, c, temp[8], 11, 0x8771f681); - c = r3(c, d, a, b, temp[11], 16, 0x6d9d6122); - b = r3(b, c, d, a, temp[14], 23, 0xfde5380c); - a = r3(a, b, c, d, temp[1], 4, 0xa4beea44); - d = r3(d, a, b, c, temp[4], 11, 0x4bdecfa9); - c = r3(c, d, a, b, temp[7], 16, 0xf6bb4b60); - b = r3(b, c, d, a, temp[10], 23, 0xbebfbc70); - a = r3(a, b, c, d, temp[13], 4, 0x289b7ec6); - d = r3(d, a, b, c, temp[0], 11, 0xeaa127fa); - c = r3(c, d, a, b, temp[3], 16, 0xd4ef3085); - b = r3(b, c, d, a, temp[6], 23, 0x04881d05); - a = r3(a, b, c, d, temp[9], 4, 0xd9d4d039); - d = r3(d, a, b, c, temp[12], 11, 0xe6db99e5); - c = r3(c, d, a, b, temp[15], 16, 0x1fa27cf8); - b = r3(b, c, d, a, temp[2], 23, 0xc4ac5665); - - a = r4(a, b, c, d, temp[0], 6, 0xf4292244); - d = r4(d, a, b, c, temp[7], 10, 0x432aff97); - c = r4(c, d, a, b, temp[14], 15, 0xab9423a7); - b = r4(b, c, d, a, temp[5], 21, 0xfc93a039); - a = r4(a, b, c, d, temp[12], 6, 0x655b59c3); - d = r4(d, a, b, c, temp[3], 10, 0x8f0ccc92); - c = r4(c, d, a, b, temp[10], 15, 0xffeff47d); - b = r4(b, c, d, a, temp[1], 21, 0x85845dd1); - a = r4(a, b, c, d, temp[8], 6, 0x6fa87e4f); - d = r4(d, a, b, c, temp[15], 10, 0xfe2ce6e0); - c = r4(c, d, a, b, temp[6], 15, 0xa3014314); - b = r4(b, c, d, a, temp[13], 21, 0x4e0811a1); - a = r4(a, b, c, d, temp[4], 6, 0xf7537e82); - d = r4(d, a, b, c, temp[11], 10, 0xbd3af235); - c = r4(c, d, a, b, temp[2], 15, 0x2ad7d2bb); - b = r4(b, c, d, a, temp[9], 21, 0xeb86d391); - - ABCDValue.A = unchecked(a + ABCDValue.A); - ABCDValue.B = unchecked(b + ABCDValue.B); - ABCDValue.C = unchecked(c + ABCDValue.C); - ABCDValue.D = unchecked(d + ABCDValue.D); - } - - // Manually unrolling these equations nets us a 20% performance improvement - private static uint r1(uint a, uint b, uint c, uint d, uint x, int s, uint t) - { - // (b + LSR((a + F(b, c, d) + x + t), s)) - // F(x, y, z) ((x & y) | ((x ^ 0xFFFFFFFF) & z)) - return unchecked(b + LSR((a + ((b & c) | ((b ^ 0xFFFFFFFF) & d)) + x + t), s)); - } - - private static uint r2(uint a, uint b, uint c, uint d, uint x, int s, uint t) - { - // (b + LSR((a + G(b, c, d) + x + t), s)) - // G(x, y, z) ((x & z) | (y & (z ^ 0xFFFFFFFF))) - return unchecked(b + LSR((a + ((b & d) | (c & (d ^ 0xFFFFFFFF))) + x + t), s)); - } - - private static uint r3(uint a, uint b, uint c, uint d, uint x, int s, uint t) - { - // (b + LSR((a + H(b, c, d) + k + i), s)) - // H(x, y, z) (x ^ y ^ z) - return unchecked(b + LSR((a + (b ^ c ^ d) + x + t), s)); - } - - private static uint r4(uint a, uint b, uint c, uint d, uint x, int s, uint t) - { - // (b + LSR((a + I(b, c, d) + k + i), s)) - // I(x, y, z) (y ^ (x | (z ^ 0xFFFFFFFF))) - return unchecked(b + LSR((a + (c ^ (b | (d ^ 0xFFFFFFFF))) + x + t), s)); - } - - // Implementation of left rotate - // s is an int instead of a uint becuase the CLR requires the argument passed to >>/<< is of - // type int. Doing the demoting inside this function would add overhead. - private static uint LSR(uint i, int s) - { - return (i << s) | (i >> (32 - s)); - } - - // Convert input array into array of UInts. - static uint[] Converter(byte[] input, int ibStart) - { - if (null == input) - throw new ArgumentNullException("input"); - - uint[] result = new uint[16]; - for (int idx = 0; idx < 16; idx++) - { - result[idx] = (uint)input[ibStart + idx * 4]; - result[idx] += (uint)input[ibStart + idx * 4 + 1] << 8; - result[idx] += (uint)input[ibStart + idx * 4 + 2] << 16; - result[idx] += (uint)input[ibStart + idx * 4 + 3] << 24; - - Debug.Assert(result[idx] == - (input[ibStart + idx * 4]) + - ((uint)input[ibStart + idx * 4 + 1] << 8) + - ((uint)input[ibStart + idx * 4 + 2] << 16) + - ((uint)input[ibStart + idx * 4 + 3] << 24)); - } - return result; - } - - // Simple struct for the (a,b,c,d) which is used to compute the mesage digest. - public struct ABCDStruct - { - public uint A; - public uint B; - public uint C; - public uint D; - } - } - } - -#if GDI && DEBUG && true_ - - // See here for details: http://archive.msdn.microsoft.com/SilverlightMD5/WorkItem/View.aspx?WorkItemId=3 - - public static class TestMD5 - { - public static void Test() - { - Random rnd = new Random(); - for (int i = 0; i < 10000; i++) - { - int count = rnd.Next(1000) + 1; - Console.WriteLine(String.Format("{0}: {1}", i, count)); - Test2(count); - } - } - - static void Test2(int count) - { - byte[] bytes = new byte[count]; - - for (int idx = 0; idx < count; idx += 16) - Array.Copy(Guid.NewGuid().ToByteArray(), 0, bytes, idx, Math.Min(16, count - idx)); - - MD5 md5dotNet = new MD5CryptoServiceProvider(); - md5dotNet.Initialize(); - MD5Managed md5m = new MD5Managed(); - md5m.Initialize(); - - byte[] result1 = md5dotNet.ComputeHash(bytes); - byte[] result2 = md5m.ComputeHash(bytes); - - if (!CompareBytes(result1, result2)) - { - count.GetType(); - //throw new Exception("Bug in MD5Managed..."); - } - } - - static bool CompareBytes(byte[] bytes1, byte[] bytes2) - { - for (int idx = 0; idx < bytes1.Length; idx++) - { - if (bytes1[idx] != bytes2[idx]) - return false; - } - return true; - } - } -#endif -} -#endif \ No newline at end of file diff --git a/PdfSharpCore/Pdf.Security/PdfSecurityHandler.cs b/PdfSharpCore/Pdf.Security/PdfSecurityHandler.cs index aa5b2c42..59399297 100644 --- a/PdfSharpCore/Pdf.Security/PdfSecurityHandler.cs +++ b/PdfSharpCore/Pdf.Security/PdfSecurityHandler.cs @@ -5,7 +5,7 @@ // // Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany) // -// http://www.PdfSharpCore.com +// http://www.PdfSharp.com // http://sourceforge.net/projects/pdfsharp // // Permission is hereby granted, free of charge, to any person obtaining a @@ -77,8 +77,12 @@ internal class Keys : KeysBase /// 1 Algorithm 3.1, with an encryption key length of 40 bits. /// 2 (PDF 1.4) Algorithm 3.1, but permitting encryption key lengths greater than 40 bits. /// 3 (PDF 1.4) An unpublished algorithm that permits encryption key lengths ranging from 40 to 128 bits. - /// 4 (PDF 1.5) The security handler defines the use of encryption and decryption in the document, using - /// the rules specified by the CF, StmF, and StrF entries. + /// 4 (PDF 1.5) The security handler defines the use of encryption and + /// decryption in the document, using the rules specified by the CF, + /// StmF, and StrF entries using algorithm 3.1 with a key length of 128 bits. + /// 5 (ExtensionLevel 3) The security handler defines the use of + /// encryption and decryption in the document, using the rules + /// specified by the CF, StmF, and StrF entries using algorithm 3.1a with a key length of 256 bits /// The default value if this entry is omitted is 0, but a value of 1 or greater is strongly recommended. /// [KeyInfo(KeyType.Integer | KeyType.Optional)] @@ -86,7 +90,9 @@ internal class Keys : KeysBase /// /// (Optional; PDF 1.4; only if V is 2 or 3) The length of the encryption key, in bits. - /// The value must be a multiple of 8, in the range 40 to 128. Default value: 40. + /// The value must be a multiple of 8, in the range 40 to 256. Default value: 40. + /// Note: Security handlers can define their own use of the Length entry + /// but are encouraged to use it to define the bit length of the encryption key. /// [KeyInfo("1.4", KeyType.Integer | KeyType.Optional)] public const string Length = "/Length"; @@ -101,7 +107,38 @@ internal class Keys : KeysBase public const string CF = "/CF"; /// - /// (Optional; meaningful only when the value of V is 4; PDF 1.5) + /// (Optional) The method used, if any, by the consumer application to decrypt data. + /// The following values are supported: + /// None The application does not decrypt data but directs the input + /// stream to the security handler for decryption. (See implementation + /// note 30 in Appendix H.) + /// V2 The application asks the security handler for the encryption key + /// and implicitly decrypts data with Algorithm 3.1, using the RC4 algorithm. + /// AESV2(PDF 1.6) The application asks the security handler for the + /// encryption key and implicitly decrypts data with Algorithm 3.1, using + /// the AES-128 algorithm in Cipher Block Chaining(CBC) with padding + /// mode with a 16-byte block size and an initialization vector that is + /// randomly generated and placed as the first 16 bytes in the stream or + /// string. The key size(Length) shall be 128 bits. + /// AESV3(ExtensionLevel 3) The application asks the security handler + /// for the encryption key and implicitly decrypts data with + /// Algorithm 3.1a, using the AES-256 algorithm in Cipher Block + /// Chaining(CBC) with padding mode with a 16-byte block size and an + /// initialization vector that is randomly generated and placed as the + /// first 16 bytes in the stream or string. The key size(Length) shall be 256 bits. + /// When the value is V2, AESV2, or AESV3, the application may ask once for + /// this encryption key and cache the key for subsequent use for streams + /// that use the same crypt filter.Therefore, there must be a one-to-one + /// relationship between a crypt filter name and the corresponding encryption key. + /// Only the values listed here are supported. Applications that encounter + /// other values should report that the file is encrypted with an unsupported algorithm. + /// Default value: None. + /// + [KeyInfo(KeyType.String | KeyType.Optional)] + public const string CFM = "/CFM"; + + /// + /// (Optional; meaningful only when the value of V is 4 or 5; PDF 1.5) /// The name of the crypt filter that is used by default when decrypting streams. /// The name must be a key in the CF dictionary or a standard crypt filter name. All streams /// in the document, except for cross-reference streams or streams that have a Crypt entry in @@ -112,7 +149,7 @@ internal class Keys : KeysBase public const string StmF = "/StmF"; /// - /// (Optional; meaningful only when the value of V is 4; PDF 1.) + /// (Optional; meaningful only when the value of V is 4 or 5; PDF 1.) /// The name of the crypt filter that is used when decrypting all strings in the document. /// The name must be a key in the CF dictionary or a standard crypt filter name. /// Default value: Identity. @@ -121,7 +158,7 @@ internal class Keys : KeysBase public const string StrF = "/StrF"; /// - /// (Optional; meaningful only when the value of V is 4; PDF 1.6) + /// (Optional; meaningful only when the value of V is 4 or 5; PDF 1.6) /// The name of the crypt filter that should be used by default when encrypting embedded /// file streams; it must correspond to a key in the CF dictionary or a standard crypt /// filter name. This entry is provided by the security handler. Applications should respect diff --git a/PdfSharpCore/Pdf.Security/PdfStandardSecurityHandler.cs b/PdfSharpCore/Pdf.Security/PdfStandardSecurityHandler.cs index 67c41c7b..9ee42857 100644 --- a/PdfSharpCore/Pdf.Security/PdfStandardSecurityHandler.cs +++ b/PdfSharpCore/Pdf.Security/PdfStandardSecurityHandler.cs @@ -1,11 +1,11 @@ #region PDFsharp - A .NET library for processing PDF // // Authors: -// Stefan Lange +// Stefan Lange (mailto:Stefan.Lange@pdfsharp.com) // -// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany) +// Copyright (c) 2005-2016 empira Software GmbH, Cologne (Germany) // -// http://www.PdfSharpCore.com +// http://www.pdfsharp.com // http://sourceforge.net/projects/pdfsharp // // Permission is hereby granted, free of charge, to any person obtaining a @@ -30,13 +30,10 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using PdfSharpCore.Pdf; +using System.Security.Cryptography; using PdfSharpCore.Pdf.IO; using PdfSharpCore.Pdf.Advanced; using PdfSharpCore.Pdf.Internal; -#if !NETFX_CORE && !UWP && !PORTABLE -using System.Security.Cryptography; -#endif #pragma warning disable 0169 #pragma warning disable 0649 @@ -49,11 +46,11 @@ namespace PdfSharpCore.Pdf.Security public sealed class PdfStandardSecurityHandler : PdfSecurityHandler { internal PdfStandardSecurityHandler(PdfDocument document) - : base(document) + : base(document) { } internal PdfStandardSecurityHandler(PdfDictionary dict) - : base(dict) + : base(dict) { } /// @@ -122,7 +119,7 @@ internal void EncryptObject(PdfObject value) { Debug.Assert(value.Reference != null); - SetHashKey(value.ObjectID); + stringEncryptor.CreateHashKey(value.ObjectID); #if DEBUG if (value.ObjectID.ObjectNumber == 10) GetType(); @@ -140,8 +137,7 @@ internal void EncryptObject(PdfObject value) if (str.Length != 0) { byte[] bytes = str.EncryptionValue; - PrepareKey(); - EncryptRC4(bytes); + bytes = stringEncryptor.Encrypt(bytes); str.EncryptionValue = bytes; } } @@ -152,7 +148,12 @@ internal void EncryptObject(PdfObject value) /// void EncryptDictionary(PdfDictionary dict) { - PdfName[] names = dict.Elements.KeyNames; + // Pdf Reference 1.7, Chapter 7.5.8.2: The cross-reference stream shall not be encrypted + // Pdf Reference 1.7, Chapter 7.6.1: Strings in the Encryption-Dictionary shall not be encrypted + if (dict.Elements.GetName("/Type") == "/XRef" + || dict.ObjectNumber == ObjectNumber) + return; + foreach (KeyValuePair item in dict.Elements) { PdfString value1; @@ -170,8 +171,8 @@ void EncryptDictionary(PdfDictionary dict) byte[] bytes = dict.Stream.Value; if (bytes.Length != 0) { - PrepareKey(); - EncryptRC4(bytes); + streamEncryptor.CreateHashKey(dict.ObjectID); + bytes = streamEncryptor.Encrypt(bytes); dict.Stream.Value = bytes; } } @@ -190,7 +191,10 @@ void EncryptArray(PdfArray array) PdfDictionary value2; PdfArray value3; if ((value1 = item as PdfString) != null) + { + stringEncryptor.CreateHashKey(array.ObjectID); EncryptString(value1); + } else if ((value2 = item as PdfDictionary) != null) EncryptDictionary(value2); else if ((value3 = item as PdfArray) != null) @@ -206,8 +210,7 @@ void EncryptString(PdfString value) if (value.Length != 0) { byte[] bytes = value.EncryptionValue; - PrepareKey(); - EncryptRC4(bytes); + bytes = stringEncryptor.Encrypt(bytes); value.EncryptionValue = bytes; } } @@ -236,35 +239,22 @@ public PasswordValidity ValidatePassword(string inputPassword) // We can handle 40 and 128 bit standard encryption. string filter = Elements.GetName(PdfSecurityHandler.Keys.Filter); int v = Elements.GetInteger(PdfSecurityHandler.Keys.V); - if (filter != "/Standard" || !(v >= 1 && v <= 3)) + if (filter != "/Standard" || !(v >= 1 && v <= 5)) throw new PdfReaderException(PSSR.UnknownEncryption); - byte[] documentID = PdfEncoders.RawEncoding.GetBytes(Owner.Internals.FirstDocumentID); - byte[] oValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.O)); - byte[] uValue = PdfEncoders.RawEncoding.GetBytes(Elements.GetString(Keys.U)); - int pValue = Elements.GetInteger(Keys.P); - int rValue = Elements.GetInteger(Keys.R); if (inputPassword == null) inputPassword = ""; - bool strongEncryption = rValue == 3; - int keyLength = strongEncryption ? 16 : 32; + EncryptorFactory.Create(_document, this, out stringEncryptor, out streamEncryptor); + stringEncryptor.InitEncryptionKey(inputPassword); + streamEncryptor.InitEncryptionKey(inputPassword); - // Try owner password first. - //byte[] password = PdfEncoders.RawEncoding.GetBytes(inputPassword); - InitWithOwnerPassword(documentID, inputPassword, oValue, pValue, strongEncryption); - if (EqualsKey(uValue, keyLength)) - { - _document.SecuritySettings._hasOwnerPermissions = true; - return PasswordValidity.OwnerPassword; - } - _document.SecuritySettings._hasOwnerPermissions = false; + stringEncryptor.ValidatePassword(inputPassword); - // Now try user password. - //password = PdfEncoders.RawEncoding.GetBytes(inputPassword); - InitWithUserPassword(documentID, inputPassword, oValue, pValue, strongEncryption); - if (EqualsKey(uValue, keyLength)) + if (stringEncryptor.PasswordValid && stringEncryptor.HaveOwnerPermission) + return PasswordValidity.OwnerPassword; + if (stringEncryptor.PasswordValid) return PasswordValidity.UserPassword; return PasswordValidity.Invalid; } @@ -296,10 +286,10 @@ static byte[] PadPassword(string password) return padded; } static readonly byte[] PasswordPadding = // 32 bytes password padding defined by Adobe - { - 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, - 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A, - }; + { + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A, + }; /// /// Generates the user key based on the padded user password. @@ -358,11 +348,9 @@ byte[] ComputeOwnerKey(byte[] userPad, byte[] ownerPad, bool strongEncryption) /// void InitEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions, bool strongEncryption) { - //#if !SILVERLIGHT _ownerKey = ownerKey; _encryptionKey = new byte[strongEncryption ? 16 : 5]; -#if !NETFX_CORE _md5.Initialize(); _md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0); _md5.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0); @@ -373,7 +361,7 @@ void InitEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int p permission[1] = (byte)(permissions >> 8); permission[2] = (byte)(permissions >> 16); permission[3] = (byte)(permissions >> 24); - + _md5.TransformBlock(permission, 0, 4, permission, 0); _md5.TransformBlock(documentID, 0, documentID.Length, documentID, 0); _md5.TransformFinalBlock(permission, 0, 0); @@ -389,17 +377,13 @@ void InitEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int p } } Array.Copy(digest, 0, _encryptionKey, 0, _encryptionKey.Length); - //#endif -#endif - } + } /// /// Computes the user key. /// void SetupUserKey(byte[] documentID) { -#if !NETFX_CORE - //#if !SILVERLIGHT if (_encryptionKey.Length == 16) { _md5.TransformBlock(PasswordPadding, 0, PasswordPadding.Length, PasswordPadding, 0); @@ -423,8 +407,6 @@ void SetupUserKey(byte[] documentID) PrepareRC4Key(_encryptionKey); EncryptRC4(PasswordPadding, _userKey); } - //#endif -#endif } /// @@ -476,9 +458,8 @@ void EncryptRC4(byte[] data) /// /// Encrypts the data. /// - // ReSharper disable InconsistentNaming + // ReSharper disable once InconsistentNaming void EncryptRC4(byte[] data, int offset, int length) - // ReSharper restore InconsistentNaming { EncryptRC4(data, offset, length, data); } @@ -486,6 +467,7 @@ void EncryptRC4(byte[] data, int offset, int length) /// /// Encrypts the data. /// + // ReSharper disable once InconsistentNaming void EncryptRC4(byte[] inputData, byte[] outputData) { EncryptRC4(inputData, 0, inputData.Length, outputData); @@ -494,6 +476,7 @@ void EncryptRC4(byte[] inputData, byte[] outputData) /// /// Encrypts the data. /// + // ReSharper disable once InconsistentNaming void EncryptRC4(byte[] inputData, int offset, int length, byte[] outputData) { length += offset; @@ -528,8 +511,6 @@ bool EqualsKey(byte[] value, int length) /// internal void SetHashKey(PdfObjectID id) { -#if !NETFX_CORE - //#if !SILVERLIGHT byte[] objectId = new byte[5]; _md5.Initialize(); // Split the object number and generation @@ -545,8 +526,6 @@ internal void SetHashKey(PdfObjectID id) _keySize = _encryptionKey.Length + 5; if (_keySize > 16) _keySize = 16; - //#endif -#endif } /// @@ -615,20 +594,7 @@ public void PrepareEncryption() /// byte[] _encryptionKey; -#if !SILVERLIGHT && !UWP && !PORTABLE - /// - /// The message digest algorithm MD5. - /// - readonly MD5 _md5 = new MD5CryptoServiceProvider(); -#if DEBUG_ - readonly MD5Managed _md5M = new MD5Managed(); -#endif -#else - readonly MD5Managed _md5 = new MD5Managed(); -#endif -#if NETFX_CORE - // readonly MD5Managed _md5 = new MD5Managed(); -#endif + readonly MD5 _md5 = MD5.Create(); /// /// Bytes used for RC4 encryption. /// @@ -654,6 +620,10 @@ public void PrepareEncryption() /// int _keySize; + private IEncryptor stringEncryptor; + + private IEncryptor streamEncryptor; + #endregion internal override void WriteObject(PdfWriter writer) @@ -680,22 +650,30 @@ internal override void WriteObject(PdfWriter writer) /// 3 if the document is encrypted with a V value of 2 or 3, or has any "Revision 3 or /// greater" access permissions set. /// 4 if the document is encrypted with a V value of 4 + /// 5 (ExtensionLevel 3) if the document is encrypted with a V value of 5 /// [KeyInfo(KeyType.Integer | KeyType.Required)] public const string R = "/R"; /// - /// (Required) A 32-byte string, based on both the owner and user passwords, that is - /// used in computing the encryption key and in determining whether a valid owner - /// password was entered. + /// (Required) A string used in computing the encryption key. + /// The value of the string depends on the value of the + /// revision number, the R entry described above. + /// The value of R is 4 or less: A 32-byte string, based on both the owner and user passwords, that is used in + /// computing the encryption key and in determining whether a valid owner password was entered. + /// The value for R is 5: (ExtensionLevel 3) A 48-byte string, based on the owner and user passwords, that is used in + /// computing the encryption key and in determining whether a valid owner password was entered. /// [KeyInfo(KeyType.String | KeyType.Required)] public const string O = "/O"; /// - /// (Required) A 32-byte string, based on the user password, that is used in determining - /// whether to prompt the user for a password and, if so, whether a valid user or owner - /// password was entered. + /// (Required) A string based on the user password. The value + /// of the string depends on the value of the revision number, the R entry described above. + /// The value of R is 4 or less: A 32-byte string, based on the user password, that is used in determining + /// whether to prompt the user for a password and, if so, whether a valid user or owner password was entered. + /// The value for R is 5: (ExtensionLevel 3) A 48-byte string, based on the user password, that is used in + /// determining whether to prompt the user for a password and, if so, whether a valid user password was entered. /// [KeyInfo(KeyType.String | KeyType.Required)] public const string U = "/U"; @@ -708,7 +686,28 @@ internal override void WriteObject(PdfWriter writer) public const string P = "/P"; /// - /// (Optional; meaningful only when the value of V is 4; PDF 1.5) Indicates whether + /// (ExtensionLevel 3; required if R is 5) + /// A 32-byte string, based on the owner and user passwords, that is used in computing the encryption key. + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string OE = "/OE"; + + /// + /// (ExtensionLevel 3; required if R is 5) + /// A 32-byte string, based on the user password, that is used in computing the encryption key. + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string UE = "/UE"; + + /// + /// (ExtensionLevel 3; required if R is 5) + /// A 16-byte string, encrypted with the file encryption key, that contains an encrypted copy of the permission flags. + /// + [KeyInfo(KeyType.Integer | KeyType.Optional)] + public const string Perms = "/Perms"; + + /// + /// (Optional; meaningful only when the value of V is 4 or 5; PDF 1.5) Indicates whether /// the document-level metadata stream is to be encrypted. Applications should respect this value. /// Default value: true. /// diff --git a/PdfSharpCore/Pdf.Security/RC4Encryptor.cs b/PdfSharpCore/Pdf.Security/RC4Encryptor.cs new file mode 100644 index 00000000..75db29b2 --- /dev/null +++ b/PdfSharpCore/Pdf.Security/RC4Encryptor.cs @@ -0,0 +1,275 @@ +using PdfSharpCore.Pdf.Internal; +using System; + +namespace PdfSharpCore.Pdf.Security +{ + class RC4Encryptor : EncryptorBase, IEncryptor + { + /// + /// Bytes used for RC4 encryption. + /// + readonly byte[] state = new byte[256]; + + /// + /// Creates the encryption Key. + /// Based on algorithm #2 (3.2 in Extension Level 3) in the Pdf 1.7 reference (7.6.3.3) + /// + public virtual void InitEncryptionKey(string password) + { + var userPad = PadPassword(password); + md5.Initialize(); + md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0); + md5.TransformBlock(ownerValue, 0, ownerValue.Length, ownerValue, 0); + var permission = new byte[4]; + permission[0] = (byte)pValue; + permission[1] = (byte)(pValue >> 8); + permission[2] = (byte)(pValue >> 16); + permission[3] = (byte)(pValue >> 24); + md5.TransformBlock(permission, 0, 4, permission, 0); + md5.TransformBlock(documentId, 0, documentId.Length, documentId, 0); + if (rValue >= 4 && !encryptMetadata) + { + var ff = new byte[] { 0xff, 0xff, 0xff, 0xff }; + md5.TransformBlock(ff, 0, ff.Length, ff, 0); + } + md5.TransformFinalBlock(permission, 0, 0); + var hash = md5.Hash; + if (rValue >= 3) + { + for (var i = 0; i < 50; i++) + { + md5.Initialize(); + hash = md5.ComputeHash(hash, 0, keyLength); + } + } + encryptionKey = new byte[keyLength]; + Array.Copy(hash, encryptionKey, keyLength); + } + + public bool ValidatePassword(string password) + { + // AESEncryptor sets these + if (HaveOwnerPermission || PasswordValid) + return true; + + ValidateOwnerPassword(password); + if (!PasswordValid) + ValidateUserPassword(password); + return PasswordValid; + + } + + private void ValidateUserPassword(string password) + { + CreateUserKey(password); + PasswordValid = CompareArrays(computedUserValue, userValue, 16); + } + + private void ValidateOwnerPassword(string password) + { + var pwdPad = PadPassword(password); + md5.Initialize(); + var pwdKey = md5.ComputeHash(pwdPad); + if (rValue >= 3) + { + for (var i = 0; i < 50; i++) + { + pwdKey = md5.ComputeHash(pwdKey, 0, keyLength); + } + } + var n = rValue <= 2 ? 5 : keyLength; + var rc4Input = new byte[n]; + Array.Copy(pwdKey, rc4Input, n); + + var ov = new byte[ownerValue.Length]; + Array.Copy(ownerValue, ov, ov.Length); + if (rValue < 3) + { + PrepareRC4Key(rc4Input, 0, n); + EncryptRC4(ov); + } + else + { + var xor = new byte[n]; + for (var i = 0; i < 20; i++) + { + for (var j = 0; j < n; j++) + xor[j] = (byte)(rc4Input[j] ^ (19 - i)); + PrepareRC4Key(xor, 0, n); + EncryptRC4(ov); + } + } + var userPass = PdfEncoders.RawEncoding.GetString(ov); + ValidateUserPassword(userPass); + if (PasswordValid) + HaveOwnerPermission = true; + } + + /// + /// Pdf Reference 1.7, Chapter 7.6.3.4, Algorithm #3 + /// + public void CreateOwnerKey(string password) + { + var pwdPad = PadPassword(password); + md5.Initialize(); + var pwdKey = md5.ComputeHash(pwdPad); + if (rValue >= 3) + { + for (var i = 0; i < 50; i++) + pwdKey = md5.ComputeHash(pwdKey); + } + var n = rValue <= 2 ? 5 : keyLength; + var rc4Input = new byte[n]; + Array.Copy(pwdKey, rc4Input, n); + if (rValue >= 3) + { + for (var i = 0; i < 20; i++) + { + for (var j = 0; j < rc4Input.Length; j++) + rc4Input[j] = (byte)(rc4Input[j] ^ i); + PrepareRC4Key(rc4Input); + EncryptRC4(pwdPad); + } + } + computedOwnerValue = new byte[n]; + Array.Copy(pwdPad, computedOwnerValue, n); + } + + /// + /// Pdf Reference 1.7, Chapter 7.6.3.4, Algorithm #4 and #5 + /// + public void CreateUserKey(string password) + { + InitEncryptionKey(password); + if (rValue == 2) + { + var data = new byte[passwordPadding.Length]; + Array.Copy(passwordPadding, data, data.Length); + PrepareRC4Key(encryptionKey); + EncryptRC4(data); + computedUserValue = new byte[data.Length]; + Array.Copy(data, computedUserValue, data.Length); + } + else + { + computedUserValue = new byte[32]; + md5.Initialize(); + md5.TransformBlock(passwordPadding, 0, passwordPadding.Length, passwordPadding, 0); + md5.TransformFinalBlock(documentId, 0, documentId.Length); + var mkey = md5.Hash; + Array.Copy(mkey, computedUserValue, mkey.Length); + for (var i = 0; i < 20; i++) + { + for (var j = 0; j < mkey.Length; j++) + mkey[j] = (byte)(encryptionKey[j] ^ i); + PrepareRC4Key(mkey); + EncryptRC4(computedUserValue, 0, 16); + } + for (var i = 16; i < 32; i++) + computedUserValue[i] = 0; + } + } + + /// + /// Pdf Reference 1.7, Chapter 7.6.2, Algorithm #1 + /// + /// + public virtual void CreateHashKey(PdfObjectID id) + { + var objectId = new byte[5]; + md5.Initialize(); + // Split the object number and generation + objectId[0] = (byte)id.ObjectNumber; + objectId[1] = (byte)(id.ObjectNumber >> 8); + objectId[2] = (byte)(id.ObjectNumber >> 16); + objectId[3] = (byte)id.GenerationNumber; + objectId[4] = (byte)(id.GenerationNumber >> 8); + md5.TransformBlock(encryptionKey, 0, encryptionKey.Length, encryptionKey, 0); // ?? incomplete + md5.TransformFinalBlock(objectId, 0, objectId.Length); + key = md5.Hash; + md5.Initialize(); + keySize = encryptionKey.Length + 5; + if (keySize > 16) + keySize = 16; + } + + public virtual byte[] Encrypt(byte[] bytes) + { + PrepareRC4Key(key); + EncryptRC4(bytes); + return bytes; + } + + /// + /// Prepare the encryption key. + /// + protected void PrepareRC4Key(byte[] key) + { + PrepareRC4Key(key, 0, keySize); + } + + /// + /// Prepare the encryption key. + /// + protected void PrepareRC4Key(byte[] key, int offset, int length) + { + int idx1 = 0; + int idx2 = 0; + for (int idx = 0; idx < 256; idx++) + this.state[idx] = (byte)idx; + byte tmp; + for (int idx = 0; idx < 256; idx++) + { + idx2 = (key[idx1 + offset] + this.state[idx] + idx2) & 255; + tmp = this.state[idx]; + this.state[idx] = this.state[idx2]; + this.state[idx2] = tmp; + idx1 = (idx1 + 1) % length; + } + } + + /// + /// Encrypts the data. + /// + protected void EncryptRC4(byte[] data) + { + EncryptRC4(data, 0, data.Length, data); + } + + /// + /// Encrypts the data. + /// + protected void EncryptRC4(byte[] data, int offset, int length) + { + EncryptRC4(data, offset, length, data); + } + + /// + /// Encrypts the data. + /// + protected void EncryptRC4(byte[] inputData, byte[] outputData) + { + EncryptRC4(inputData, 0, inputData.Length, outputData); + } + + /// + /// Encrypts the data. + /// + protected void EncryptRC4(byte[] inputData, int offset, int length, byte[] outputData) + { + length += offset; + int x = 0, y = 0; + byte b; + for (int idx = offset; idx < length; idx++) + { + x = (x + 1) & 255; + y = (this.state[x] + y) & 255; + b = this.state[x]; + this.state[x] = this.state[y]; + this.state[y] = b; + outputData[idx] = (byte)(inputData[idx] ^ state[(this.state[x] + this.state[y]) & 255]); + } + } + + } +} diff --git a/PdfSharpCore/Pdf/EntryInfoAttribute.cs b/PdfSharpCore/Pdf/EntryInfoAttribute.cs index c7002ffa..942b947f 100644 --- a/PdfSharpCore/Pdf/EntryInfoAttribute.cs +++ b/PdfSharpCore/Pdf/EntryInfoAttribute.cs @@ -28,6 +28,7 @@ #endregion using System; +using System.Diagnostics.CodeAnalysis; namespace PdfSharpCore.Pdf { @@ -90,14 +91,16 @@ public KeyInfoAttribute(string version, KeyType keyType) KeyType = keyType; } - public KeyInfoAttribute(KeyType keyType, Type objectType) + public KeyInfoAttribute(KeyType keyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type objectType) { //_version = version; KeyType = keyType; _objectType = objectType; } - public KeyInfoAttribute(string version, KeyType keyType, Type objectType) + public KeyInfoAttribute(string version, KeyType keyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type objectType) { //_version = version; KeyType = keyType; @@ -118,11 +121,14 @@ public KeyType KeyType } KeyType _entryType; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] public Type ObjectType { get { return _objectType; } set { _objectType = value; } } + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type _objectType; public string FixedValue diff --git a/PdfSharpCore/Pdf/KeysBase.cs b/PdfSharpCore/Pdf/KeysBase.cs index 5340dd06..b7b904aa 100644 --- a/PdfSharpCore/Pdf/KeysBase.cs +++ b/PdfSharpCore/Pdf/KeysBase.cs @@ -28,6 +28,7 @@ #endregion using System; +using System.Diagnostics.CodeAnalysis; namespace PdfSharpCore.Pdf { @@ -36,7 +37,7 @@ namespace PdfSharpCore.Pdf /// public class KeysBase { - internal static DictionaryMeta CreateMeta(Type type) + internal static DictionaryMeta CreateMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type) { return new DictionaryMeta(type); } diff --git a/PdfSharpCore/Pdf/KeysMeta.cs b/PdfSharpCore/Pdf/KeysMeta.cs index 17932fc1..96bd1399 100644 --- a/PdfSharpCore/Pdf/KeysMeta.cs +++ b/PdfSharpCore/Pdf/KeysMeta.cs @@ -31,6 +31,7 @@ using System.Diagnostics; using System.Collections.Generic; using System.Reflection; +using System.Diagnostics.CodeAnalysis; namespace PdfSharpCore.Pdf { @@ -85,11 +86,13 @@ public string FixedValue } readonly string _fixedValue; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] public Type ObjectType { get { return _objectType; } set { _objectType = value; } } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type _objectType; public bool CanBeIndirect @@ -100,6 +103,7 @@ public bool CanBeIndirect /// /// Returns the type of the object to be created as value for the described key. /// + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] public Type GetValueType() { Type type = _objectType; @@ -180,33 +184,21 @@ public Type GetValueType() ///
internal class DictionaryMeta { - public DictionaryMeta(Type type) + public DictionaryMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type) { - //#if (NETFX_CORE && DEBUG) || CORE - // if (type == typeof(PdfPages.Keys)) - // { - // var x = typeof(PdfPages).GetRuntimeFields(); - // var y = typeof(PdfPages).GetTypeInfo().DeclaredFields; - // x.GetType(); - // y.GetType(); - // Debug-Break.Break(); - // Test.It(); - // } - //#endif -#if !NETFX_CORE && !UWP && !PORTABLE + #if NET5_0_OR_GREATER FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); foreach (FieldInfo field in fields) { - object[] attributes = field.GetCustomAttributes(typeof(KeyInfoAttribute), false); - if (attributes.Length == 1) + var attributes = field.GetCustomAttributes(false); + foreach (var attribute in attributes) { - KeyInfoAttribute attribute = (KeyInfoAttribute)attributes[0]; KeyDescriptor descriptor = new KeyDescriptor(attribute); descriptor.KeyValue = (string)field.GetValue(null); _keyDescriptors[descriptor.KeyValue] = descriptor; } } -#else + #else // Rewritten for WinRT. CollectKeyDescriptors(type); //var fields = type.GetRuntimeFields(); // does not work @@ -221,10 +213,10 @@ public DictionaryMeta(Type type) // _keyDescriptors[descriptor.KeyValue] = descriptor; // } //} -#endif + #endif } -#if NETFX_CORE || UWP || PORTABLE + #if !NET5_0_OR_GREATER // Background: The function GetRuntimeFields gets constant fields only for the specified type, // not for its base types. So we have to walk recursively through base classes. // The docmentation says full trust for the immediate caller is required for property BaseClass. @@ -247,42 +239,8 @@ void CollectKeyDescriptors(Type type) if (type != typeof(object) && type != typeof(PdfObject)) CollectKeyDescriptors(type); } -#endif - -#if (NETFX_CORE || CORE) && true_ - public class A - { - public string _a; - public const string _ca = "x"; - } - public class B : A - { - public string _b; - public const string _cb = "x"; - - void Foo() - { - var str = A._ca; - } - } - class Test - { - public static void It() - { - string s = "Runtime fields of B:"; - foreach (var fieldInfo in typeof(B).GetRuntimeFields()) { s += " " + fieldInfo.Name; } - Debug.WriteLine(s); + #endif - s = "Declared fields of B:"; - foreach (var fieldInfo in typeof(B).GetTypeInfo().DeclaredFields) { s += " " + fieldInfo.Name; } - Debug.WriteLine(s); - - s = "Runtime fields of PdfPages.Keys:"; - foreach (var fieldInfo in typeof(PdfPages.Keys).GetRuntimeFields()) { s += " " + fieldInfo.Name; } - Debug.WriteLine(s); - } - } -#endif /// /// Gets the KeyDescriptor of the specified key, or null if no such descriptor exits. /// diff --git a/PdfSharpCore/Pdf/PdfArray.cs b/PdfSharpCore/Pdf/PdfArray.cs index 91be09ba..0b43ce0c 100644 --- a/PdfSharpCore/Pdf/PdfArray.cs +++ b/PdfSharpCore/Pdf/PdfArray.cs @@ -1,4 +1,4 @@ -#region PDFsharp - A .NET library for processing PDF +#region PDFsharp - A .NET library for processing PDF // // Authors: // Stefan Lange @@ -213,7 +213,7 @@ public bool GetBoolean(int index) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; - if (obj == null) + if (obj == null || obj is PdfNull) return false; PdfBoolean boolean = obj as PdfBoolean; @@ -239,7 +239,7 @@ public int GetInteger(int index) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; - if (obj == null) + if (obj == null || obj is PdfNull) return 0; PdfInteger integer = obj as PdfInteger; @@ -265,7 +265,7 @@ public double GetReal(int index) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; - if (obj == null) + if (obj == null || obj is PdfNull) return 0; PdfReal real = obj as PdfReal; @@ -299,7 +299,7 @@ public string GetString(int index) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; - if (obj == null) + if (obj == null || obj is PdfNull) return String.Empty; PdfString str = obj as PdfString; @@ -325,7 +325,7 @@ public string GetName(int index) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; - if (obj == null) + if (obj == null || obj is PdfNull) return String.Empty; PdfName name = obj as PdfName; @@ -561,11 +561,8 @@ string DebuggerDisplay { get { -#if true return String.Format(CultureInfo.InvariantCulture, "array({0},[{1}])", ObjectID.DebuggerDisplay, _elements == null ? 0 : _elements.Count); -#else - return String.Format(CultureInfo.InvariantCulture, "array({0},[{1}])", ObjectID.DebuggerDisplay, _elements == null ? 0 : _elements.Count); -#endif + } } } diff --git a/PdfSharpCore/Pdf/PdfDate.cs b/PdfSharpCore/Pdf/PdfDate.cs index 9c08bbd0..95d02d72 100644 --- a/PdfSharpCore/Pdf/PdfDate.cs +++ b/PdfSharpCore/Pdf/PdfDate.cs @@ -39,12 +39,6 @@ namespace PdfSharpCore.Pdf [DebuggerDisplay("({Value})")] public sealed class PdfDate : PdfItem { - /// - /// Initializes a new instance of the class. - /// - public PdfDate() - { } - /// /// Initializes a new instance of the class. /// @@ -64,20 +58,19 @@ public PdfDate(DateTime value) /// /// Gets the value as DateTime. /// - public DateTime Value - { + public DateTime Value => // This class must behave like a value type. Therefore it cannot be changed (like System.String). - get { return _value; } - } - DateTime _value; + _value; + + readonly DateTime _value; /// /// Returns the value in the PDF date format. /// public override string ToString() { - string delta = _value.ToString("zzz").Replace(':', '\''); - return String.Format("D:{0:yyyyMMddHHmmss}{1}'", _value, delta); + var delta = _value.ToString("zzz").Replace(':', '\''); + return $"D:{_value:yyyyMMddHHmmss}{delta}'"; } /// diff --git a/PdfSharpCore/Pdf/PdfDictionary.cs b/PdfSharpCore/Pdf/PdfDictionary.cs index a12fdbc3..65a529f2 100644 --- a/PdfSharpCore/Pdf/PdfDictionary.cs +++ b/PdfSharpCore/Pdf/PdfDictionary.cs @@ -39,6 +39,7 @@ using PdfSharpCore.Pdf.Filters; using PdfSharpCore.Pdf.Advanced; using PdfSharpCore.Pdf.Internal; +using System.Diagnostics.CodeAnalysis; namespace PdfSharpCore.Pdf { @@ -395,6 +396,10 @@ public int GetInteger(string key, bool create) this[key] = new PdfInteger(); return 0; } + + if (obj is PdfNull) + return 0; + PdfReference reference = obj as PdfReference; if (reference != null) obj = reference.Value; @@ -586,6 +591,14 @@ public void SetString(string key, string value) this[key] = new PdfString(value); } + /// + /// Sets the entry to a string value with the specified encoding. + /// + public void SetString(string key, string value, PdfStringEncoding encoding) + { + this[key] = new PdfString(value, encoding); + } + /// /// Converts the specified value to a name. /// If the value does not exist, the function returns the empty string. @@ -825,26 +838,9 @@ public PdfItem GetValue(string key, VCF options) { 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 && !PORTABLE - 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."); @@ -858,7 +854,6 @@ public PdfItem GetValue(string key, VCF options) } else throw new NotImplementedException("Type other than array or dictionary."); -#endif if (options == VCF.CreateIndirect) { _ownerDictionary.Owner._irefTable.Add(obj); @@ -890,23 +885,6 @@ public PdfItem GetValue(string key, VCF options) 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 && !PORTABLE - if (type != null && type != value.GetType()) - { - if (typeof(PdfDictionary).IsAssignableFrom(type)) - { - Debug.Assert(value is PdfDictionary, "Bug in PdfSharpCore. 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 PdfSharpCore. 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()) @@ -924,7 +902,6 @@ public PdfItem GetValue(string key, VCF options) else throw new NotImplementedException("Type other than array or dictionary."); } -#endif } return value; } @@ -971,6 +948,7 @@ public PdfItem GetValue(string key) /// /// Returns the type of the object to be created as value of the specified key. /// + [return:DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type GetValueType(string key) // TODO: move to PdfObject { Type type = null; @@ -988,29 +966,8 @@ Type GetValueType(string key) // TODO: move to PdfObject return type; } - PdfArray CreateArray(Type type, PdfArray oldArray) + PdfArray CreateArray([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]Type type, PdfArray oldArray) { -#if !NETFX_CORE && !UWP && !PORTABLE - ConstructorInfo ctorInfo; - PdfArray array; - if (oldArray == null) - { - // Use contstructor 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 contstructor 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) @@ -1046,32 +1003,11 @@ PdfArray CreateArray(Type type, PdfArray oldArray) Debug.Assert(array != null, "No appropriate constructor found for type: " + type.Name); } return array; -#endif } - PdfDictionary CreateDictionary(Type type, PdfDictionary oldDictionary) + PdfDictionary CreateDictionary([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type type, PdfDictionary oldDictionary) { -#if !NETFX_CORE && !UWP && !PORTABLE - ConstructorInfo ctorInfo; - PdfDictionary dict; - if (oldDictionary == null) - { - // Use contstructor 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 contstructor 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) @@ -1105,27 +1041,11 @@ PdfDictionary CreateDictionary(Type type, PdfDictionary oldDictionary) Debug.Assert(dict != null, "No appropriate constructor found for type: " + type.Name); } return dict; -#endif } - PdfItem CreateValue(Type type, PdfDictionary oldValue) + PdfItem CreateValue([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]Type type, PdfDictionary oldValue) { -#if !NETFX_CORE && !UWP && !PORTABLE - 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); @@ -1150,7 +1070,6 @@ PdfItem CreateValue(Type type, PdfDictionary oldValue) } } return obj; -#endif } /// @@ -1624,59 +1543,6 @@ public int Length get { return _value != null ? _value.Length : 0; } } - /// - /// Gets a value indicating whether this stream has decode parameters. - /// - 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; - } - } - - /// - /// Gets the decode predictor for LZW- or FlateDecode. - /// Returns 0 if no such value exists. - /// - 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; - } - } - - /// - /// Gets the decode Columns for LZW- or FlateDecode. - /// Returns 0 if no such value exists. - /// - 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; - } - } - /// /// Get or sets the bytes of the stream as they are, i.e. if one or more filters exist the bytes are /// not unfiltered. @@ -1704,10 +1570,11 @@ public byte[] UnfilteredValue byte[] bytes = null; if (_value != null) { - PdfItem filter = _ownerDictionary.Elements["/Filter"]; + PdfItem filter = _ownerDictionary.Elements[Keys.Filter]; if (filter != null) { - bytes = Filtering.Decode(_value, filter); + var decodeParms = _ownerDictionary.Elements[Keys.DecodeParms]; + bytes = Filtering.Decode(_value, filter, decodeParms); if (bytes == null) { string message = String.Format("«Cannot decode filter '{0}'»", filter); @@ -1730,18 +1597,20 @@ public byte[] UnfilteredValue /// Otherwise the content remains untouched and the function returns false. /// The function is useful for analyzing existing PDF files. /// - public bool TryUnfilter() // TODO: Take DecodeParams into account. + public bool TryUnfilter() { if (_value != null) { - PdfItem filter = _ownerDictionary.Elements["/Filter"]; + PdfItem filter = _ownerDictionary.Elements[Keys.Filter]; if (filter != null) { + var decodeParms = _ownerDictionary.Elements[Keys.DecodeParms]; // PDFsharp can only uncompress streams that are compressed with the ZIP or LZH algorithm. - byte[] bytes = Filtering.Decode(_value, filter); + byte[] bytes = Filtering.Decode(_value, filter, decodeParms); if (bytes != null) { _ownerDictionary.Elements.Remove(Keys.Filter); + _ownerDictionary.Elements.Remove(Keys.DecodeParms); Value = bytes; } else @@ -1760,11 +1629,11 @@ public void Zip() if (_value == null) return; - if (!_ownerDictionary.Elements.ContainsKey("/Filter")) + if (!_ownerDictionary.Elements.ContainsKey(Keys.Filter)) { _value = Filtering.FlateDecode.Encode(_value, _ownerDictionary._document.Options.FlateEncodeMode); - _ownerDictionary.Elements["/Filter"] = new PdfName("/FlateDecode"); - _ownerDictionary.Elements["/Length"] = new PdfInteger(_value.Length); + _ownerDictionary.Elements[Keys.Filter] = new PdfName("/FlateDecode"); + _ownerDictionary.Elements[Keys.Length] = new PdfInteger(_value.Length); } } @@ -1777,11 +1646,12 @@ public override string ToString() return "«null»"; string stream; - PdfItem filter = _ownerDictionary.Elements["/Filter"]; + PdfItem filter = _ownerDictionary.Elements[Keys.Filter]; if (filter != null) { #if true - byte[] bytes = Filtering.Decode(_value, filter); + var decodeParms = _ownerDictionary.Elements[Keys.DecodeParms]; + byte[] bytes = Filtering.Decode(_value, filter, decodeParms); if (bytes != null) stream = PdfEncoders.RawEncoding.GetString(bytes, 0, bytes.Length); #else diff --git a/PdfSharpCore/Pdf/PdfDocument.cs b/PdfSharpCore/Pdf/PdfDocument.cs index 1aab72ef..674ef4b0 100644 --- a/PdfSharpCore/Pdf/PdfDocument.cs +++ b/PdfSharpCore/Pdf/PdfDocument.cs @@ -28,11 +28,12 @@ #endregion using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; -#if NETFX_CORE -using System.Threading.Tasks; -#endif +using System.Linq; +using System.Security.Cryptography; +using System.Text; using PdfSharpCore.Pdf.Advanced; using PdfSharpCore.Pdf.Internal; using PdfSharpCore.Pdf.IO; @@ -93,11 +94,7 @@ public PdfDocument(string filename) Info.CreationDate = _creation; // TODO 4STLA: encapsulate the whole c'tor with #if !NETFX_CORE? -#if !NETFX_CORE && !PORTABLE - _outStream = new FileStream(filename, FileMode.Create); -#else throw new NotImplementedException(); -#endif } /// @@ -243,7 +240,6 @@ public void Close() } } -#if true //!NETFX_CORE /// /// Saves the document to the specified path. If a file already exists, it will be overwritten. /// @@ -252,58 +248,12 @@ public void Save(string path) if (!CanModify) throw new InvalidOperationException(PSSR.CannotModify); -#if !NETFX_CORE && !PORTABLE - using (Stream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) - { - Save(stream); - } -#elif PORTABLE + using (Stream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) { Save(stream); } -#else - var task = SaveAsync(path, true); - - ////var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("MyWav.wav", Windows.Storage.CreationCollisionOption.ReplaceExisting); - ////var stream = file.OpenStreamForWriteAsync(); - ////var writer = new StreamWriter(stream); - ////Save(stream); - - //var ms = new MemoryStream(); - //Save(ms, false); - //byte[] pdf = ms.ToArray(); - //ms.Close(); -#endif } -#endif - -#if NETFX_CORE - /// - /// Saves the document to the specified path. If a file already exists, it will be overwritten. - /// - public async Task SaveAsync(string path, bool closeStream) - { - if (!CanModify) - throw new InvalidOperationException(PSSR.CannotModify); - - // Just march through... - - var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("My1st.pdf", Windows.Storage.CreationCollisionOption.ReplaceExisting); - var stream = await file.OpenStreamForWriteAsync(); - using (var writer = new StreamWriter(stream)) - { - Save(stream, false); - } - - //var ms = new MemoryStream(); - //Save(ms, false); - //byte[] pdf = ms.ToArray(); - //ms.Close(); - //await stream.WriteAsync(pdf, 0, pdf.Length); - //stream.Close(); - } -#endif /// /// Saves the document to the specified stream. @@ -334,11 +284,7 @@ public void Save(Stream stream, bool closeStream) if (stream != null) { if (closeStream) -#if UWP || PORTABLE stream.Dispose(); -#else - stream.Close(); -#endif else stream.Position = 0; // Reset the stream position if the stream is kept open. } @@ -414,7 +360,7 @@ void DoSave(PdfWriter writer) iref.Position = writer.Position; iref.Value.WriteObject(writer); } - int startxref = writer.Position; + var startxref = writer.Position; _irefTable.WriteObject(writer); writer.WriteRaw("trailer\n"); _trailer.Elements.SetInteger("/Size", count + 1); @@ -826,7 +772,7 @@ public PdfPage AddPage() /// it is imported to this document. In this case the returned page is not the same /// object as the specified one. /// - public PdfPage AddPage(PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + public PdfPage AddPage(PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (!CanModify) throw new InvalidOperationException(PSSR.CannotModify); @@ -848,13 +794,101 @@ public PdfPage InsertPage(int index) /// it is imported to this document. In this case the returned page is not the same /// object as the specified one. /// - public PdfPage InsertPage(int index, PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + public PdfPage InsertPage(int index, PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (!CanModify) throw new InvalidOperationException(PSSR.CannotModify); return Catalog.Pages.Insert(index, page, annotationCopying); } + /// + /// Marks the acroform fields readonly + /// + public void MakeAcroFormsReadOnly() + { + for (var i = 0; i < AcroForm?.Fields.Count(); i++) + { + AcroForm.Fields[i].ReadOnly = true; + } + } + + public void ConsolidateImages() + { + var images = ImageInfo.FindAll(this); + + var mapHashcodeToMd5 = new Dictionary(); + var mapMd5ToPdfItem = new Dictionary(); + + // Calculate MD5 for each image XObject and build lookups for all images. + foreach (ImageInfo img in images) + { + mapHashcodeToMd5[img.XObject.GetHashCode()] = img.XObjectMD5; + mapMd5ToPdfItem[img.XObjectMD5] = img.Item.Value; + } + + // Set the PdfItem for each image to the one chosen for the MD5. + foreach (ImageInfo img in images) + { + string md5 = mapHashcodeToMd5[img.XObject.GetHashCode()]; + img.XObjects.Elements[img.Item.Key] = mapMd5ToPdfItem[md5]; + } + } + + internal class ImageInfo + { + public PdfDictionary XObjects { get; } + public KeyValuePair Item { get; } + public PdfDictionary XObject { get; } + public string XObjectMD5 { get; } + + private static readonly MD5 Hasher = MD5.Create(); + + public ImageInfo(PdfDictionary xObjects, KeyValuePair item, PdfDictionary xObject) + { + XObjects = xObjects; + Item = item; + XObject = xObject; + XObjectMD5 = ComputeMD5(xObject.Stream.Value); + } + + /// + /// Get info for each image in the document. + /// + internal static List FindAll(PdfDocument doc) => + doc.Pages.Cast() + .Select(page => page.Elements.GetDictionary("/Resources")) + .Select(resources => resources?.Elements?.GetDictionary("/XObject")) + .Where(xObjects => xObjects?.Elements != null) + .SelectMany(xObjects => + from item in xObjects.Elements + let xObject = (item.Value as PdfReference)?.Value as PdfDictionary + where xObject?.Elements?.GetString("/Subtype") == "/Image" + select new ImageInfo(xObjects, item, xObject) + ) + .ToList(); + + /// + /// Compute and return the MD5 hash of the input data. + /// + internal static string ComputeMD5(byte[] input) + { + byte[] hashBytes; + lock (Hasher) + { + hashBytes = Hasher.ComputeHash(input); + Hasher.Initialize(); + } + + var sb = new StringBuilder(); + foreach (var x in hashBytes) + { + sb.Append(x.ToString("x2")); + } + + return sb.ToString(); + } + } + /// /// Gets the security handler. /// diff --git a/PdfSharpCore/Pdf/PdfDocumentInformation.cs b/PdfSharpCore/Pdf/PdfDocumentInformation.cs index f9e26ec1..55116c30 100644 --- a/PdfSharpCore/Pdf/PdfDocumentInformation.cs +++ b/PdfSharpCore/Pdf/PdfDocumentInformation.cs @@ -53,7 +53,7 @@ internal PdfDocumentInformation(PdfDictionary dict) public string Title { get { return Elements.GetString(Keys.Title); } - set { Elements.SetString(Keys.Title, value); } + set { Elements.SetString(Keys.Title, value, PdfStringEncoding.Unicode); } } /// @@ -62,7 +62,7 @@ public string Title public string Author { get { return Elements.GetString(Keys.Author); } - set { Elements.SetString(Keys.Author, value); } + set { Elements.SetString(Keys.Author, value, PdfStringEncoding.Unicode); } } /// @@ -71,7 +71,7 @@ public string Author public string Subject { get { return Elements.GetString(Keys.Subject); } - set { Elements.SetString(Keys.Subject, value); } + set { Elements.SetString(Keys.Subject, value, PdfStringEncoding.Unicode); } } /// @@ -80,7 +80,7 @@ public string Subject public string Keywords { get { return Elements.GetString(Keys.Keywords); } - set { Elements.SetString(Keys.Keywords, value); } + set { Elements.SetString(Keys.Keywords, value, PdfStringEncoding.Unicode); } } /// @@ -89,7 +89,7 @@ public string Keywords public string Creator { get { return Elements.GetString(Keys.Creator); } - set { Elements.SetString(Keys.Creator, value); } + set { Elements.SetString(Keys.Creator, value, PdfStringEncoding.Unicode); } } /// diff --git a/PdfSharpCore/Pdf/PdfInteger.cs b/PdfSharpCore/Pdf/PdfInteger.cs index 6f870273..4611ec0d 100644 --- a/PdfSharpCore/Pdf/PdfInteger.cs +++ b/PdfSharpCore/Pdf/PdfInteger.cs @@ -38,7 +38,7 @@ namespace PdfSharpCore.Pdf /// Represents a direct integer value. /// [DebuggerDisplay("({Value})")] - public sealed class PdfInteger : PdfNumber, IConvertible + public sealed class PdfInteger : PdfNumber, IConvertible, IFormattable { /// /// Initializes a new instance of the class. @@ -175,5 +175,14 @@ uint IConvertible.ToUInt32(IFormatProvider provider) } #endregion + + #region IFormattable Members + + string IFormattable.ToString(string _value, IFormatProvider provider) + { + return _value; + } + + #endregion } } \ No newline at end of file diff --git a/PdfSharpCore/Pdf/PdfLong.cs b/PdfSharpCore/Pdf/PdfLong.cs new file mode 100644 index 00000000..ab85a1b5 --- /dev/null +++ b/PdfSharpCore/Pdf/PdfLong.cs @@ -0,0 +1,225 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Authors: +// Stefan Lange +// +// Copyright (c) 2005-2016 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.Globalization; +using PdfSharpCore.Pdf.IO; + +namespace PdfSharpCore.Pdf +{ + /// + /// Represents a long + /// + [DebuggerDisplay("({Value})")] + public sealed class PdfLong : PdfNumber, IConvertible + { + /// + /// Initializes a new instance of the class. + /// + public PdfLong() + { } + + /// + /// Initializes a new instance of the class. + /// + public PdfLong(long value) + { + _value = value; + } + + /// + /// Gets the value as long. + /// + public long Value => _value; + // This class must behave like a value type. Therefore it cannot be changed (like System.String). + + readonly long _value; + + /// + /// Returns the long as string. + /// + public override string ToString() + { + // ToString is impure but does not change the value of _value. + // ReSharper disable ImpureMethodCallOnReadonlyValueField + return _value.ToString(CultureInfo.InvariantCulture); + // ReSharper restore ImpureMethodCallOnReadonlyValueField + } + + /// + /// Writes the long as string. + /// + internal override void WriteObject(PdfWriter writer) + { + writer.Write(this); + } + + #region IConvertible Members + + /// + /// Converts the value of this instance to an equivalent 64-bit unsigned integer. + /// + public ulong ToUInt64(IFormatProvider provider) + { + return Convert.ToUInt64(_value); + } + + /// + /// Converts the value of this instance to an equivalent 8-bit signed integer. + /// + public sbyte ToSByte(IFormatProvider provider) + { + throw new InvalidCastException(); + } + + /// + /// Converts the value of this instance to an equivalent double-precision floating-point number. + /// + public double ToDouble(IFormatProvider provider) + { + return _value; + } + + /// + /// Returns an undefined DateTime structure. + /// + public DateTime ToDateTime(IFormatProvider provider) + { + return new DateTime(_value); + } + + /// + /// Converts the value of this instance to an equivalent single-precision floating-point number. + /// + public float ToSingle(IFormatProvider provider) + { + return _value; + } + + /// + /// Converts the value of this instance to an equivalent Boolean value. + /// + public bool ToBoolean(IFormatProvider provider) + { + return Convert.ToBoolean(_value); + } + + /// + /// Converts the value of this instance to an equivalent 32-bit signed integer. + /// + public int ToInt32(IFormatProvider provider) + { + return Convert.ToInt32(_value); + } + + /// + /// Converts the value of this instance to an equivalent 16-bit unsigned integer. + /// + public ushort ToUInt16(IFormatProvider provider) + { + return Convert.ToUInt16(_value); + } + + /// + /// Converts the value of this instance to an equivalent 16-bit signed integer. + /// + public short ToInt16(IFormatProvider provider) + { + return Convert.ToInt16(_value); + } + + /// + /// Converts the value of this instance to an equivalent . + /// + string IConvertible.ToString(IFormatProvider provider) + { + return _value.ToString(provider); + } + + /// + /// Converts the value of this instance to an equivalent 8-bit unsigned integer. + /// + public byte ToByte(IFormatProvider provider) + { + return Convert.ToByte(_value); + } + + /// + /// Converts the value of this instance to an equivalent Unicode character. + /// + public char ToChar(IFormatProvider provider) + { + return Convert.ToChar(_value); + } + + /// + /// Converts the value of this instance to an equivalent 64-bit signed integer. + /// + public long ToInt64(IFormatProvider provider) + { + return _value; + } + + /// + /// Returns type code for 32-bit integers. + /// + public TypeCode GetTypeCode() + { + return TypeCode.Int32; + } + + /// + /// Converts the value of this instance to an equivalent number. + /// + public decimal ToDecimal(IFormatProvider provider) + { + return _value; + } + + /// + /// Returns null. + /// + public object ToType(Type conversionType, IFormatProvider provider) + { + // TODO: Add PdfLong.ToType implementation + return null; + } + + /// + /// Converts the value of this instance to an equivalent 32-bit unsigned integer. + /// + public uint ToUInt32(IFormatProvider provider) + { + return Convert.ToUInt32(_value); + } + + #endregion + } +} \ No newline at end of file diff --git a/PdfSharpCore/Pdf/PdfLongObject.cs b/PdfSharpCore/Pdf/PdfLongObject.cs new file mode 100644 index 00000000..09d1f3ad --- /dev/null +++ b/PdfSharpCore/Pdf/PdfLongObject.cs @@ -0,0 +1,93 @@ +#region PDFsharp - A .NET library for processing PDF +// +// Authors: +// Stefan Lange +// +// Copyright (c) 2005-2016 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.Diagnostics; +using System.Globalization; +using PdfSharpCore.Pdf.IO; + +namespace PdfSharpCore.Pdf +{ + /// + /// Represents an indirect long value. This type is not used by PdfSharpCore. If it is imported from + /// an external PDF file, the value is converted into a direct object. + /// + [DebuggerDisplay("({Value})")] + public sealed class PdfLongObject : PdfNumberObject + { + /// + /// Initializes a new instance of the class. + /// + public PdfLongObject() + { } + + /// + /// Initializes a new instance of the class. + /// + public PdfLongObject(long value) + { + _value = value; + } + + /// + /// Initializes a new instance of the class. + /// + public PdfLongObject(PdfDocument document, long value) + : base(document) + { + _value = value; + } + + /// + /// Gets the value as long. + /// + public long Value + { + get { return _value; } + } + readonly long _value; + + /// + /// Returns the long as string. + /// + public override string ToString() + { + return _value.ToString(CultureInfo.InvariantCulture); + } + + /// + /// Writes the long literal. + /// + internal override void WriteObject(PdfWriter writer) + { + writer.WriteBeginObject(this); + writer.Write(_value); + writer.WriteEndObject(); + } + } +} diff --git a/PdfSharpCore/Pdf/PdfName.cs b/PdfSharpCore/Pdf/PdfName.cs index 1528f44a..bb7b75b1 100644 --- a/PdfSharpCore/Pdf/PdfName.cs +++ b/PdfSharpCore/Pdf/PdfName.cs @@ -152,8 +152,7 @@ public class PdfXNameComparer : IComparer /// The second object to compare. public int Compare(PdfName l, PdfName r) { -#if true_ -#else + if (l != null) { if (r != null) @@ -163,7 +162,6 @@ public int Compare(PdfName l, PdfName r) if (r != null) return 1; return 0; -#endif } } } diff --git a/PdfSharpCore/Pdf/PdfOutline.cs b/PdfSharpCore/Pdf/PdfOutline.cs index 0a759749..39f5b5f9 100644 --- a/PdfSharpCore/Pdf/PdfOutline.cs +++ b/PdfSharpCore/Pdf/PdfOutline.cs @@ -1,4 +1,4 @@ -#region PDFsharp - A .NET library for processing PDF +#region PDFsharp - A .NET library for processing PDF // // Authors: // Stefan Lange @@ -240,7 +240,7 @@ public double Zoom get { return _zoom; } set { _zoom = value; } } - double _zoom; // PDF teats 0 and null equally. + double _zoom = double.NaN; // PDF teats 0 and null equally. /// /// Gets or sets whether the outline item is opened (or expanded). @@ -248,28 +248,7 @@ public double Zoom public bool Opened { get { return _opened; } -#if true set { _opened = value; } -#else - // TODO: adjust openCount of ascendant... - set - { - if (_opened != value) - { - _opened = value; - int sign = value ? 1 : -1; - PdfOutline parent = _parent; - if (_opened) - { - while (parent != null) - parent.openCount += 1 + _openCount; - } - else - { - } - } - } -#endif } bool _opened; @@ -354,11 +333,9 @@ void Initialize() PdfItem a = Elements.GetValue(Keys.A); Debug.Assert(dest == null || a == null, "Either destination or goto action."); - PdfArray destArray = null; if (dest != null) { - destArray = dest as PdfArray; - if (destArray != null) + if (dest is PdfArray destArray) { SplitDestinationPage(destArray); } @@ -374,14 +351,20 @@ void Initialize() if (action != null && action.Elements.GetName(PdfAction.Keys.S) == "/GoTo") { dest = action.Elements[PdfGoToAction.Keys.D]; - destArray = dest as PdfArray; - if (destArray != null) + if (dest is PdfArray destArray) { // Replace Action with /Dest entry. Elements.Remove(Keys.A); Elements.Add(Keys.Dest, destArray); SplitDestinationPage(destArray); } + else if (dest is PdfReference detRef) + { + // Replace Action with /Dest entry. + Elements.Remove(Keys.A); + Elements.Add(Keys.Dest, detRef.Value); + SplitDestinationPage((PdfArray)detRef.Value); + } else { throw new Exception("Destination Array expected."); @@ -406,7 +389,9 @@ void SplitDestinationPage(PdfArray destination) // Reference: 8.2 Destination s #pragma warning disable 162 // The destination page may not yet transformed to PdfPage. - PdfDictionary destPage = (PdfDictionary)((PdfReference)(destination.Elements[0])).Value; + PdfDictionary destPage = (destination.Elements[0] is PdfInteger) ? + destination.Owner.Pages[((PdfInteger)destination.Elements[0]).Value] : + (PdfDictionary)((PdfReference)destination.Elements[0]).Value; PdfPage page = destPage as PdfPage; if (page == null) page = new PdfPage(destPage); @@ -732,14 +717,14 @@ internal sealed class Keys : KeysBase /// /// (Required if the item has any descendants; must be an indirect reference) - /// The first of this items immediate children in the outline hierarchy. + /// The first of this item’s immediate children in the outline hierarchy. /// [KeyInfo(KeyType.Dictionary | KeyType.Required)] public const string First = "/First"; /// /// (Required if the item has any descendants; must be an indirect reference) - /// The last of this items immediate children in the outline hierarchy. + /// The last of this item’s immediate children in the outline hierarchy. /// [KeyInfo(KeyType.Dictionary | KeyType.Required)] public const string Last = "/Last"; @@ -780,7 +765,7 @@ internal sealed class Keys : KeysBase /// /// (Optional; PDF 1.4) An array of three numbers in the range 0.0 to 1.0, representing the - /// components in the DeviceRGB color space of the color to be used for the outline entrys text. + /// components in the DeviceRGB color space of the color to be used for the outline entry’s text. /// Default value: [0.0 0.0 0.0]. /// [KeyInfo(KeyType.Array | KeyType.Optional)] @@ -788,7 +773,7 @@ internal sealed class Keys : KeysBase /// /// (Optional; PDF 1.4) A set of flags specifying style characteristics for displaying the outline - /// items text. Default value: 0. + /// item’s text. Default value: 0. /// [KeyInfo(KeyType.Integer | KeyType.Optional)] public const string F = "/F"; diff --git a/PdfSharpCore/Pdf/PdfOutlineCollection.cs b/PdfSharpCore/Pdf/PdfOutlineCollection.cs index e8cd750f..1771450a 100644 --- a/PdfSharpCore/Pdf/PdfOutlineCollection.cs +++ b/PdfSharpCore/Pdf/PdfOutlineCollection.cs @@ -39,7 +39,7 @@ namespace PdfSharpCore.Pdf /// /// Represents a collection of outlines. /// - public class PdfOutlineCollection : PdfObject, ICollection, IList + public class PdfOutlineCollection : PdfObject, IList { /// /// Can only be created as part of PdfOutline. @@ -66,18 +66,12 @@ public bool Remove(PdfOutline item) /// /// Gets the number of entries in this collection. /// - public int Count - { - get { return _outlines.Count; } - } + public int Count => _outlines.Count; /// /// Returns false. /// - public bool IsReadOnly - { - get { return false; } - } + public bool IsReadOnly => false; /// /// Adds the specified outline. @@ -85,7 +79,7 @@ public bool IsReadOnly public void Add(PdfOutline outline) { if (outline == null) - throw new ArgumentNullException("outline"); + throw new ArgumentNullException(nameof(outline)); // DestinationPage is optional. PDFsharp does not yet support outlines with action ("/A") instead of destination page ("/DEST") if (outline.DestinationPage != null && !ReferenceEquals(Owner, outline.DestinationPage.Owner)) @@ -209,9 +203,9 @@ public int IndexOf(PdfOutline item) public void Insert(int index, PdfOutline outline) { if (outline == null) - throw new ArgumentNullException("outline"); + throw new ArgumentNullException(nameof(outline)); if (index < 0 || index >= _outlines.Count) - throw new ArgumentOutOfRangeException("index", index, PSSR.OutlineIndexOutOfRange); + throw new ArgumentOutOfRangeException(nameof(index), index, PSSR.OutlineIndexOutOfRange); AddToOutlinesTree(outline); _outlines.Insert(index, outline); @@ -235,15 +229,15 @@ public PdfOutline this[int index] get { if (index < 0 || index >= _outlines.Count) - throw new ArgumentOutOfRangeException("index", index, PSSR.OutlineIndexOutOfRange); + throw new ArgumentOutOfRangeException(nameof(index), index, PSSR.OutlineIndexOutOfRange); return _outlines[index]; } set { if (index < 0 || index >= _outlines.Count) - throw new ArgumentOutOfRangeException("index", index, PSSR.OutlineIndexOutOfRange); + throw new ArgumentOutOfRangeException(nameof(index), index, PSSR.OutlineIndexOutOfRange); if (value == null) - throw new ArgumentOutOfRangeException("value", null, PSSR.SetValueMustNotBeNull); + throw new ArgumentOutOfRangeException(nameof(value), null, PSSR.SetValueMustNotBeNull); AddToOutlinesTree(value); _outlines[index] = value; @@ -274,7 +268,7 @@ internal int CountOpen() void AddToOutlinesTree(PdfOutline outline) { if (outline == null) - throw new ArgumentNullException("outline"); + throw new ArgumentNullException(nameof(outline)); // DestinationPage is optional. PDFsharp does not yet support outlines with action ("/A") instead of destination page ("/DEST") if (outline.DestinationPage != null && !ReferenceEquals(Owner, outline.DestinationPage.Owner)) @@ -287,10 +281,10 @@ void AddToOutlinesTree(PdfOutline outline) //_outlines.Add(outline); if (!Owner._irefTable.Contains(outline.ObjectID)) Owner._irefTable.Add(outline); - else - { - outline.GetType(); - } + // else + // { + // outline.GetType(); + // } //if (outline.Opened) //{ @@ -306,7 +300,7 @@ void AddToOutlinesTree(PdfOutline outline) void RemoveFromOutlinesTree(PdfOutline outline) { if (outline == null) - throw new ArgumentNullException("outline"); + throw new ArgumentNullException(nameof(outline)); // TODO check the parent problems... //outline.Document = Owner; @@ -316,7 +310,7 @@ void RemoveFromOutlinesTree(PdfOutline outline) } /// - /// The parent outine of this collection. + /// The parent outline of this collection. /// readonly PdfOutline _parent; diff --git a/PdfSharpCore/Pdf/PdfPage.cs b/PdfSharpCore/Pdf/PdfPage.cs index 437f6e08..1d69ecb3 100644 --- a/PdfSharpCore/Pdf/PdfPage.cs +++ b/PdfSharpCore/Pdf/PdfPage.cs @@ -591,8 +591,7 @@ internal override void WriteObject(PdfWriter writer) { // HACK: temporarily flip media box if Landscape PdfRectangle mediaBox = MediaBox; - // TODO: Take /Rotate into account - if (_orientation == PageOrientation.Landscape) + if (_orientation == PageOrientation.Landscape && Math.Abs(Rotate / 90) % 2 == 0) MediaBox = new PdfRectangle(mediaBox.X1, mediaBox.Y1, mediaBox.Y2, mediaBox.X2); #if true diff --git a/PdfSharpCore/Pdf/PdfPages.cs b/PdfSharpCore/Pdf/PdfPages.cs index e74627eb..a194c58f 100644 --- a/PdfSharpCore/Pdf/PdfPages.cs +++ b/PdfSharpCore/Pdf/PdfPages.cs @@ -115,7 +115,7 @@ public PdfPage Add() /// Adds the specified PdfPage to the end of this document and maybe returns a new PdfPage object. /// The value returned is a new object if the added page comes from a foreign document. /// - public PdfPage Add(PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + public PdfPage Add(PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { return Insert(Count, page, annotationCopying); } @@ -134,7 +134,7 @@ public PdfPage Insert(int index) /// Inserts the specified PdfPage at the specified position to this document and maybe returns a new PdfPage object. /// The value returned is a new object if the inserted page comes from a foreign document. /// - public PdfPage Insert(int index, PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + public PdfPage Insert(int index, PdfPage page, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (page == null) throw new ArgumentNullException("page"); @@ -204,8 +204,8 @@ public PdfPage Insert(int index, PdfPage page, AnnotationCopyingType annotationC /// The document to be inserted. /// The index of the first page to be inserted. /// The number of pages to be inserted. - /// Annotation copying action, by default annotations are not copied. - public void InsertRange(int index, PdfDocument document, int startIndex, int pageCount, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + /// Annotation copying action, by default annotations are copied shallowly. + public void InsertRange(int index, PdfDocument document, int startIndex, int pageCount, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (document == null) throw new ArgumentNullException("document"); @@ -358,8 +358,8 @@ public void InsertRange(int index, PdfDocument document, int startIndex, int pag /// /// The index in this document where to insert the page . /// The document to be inserted. - /// Annotation copying action, by default annotations are not copied. - public void InsertRange(int index, PdfDocument document, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + /// Annotation copying action, by default annotations are copied shallowly. + public void InsertRange(int index, PdfDocument document, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (document == null) throw new ArgumentNullException("document"); @@ -373,8 +373,8 @@ public void InsertRange(int index, PdfDocument document, AnnotationCopyingType a /// The index in this document where to insert the page . /// The document to be inserted. /// The index of the first page to be inserted. - /// Annotation copying action, by default annotations are not copied. - public void InsertRange(int index, PdfDocument document, int startIndex, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + /// Annotation copying action, by default annotations are copied shallowly. + public void InsertRange(int index, PdfDocument document, int startIndex, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (document == null) throw new ArgumentNullException("document"); @@ -426,7 +426,7 @@ public void MovePage(int oldIndex, int newIndex) /// of their transitive closure. Any reuse of already imported objects is not intended because /// any modification of an imported page must not change another page. /// - PdfPage ImportExternalPage(PdfPage importPage, AnnotationCopyingType annotationCopying = AnnotationCopyingType.DoNotCopy) + PdfPage ImportExternalPage(PdfPage importPage, AnnotationCopyingType annotationCopying = AnnotationCopyingType.ShallowCopy) { if (importPage.Owner._openMode != PdfDocumentOpenMode.Import) throw new InvalidOperationException("A PDF document must be opened with PdfDocumentOpenMode.Import to import pages from it."); diff --git a/PdfSharpCore/Pdf/PdfRectangle.cs b/PdfSharpCore/Pdf/PdfRectangle.cs index 4b0a4eb8..650204c6 100644 --- a/PdfSharpCore/Pdf/PdfRectangle.cs +++ b/PdfSharpCore/Pdf/PdfRectangle.cs @@ -30,12 +30,6 @@ using System; using System.Diagnostics; using System.Globalization; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows.Media; -#endif using PdfSharpCore.Drawing; using PdfSharpCore.Pdf.Advanced; using PdfSharpCore.Pdf.IO; @@ -71,20 +65,6 @@ internal PdfRectangle(double x1, double y1, double x2, double y2) _y2 = y2; } -#if GDI - /// - /// Initializes a new instance of the PdfRectangle class with two points specifying - /// two diagonally opposite corners. - /// - public PdfRectangle(PointF pt1, PointF pt2) - { - _x1 = pt1.X; - _y1 = pt1.Y; - _x2 = pt2.X; - _y2 = pt2.Y; - } -#endif - /// /// Initializes a new instance of the PdfRectangle class with two points specifying /// two diagonally opposite corners. @@ -97,19 +77,6 @@ public PdfRectangle(XPoint pt1, XPoint pt2) _y2 = pt2.Y; } -#if GDI - /// - /// Initializes a new instance of the PdfRectangle class with the specified location and size. - /// - public PdfRectangle(PointF pt, SizeF size) - { - _x1 = pt.X; - _y1 = pt.Y; - _x2 = pt.X + size.Width; - _y2 = pt.Y + size.Height; - } -#endif - /// /// Initializes a new instance of the PdfRectangle class with the specified location and size. /// @@ -328,17 +295,6 @@ public bool Contains(double x, double y) return _x1 <= x && x <= _x2 && _y1 <= y && y <= _y2; } -#if GDI - /// - /// Determines if the rectangular region represented by rect is entirely contained within this PdfRectangle. - /// - public bool Contains(RectangleF rect) - { - return _x1 <= rect.X && (rect.X + rect.Width) <= _x2 && - _y1 <= rect.Y && (rect.Y + rect.Height) <= _y2; - } -#endif - /// /// Determines if the rectangular region represented by rect is entirely contained within this PdfRectangle. /// diff --git a/PdfSharpCore/Pdf/PdfString.cs b/PdfSharpCore/Pdf/PdfString.cs index 8d2cf1b0..2ed2acbe 100644 --- a/PdfSharpCore/Pdf/PdfString.cs +++ b/PdfSharpCore/Pdf/PdfString.cs @@ -217,10 +217,33 @@ public string Value /// internal byte[] EncryptionValue { - // TODO: Unicode case is not handled! - get { return _value == null ? new byte[0] : PdfEncoders.RawEncoding.GetBytes(_value); } + get { return _value == null ? new byte[0] : GetBytesFromEncoding(); } // BUG: May lead to trouble with the value semantics of PdfString - set { _value = PdfEncoders.RawEncoding.GetString(value, 0, value.Length); } + set + { + var encoding = (PdfStringEncoding)(_flags & PdfStringFlags.EncodingMask); + switch (encoding) + { + case PdfStringEncoding.Unicode: + _value = PdfEncoders.RawUnicodeEncoding.GetString(value); + break; + default: + _value = PdfEncoders.RawEncoding.GetString(value); + break; + } + } + } + + private byte[] GetBytesFromEncoding() + { + var encoding = (PdfStringEncoding)(_flags & PdfStringFlags.EncodingMask); + switch (encoding) + { + case PdfStringEncoding.Unicode: + return PdfEncoders.RawUnicodeEncoding.GetBytes(_value); + default: + return PdfEncoders.RawEncoding.GetBytes(_value); + } } /// diff --git a/PdfSharpCore/PdfSharpCore.csproj b/PdfSharpCore/PdfSharpCore.csproj index a7f5cc2f..7fc4d462 100644 --- a/PdfSharpCore/PdfSharpCore.csproj +++ b/PdfSharpCore/PdfSharpCore.csproj @@ -1,27 +1,37 @@  - netstandard1.3;netstandard2.0;netcoreapp3.1;net5.0 + netstandard2.0;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + false True Stefan Steiger and Contributors PdfSharp for .NET Core PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32). Images have been implemented with ImageSharp from https://www.nuget.org/packages/SixLabors.ImageSharp Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany) - LICENCE.md + README.md + LICENSE.md https://github.com/ststeiger/PdfSharpCore https://github.com/ststeiger/PdfSharpCore PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally MigraDoc has been ported as well (from version 1.32) NuggetV1.0.0 (8ea343d5898342a563b9d4df2d67e27aaea9ac01) - PdfSharp for .NET Core + PdfSharp for .NET Core + true + true + 1.0.1 - TRACE;DEBUG;NETCOREAPP1_1;PORTABLE + TRACE;DEBUG; + + + NU5104 + + - TRACE;RELEASE;NETCOREAPP1_1;PORTABLE + TRACE;RELEASE; @@ -38,12 +48,14 @@ PdfSharpCore is a partial port of PdfSharp.Xamarin for .NET Core Additionally Mi + - + - + + diff --git a/PdfSharpCore/SharpZipLib/Checksums/Adler32.cs b/PdfSharpCore/SharpZipLib/Checksums/Adler32.cs deleted file mode 100644 index 2821ce21..00000000 --- a/PdfSharpCore/SharpZipLib/Checksums/Adler32.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Adler32.cs - Computes Adler32 data checksum of a data stream -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Checksums -{ - - /// - /// Computes Adler32 checksum for a stream of data. An Adler32 - /// checksum is not as reliable as a CRC32 checksum, but a lot faster to - /// compute. - /// - /// The specification for Adler32 may be found in RFC 1950. - /// ZLIB Compressed Data Format Specification version 3.3) - /// - /// - /// From that document: - /// - /// "ADLER32 (Adler-32 checksum) - /// This contains a checksum value of the uncompressed data - /// (excluding any dictionary data) computed according to Adler-32 - /// algorithm. This algorithm is a 32-bit extension and improvement - /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 - /// standard. - /// - /// Adler-32 is composed of two sums accumulated per byte: s1 is - /// the sum of all bytes, s2 is the sum of all s1 values. Both sums - /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The - /// Adler-32 checksum is stored as s2*65536 + s1 in most- - /// significant-byte first (network) order." - /// - /// "8.2. The Adler-32 algorithm - /// - /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet - /// still provides an extremely low probability of undetected errors. - /// - /// The modulo on unsigned long accumulators can be delayed for 5552 - /// bytes, so the modulo operation time is negligible. If the bytes - /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position - /// and order sensitive, unlike the first sum, which is just a - /// checksum. That 65521 is prime is important to avoid a possible - /// large class of two-byte errors that leave the check unchanged. - /// (The Fletcher checksum uses 255, which is not prime and which also - /// makes the Fletcher check insensitive to single byte changes 0 - - /// 255.) - /// - /// The sum s1 is initialized to 1 instead of zero to make the length - /// of the sequence part of s2, so that the length does not have to be - /// checked separately. (Any sequence of zeroes has a Fletcher - /// checksum of zero.)" - /// - /// - /// - internal sealed class Adler32 : IChecksum - { - /// - /// largest prime smaller than 65536 - /// - const uint BASE = 65521; - - /// - /// Returns the Adler32 data checksum computed so far. - /// - public long Value - { - get - { - return checksum; - } - } - - /// - /// Creates a new instance of the Adler32 class. - /// The checksum starts off with a value of 1. - /// - public Adler32() - { - Reset(); - } - - /// - /// Resets the Adler32 checksum to the initial value. - /// - public void Reset() - { - checksum = 1; - } - - /// - /// Updates the checksum with a byte value. - /// - /// - /// The data value to add. The high byte of the int is ignored. - /// - public void Update(int value) - { - // We could make a length 1 byte array and call update again, but I - // would rather not have that overhead - uint s1 = checksum & 0xFFFF; - uint s2 = checksum >> 16; - - s1 = (s1 + ((uint)value & 0xFF)) % BASE; - s2 = (s1 + s2) % BASE; - - checksum = (s2 << 16) + s1; - } - - /// - /// Updates the checksum with an array of bytes. - /// - /// - /// The source of the data to update with. - /// - public void Update(byte[] buffer) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - Update(buffer, 0, buffer.Length); - } - - /// - /// Updates the checksum with the bytes taken from the array. - /// - /// - /// an array of bytes - /// - /// - /// the start of the data used for this update - /// - /// - /// the number of bytes to use for this update - /// - public void Update(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (offset < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("offset"); -#else - throw new ArgumentOutOfRangeException("offset", "cannot be negative"); -#endif - } - - if (count < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("count"); -#else - throw new ArgumentOutOfRangeException("count", "cannot be negative"); -#endif - } - - if (offset >= buffer.Length) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("offset"); -#else - throw new ArgumentOutOfRangeException("offset", "not a valid index into buffer"); -#endif - } - - if (offset + count > buffer.Length) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("count"); -#else - throw new ArgumentOutOfRangeException("count", "exceeds buffer size"); -#endif - } - - //(By Per Bothner) - uint s1 = checksum & 0xFFFF; - uint s2 = checksum >> 16; - - while (count > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - int n = 3800; - if (n > count) - { - n = count; - } - count -= n; - while (--n >= 0) - { - s1 = s1 + (uint)(buffer[offset++] & 0xff); - s2 = s2 + s1; - } - s1 %= BASE; - s2 %= BASE; - } - - checksum = (s2 << 16) | s1; - } - - #region Instance Fields - uint checksum; - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Checksums/CRC32.cs b/PdfSharpCore/SharpZipLib/Checksums/CRC32.cs deleted file mode 100644 index cc3f3a01..00000000 --- a/PdfSharpCore/SharpZipLib/Checksums/CRC32.cs +++ /dev/null @@ -1,231 +0,0 @@ -// CRC32.cs - Computes CRC32 data checksum of a data stream -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Checksums -{ - - /// - /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: - /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - /// - /// Polynomials over GF(2) are represented in binary, one bit per coefficient, - /// with the lowest powers in the most significant bit. Then adding polynomials - /// is just exclusive-or, and multiplying a polynomial by x is a right shift by - /// one. If we call the above polynomial p, and represent a byte as the - /// polynomial q, also with the lowest power in the most significant bit (so the - /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - /// where a mod b means the remainder after dividing a by b. - /// - /// This calculation is done using the shift-register method of multiplying and - /// taking the remainder. The register is initialized to zero, and for each - /// incoming bit, x^32 is added mod p to the register if the bit is a one (where - /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - /// x (which is shifting right by one and adding x^32 mod p if the bit shifted - /// out is a one). We start with the highest power (least significant bit) of - /// q and repeat for all eight bits of q. - /// - /// The table is simply the CRC of all possible eight bit values. This is all - /// the information needed to generate CRC's on data a byte at a time for all - /// combinations of CRC register values and incoming bytes. - /// - internal sealed class Crc32 : IChecksum - { - const uint CrcSeed = 0xFFFFFFFF; - - readonly static uint[] CrcTable = new uint[] { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, - 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, - 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, - 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, - 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, - 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, - 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, - 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, - 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, - 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, - 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, - 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, - 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, - 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, - 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, - 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, - 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, - 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, - 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, - 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, - 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, - 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, - 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, - 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, - 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, - 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, - 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, - 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, - 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, - 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, - 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, - 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, - 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, - 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, - 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, - 0x2D02EF8D - }; - - internal static uint ComputeCrc32(uint oldCrc, byte value) - { - return (uint)(Crc32.CrcTable[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8)); - } - - /// - /// The crc data checksum so far. - /// - uint crc; - - /// - /// Returns the CRC32 data checksum computed so far. - /// - public long Value - { - get - { - return (long)crc; - } - set - { - crc = (uint)value; - } - } - - /// - /// Resets the CRC32 data checksum as if no update was ever called. - /// - public void Reset() - { - crc = 0; - } - - /// - /// Updates the checksum with the int bval. - /// - /// - /// the byte is taken as the lower 8 bits of value - /// - public void Update(int value) - { - crc ^= CrcSeed; - crc = CrcTable[(crc ^ value) & 0xFF] ^ (crc >> 8); - crc ^= CrcSeed; - } - - /// - /// Updates the checksum with the bytes taken from the array. - /// - /// - /// buffer an array of bytes - /// - public void Update(byte[] buffer) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - Update(buffer, 0, buffer.Length); - } - - /// - /// Adds the byte array to the data checksum. - /// - /// - /// The buffer which contains the data - /// - /// - /// The offset in the buffer where the data starts - /// - /// - /// The number of data bytes to update the CRC with. - /// - public void Update(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (count < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("count"); -#else - throw new ArgumentOutOfRangeException("count", "Count cannot be less than zero"); -#endif - } - - if (offset < 0 || offset + count > buffer.Length) - { - throw new ArgumentOutOfRangeException("offset"); - } - - crc ^= CrcSeed; - - while (--count >= 0) - { - crc = CrcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8); - } - - crc ^= CrcSeed; - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Checksums/IChecksum.cs b/PdfSharpCore/SharpZipLib/Checksums/IChecksum.cs deleted file mode 100644 index 21b0d568..00000000 --- a/PdfSharpCore/SharpZipLib/Checksums/IChecksum.cs +++ /dev/null @@ -1,93 +0,0 @@ -// IChecksum.cs - Interface to compute a data checksum -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -namespace PdfSharpCore.SharpZipLib.Checksums -{ - - /// - /// Interface to compute a data checksum used by checked input/output streams. - /// A data checksum can be updated by one byte or with a byte array. After each - /// update the value of the current checksum can be returned by calling - /// getValue. The complete checksum object can also be reset - /// so it can be used again with new data. - /// - internal interface IChecksum - { - /// - /// Returns the data checksum computed so far. - /// - long Value - { - get; - } - - /// - /// Resets the data checksum as if no update was ever called. - /// - void Reset(); - - /// - /// Adds one byte to the data checksum. - /// - /// - /// the data value to add. The high byte of the int is ignored. - /// - void Update(int value); - - /// - /// Updates the data checksum with the bytes taken from the array. - /// - /// - /// buffer an array of bytes - /// - void Update(byte[] buffer); - - /// - /// Adds the byte array to the data checksum. - /// - /// - /// The buffer which contains the data - /// - /// - /// The offset in the buffer where the data starts - /// - /// - /// the number of data bytes to add. - /// - void Update(byte[] buffer, int offset, int count); - } -} diff --git a/PdfSharpCore/SharpZipLib/ReadMe.txt b/PdfSharpCore/SharpZipLib/ReadMe.txt deleted file mode 100644 index bf61d580..00000000 --- a/PdfSharpCore/SharpZipLib/ReadMe.txt +++ /dev/null @@ -1,3 +0,0 @@ - -This code is an excerpt from the SharpZipLib. The code is unmodified except that all classes -are made internal and moved to the namespace PdfSharpCore.SharpZipLib. diff --git a/PdfSharpCore/SharpZipLib/SharpZipBaseException.cs b/PdfSharpCore/SharpZipLib/SharpZipBaseException.cs deleted file mode 100644 index f34848e0..00000000 --- a/PdfSharpCore/SharpZipLib/SharpZipBaseException.cs +++ /dev/null @@ -1,87 +0,0 @@ -// SharpZipBaseException.cs -// -// Copyright 2004 John Reilly -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib -{ - /// - /// SharpZipBaseException is the base exception class for the SharpZipLibrary. - /// All library exceptions are derived from this. - /// - /// NOTE: Not all exceptions thrown will be derived from this class. - /// A variety of other exceptions are possible for example - internal class SharpZipBaseException : ApplicationException - { -#if false//!NETCF_1_0 && !NETCF_2_0 - /// - /// Deserialization constructor - /// - /// for this constructor - /// for this constructor - protected SharpZipBaseException(SerializationInfo info, StreamingContext context ) - : base( info, context ) - { - } -#endif - - /// - /// Initializes a new instance of the SharpZipBaseException class. - /// - public SharpZipBaseException() - { - } - - /// - /// Initializes a new instance of the SharpZipBaseException class with a specified error message. - /// - /// A message describing the exception. - public SharpZipBaseException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the SharpZipBaseException class with a specified - /// error message and a reference to the inner exception that is the cause of this exception. - /// - /// A message describing the exception. - /// The inner exception - public SharpZipBaseException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Deflater.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Deflater.cs deleted file mode 100644 index a32d74d6..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Deflater.cs +++ /dev/null @@ -1,595 +0,0 @@ -// Deflater.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// This is the Deflater class. The deflater class compresses input - /// with the deflate algorithm described in RFC 1951. It has several - /// compression levels and three different strategies described below. - /// - /// This class is not thread safe. This is inherent in the API, due - /// to the split of deflate and setInput. - /// - /// Author of the original java version: Jochen Hoenicke - /// - internal class Deflater - { - #region Deflater Documentation - /* - * The Deflater can do the following state transitions: - * - * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---. - * / | (2) (5) | - * / v (5) | - * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3) - * \ | (3) | ,--------' - * | | | (3) / - * v v (5) v v - * (1) -> BUSY_STATE ----> FINISHING_STATE - * | (6) - * v - * FINISHED_STATE - * \_____________________________________/ - * | (7) - * v - * CLOSED_STATE - * - * (1) If we should produce a header we start in INIT_STATE, otherwise - * we start in BUSY_STATE. - * (2) A dictionary may be set only when we are in INIT_STATE, then - * we change the state as indicated. - * (3) Whether a dictionary is set or not, on the first call of deflate - * we change to BUSY_STATE. - * (4) -- intentionally left blank -- :) - * (5) FINISHING_STATE is entered, when flush() is called to indicate that - * there is no more INPUT. There are also states indicating, that - * the header wasn't written yet. - * (6) FINISHED_STATE is entered, when everything has been flushed to the - * internal pending output buffer. - * (7) At any time (7) - * - */ - #endregion - #region Public Constants - /// - /// The best and slowest compression level. This tries to find very - /// long and distant string repetitions. - /// - public const int BEST_COMPRESSION = 9; - - /// - /// The worst but fastest compression level. - /// - public const int BEST_SPEED = 1; - - /// - /// The default compression level. - /// - public const int DEFAULT_COMPRESSION = -1; - - /// - /// This level won't compress at all but output uncompressed blocks. - /// - public const int NO_COMPRESSION = 0; - - /// - /// The compression method. This is the only method supported so far. - /// There is no need to use this constant at all. - /// - public const int DEFLATED = 8; - #endregion - #region Local Constants - private const int IS_SETDICT = 0x01; - private const int IS_FLUSHING = 0x04; - private const int IS_FINISHING = 0x08; - - private const int INIT_STATE = 0x00; - private const int SETDICT_STATE = 0x01; - // private static int INIT_FINISHING_STATE = 0x08; - // private static int SETDICT_FINISHING_STATE = 0x09; - private const int BUSY_STATE = 0x10; - private const int FLUSHING_STATE = 0x14; - private const int FINISHING_STATE = 0x1c; - private const int FINISHED_STATE = 0x1e; - private const int CLOSED_STATE = 0x7f; - #endregion - #region Constructors - /// - /// Creates a new deflater with default compression level. - /// - public Deflater() - : this(DEFAULT_COMPRESSION, false) - { - - } - - /// - /// Creates a new deflater with given compression level. - /// - /// - /// the compression level, a value between NO_COMPRESSION - /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION. - /// - /// if lvl is out of range. - public Deflater(int level) - : this(level, false) - { - - } - - /// - /// Creates a new deflater with given compression level. - /// - /// - /// the compression level, a value between NO_COMPRESSION - /// and BEST_COMPRESSION. - /// - /// - /// true, if we should suppress the Zlib/RFC1950 header at the - /// beginning and the adler checksum at the end of the output. This is - /// useful for the GZIP/PKZIP formats. - /// - /// if lvl is out of range. - public Deflater(int level, bool noZlibHeaderOrFooter) - { - if (level == DEFAULT_COMPRESSION) - { - level = 6; - } - else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) - { - throw new ArgumentOutOfRangeException("level"); - } - - pending = new DeflaterPending(); - engine = new DeflaterEngine(pending); - this.noZlibHeaderOrFooter = noZlibHeaderOrFooter; - SetStrategy(DeflateStrategy.Default); - SetLevel(level); - Reset(); - } - #endregion - - /// - /// Resets the deflater. The deflater acts afterwards as if it was - /// just created with the same compression level and strategy as it - /// had before. - /// - public void Reset() - { - state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE); - totalOut = 0; - pending.Reset(); - engine.Reset(); - } - - /// - /// Gets the current adler checksum of the data that was processed so far. - /// - public int Adler - { - get - { - return engine.Adler; - } - } - - /// - /// Gets the number of input bytes processed so far. - /// - public long TotalIn - { - get - { - return engine.TotalIn; - } - } - - /// - /// Gets the number of output bytes so far. - /// - public long TotalOut - { - get - { - return totalOut; - } - } - - /// - /// Flushes the current input block. Further calls to deflate() will - /// produce enough output to inflate everything in the current input - /// block. This is not part of Sun's JDK so I have made it package - /// private. It is used by DeflaterOutputStream to implement - /// flush(). - /// - public void Flush() - { - state |= IS_FLUSHING; - } - - /// - /// Finishes the deflater with the current input block. It is an error - /// to give more input after this method was called. This method must - /// be called to force all bytes to be flushed. - /// - public void Finish() - { - state |= (IS_FLUSHING | IS_FINISHING); - } - - /// - /// Returns true if the stream was finished and no more output bytes - /// are available. - /// - public bool IsFinished - { - get - { - return (state == FINISHED_STATE) && pending.IsFlushed; - } - } - - /// - /// Returns true, if the input buffer is empty. - /// You should then call setInput(). - /// NOTE: This method can also return true when the stream - /// was finished. - /// - public bool IsNeedingInput - { - get - { - return engine.NeedsInput(); - } - } - - /// - /// Sets the data which should be compressed next. This should be only - /// called when needsInput indicates that more input is needed. - /// If you call setInput when needsInput() returns false, the - /// previous input that is still pending will be thrown away. - /// The given byte array should not be changed, before needsInput() returns - /// true again. - /// This call is equivalent to setInput(input, 0, input.length). - /// - /// - /// the buffer containing the input data. - /// - /// - /// if the buffer was finished() or ended(). - /// - public void SetInput(byte[] input) - { - SetInput(input, 0, input.Length); - } - - /// - /// Sets the data which should be compressed next. This should be - /// only called when needsInput indicates that more input is needed. - /// The given byte array should not be changed, before needsInput() returns - /// true again. - /// - /// - /// the buffer containing the input data. - /// - /// - /// the start of the data. - /// - /// - /// the number of data bytes of input. - /// - /// - /// if the buffer was Finish()ed or if previous input is still pending. - /// - public void SetInput(byte[] input, int offset, int count) - { - if ((state & IS_FINISHING) != 0) - { - throw new InvalidOperationException("Finish() already called"); - } - engine.SetInput(input, offset, count); - } - - /// - /// Sets the compression level. There is no guarantee of the exact - /// position of the change, but if you call this when needsInput is - /// true the change of compression level will occur somewhere near - /// before the end of the so far given input. - /// - /// - /// the new compression level. - /// - public void SetLevel(int level) - { - if (level == DEFAULT_COMPRESSION) - { - level = 6; - } - else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) - { - throw new ArgumentOutOfRangeException("level"); - } - - if (this.level != level) - { - this.level = level; - engine.SetLevel(level); - } - } - - /// - /// Get current compression level - /// - /// Returns the current compression level - public int GetLevel() - { - return level; - } - - /// - /// Sets the compression strategy. Strategy is one of - /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact - /// position where the strategy is changed, the same as for - /// SetLevel() applies. - /// - /// - /// The new compression strategy. - /// - public void SetStrategy(DeflateStrategy strategy) - { - engine.Strategy = strategy; - } - - /// - /// Deflates the current input block with to the given array. - /// - /// - /// The buffer where compressed data is stored - /// - /// - /// The number of compressed bytes added to the output, or 0 if either - /// IsNeedingInput() or IsFinished returns true or length is zero. - /// - public int Deflate(byte[] output) - { - return Deflate(output, 0, output.Length); - } - - /// - /// Deflates the current input block to the given array. - /// - /// - /// Buffer to store the compressed data. - /// - /// - /// Offset into the output array. - /// - /// - /// The maximum number of bytes that may be stored. - /// - /// - /// The number of compressed bytes added to the output, or 0 if either - /// needsInput() or finished() returns true or length is zero. - /// - /// - /// If Finish() was previously called. - /// - /// - /// If offset or length don't match the array length. - /// - public int Deflate(byte[] output, int offset, int length) - { - int origLength = length; - - if (state == CLOSED_STATE) - { - throw new InvalidOperationException("Deflater closed"); - } - - if (state < BUSY_STATE) - { - // output header - int header = (DEFLATED + - ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8; - int level_flags = (level - 1) >> 1; - if (level_flags < 0 || level_flags > 3) - { - level_flags = 3; - } - header |= level_flags << 6; - if ((state & IS_SETDICT) != 0) - { - // Dictionary was set - header |= DeflaterConstants.PRESET_DICT; - } - header += 31 - (header % 31); - - pending.WriteShortMSB(header); - if ((state & IS_SETDICT) != 0) - { - int chksum = engine.Adler; - engine.ResetAdler(); - pending.WriteShortMSB(chksum >> 16); - pending.WriteShortMSB(chksum & 0xffff); - } - - state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING)); - } - - for (; ; ) - { - int count = pending.Flush(output, offset, length); - offset += count; - totalOut += count; - length -= count; - - if (length == 0 || state == FINISHED_STATE) - { - break; - } - - if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) - { - if (state == BUSY_STATE) - { - // We need more input now - return origLength - length; - } - else if (state == FLUSHING_STATE) - { - if (level != NO_COMPRESSION) - { - /* We have to supply some lookahead. 8 bit lookahead - * is needed by the zlib inflater, and we must fill - * the next byte, so that all bits are flushed. - */ - int neededbits = 8 + ((-pending.BitCount) & 7); - while (neededbits > 0) - { - /* write a static tree block consisting solely of - * an EOF: - */ - pending.WriteBits(2, 10); - neededbits -= 10; - } - } - state = BUSY_STATE; - } - else if (state == FINISHING_STATE) - { - pending.AlignToByte(); - - // Compressed data is complete. Write footer information if required. - if (!noZlibHeaderOrFooter) - { - int adler = engine.Adler; - pending.WriteShortMSB(adler >> 16); - pending.WriteShortMSB(adler & 0xffff); - } - state = FINISHED_STATE; - } - } - } - return origLength - length; - } - - /// - /// Sets the dictionary which should be used in the deflate process. - /// This call is equivalent to setDictionary(dict, 0, dict.Length). - /// - /// - /// the dictionary. - /// - /// - /// if SetInput () or Deflate () were already called or another dictionary was already set. - /// - public void SetDictionary(byte[] dictionary) - { - SetDictionary(dictionary, 0, dictionary.Length); - } - - /// - /// Sets the dictionary which should be used in the deflate process. - /// The dictionary is a byte array containing strings that are - /// likely to occur in the data which should be compressed. The - /// dictionary is not stored in the compressed output, only a - /// checksum. To decompress the output you need to supply the same - /// dictionary again. - /// - /// - /// The dictionary data - /// - /// - /// The index where dictionary information commences. - /// - /// - /// The number of bytes in the dictionary. - /// - /// - /// If SetInput () or Deflate() were already called or another dictionary was already set. - /// - public void SetDictionary(byte[] dictionary, int index, int count) - { - if (state != INIT_STATE) - { - throw new InvalidOperationException(); - } - - state = SETDICT_STATE; - engine.SetDictionary(dictionary, index, count); - } - - #region Instance Fields - /// - /// Compression level. - /// - int level; - - /// - /// If true no Zlib/RFC1950 headers or footers are generated - /// - bool noZlibHeaderOrFooter; - - /// - /// The current state. - /// - int state; - - /// - /// The total bytes of output written. - /// - long totalOut; - - /// - /// The pending output. - /// - DeflaterPending pending; - - /// - /// The deflater engine. - /// - DeflaterEngine engine; - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterConstants.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterConstants.cs deleted file mode 100644 index 780c7cd0..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterConstants.cs +++ /dev/null @@ -1,191 +0,0 @@ -// DeflaterConstants.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// This class contains constants used for deflation. - /// - internal class DeflaterConstants - { - /// - /// Set to true to enable debugging - /// - public static bool DEBUGGING - { - // Prevent warning 'CS0162: Unreachable code detected' when referencing DEBUGGING - get { return false; } - } - //public const bool DEBUGGING = false; - - /// - /// Written to Zip file to identify a stored block - /// - public const int STORED_BLOCK = 0; - - /// - /// Identifies static tree in Zip file - /// - public const int STATIC_TREES = 1; - - /// - /// Identifies dynamic tree in Zip file - /// - public const int DYN_TREES = 2; - - /// - /// Header flag indicating a preset dictionary for deflation - /// - public const int PRESET_DICT = 0x20; - - /// - /// Sets internal buffer sizes for Huffman encoding - /// - public const int DEFAULT_MEM_LEVEL = 8; - - /// - /// Internal compression engine constant - /// - public const int MAX_MATCH = 258; - - /// - /// Internal compression engine constant - /// - public const int MIN_MATCH = 3; - - /// - /// Internal compression engine constant - /// - public const int MAX_WBITS = 15; - - /// - /// Internal compression engine constant - /// - public const int WSIZE = 1 << MAX_WBITS; - - /// - /// Internal compression engine constant - /// - public const int WMASK = WSIZE - 1; - - /// - /// Internal compression engine constant - /// - public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7; - - /// - /// Internal compression engine constant - /// - public const int HASH_SIZE = 1 << HASH_BITS; - - /// - /// Internal compression engine constant - /// - public const int HASH_MASK = HASH_SIZE - 1; - - /// - /// Internal compression engine constant - /// - public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH; - - /// - /// Internal compression engine constant - /// - public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; - - /// - /// Internal compression engine constant - /// - public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD; - - /// - /// Internal compression engine constant - /// - public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8); - - /// - /// Internal compression engine constant - /// - public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE - 5); - - /// - /// Internal compression engine constant - /// - public const int DEFLATE_STORED = 0; - - /// - /// Internal compression engine constant - /// - public const int DEFLATE_FAST = 1; - - /// - /// Internal compression engine constant - /// - public const int DEFLATE_SLOW = 2; - - /// - /// Internal compression engine constant - /// - public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 }; - - /// - /// Internal compression engine constant - /// - public static int[] MAX_LAZY = { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 }; - - /// - /// Internal compression engine constant - /// - public static int[] NICE_LENGTH = { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 }; - - /// - /// Internal compression engine constant - /// - public static int[] MAX_CHAIN = { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 }; - - /// - /// Internal compression engine constant - /// - public static int[] COMPR_FUNC = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 }; - - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterEngine.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterEngine.cs deleted file mode 100644 index 225074c1..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterEngine.cs +++ /dev/null @@ -1,926 +0,0 @@ -// DeflaterEngine.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; -using PdfSharpCore.SharpZipLib.Checksums; - -// ReSharper disable RedundantThisQualifier - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// Strategies for deflater - /// - internal enum DeflateStrategy - { - /// - /// The default strategy - /// - Default = 0, - - /// - /// This strategy will only allow longer string repetitions. It is - /// useful for random data with a small character set. - /// - Filtered = 1, - - - /// - /// This strategy will not look for string repetitions at all. It - /// only encodes with Huffman trees (which means, that more common - /// characters get a smaller encoding. - /// - HuffmanOnly = 2 - } - - // DEFLATE ALGORITHM: - // - // The uncompressed stream is inserted into the window array. When - // the window array is full the first half is thrown away and the - // second half is copied to the beginning. - // - // The head array is a hash table. Three characters build a hash value - // and they the value points to the corresponding index in window of - // the last string with this hash. The prev array implements a - // linked list of matches with the same hash: prev[index & WMASK] points - // to the previous index with the same hash. - // - - - /// - /// Low level compression engine for deflate algorithm which uses a 32K sliding window - /// with secondary compression from Huffman/Shannon-Fano codes. - /// - internal class DeflaterEngine : DeflaterConstants - { - #region Constants - const int TooFar = 4096; - #endregion - - #region Constructors - /// - /// Construct instance with pending buffer - /// - /// - /// Pending buffer to use - /// > - public DeflaterEngine(DeflaterPending pending) - { - this.pending = pending; - huffman = new DeflaterHuffman(pending); - adler = new Adler32(); - - window = new byte[2 * WSIZE]; - head = new short[HASH_SIZE]; - prev = new short[WSIZE]; - - // We start at index 1, to avoid an implementation deficiency, that - // we cannot build a repeat pattern at index 0. - blockStart = strstart = 1; - } - - #endregion - - /// - /// Deflate drives actual compression of data - /// - /// True to flush input buffers - /// Finish deflation with the current input. - /// Returns true if progress has been made. - public bool Deflate(bool flush, bool finish) - { - bool progress; - do - { - FillWindow(); - bool canFlush = flush && (inputOff == inputEnd); - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) { - Console.WriteLine("window: [" + blockStart + "," + strstart + "," - + lookahead + "], " + compressionFunction + "," + canFlush); - } -#endif - switch (compressionFunction) - { - case DEFLATE_STORED: - progress = DeflateStored(canFlush, finish); - break; - case DEFLATE_FAST: - progress = DeflateFast(canFlush, finish); - break; - case DEFLATE_SLOW: - progress = DeflateSlow(canFlush, finish); - break; - default: - throw new InvalidOperationException("unknown compressionFunction"); - } - } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made - return progress; - } - - /// - /// Sets input data to be deflated. Should only be called when NeedsInput() - /// returns true - /// - /// The buffer containing input data. - /// The offset of the first byte of data. - /// The number of bytes of data to use as input. - public void SetInput(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (offset < 0) - { - throw new ArgumentOutOfRangeException("offset"); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - if (inputOff < inputEnd) - { - throw new InvalidOperationException("Old input was not completely processed"); - } - - int end = offset + count; - - /* We want to throw an ArrayIndexOutOfBoundsException early. The - * check is very tricky: it also handles integer wrap around. - */ - if ((offset > end) || (end > buffer.Length)) - { - throw new ArgumentOutOfRangeException("count"); - } - - inputBuf = buffer; - inputOff = offset; - inputEnd = end; - } - - /// - /// Determines if more input is needed. - /// - /// Return true if input is needed via SetInput - public bool NeedsInput() - { - return (inputEnd == inputOff); - } - - /// - /// Set compression dictionary - /// - /// The buffer containing the dictionary data - /// The offset in the buffer for the first byte of data - /// The length of the dictionary data. - public void SetDictionary(byte[] buffer, int offset, int length) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (strstart != 1) ) - { - throw new InvalidOperationException("strstart not 1"); - } -#endif - adler.Update(buffer, offset, length); - if (length < MIN_MATCH) - { - return; - } - - if (length > MAX_DIST) - { - offset += length - MAX_DIST; - length = MAX_DIST; - } - - System.Array.Copy(buffer, offset, window, strstart, length); - - UpdateHash(); - --length; - while (--length > 0) - { - InsertString(); - strstart++; - } - strstart += 2; - blockStart = strstart; - } - - /// - /// Reset internal state - /// - public void Reset() - { - huffman.Reset(); - adler.Reset(); - blockStart = strstart = 1; - lookahead = 0; - totalIn = 0; - prevAvailable = false; - matchLen = MIN_MATCH - 1; - - for (int i = 0; i < HASH_SIZE; i++) - { - head[i] = 0; - } - - for (int i = 0; i < WSIZE; i++) - { - prev[i] = 0; - } - } - - /// - /// Reset Adler checksum - /// - public void ResetAdler() - { - adler.Reset(); - } - - /// - /// Get current value of Adler checksum - /// - public int Adler - { - get - { - return unchecked((int)adler.Value); - } - } - - /// - /// Total data processed - /// - public long TotalIn - { - get - { - return totalIn; - } - } - - /// - /// Get/set the deflate strategy - /// - public DeflateStrategy Strategy - { - get - { - return strategy; - } - set - { - strategy = value; - } - } - - /// - /// Set the deflate level (0-9) - /// - /// The value to set the level to. - public void SetLevel(int level) - { - if ((level < 0) || (level > 9)) - { - throw new ArgumentOutOfRangeException("level"); - } - - goodLength = DeflaterConstants.GOOD_LENGTH[level]; - max_lazy = DeflaterConstants.MAX_LAZY[level]; - niceLength = DeflaterConstants.NICE_LENGTH[level]; - max_chain = DeflaterConstants.MAX_CHAIN[level]; - - if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) - { - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) { - Console.WriteLine("Change from " + compressionFunction + " to " - + DeflaterConstants.COMPR_FUNC[level]); - } -#endif - switch (compressionFunction) - { - case DEFLATE_STORED: - if (strstart > blockStart) - { - huffman.FlushStoredBlock(window, blockStart, - strstart - blockStart, false); - blockStart = strstart; - } - UpdateHash(); - break; - - case DEFLATE_FAST: - if (strstart > blockStart) - { - huffman.FlushBlock(window, blockStart, strstart - blockStart, - false); - blockStart = strstart; - } - break; - - case DEFLATE_SLOW: - if (prevAvailable) - { - huffman.TallyLit(window[strstart - 1] & 0xff); - } - if (strstart > blockStart) - { - huffman.FlushBlock(window, blockStart, strstart - blockStart, false); - blockStart = strstart; - } - prevAvailable = false; - matchLen = MIN_MATCH - 1; - break; - } - compressionFunction = COMPR_FUNC[level]; - } - } - - /// - /// Fill the window - /// - public void FillWindow() - { - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (strstart >= WSIZE + MAX_DIST) - { - SlideWindow(); - } - - /* If there is not enough lookahead, but still some input left, - * read in the input - */ - while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) - { - int more = 2 * WSIZE - lookahead - strstart; - - if (more > inputEnd - inputOff) - { - more = inputEnd - inputOff; - } - - System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more); - adler.Update(inputBuf, inputOff, more); - - inputOff += more; - totalIn += more; - lookahead += more; - } - - if (lookahead >= MIN_MATCH) - { - UpdateHash(); - } - } - - void UpdateHash() - { - /* - if (DEBUGGING) { - Console.WriteLine("updateHash: "+strstart); - } - */ - ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1]; - } - - /// - /// Inserts the current string in the head hash and returns the previous - /// value for this hash. - /// - /// The previous hash value - int InsertString() - { - short match; - int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH - 1)]) & HASH_MASK; - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) - { - if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^ - (window[strstart + 1] << HASH_SHIFT) ^ - (window[strstart + 2])) & HASH_MASK)) { - throw new SharpZipBaseException("hash inconsistent: " + hash + "/" - +window[strstart] + "," - +window[strstart + 1] + "," - +window[strstart + 2] + "," + HASH_SHIFT); - } - } -#endif - prev[strstart & WMASK] = match = head[hash]; - head[hash] = unchecked((short)strstart); - ins_h = hash; - return match & 0xffff; - } - - void SlideWindow() - { - Array.Copy(window, WSIZE, window, 0, WSIZE); - matchStart -= WSIZE; - strstart -= WSIZE; - blockStart -= WSIZE; - - // Slide the hash table (could be avoided with 32 bit values - // at the expense of memory usage). - for (int i = 0; i < HASH_SIZE; ++i) - { - int m = head[i] & 0xffff; - head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0); - } - - // Slide the prev table. - for (int i = 0; i < WSIZE; i++) - { - int m = prev[i] & 0xffff; - prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0); - } - } - - /// - /// Find the best (longest) string in the window matching the - /// string starting at strstart. - /// - /// Preconditions: - /// - /// strstart + MAX_MATCH <= window.length. - /// - /// - /// True if a match greater than the minimum length is found - bool FindLongestMatch(int curMatch) - { - int chainLength = this.max_chain; - int niceLength = this.niceLength; - short[] prev = this.prev; - int scan = this.strstart; - int match; - int best_end = this.strstart + matchLen; - int best_len = Math.Max(matchLen, MIN_MATCH - 1); - - int limit = Math.Max(strstart - MAX_DIST, 0); - - int strend = strstart + MAX_MATCH - 1; - byte scan_end1 = window[best_end - 1]; - byte scan_end = window[best_end]; - - // Do not waste too much time if we already have a good match: - if (best_len >= this.goodLength) - { - chainLength >>= 2; - } - - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (niceLength > lookahead) - { - niceLength = lookahead; - } - -#if DebugDeflation - - if (DeflaterConstants.DEBUGGING && (strstart > 2 * WSIZE - MIN_LOOKAHEAD)) - { - throw new InvalidOperationException("need lookahead"); - } -#endif - - do - { - -#if DebugDeflation - - if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) ) - { - throw new InvalidOperationException("no future"); - } -#endif - if (window[curMatch + best_len] != scan_end || - window[curMatch + best_len - 1] != scan_end1 || - window[curMatch] != window[scan] || - window[curMatch + 1] != window[scan + 1]) - { - continue; - } - - match = curMatch + 2; - scan += 2; - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart + 258. - */ - while ( - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - (scan < strend)) - { - // Do nothing - } - - if (scan > best_end) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (ins_h == 0) ) - Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart)); -#endif - matchStart = curMatch; - best_end = scan; - best_len = scan - strstart; - - if (best_len >= niceLength) - { - break; - } - - scan_end1 = window[best_end - 1]; - scan_end = window[best_end]; - } - scan = strstart; - } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0); - - matchLen = Math.Min(best_len, lookahead); - return matchLen >= MIN_MATCH; - } - - bool DeflateStored(bool flush, bool finish) - { - if (!flush && (lookahead == 0)) - { - return false; - } - - strstart += lookahead; - lookahead = 0; - - int storedLength = strstart - blockStart; - - if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full - (blockStart < WSIZE && storedLength >= MAX_DIST) || // Block may move out of window - flush) - { - bool lastBlock = finish; - if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) - { - storedLength = DeflaterConstants.MAX_BLOCK_SIZE; - lastBlock = false; - } - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) - { - Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]"); - } -#endif - - huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock); - blockStart += storedLength; - return !lastBlock; - } - return true; - } - - bool DeflateFast(bool flush, bool finish) - { - if (lookahead < MIN_LOOKAHEAD && !flush) - { - return false; - } - - while (lookahead >= MIN_LOOKAHEAD || flush) - { - if (lookahead == 0) - { - // We are flushing everything - huffman.FlushBlock(window, blockStart, strstart - blockStart, finish); - blockStart = strstart; - return false; - } - - if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) - { - /* slide window, as FindLongestMatch needs this. - * This should only happen when flushing and the window - * is almost full. - */ - SlideWindow(); - } - - int hashHead; - if (lookahead >= MIN_MATCH && - (hashHead = InsertString()) != 0 && - strategy != DeflateStrategy.HuffmanOnly && - strstart - hashHead <= MAX_DIST && - FindLongestMatch(hashHead)) - { - // longestMatch sets matchStart and matchLen -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) - { - for (int i = 0 ; i < matchLen; i++) { - if (window[strstart + i] != window[matchStart + i]) { - throw new SharpZipBaseException("Match failure"); - } - } - } -#endif - - bool full = huffman.TallyDist(strstart - matchStart, matchLen); - - lookahead -= matchLen; - if (matchLen <= max_lazy && lookahead >= MIN_MATCH) - { - while (--matchLen > 0) - { - ++strstart; - InsertString(); - } - ++strstart; - } - else - { - strstart += matchLen; - if (lookahead >= MIN_MATCH - 1) - { - UpdateHash(); - } - } - matchLen = MIN_MATCH - 1; - if (!full) - { - continue; - } - } - else - { - // No match found - huffman.TallyLit(window[strstart] & 0xff); - ++strstart; - --lookahead; - } - - if (huffman.IsFull()) - { - bool lastBlock = finish && (lookahead == 0); - huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock); - blockStart = strstart; - return !lastBlock; - } - } - return true; - } - - bool DeflateSlow(bool flush, bool finish) - { - if (lookahead < MIN_LOOKAHEAD && !flush) - { - return false; - } - - while (lookahead >= MIN_LOOKAHEAD || flush) - { - if (lookahead == 0) - { - if (prevAvailable) - { - huffman.TallyLit(window[strstart - 1] & 0xff); - } - prevAvailable = false; - - // We are flushing everything -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && !flush) - { - throw new SharpZipBaseException("Not flushing, but no lookahead"); - } -#endif - huffman.FlushBlock(window, blockStart, strstart - blockStart, - finish); - blockStart = strstart; - return false; - } - - if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) - { - /* slide window, as FindLongestMatch needs this. - * This should only happen when flushing and the window - * is almost full. - */ - SlideWindow(); - } - - int prevMatch = matchStart; - int prevLen = matchLen; - if (lookahead >= MIN_MATCH) - { - - int hashHead = InsertString(); - - if (strategy != DeflateStrategy.HuffmanOnly && - hashHead != 0 && - strstart - hashHead <= MAX_DIST && - FindLongestMatch(hashHead)) - { - - // longestMatch sets matchStart and matchLen - - // Discard match if too small and too far away - if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) - { - matchLen = MIN_MATCH - 1; - } - } - } - - // previous match was better - if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen)) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) - { - for (int i = 0 ; i < matchLen; i++) { - if (window[strstart-1+i] != window[prevMatch + i]) - throw new SharpZipBaseException(); - } - } -#endif - huffman.TallyDist(strstart - 1 - prevMatch, prevLen); - prevLen -= 2; - do - { - strstart++; - lookahead--; - if (lookahead >= MIN_MATCH) - { - InsertString(); - } - } while (--prevLen > 0); - - strstart++; - lookahead--; - prevAvailable = false; - matchLen = MIN_MATCH - 1; - } - else - { - if (prevAvailable) - { - huffman.TallyLit(window[strstart - 1] & 0xff); - } - prevAvailable = true; - strstart++; - lookahead--; - } - - if (huffman.IsFull()) - { - int len = strstart - blockStart; - if (prevAvailable) - { - len--; - } - bool lastBlock = (finish && (lookahead == 0) && !prevAvailable); - huffman.FlushBlock(window, blockStart, len, lastBlock); - blockStart += len; - return !lastBlock; - } - } - return true; - } - - #region Instance Fields - - // Hash index of string to be inserted - int ins_h; - - /// - /// Hashtable, hashing three characters to an index for window, so - /// that window[index]..window[index+2] have this hash code. - /// Note that the array should really be unsigned short, so you need - /// to and the values with 0xffff. - /// - short[] head; - - /// - /// prev[index & WMASK] points to the previous index that has the - /// same hash code as the string starting at index. This way - /// entries with the same hash code are in a linked list. - /// Note that the array should really be unsigned short, so you need - /// to and the values with 0xffff. - /// - short[] prev; - - int matchStart; - // Length of best match - int matchLen; - // Set if previous match exists - bool prevAvailable; - int blockStart; - - /// - /// Points to the current character in the window. - /// - int strstart; - - /// - /// lookahead is the number of characters starting at strstart in - /// window that are valid. - /// So window[strstart] until window[strstart+lookahead-1] are valid - /// characters. - /// - int lookahead; - - /// - /// This array contains the part of the uncompressed stream that - /// is of relevance. The current character is indexed by strstart. - /// - byte[] window; - - DeflateStrategy strategy; - int max_chain, max_lazy, niceLength, goodLength; - - /// - /// The current compression function. - /// - int compressionFunction; - - /// - /// The input data for compression. - /// - byte[] inputBuf; - - /// - /// The total bytes of input read. - /// - long totalIn; - - /// - /// The offset into inputBuf, where input data starts. - /// - int inputOff; - - /// - /// The end offset of the input data. - /// - int inputEnd; - - DeflaterPending pending; - DeflaterHuffman huffman; - - /// - /// The adler checksum - /// - Adler32 adler; - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterHuffman.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterHuffman.cs deleted file mode 100644 index 49c24cd9..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterHuffman.cs +++ /dev/null @@ -1,999 +0,0 @@ -// DeflaterHuffman.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -// ReSharper disable RedundantThisQualifier - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// This is the DeflaterHuffman class. - /// - /// This class is not thread safe. This is inherent in the API, due - /// to the split of Deflate and SetInput. - /// - /// author of the original java version : Jochen Hoenicke - /// - internal class DeflaterHuffman - { - const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6); - const int LITERAL_NUM = 286; - - // Number of distance codes - const int DIST_NUM = 30; - // Number of codes used to transfer bit lengths - const int BITLEN_NUM = 19; - - // repeat previous bit length 3-6 times (2 bits of repeat count) - const int REP_3_6 = 16; - // repeat a zero length 3-10 times (3 bits of repeat count) - const int REP_3_10 = 17; - // repeat a zero length 11-138 times (7 bits of repeat count) - const int REP_11_138 = 18; - - const int EOF_SYMBOL = 256; - - // The lengths of the bit length codes are sent in order of decreasing - // probability, to avoid transmitting the lengths for unused bit length codes. - static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - - static readonly byte[] bit4Reverse = { - 0, - 8, - 4, - 12, - 2, - 10, - 6, - 14, - 1, - 9, - 5, - 13, - 3, - 11, - 7, - 15 - }; - - static short[] staticLCodes; - static byte[] staticLLength; - static short[] staticDCodes; - static byte[] staticDLength; - - class Tree - { - #region Instance Fields - public short[] freqs; - - public byte[] length; - - public int minNumCodes; - - public int numCodes; - - short[] codes; - int[] bl_counts; - int maxLength; - DeflaterHuffman dh; - #endregion - - #region Constructors - public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) - { - this.dh = dh; - this.minNumCodes = minCodes; - this.maxLength = maxLength; - freqs = new short[elems]; - bl_counts = new int[maxLength]; - } - - #endregion - - /// - /// Resets the internal state of the tree - /// - public void Reset() - { - for (int i = 0; i < freqs.Length; i++) - { - freqs[i] = 0; - } - codes = null; - length = null; - } - - public void WriteSymbol(int code) - { - // if (DeflaterConstants.DEBUGGING) { - // freqs[code]--; - // // Console.Write("writeSymbol("+freqs.length+","+code+"): "); - // } - dh.pending.WriteBits(codes[code] & 0xffff, length[code]); - } - - /// - /// Check that all frequencies are zero - /// - /// - /// At least one frequency is non-zero - /// - public void CheckEmpty() - { - bool empty = true; - for (int i = 0; i < freqs.Length; i++) - { - if (freqs[i] != 0) - { - //Console.WriteLine("freqs[" + i + "] == " + freqs[i]); - empty = false; - } - } - - if (!empty) - { - throw new SharpZipBaseException("!Empty"); - } - } - - /// - /// Set static codes and length - /// - /// new codes - /// length for new codes - public void SetStaticCodes(short[] staticCodes, byte[] staticLengths) - { - codes = staticCodes; - length = staticLengths; - } - - /// - /// Build dynamic codes and lengths - /// - public void BuildCodes() - { - int numSymbols = freqs.Length; - int[] nextCode = new int[maxLength]; - int code = 0; - - codes = new short[freqs.Length]; - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("buildCodes: "+freqs.Length); - // } - - for (int bits = 0; bits < maxLength; bits++) - { - nextCode[bits] = code; - code += bl_counts[bits] << (15 - bits); - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits] - // +" nextCode: "+code); - // } - } - -#if DebugDeflation - if ( DeflaterConstants.DEBUGGING && (code != 65536) ) - { - throw new SharpZipBaseException("Inconsistent bl_counts!"); - } -#endif - for (int i = 0; i < numCodes; i++) - { - int bits = length[i]; - if (bits > 0) - { - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"), - // +bits); - // } - - codes[i] = BitReverse(nextCode[bits - 1]); - nextCode[bits - 1] += 1 << (16 - bits); - } - } - } - - public void BuildTree() - { - int numSymbols = freqs.Length; - - /* heap is a priority queue, sorted by frequency, least frequent - * nodes first. The heap is a binary tree, with the property, that - * the parent node is smaller than both child nodes. This assures - * that the smallest node is the first parent. - * - * The binary tree is encoded in an array: 0 is root node and - * the nodes 2*n+1, 2*n+2 are the child nodes of node n. - */ - int[] heap = new int[numSymbols]; - int heapLen = 0; - int maxCode = 0; - for (int n = 0; n < numSymbols; n++) - { - int freq = freqs[n]; - if (freq != 0) - { - // Insert n into heap - int pos = heapLen++; - int ppos; - while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) - { - heap[pos] = heap[ppos]; - pos = ppos; - } - heap[pos] = n; - - maxCode = n; - } - } - - /* We could encode a single literal with 0 bits but then we - * don't see the literals. Therefore we force at least two - * literals to avoid this case. We don't care about order in - * this case, both literals get a 1 bit code. - */ - while (heapLen < 2) - { - int node = maxCode < 2 ? ++maxCode : 0; - heap[heapLen++] = node; - } - - numCodes = Math.Max(maxCode + 1, minNumCodes); - - int numLeafs = heapLen; - int[] childs = new int[4 * heapLen - 2]; - int[] values = new int[2 * heapLen - 1]; - int numNodes = numLeafs; - for (int i = 0; i < heapLen; i++) - { - int node = heap[i]; - childs[2 * i] = node; - childs[2 * i + 1] = -1; - values[i] = freqs[node] << 8; - heap[i] = i; - } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - do - { - int first = heap[0]; - int last = heap[--heapLen]; - - // Propagate the hole to the leafs of the heap - int ppos = 0; - int path = 1; - - while (path < heapLen) - { - if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) - { - path++; - } - - heap[ppos] = heap[path]; - ppos = path; - path = path * 2 + 1; - } - - /* Now propagate the last element down along path. Normally - * it shouldn't go too deep. - */ - int lastVal = values[last]; - while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) - { - heap[path] = heap[ppos]; - } - heap[path] = last; - - - int second = heap[0]; - - // Create a new node father of first and second - last = numNodes++; - childs[2 * last] = first; - childs[2 * last + 1] = second; - int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff); - values[last] = lastVal = values[first] + values[second] - mindepth + 1; - - // Again, propagate the hole to the leafs - ppos = 0; - path = 1; - - while (path < heapLen) - { - if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) - { - path++; - } - - heap[ppos] = heap[path]; - ppos = path; - path = ppos * 2 + 1; - } - - // Now propagate the new element down along path - while ((path = ppos) > 0 && values[heap[ppos = (path - 1) / 2]] > lastVal) - { - heap[path] = heap[ppos]; - } - heap[path] = last; - } while (heapLen > 1); - - if (heap[0] != childs.Length / 2 - 1) - { - throw new SharpZipBaseException("Heap invariant violated"); - } - - BuildLength(childs); - } - - /// - /// Get encoded length - /// - /// Encoded length, the sum of frequencies * lengths - public int GetEncodedLength() - { - int len = 0; - for (int i = 0; i < freqs.Length; i++) - { - len += freqs[i] * length[i]; - } - return len; - } - - /// - /// Scan a literal or distance tree to determine the frequencies of the codes - /// in the bit length tree. - /// - public void CalcBLFreq(Tree blTree) - { - int max_count; /* max repeat count */ - int min_count; /* min repeat count */ - int count; /* repeat count of the current code */ - int curlen = -1; /* length of current code */ - - int i = 0; - while (i < numCodes) - { - count = 1; - int nextlen = length[i]; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else - { - max_count = 6; - min_count = 3; - if (curlen != nextlen) - { - blTree.freqs[nextlen]++; - count = 0; - } - } - curlen = nextlen; - i++; - - while (i < numCodes && curlen == length[i]) - { - i++; - if (++count >= max_count) - { - break; - } - } - - if (count < min_count) - { - blTree.freqs[curlen] += (short)count; - } - else if (curlen != 0) - { - blTree.freqs[REP_3_6]++; - } - else if (count <= 10) - { - blTree.freqs[REP_3_10]++; - } - else - { - blTree.freqs[REP_11_138]++; - } - } - } - - /// - /// Write tree values - /// - /// Tree to write - public void WriteTree(Tree blTree) - { - int max_count; // max repeat count - int min_count; // min repeat count - int count; // repeat count of the current code - int curlen = -1; // length of current code - - int i = 0; - while (i < numCodes) - { - count = 1; - int nextlen = length[i]; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else - { - max_count = 6; - min_count = 3; - if (curlen != nextlen) - { - blTree.WriteSymbol(nextlen); - count = 0; - } - } - curlen = nextlen; - i++; - - while (i < numCodes && curlen == length[i]) - { - i++; - if (++count >= max_count) - { - break; - } - } - - if (count < min_count) - { - while (count-- > 0) - { - blTree.WriteSymbol(curlen); - } - } - else if (curlen != 0) - { - blTree.WriteSymbol(REP_3_6); - dh.pending.WriteBits(count - 3, 2); - } - else if (count <= 10) - { - blTree.WriteSymbol(REP_3_10); - dh.pending.WriteBits(count - 3, 3); - } - else - { - blTree.WriteSymbol(REP_11_138); - dh.pending.WriteBits(count - 11, 7); - } - } - } - - void BuildLength(int[] childs) - { - this.length = new byte[freqs.Length]; - int numNodes = childs.Length / 2; - int numLeafs = (numNodes + 1) / 2; - int overflow = 0; - - for (int i = 0; i < maxLength; i++) - { - bl_counts[i] = 0; - } - - // First calculate optimal bit lengths - int[] lengths = new int[numNodes]; - lengths[numNodes - 1] = 0; - - for (int i = numNodes - 1; i >= 0; i--) - { - if (childs[2 * i + 1] != -1) - { - int bitLength = lengths[i] + 1; - if (bitLength > maxLength) - { - bitLength = maxLength; - overflow++; - } - lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength; - } - else - { - // A leaf node - int bitLength = lengths[i]; - bl_counts[bitLength - 1]++; - this.length[childs[2 * i]] = (byte)lengths[i]; - } - } - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("Tree "+freqs.Length+" lengths:"); - // for (int i=0; i < numLeafs; i++) { - // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] - // + " len: "+length[childs[2*i]]); - // } - // } - - if (overflow == 0) - { - return; - } - - int incrBitLen = maxLength - 1; - do - { - // Find the first bit length which could increase: - while (bl_counts[--incrBitLen] == 0) - ; - - // Move this node one down and remove a corresponding - // number of overflow nodes. - do - { - bl_counts[incrBitLen]--; - bl_counts[++incrBitLen]++; - overflow -= 1 << (maxLength - 1 - incrBitLen); - } while (overflow > 0 && incrBitLen < maxLength - 1); - } while (overflow > 0); - - /* We may have overshot above. Move some nodes from maxLength to - * maxLength-1 in that case. - */ - bl_counts[maxLength - 1] += overflow; - bl_counts[maxLength - 2] -= overflow; - - /* Now recompute all bit lengths, scanning in increasing - * frequency. It is simpler to reconstruct all lengths instead of - * fixing only the wrong ones. This idea is taken from 'ar' - * written by Haruhiko Okumura. - * - * The nodes were inserted with decreasing frequency into the childs - * array. - */ - int nodePtr = 2 * numLeafs; - for (int bits = maxLength; bits != 0; bits--) - { - int n = bl_counts[bits - 1]; - while (n > 0) - { - int childPtr = 2 * childs[nodePtr++]; - if (childs[childPtr + 1] == -1) - { - // We found another leaf - length[childs[childPtr]] = (byte)bits; - n--; - } - } - } - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("*** After overflow elimination. ***"); - // for (int i=0; i < numLeafs; i++) { - // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] - // + " len: "+length[childs[2*i]]); - // } - // } - } - - } - - #region Instance Fields - /// - /// Pending buffer to use - /// - public DeflaterPending pending; - - Tree literalTree; - Tree distTree; - Tree blTree; - - // Buffer for distances - short[] d_buf; - byte[] l_buf; - int last_lit; - int extra_bits; - #endregion - - static DeflaterHuffman() - { - // See RFC 1951 3.2.6 - // Literal codes - staticLCodes = new short[LITERAL_NUM]; - staticLLength = new byte[LITERAL_NUM]; - - int i = 0; - while (i < 144) - { - staticLCodes[i] = BitReverse((0x030 + i) << 8); - staticLLength[i++] = 8; - } - - while (i < 256) - { - staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7); - staticLLength[i++] = 9; - } - - while (i < 280) - { - staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9); - staticLLength[i++] = 7; - } - - while (i < LITERAL_NUM) - { - staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8); - staticLLength[i++] = 8; - } - - // Distance codes - staticDCodes = new short[DIST_NUM]; - staticDLength = new byte[DIST_NUM]; - for (i = 0; i < DIST_NUM; i++) - { - staticDCodes[i] = BitReverse(i << 11); - staticDLength[i] = 5; - } - } - - /// - /// Construct instance with pending buffer - /// - /// Pending buffer to use - public DeflaterHuffman(DeflaterPending pending) - { - this.pending = pending; - - literalTree = new Tree(this, LITERAL_NUM, 257, 15); - distTree = new Tree(this, DIST_NUM, 1, 15); - blTree = new Tree(this, BITLEN_NUM, 4, 7); - - d_buf = new short[BUFSIZE]; - l_buf = new byte[BUFSIZE]; - } - - /// - /// Reset internal state - /// - public void Reset() - { - last_lit = 0; - extra_bits = 0; - literalTree.Reset(); - distTree.Reset(); - blTree.Reset(); - } - - /// - /// Write all trees to pending buffer - /// - /// The number/rank of treecodes to send. - public void SendAllTrees(int blTreeCodes) - { - blTree.BuildCodes(); - literalTree.BuildCodes(); - distTree.BuildCodes(); - pending.WriteBits(literalTree.numCodes - 257, 5); - pending.WriteBits(distTree.numCodes - 1, 5); - pending.WriteBits(blTreeCodes - 4, 4); - for (int rank = 0; rank < blTreeCodes; rank++) - { - pending.WriteBits(blTree.length[BL_ORDER[rank]], 3); - } - literalTree.WriteTree(blTree); - distTree.WriteTree(blTree); - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) { - blTree.CheckEmpty(); - } -#endif - } - - /// - /// Compress current buffer writing data to pending buffer - /// - public void CompressBlock() - { - for (int i = 0; i < last_lit; i++) - { - int litlen = l_buf[i] & 0xff; - int dist = d_buf[i]; - if (dist-- != 0) - { - // if (DeflaterConstants.DEBUGGING) { - // Console.Write("["+(dist+1)+","+(litlen+3)+"]: "); - // } - - int lc = Lcode(litlen); - literalTree.WriteSymbol(lc); - - int bits = (lc - 261) / 4; - if (bits > 0 && bits <= 5) - { - pending.WriteBits(litlen & ((1 << bits) - 1), bits); - } - - int dc = Dcode(dist); - distTree.WriteSymbol(dc); - - bits = dc / 2 - 1; - if (bits > 0) - { - pending.WriteBits(dist & ((1 << bits) - 1), bits); - } - } - else - { - // if (DeflaterConstants.DEBUGGING) { - // if (litlen > 32 && litlen < 127) { - // Console.Write("("+(char)litlen+"): "); - // } else { - // Console.Write("{"+litlen+"}: "); - // } - // } - literalTree.WriteSymbol(litlen); - } - } - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) { - Console.Write("EOF: "); - } -#endif - literalTree.WriteSymbol(EOF_SYMBOL); - -#if DebugDeflation - if (DeflaterConstants.DEBUGGING) { - literalTree.CheckEmpty(); - distTree.CheckEmpty(); - } -#endif - } - - /// - /// Flush block to output with no compression - /// - /// Data to write - /// Index of first byte to write - /// Count of bytes to write - /// True if this is the last block - public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) - { -#if DebugDeflation - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("Flushing stored block "+ storedLength); - // } -#endif - pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3); - pending.AlignToByte(); - pending.WriteShort(storedLength); - pending.WriteShort(~storedLength); - pending.WriteBlock(stored, storedOffset, storedLength); - Reset(); - } - - /// - /// Flush block to output with compression - /// - /// Data to flush - /// Index of first byte to flush - /// Count of bytes to flush - /// True if this is the last block - public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) - { - literalTree.freqs[EOF_SYMBOL]++; - - // Build trees - literalTree.BuildTree(); - distTree.BuildTree(); - - // Calculate bitlen frequency - literalTree.CalcBLFreq(blTree); - distTree.CalcBLFreq(blTree); - - // Build bitlen tree - blTree.BuildTree(); - - int blTreeCodes = 4; - for (int i = 18; i > blTreeCodes; i--) - { - if (blTree.length[BL_ORDER[i]] > 0) - { - blTreeCodes = i + 1; - } - } - int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() + - literalTree.GetEncodedLength() + distTree.GetEncodedLength() + - extra_bits; - - int static_len = extra_bits; - for (int i = 0; i < LITERAL_NUM; i++) - { - static_len += literalTree.freqs[i] * staticLLength[i]; - } - for (int i = 0; i < DIST_NUM; i++) - { - static_len += distTree.freqs[i] * staticDLength[i]; - } - if (opt_len >= static_len) - { - // Force static trees - opt_len = static_len; - } - - if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) - { - // Store Block - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len - // + " <= " + static_len); - // } - FlushStoredBlock(stored, storedOffset, storedLength, lastBlock); - } - else if (opt_len == static_len) - { - // Encode with static tree - pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3); - literalTree.SetStaticCodes(staticLCodes, staticLLength); - distTree.SetStaticCodes(staticDCodes, staticDLength); - CompressBlock(); - Reset(); - } - else - { - // Encode with dynamic tree - pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3); - SendAllTrees(blTreeCodes); - CompressBlock(); - Reset(); - } - } - - /// - /// Get value indicating if internal buffer is full - /// - /// true if buffer is full - public bool IsFull() - { - return last_lit >= BUFSIZE; - } - - /// - /// Add literal to buffer - /// - /// Literal value to add to buffer. - /// Value indicating internal buffer is full - public bool TallyLit(int literal) - { - // if (DeflaterConstants.DEBUGGING) { - // if (lit > 32 && lit < 127) { - // //Console.WriteLine("("+(char)lit+")"); - // } else { - // //Console.WriteLine("{"+lit+"}"); - // } - // } - d_buf[last_lit] = 0; - l_buf[last_lit++] = (byte)literal; - literalTree.freqs[literal]++; - return IsFull(); - } - - /// - /// Add distance code and length to literal and distance trees - /// - /// Distance code - /// Length - /// Value indicating if internal buffer is full - public bool TallyDist(int distance, int length) - { - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("[" + distance + "," + length + "]"); - // } - - d_buf[last_lit] = (short)distance; - l_buf[last_lit++] = (byte)(length - 3); - - int lc = Lcode(length - 3); - literalTree.freqs[lc]++; - if (lc >= 265 && lc < 285) - { - extra_bits += (lc - 261) / 4; - } - - int dc = Dcode(distance - 1); - distTree.freqs[dc]++; - if (dc >= 4) - { - extra_bits += dc / 2 - 1; - } - return IsFull(); - } - - - /// - /// Reverse the bits of a 16 bit value. - /// - /// Value to reverse bits - /// Value with bits reversed - public static short BitReverse(int toReverse) - { - return (short)(bit4Reverse[toReverse & 0xF] << 12 | - bit4Reverse[(toReverse >> 4) & 0xF] << 8 | - bit4Reverse[(toReverse >> 8) & 0xF] << 4 | - bit4Reverse[toReverse >> 12]); - } - - static int Lcode(int length) - { - if (length == 255) - { - return 285; - } - - int code = 257; - while (length >= 8) - { - code += 4; - length >>= 1; - } - return code + length; - } - - static int Dcode(int distance) - { - int code = 0; - while (distance >= 4) - { - code += 2; - distance >>= 1; - } - return code + distance; - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterPending.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterPending.cs deleted file mode 100644 index 4ac7fad5..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/DeflaterPending.cs +++ /dev/null @@ -1,58 +0,0 @@ -// DeflaterPending.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// This class stores the pending output of the Deflater. - /// - /// Author of the original java version: Jochen Hoenicke - /// - internal class DeflaterPending : PendingBuffer - { - /// - /// Construct instance with default buffer size - /// - public DeflaterPending() - : base(DeflaterConstants.PENDING_BUF_SIZE) - { - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Inflater.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Inflater.cs deleted file mode 100644 index 3a4037bd..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Inflater.cs +++ /dev/null @@ -1,915 +0,0 @@ -// Inflater.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; -using PdfSharpCore.SharpZipLib.Checksums; -using PdfSharpCore.SharpZipLib.Zip.Compression.Streams; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - /// - /// Inflater is used to decompress data that has been compressed according - /// to the "deflate" standard described in rfc1951. - /// - /// By default Zlib (rfc1950) headers and footers are expected in the input. - /// You can use constructor public Inflater(bool noHeader) passing true - /// if there is no Zlib header information - /// - /// The usage is as following. First you have to set some input with - /// SetInput(), then Inflate() it. If inflate doesn't - /// inflate any bytes there may be three reasons: - ///
    - ///
  • IsNeedingInput() returns true because the input buffer is empty. - /// You have to provide more input with SetInput(). - /// NOTE: IsNeedingInput() also returns true when, the stream is finished. - ///
  • - ///
  • IsNeedingDictionary() returns true, you have to provide a preset - /// dictionary with SetDictionary().
  • - ///
  • IsFinished returns true, the inflater has finished.
  • - ///
- /// Once the first output byte is produced, a dictionary will not be - /// needed at a later stage. - /// - /// Author of the original java version: John Leuner, Jochen Hoenicke - ///
- internal class Inflater - { - #region Constants/Readonly - /// - /// Copy lengths for literal codes 257..285 - /// - static readonly int[] CPLENS = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 - }; - - /// - /// Extra bits for literal codes 257..285 - /// - static readonly int[] CPLEXT = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 - }; - - /// - /// Copy offsets for distance codes 0..29 - /// - static readonly int[] CPDIST = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - - /// - /// Extra bits for distance codes - /// - static readonly int[] CPDEXT = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /// - /// These are the possible states for an inflater - /// - const int DECODE_HEADER = 0; - const int DECODE_DICT = 1; - const int DECODE_BLOCKS = 2; - const int DECODE_STORED_LEN1 = 3; - const int DECODE_STORED_LEN2 = 4; - const int DECODE_STORED = 5; - const int DECODE_DYN_HEADER = 6; - const int DECODE_HUFFMAN = 7; - const int DECODE_HUFFMAN_LENBITS = 8; - const int DECODE_HUFFMAN_DIST = 9; - const int DECODE_HUFFMAN_DISTBITS = 10; - const int DECODE_CHKSUM = 11; - const int FINISHED = 12; - #endregion - - #region Instance Fields - /// - /// This variable contains the current state. - /// - int mode; - - /// - /// The adler checksum of the dictionary or of the decompressed - /// stream, as it is written in the header resp. footer of the - /// compressed stream. - /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM. - /// - int readAdler; - - /// - /// The number of bits needed to complete the current state. This - /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM, - /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS. - /// - int neededBits; - int repLength; - int repDist; - int uncomprLen; - - /// - /// True, if the last block flag was set in the last block of the - /// inflated stream. This means that the stream ends after the - /// current block. - /// - bool isLastBlock; - - /// - /// The total number of inflated bytes. - /// - long totalOut; - - /// - /// The total number of bytes set with setInput(). This is not the - /// value returned by the TotalIn property, since this also includes the - /// unprocessed input. - /// - long totalIn; - - /// - /// This variable stores the noHeader flag that was given to the constructor. - /// True means, that the inflated stream doesn't contain a Zlib header or - /// footer. - /// - bool noHeader; - - StreamManipulator input; - OutputWindow outputWindow; - InflaterDynHeader dynHeader; - InflaterHuffmanTree litlenTree, distTree; - Adler32 adler; - #endregion - - #region Constructors - /// - /// Creates a new inflater or RFC1951 decompressor - /// RFC1950/Zlib headers and footers will be expected in the input data - /// - public Inflater() - : this(false) - { - } - - /// - /// Creates a new inflater. - /// - /// - /// True if no RFC1950/Zlib header and footer fields are expected in the input data - /// - /// This is used for GZIPed/Zipped input. - /// - /// For compatibility with - /// Sun JDK you should provide one byte of input more than needed in - /// this case. - /// - public Inflater(bool noHeader) - { - this.noHeader = noHeader; - this.adler = new Adler32(); - input = new StreamManipulator(); - outputWindow = new OutputWindow(); - mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; - } - #endregion - - /// - /// Resets the inflater so that a new stream can be decompressed. All - /// pending input and output will be discarded. - /// - public void Reset() - { - mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; - totalIn = 0; - totalOut = 0; - input.Reset(); - outputWindow.Reset(); - dynHeader = null; - litlenTree = null; - distTree = null; - isLastBlock = false; - adler.Reset(); - } - - /// - /// Decodes a zlib/RFC1950 header. - /// - /// - /// False if more input is needed. - /// - /// - /// The header is invalid. - /// - private bool DecodeHeader() - { - int header = input.PeekBits(16); - if (header < 0) - { - return false; - } - input.DropBits(16); - - // The header is written in "wrong" byte order - header = ((header << 8) | (header >> 8)) & 0xffff; - if (header % 31 != 0) - { - throw new SharpZipBaseException("Header checksum illegal"); - } - - if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) - { - throw new SharpZipBaseException("Compression Method unknown"); - } - - /* Maximum size of the backwards window in bits. - * We currently ignore this, but we could use it to make the - * inflater window more space efficient. On the other hand the - * full window (15 bits) is needed most times, anyway. - int max_wbits = ((header & 0x7000) >> 12) + 8; - */ - - if ((header & 0x0020) == 0) - { // Dictionary flag? - mode = DECODE_BLOCKS; - } - else - { - mode = DECODE_DICT; - neededBits = 32; - } - return true; - } - - /// - /// Decodes the dictionary checksum after the deflate header. - /// - /// - /// False if more input is needed. - /// - private bool DecodeDict() - { - while (neededBits > 0) - { - int dictByte = input.PeekBits(8); - if (dictByte < 0) - { - return false; - } - input.DropBits(8); - readAdler = (readAdler << 8) | dictByte; - neededBits -= 8; - } - return false; - } - - /// - /// Decodes the huffman encoded symbols in the input stream. - /// - /// - /// false if more input is needed, true if output window is - /// full or the current block ends. - /// - /// - /// if deflated stream is invalid. - /// - private bool DecodeHuffman() - { - int free = outputWindow.GetFreeSpace(); - while (free >= 258) - { - int symbol; - switch (mode) - { - case DECODE_HUFFMAN: - // This is the inner loop so it is optimized a bit - while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) - { - outputWindow.Write(symbol); - if (--free < 258) - { - return true; - } - } - - if (symbol < 257) - { - if (symbol < 0) - { - return false; - } - else - { - // symbol == 256: end of block - distTree = null; - litlenTree = null; - mode = DECODE_BLOCKS; - return true; - } - } - - try - { - repLength = CPLENS[symbol - 257]; - neededBits = CPLEXT[symbol - 257]; - } - catch (Exception) - { - throw new SharpZipBaseException("Illegal rep length code"); - } - goto case DECODE_HUFFMAN_LENBITS; // fall through - - case DECODE_HUFFMAN_LENBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_LENBITS; - int i = input.PeekBits(neededBits); - if (i < 0) - { - return false; - } - input.DropBits(neededBits); - repLength += i; - } - mode = DECODE_HUFFMAN_DIST; - goto case DECODE_HUFFMAN_DIST; // fall through - - case DECODE_HUFFMAN_DIST: - symbol = distTree.GetSymbol(input); - if (symbol < 0) - { - return false; - } - - try - { - repDist = CPDIST[symbol]; - neededBits = CPDEXT[symbol]; - } - catch (Exception) - { - throw new SharpZipBaseException("Illegal rep dist code"); - } - - goto case DECODE_HUFFMAN_DISTBITS; // fall through - - case DECODE_HUFFMAN_DISTBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_DISTBITS; - int i = input.PeekBits(neededBits); - if (i < 0) - { - return false; - } - input.DropBits(neededBits); - repDist += i; - } - - outputWindow.Repeat(repLength, repDist); - free -= repLength; - mode = DECODE_HUFFMAN; - break; - - default: - throw new SharpZipBaseException("Inflater unknown mode"); - } - } - return true; - } - - /// - /// Decodes the adler checksum after the deflate stream. - /// - /// - /// false if more input is needed. - /// - /// - /// If checksum doesn't match. - /// - private bool DecodeChksum() - { - while (neededBits > 0) - { - int chkByte = input.PeekBits(8); - if (chkByte < 0) - { - return false; - } - input.DropBits(8); - readAdler = (readAdler << 8) | chkByte; - neededBits -= 8; - } - - if ((int)adler.Value != readAdler) - { - throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler); - } - - mode = FINISHED; - return false; - } - - /// - /// Decodes the deflated stream. - /// - /// - /// false if more input is needed, or if finished. - /// - /// - /// if deflated stream is invalid. - /// - private bool Decode() - { - switch (mode) - { - case DECODE_HEADER: - return DecodeHeader(); - - case DECODE_DICT: - return DecodeDict(); - - case DECODE_CHKSUM: - return DecodeChksum(); - - case DECODE_BLOCKS: - if (isLastBlock) - { - if (noHeader) - { - mode = FINISHED; - return false; - } - else - { - input.SkipToByteBoundary(); - neededBits = 32; - mode = DECODE_CHKSUM; - return true; - } - } - - int type = input.PeekBits(3); - if (type < 0) - { - return false; - } - input.DropBits(3); - - if ((type & 1) != 0) - { - isLastBlock = true; - } - switch (type >> 1) - { - case DeflaterConstants.STORED_BLOCK: - input.SkipToByteBoundary(); - mode = DECODE_STORED_LEN1; - break; - case DeflaterConstants.STATIC_TREES: - litlenTree = InflaterHuffmanTree.defLitLenTree; - distTree = InflaterHuffmanTree.defDistTree; - mode = DECODE_HUFFMAN; - break; - case DeflaterConstants.DYN_TREES: - dynHeader = new InflaterDynHeader(); - mode = DECODE_DYN_HEADER; - break; - default: - throw new SharpZipBaseException("Unknown block type " + type); - } - return true; - - case DECODE_STORED_LEN1: - { - if ((uncomprLen = input.PeekBits(16)) < 0) - { - return false; - } - input.DropBits(16); - mode = DECODE_STORED_LEN2; - } - goto case DECODE_STORED_LEN2; // fall through - - case DECODE_STORED_LEN2: - { - int nlen = input.PeekBits(16); - if (nlen < 0) - { - return false; - } - input.DropBits(16); - if (nlen != (uncomprLen ^ 0xffff)) - { - throw new SharpZipBaseException("broken uncompressed block"); - } - mode = DECODE_STORED; - } - goto case DECODE_STORED; // fall through - - case DECODE_STORED: - { - int more = outputWindow.CopyStored(input, uncomprLen); - uncomprLen -= more; - if (uncomprLen == 0) - { - mode = DECODE_BLOCKS; - return true; - } - return !input.IsNeedingInput; - } - - case DECODE_DYN_HEADER: - if (!dynHeader.Decode(input)) - { - return false; - } - - litlenTree = dynHeader.BuildLitLenTree(); - distTree = dynHeader.BuildDistTree(); - mode = DECODE_HUFFMAN; - goto case DECODE_HUFFMAN; // fall through - - case DECODE_HUFFMAN: - case DECODE_HUFFMAN_LENBITS: - case DECODE_HUFFMAN_DIST: - case DECODE_HUFFMAN_DISTBITS: - return DecodeHuffman(); - - case FINISHED: - return false; - - default: - throw new SharpZipBaseException("Inflater.Decode unknown mode"); - } - } - - /// - /// Sets the preset dictionary. This should only be called, if - /// needsDictionary() returns true and it should set the same - /// dictionary, that was used for deflating. The getAdler() - /// function returns the checksum of the dictionary needed. - /// - /// - /// The dictionary. - /// - public void SetDictionary(byte[] buffer) - { - SetDictionary(buffer, 0, buffer.Length); - } - - /// - /// Sets the preset dictionary. This should only be called, if - /// needsDictionary() returns true and it should set the same - /// dictionary, that was used for deflating. The getAdler() - /// function returns the checksum of the dictionary needed. - /// - /// - /// The dictionary. - /// - /// - /// The index into buffer where the dictionary starts. - /// - /// - /// The number of bytes in the dictionary. - /// - /// - /// No dictionary is needed. - /// - /// - /// The adler checksum for the buffer is invalid - /// - public void SetDictionary(byte[] buffer, int index, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (index < 0) - { - throw new ArgumentOutOfRangeException("index"); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - if (!IsNeedingDictionary) - { - throw new InvalidOperationException("Dictionary is not needed"); - } - - adler.Update(buffer, index, count); - - if ((int)adler.Value != readAdler) - { - throw new SharpZipBaseException("Wrong adler checksum"); - } - adler.Reset(); - outputWindow.CopyDict(buffer, index, count); - mode = DECODE_BLOCKS; - } - - /// - /// Sets the input. This should only be called, if needsInput() - /// returns true. - /// - /// - /// the input. - /// - public void SetInput(byte[] buffer) - { - SetInput(buffer, 0, buffer.Length); - } - - /// - /// Sets the input. This should only be called, if needsInput() - /// returns true. - /// - /// - /// The source of input data - /// - /// - /// The index into buffer where the input starts. - /// - /// - /// The number of bytes of input to use. - /// - /// - /// No input is needed. - /// - /// - /// The index and/or count are wrong. - /// - public void SetInput(byte[] buffer, int index, int count) - { - input.SetInput(buffer, index, count); - totalIn += (long)count; - } - - /// - /// Inflates the compressed stream to the output buffer. If this - /// returns 0, you should check, whether IsNeedingDictionary(), - /// IsNeedingInput() or IsFinished() returns true, to determine why no - /// further output is produced. - /// - /// - /// the output buffer. - /// - /// - /// The number of bytes written to the buffer, 0 if no further - /// output can be produced. - /// - /// - /// if buffer has length 0. - /// - /// - /// if deflated stream is invalid. - /// - public int Inflate(byte[] buffer) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - return Inflate(buffer, 0, buffer.Length); - } - - /// - /// Inflates the compressed stream to the output buffer. If this - /// returns 0, you should check, whether needsDictionary(), - /// needsInput() or finished() returns true, to determine why no - /// further output is produced. - /// - /// - /// the output buffer. - /// - /// - /// the offset in buffer where storing starts. - /// - /// - /// the maximum number of bytes to output. - /// - /// - /// the number of bytes written to the buffer, 0 if no further output can be produced. - /// - /// - /// if count is less than 0. - /// - /// - /// if the index and / or count are wrong. - /// - /// - /// if deflated stream is invalid. - /// - public int Inflate(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (count < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("count"); -#else - throw new ArgumentOutOfRangeException("count", "count cannot be negative"); -#endif - } - - if (offset < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("offset"); -#else - throw new ArgumentOutOfRangeException("offset", "offset cannot be negative"); -#endif - } - - if (offset + count > buffer.Length) - { - throw new ArgumentException("count exceeds buffer bounds"); - } - - // Special case: count may be zero - if (count == 0) - { - if (!IsFinished) - { // -jr- 08-Nov-2003 INFLATE_BUG fix.. - Decode(); - } - return 0; - } - - int bytesCopied = 0; - - do - { - if (mode != DECODE_CHKSUM) - { - /* Don't give away any output, if we are waiting for the - * checksum in the input stream. - * - * With this trick we have always: - * IsNeedingInput() and not IsFinished() - * implies more output can be produced. - */ - int more = outputWindow.CopyOutput(buffer, offset, count); - if (more > 0) - { - adler.Update(buffer, offset, more); - offset += more; - bytesCopied += more; - totalOut += (long)more; - count -= more; - if (count == 0) - { - return bytesCopied; - } - } - } - } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM))); - return bytesCopied; - } - - /// - /// Returns true, if the input buffer is empty. - /// You should then call setInput(). - /// NOTE: This method also returns true when the stream is finished. - /// - public bool IsNeedingInput - { - get - { - return input.IsNeedingInput; - } - } - - /// - /// Returns true, if a preset dictionary is needed to inflate the input. - /// - public bool IsNeedingDictionary - { - get - { - return mode == DECODE_DICT && neededBits == 0; - } - } - - /// - /// Returns true, if the inflater has finished. This means, that no - /// input is needed and no output can be produced. - /// - public bool IsFinished - { - get - { - return mode == FINISHED && outputWindow.GetAvailable() == 0; - } - } - - /// - /// Gets the adler checksum. This is either the checksum of all - /// uncompressed bytes returned by inflate(), or if needsDictionary() - /// returns true (and thus no output was yet produced) this is the - /// adler checksum of the expected dictionary. - /// - /// - /// the adler checksum. - /// - public int Adler - { - get - { - return IsNeedingDictionary ? readAdler : (int)adler.Value; - } - } - - /// - /// Gets the total number of output bytes returned by Inflate(). - /// - /// - /// the total number of output bytes. - /// - public long TotalOut - { - get - { - return totalOut; - } - } - - /// - /// Gets the total number of processed compressed input bytes. - /// - /// - /// The total number of bytes of processed input bytes. - /// - public long TotalIn - { - get - { - return totalIn - (long)RemainingInput; - } - } - - /// - /// Gets the number of unprocessed input bytes. Useful, if the end of the - /// stream is reached and you want to further process the bytes after - /// the deflate stream. - /// - /// - /// The number of bytes of the input which have not been processed. - /// - public int RemainingInput - { - // TODO: This should be a long? - get - { - return input.AvailableBytes; - } - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterDynHeader.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterDynHeader.cs deleted file mode 100644 index ee5fa159..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterDynHeader.cs +++ /dev/null @@ -1,224 +0,0 @@ -// InflaterDynHeader.cs -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -using PdfSharpCore.SharpZipLib.Zip.Compression.Streams; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - class InflaterDynHeader - { - const int LNUM = 0; - const int DNUM = 1; - const int BLNUM = 2; - const int BLLENS = 3; - const int LENS = 4; - const int REPS = 5; - - static readonly int[] repMin = { 3, 3, 11 }; - static readonly int[] repBits = { 2, 3, 7 }; - - byte[] blLens; - byte[] litdistLens; - - InflaterHuffmanTree blTree; - - int mode; - int lnum, dnum, blnum, num; - int repSymbol; - byte lastLen; - int ptr; - - static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - - public InflaterDynHeader() - { - } - - public bool Decode(StreamManipulator input) - { - decode_loop: - for (; ; ) - { - switch (mode) - { - case LNUM: - lnum = input.PeekBits(5); - if (lnum < 0) - { - return false; - } - lnum += 257; - input.DropBits(5); - // System.err.println("LNUM: "+lnum); - mode = DNUM; - goto case DNUM; // fall through - case DNUM: - dnum = input.PeekBits(5); - if (dnum < 0) - { - return false; - } - dnum++; - input.DropBits(5); - // System.err.println("DNUM: "+dnum); - num = lnum + dnum; - litdistLens = new byte[num]; - mode = BLNUM; - goto case BLNUM; // fall through - case BLNUM: - blnum = input.PeekBits(4); - if (blnum < 0) - { - return false; - } - blnum += 4; - input.DropBits(4); - blLens = new byte[19]; - ptr = 0; - // System.err.println("BLNUM: "+blnum); - mode = BLLENS; - goto case BLLENS; // fall through - case BLLENS: - while (ptr < blnum) - { - int len = input.PeekBits(3); - if (len < 0) - { - return false; - } - input.DropBits(3); - // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); - blLens[BL_ORDER[ptr]] = (byte)len; - ptr++; - } - blTree = new InflaterHuffmanTree(blLens); - blLens = null; - ptr = 0; - mode = LENS; - goto case LENS; // fall through - case LENS: - { - int symbol; - while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) - { - /* Normal case: symbol in [0..15] */ - - // System.err.println("litdistLens["+ptr+"]: "+symbol); - litdistLens[ptr++] = lastLen = (byte)symbol; - - if (ptr == num) - { - /* Finished */ - return true; - } - } - - /* need more input ? */ - if (symbol < 0) - { - return false; - } - - /* otherwise repeat code */ - if (symbol >= 17) - { - /* repeat zero */ - // System.err.println("repeating zero"); - lastLen = 0; - } - else - { - if (ptr == 0) - { - throw new SharpZipBaseException(); - } - } - repSymbol = symbol - 16; - } - mode = REPS; - goto case REPS; // fall through - case REPS: - { - int bits = repBits[repSymbol]; - int count = input.PeekBits(bits); - if (count < 0) - { - return false; - } - input.DropBits(bits); - count += repMin[repSymbol]; - // System.err.println("litdistLens repeated: "+count); - - if (ptr + count > num) - { - throw new SharpZipBaseException(); - } - while (count-- > 0) - { - litdistLens[ptr++] = lastLen; - } - - if (ptr == num) - { - /* Finished */ - return true; - } - } - mode = LENS; - goto decode_loop; - } - } - } - - public InflaterHuffmanTree BuildLitLenTree() - { - byte[] litlenLens = new byte[lnum]; - Array.Copy(litdistLens, 0, litlenLens, 0, lnum); - return new InflaterHuffmanTree(litlenLens); - } - - public InflaterHuffmanTree BuildDistTree() - { - byte[] distLens = new byte[dnum]; - Array.Copy(litdistLens, lnum, distLens, 0, dnum); - return new InflaterHuffmanTree(distLens); - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs deleted file mode 100644 index 2a4971d8..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs +++ /dev/null @@ -1,258 +0,0 @@ -// InflaterHuffmanTree.cs -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -using PdfSharpCore.SharpZipLib.Zip.Compression.Streams; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - /// - /// Huffman tree used for inflation - /// - internal class InflaterHuffmanTree - { - static int MAX_BITLEN = 15; - short[] tree; - - /// - /// Literal length tree - /// - public static InflaterHuffmanTree defLitLenTree; - - /// - /// Distance tree - /// - public static InflaterHuffmanTree defDistTree; - - static InflaterHuffmanTree() - { - try - { - byte[] codeLengths = new byte[288]; - int i = 0; - while (i < 144) - { - codeLengths[i++] = 8; - } - while (i < 256) - { - codeLengths[i++] = 9; - } - while (i < 280) - { - codeLengths[i++] = 7; - } - while (i < 288) - { - codeLengths[i++] = 8; - } - defLitLenTree = new InflaterHuffmanTree(codeLengths); - - codeLengths = new byte[32]; - i = 0; - while (i < 32) - { - codeLengths[i++] = 5; - } - defDistTree = new InflaterHuffmanTree(codeLengths); - } - catch (Exception) - { - throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal"); - } - } - - /// - /// Constructs a Huffman tree from the array of code lengths. - /// - /// - /// the array of code lengths - /// - public InflaterHuffmanTree(byte[] codeLengths) - { - BuildTree(codeLengths); - } - - void BuildTree(byte[] codeLengths) - { - int[] blCount = new int[MAX_BITLEN + 1]; - int[] nextCode = new int[MAX_BITLEN + 1]; - - for (int i = 0; i < codeLengths.Length; i++) - { - int bits = codeLengths[i]; - if (bits > 0) - { - blCount[bits]++; - } - } - - int code = 0; - int treeSize = 512; - for (int bits = 1; bits <= MAX_BITLEN; bits++) - { - nextCode[bits] = code; - code += blCount[bits] << (16 - bits); - if (bits >= 10) - { - /* We need an extra table for bit lengths >= 10. */ - int start = nextCode[bits] & 0x1ff80; - int end = code & 0x1ff80; - treeSize += (end - start) >> (16 - bits); - } - } - - /* -jr comment this out! doesn't work for dynamic trees and pkzip 2.04g - if (code != 65536) - { - throw new SharpZipBaseException("Code lengths don't add up properly."); - } - */ - /* Now create and fill the extra tables from longest to shortest - * bit len. This way the sub trees will be aligned. - */ - tree = new short[treeSize]; - int treePtr = 512; - for (int bits = MAX_BITLEN; bits >= 10; bits--) - { - int end = code & 0x1ff80; - code -= blCount[bits] << (16 - bits); - int start = code & 0x1ff80; - for (int i = start; i < end; i += 1 << 7) - { - tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits); - treePtr += 1 << (bits - 9); - } - } - - for (int i = 0; i < codeLengths.Length; i++) - { - int bits = codeLengths[i]; - if (bits == 0) - { - continue; - } - code = nextCode[bits]; - int revcode = DeflaterHuffman.BitReverse(code); - if (bits <= 9) - { - do - { - tree[revcode] = (short)((i << 4) | bits); - revcode += 1 << bits; - } while (revcode < 512); - } - else - { - int subTree = tree[revcode & 511]; - int treeLen = 1 << (subTree & 15); - subTree = -(subTree >> 4); - do - { - tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits); - revcode += 1 << bits; - } while (revcode < treeLen); - } - nextCode[bits] = code + (1 << (16 - bits)); - } - - } - - /// - /// Reads the next symbol from input. The symbol is encoded using the - /// huffman tree. - /// - /// - /// input the input source. - /// - /// - /// the next symbol, or -1 if not enough input is available. - /// - public int GetSymbol(StreamManipulator input) - { - int lookahead, symbol; - if ((lookahead = input.PeekBits(9)) >= 0) - { - if ((symbol = tree[lookahead]) >= 0) - { - input.DropBits(symbol & 15); - return symbol >> 4; - } - int subtree = -(symbol >> 4); - int bitlen = symbol & 15; - if ((lookahead = input.PeekBits(bitlen)) >= 0) - { - symbol = tree[subtree | (lookahead >> 9)]; - input.DropBits(symbol & 15); - return symbol >> 4; - } - else - { - int bits = input.AvailableBits; - lookahead = input.PeekBits(bits); - symbol = tree[subtree | (lookahead >> 9)]; - if ((symbol & 15) <= bits) - { - input.DropBits(symbol & 15); - return symbol >> 4; - } - else - { - return -1; - } - } - } - else - { - int bits = input.AvailableBits; - lookahead = input.PeekBits(bits); - symbol = tree[lookahead]; - if (symbol >= 0 && (symbol & 15) <= bits) - { - input.DropBits(symbol & 15); - return symbol >> 4; - } - else - { - return -1; - } - } - } - } -} - diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/PendingBuffer.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/PendingBuffer.cs deleted file mode 100644 index 06612fe5..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/PendingBuffer.cs +++ /dev/null @@ -1,306 +0,0 @@ -// PendingBuffer.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression -{ - - /// - /// This class is general purpose class for writing data to a buffer. - /// - /// It allows you to write bits as well as bytes - /// Based on DeflaterPending.java - /// - /// Author of the original java version: Jochen Hoenicke - /// - internal class PendingBuffer - { - #region Instance Fields - /// - /// Internal work buffer - /// - byte[] buffer_; - - int start; - int end; - - uint bits; - int bitCount; - #endregion - - #region Constructors - /// - /// construct instance using default buffer size of 4096 - /// - public PendingBuffer() - : this(4096) - { - } - - /// - /// construct instance using specified buffer size - /// - /// - /// size to use for internal buffer - /// - public PendingBuffer(int bufferSize) - { - buffer_ = new byte[bufferSize]; - } - - #endregion - - /// - /// Clear internal state/buffers - /// - public void Reset() - { - start = end = bitCount = 0; - } - - /// - /// Write a byte to buffer - /// - /// - /// The value to write - /// - public void WriteByte(int value) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - buffer_[end++] = unchecked((byte)value); - } - - /// - /// Write a short value to buffer LSB first - /// - /// - /// The value to write. - /// - public void WriteShort(int value) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - buffer_[end++] = unchecked((byte)value); - buffer_[end++] = unchecked((byte)(value >> 8)); - } - - /// - /// write an integer LSB first - /// - /// The value to write. - public void WriteInt(int value) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - buffer_[end++] = unchecked((byte)value); - buffer_[end++] = unchecked((byte)(value >> 8)); - buffer_[end++] = unchecked((byte)(value >> 16)); - buffer_[end++] = unchecked((byte)(value >> 24)); - } - - /// - /// Write a block of data to buffer - /// - /// data to write - /// offset of first byte to write - /// number of bytes to write - public void WriteBlock(byte[] block, int offset, int length) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - System.Array.Copy(block, offset, buffer_, end, length); - end += length; - } - - /// - /// The number of bits written to the buffer - /// - public int BitCount - { - get - { - return bitCount; - } - } - - /// - /// Align internal buffer on a byte boundary - /// - public void AlignToByte() - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - if (bitCount > 0) - { - buffer_[end++] = unchecked((byte)bits); - if (bitCount > 8) - { - buffer_[end++] = unchecked((byte)(bits >> 8)); - } - } - bits = 0; - bitCount = 0; - } - - /// - /// Write bits to internal buffer - /// - /// source of bits - /// number of bits to write - public void WriteBits(int b, int count) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } - - // if (DeflaterConstants.DEBUGGING) { - // //Console.WriteLine("writeBits("+b+","+count+")"); - // } -#endif - bits |= (uint)(b << bitCount); - bitCount += count; - if (bitCount >= 16) - { - buffer_[end++] = unchecked((byte)bits); - buffer_[end++] = unchecked((byte)(bits >> 8)); - bits >>= 16; - bitCount -= 16; - } - } - - /// - /// Write a short value to internal buffer most significant byte first - /// - /// value to write - public void WriteShortMSB(int s) - { -#if DebugDeflation - if (DeflaterConstants.DEBUGGING && (start != 0) ) - { - throw new SharpZipBaseException("Debug check: start != 0"); - } -#endif - buffer_[end++] = unchecked((byte)(s >> 8)); - buffer_[end++] = unchecked((byte)s); - } - - /// - /// Indicates if buffer has been flushed - /// - public bool IsFlushed - { - get - { - return end == 0; - } - } - - /// - /// Flushes the pending buffer into the given output array. If the - /// output array is to small, only a partial flush is done. - /// - /// The output array. - /// The offset into output array. - /// The maximum number of bytes to store. - /// The number of bytes flushed. - public int Flush(byte[] output, int offset, int length) - { - if (bitCount >= 8) - { - buffer_[end++] = unchecked((byte)bits); - bits >>= 8; - bitCount -= 8; - } - - if (length > end - start) - { - length = end - start; - System.Array.Copy(buffer_, start, output, offset, length); - start = 0; - end = 0; - } - else - { - System.Array.Copy(buffer_, start, output, offset, length); - start += length; - } - return length; - } - - /// - /// Convert internal buffer to byte array. - /// Buffer is empty on completion - /// - /// - /// The internal buffer contents converted to a byte array. - /// - public byte[] ToByteArray() - { - byte[] result = new byte[end - start]; - System.Array.Copy(buffer_, start, result, 0, result.Length); - start = 0; - end = 0; - return result; - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs deleted file mode 100644 index 2bc239e8..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs +++ /dev/null @@ -1,676 +0,0 @@ -// DeflaterOutputStream.cs -// -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -// HISTORY -// 22-12-2009 DavidPierson Added AES support - -using System; -using System.IO; -using PdfSharpCore.SharpZipLib.Checksums; - -// ReSharper disable RedundantThisQualifier - -//#if !NETCF_1_0 -//using System.Security.Cryptography; -//using PdfSharpCore.SharpZipLib.Encryption; -//#endif - -namespace PdfSharpCore.SharpZipLib.Zip.Compression.Streams -{ - /// - /// A special stream deflating or compressing the bytes that are - /// written to it. It uses a Deflater to perform actual deflating.
- /// Authors of the original java version: Tom Tromey, Jochen Hoenicke - ///
- internal class DeflaterOutputStream : Stream - { - #region Constructors - /// - /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size. - /// - /// - /// the output stream where deflated output should be written. - /// - public DeflaterOutputStream(Stream baseOutputStream) - : this(baseOutputStream, new Deflater(), 512) - { - } - - /// - /// Creates a new DeflaterOutputStream with the given Deflater and - /// default buffer size. - /// - /// - /// the output stream where deflated output should be written. - /// - /// - /// the underlying deflater. - /// - public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater) - : this(baseOutputStream, deflater, 512) - { - } - - /// - /// Creates a new DeflaterOutputStream with the given Deflater and - /// buffer size. - /// - /// - /// The output stream where deflated output is written. - /// - /// - /// The underlying deflater to use - /// - /// - /// The buffer size in bytes to use when deflating (minimum value 512) - /// - /// - /// bufsize is less than or equal to zero. - /// - /// - /// baseOutputStream does not support writing - /// - /// - /// deflater instance is null - /// - public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize) - { - if (baseOutputStream == null) - { - throw new ArgumentNullException("baseOutputStream"); - } - - if (baseOutputStream.CanWrite == false) - { - throw new ArgumentException("Must support writing", "baseOutputStream"); - } - - if (deflater == null) - { - throw new ArgumentNullException("deflater"); - } - - if (bufferSize < 512) - { - throw new ArgumentOutOfRangeException("bufferSize"); - } - - baseOutputStream_ = baseOutputStream; - buffer_ = new byte[bufferSize]; - deflater_ = deflater; - } - #endregion - - #region Public API - /// - /// Finishes the stream by calling finish() on the deflater. - /// - /// - /// Not all input is deflated - /// - public virtual void Finish() - { - deflater_.Finish(); - while (!deflater_.IsFinished) - { - int len = deflater_.Deflate(buffer_, 0, buffer_.Length); - if (len <= 0) - { - break; - } - -#if true//NETCF_1_0 - if (keys != null) - { -#else - if (cryptoTransform_ != null) { -#endif - EncryptBlock(buffer_, 0, len); - } - - baseOutputStream_.Write(buffer_, 0, len); - } - - if (!deflater_.IsFinished) - { - throw new SharpZipBaseException("Can't deflate all input?"); - } - - baseOutputStream_.Flush(); - -#if true//NETCF_1_0 - if (keys != null) - { - keys = null; - } -#else - if (cryptoTransform_ != null) { -#if !NET_1_1 && !NETCF_2_0 - if (cryptoTransform_ is ZipAESTransform) { - AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode(); - } -#endif - cryptoTransform_.Dispose(); - cryptoTransform_ = null; - } -#endif - } - - /// - /// Get/set flag indicating ownership of the underlying stream. - /// When the flag is true will close the underlying stream also. - /// - public bool IsStreamOwner - { - get { return isStreamOwner_; } - set { isStreamOwner_ = value; } - } - - /// - /// Allows client to determine if an entry can be patched after its added - /// - public bool CanPatchEntries - { - get - { - return baseOutputStream_.CanSeek; - } - } - - #endregion - - #region Encryption - - string password; - -#if true//NETCF_1_0 - uint[] keys; -#else - ICryptoTransform cryptoTransform_; - - /// - /// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream. - /// - protected byte[] AESAuthCode; -#endif - - /// - /// Get/set the password used for encryption. - /// - /// When set to null or if the password is empty no encryption is performed - public string Password - { - get - { - return password; - } - set - { - if ((value != null) && (value.Length == 0)) - { - password = null; - } - else - { - password = value; - } - } - } - - /// - /// Encrypt a block of data - /// - /// - /// Data to encrypt. NOTE the original contents of the buffer are lost - /// - /// - /// Offset of first byte in buffer to encrypt - /// - /// - /// Number of bytes in buffer to encrypt - /// - protected void EncryptBlock(byte[] buffer, int offset, int length) - { -#if true//NETCF_1_0 - for (int i = offset; i < offset + length; ++i) - { - byte oldbyte = buffer[i]; - buffer[i] ^= EncryptByte(); - UpdateKeys(oldbyte); - } -#else - cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0); -#endif - } - - /// - /// Initializes encryption keys based on given . - /// - /// The password. - protected void InitializePassword(string password) - { -#if true//NETCF_1_0 - keys = new uint[] { - 0x12345678, - 0x23456789, - 0x34567890 - }; - - byte[] rawPassword = ZipConstants.ConvertToArray(password); - - for (int i = 0; i < rawPassword.Length; ++i) - { - UpdateKeys((byte)rawPassword[i]); - } - -#else - PkzipClassicManaged pkManaged = new PkzipClassicManaged(); - byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password)); - cryptoTransform_ = pkManaged.CreateEncryptor(key, null); -#endif - } - -#if false//!NET_1_1 && !NETCF_2_0 - /// - /// Initializes encryption keys based on given password. - /// - protected void InitializeAESPassword(ZipEntry entry, string rawPassword, - out byte[] salt, out byte[] pwdVerifier) { - salt = new byte[entry.AESSaltLen]; - // Salt needs to be cryptographically random, and unique per file - if (_aesRnd == null) - _aesRnd = new RNGCryptoServiceProvider(); - _aesRnd.GetBytes(salt); - int blockSize = entry.AESKeySize / 8; // bits to bytes - - cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true); - pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier; - } -#endif - -#if true//NETCF_1_0 - - /// - /// Encrypt a single byte - /// - /// - /// The encrypted value - /// - protected byte EncryptByte() - { - uint temp = ((keys[2] & 0xFFFF) | 2); - return (byte)((temp * (temp ^ 1)) >> 8); - } - - /// - /// Update encryption keys - /// - protected void UpdateKeys(byte ch) - { - keys[0] = Crc32.ComputeCrc32(keys[0], ch); - keys[1] = keys[1] + (byte)keys[0]; - keys[1] = keys[1] * 134775813 + 1; - keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24)); - } -#endif - - #endregion - - #region Deflation Support - /// - /// Deflates everything in the input buffers. This will call - /// def.deflate() until all bytes from the input buffers - /// are processed. - /// - protected void Deflate() - { - while (!deflater_.IsNeedingInput) - { - int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length); - - if (deflateCount <= 0) - { - break; - } -#if true//NETCF_1_0 - if (keys != null) -#else - if (cryptoTransform_ != null) -#endif - { - EncryptBlock(buffer_, 0, deflateCount); - } - - baseOutputStream_.Write(buffer_, 0, deflateCount); - } - - if (!deflater_.IsNeedingInput) - { - throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?"); - } - } - #endregion - - #region Stream Overrides - /// - /// Gets value indicating stream can be read from - /// - public override bool CanRead - { - get - { - return false; - } - } - - /// - /// Gets a value indicating if seeking is supported for this stream - /// This property always returns false - /// - public override bool CanSeek - { - get - { - return false; - } - } - - /// - /// Get value indicating if this stream supports writing - /// - public override bool CanWrite - { - get - { - return baseOutputStream_.CanWrite; - } - } - - /// - /// Get current length of stream - /// - public override long Length - { - get - { - return baseOutputStream_.Length; - } - } - - /// - /// Gets the current position within the stream. - /// - /// Any attempt to set position - public override long Position - { - get - { - return baseOutputStream_.Position; - } - set - { - throw new NotSupportedException("Position property not supported"); - } - } - - /// - /// Sets the current position of this stream to the given value. Not supported by this class! - /// - /// The offset relative to the to seek. - /// The to seek from. - /// The new position in the stream. - /// Any access - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException("DeflaterOutputStream Seek not supported"); - } - - /// - /// Sets the length of this stream to the given value. Not supported by this class! - /// - /// The new stream length. - /// Any access - public override void SetLength(long value) - { - throw new NotSupportedException("DeflaterOutputStream SetLength not supported"); - } - - /// - /// Read a byte from stream advancing position by one - /// - /// The byte read cast to an int. THe value is -1 if at the end of the stream. - /// Any access - public override int ReadByte() - { - throw new NotSupportedException("DeflaterOutputStream ReadByte not supported"); - } - - /// - /// Read a block of bytes from stream - /// - /// The buffer to store read data in. - /// The offset to start storing at. - /// The maximum number of bytes to read. - /// The actual number of bytes read. Zero if end of stream is detected. - /// Any access - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException("DeflaterOutputStream Read not supported"); - } - -#if !NETFX_CORE && !UWP && !PORTABLE - /// - /// Asynchronous reads are not supported a NotSupportedException is always thrown - /// - /// The buffer to read into. - /// The offset to start storing data at. - /// The number of bytes to read - /// The async callback to use. - /// The state to use. - /// Returns an - /// Any access - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported"); - } -#endif - -#if !NETFX_CORE && !UWP && !PORTABLE - /// - /// Asynchronous writes arent supported, a NotSupportedException is always thrown - /// - /// The buffer to write. - /// The offset to begin writing at. - /// The number of bytes to write. - /// The to use. - /// The state object. - /// Returns an IAsyncResult. - /// Any access - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - throw new NotSupportedException("BeginWrite is not supported"); - } -#endif - - /// - /// Flushes the stream by calling Flush on the deflater and then - /// on the underlying stream. This ensures that all bytes are flushed. - /// - public override void Flush() - { - deflater_.Flush(); - Deflate(); - baseOutputStream_.Flush(); - } - -#if !NETFX_CORE && !UWP && !PORTABLE - /// - /// Calls and closes the underlying - /// stream when is true. - /// - public override void Close() - { - if ( !isClosed_ ) { - isClosed_ = true; - - try { - Finish(); -#if true//NETCF_1_0 - keys =null; -#else - if ( cryptoTransform_ != null ) { - GetAuthCodeIfAES(); - cryptoTransform_.Dispose(); - cryptoTransform_ = null; - } -#endif - } - finally { - if( isStreamOwner_ ) { - baseOutputStream_.Close(); - } - } - } - } -#else - public void Close() - { - if (!isClosed_) - { - isClosed_ = true; - - try - { - Finish(); -#if true//NETCF_1_0 - keys = null; -#else - if ( cryptoTransform_ != null ) { - GetAuthCodeIfAES(); - cryptoTransform_.Dispose(); - cryptoTransform_ = null; - } -#endif - } - finally - { - if (isStreamOwner_) - { - //baseOutputStream_.Close(); - baseOutputStream_.Dispose(); - } - } - } - } -#endif - - - private void GetAuthCodeIfAES() - { -#if false//!NET_1_1 && !NETCF_2_0 - if (cryptoTransform_ is ZipAESTransform) { - AESAuthCode = ((ZipAESTransform)cryptoTransform_).GetAuthCode(); - } -#endif - } - - /// - /// Writes a single byte to the compressed output stream. - /// - /// - /// The byte value. - /// - public override void WriteByte(byte value) - { - byte[] b = new byte[1]; - b[0] = value; - Write(b, 0, 1); - } - - /// - /// Writes bytes from an array to the compressed stream. - /// - /// - /// The byte array - /// - /// - /// The offset into the byte array where to start. - /// - /// - /// The number of bytes to write. - /// - public override void Write(byte[] buffer, int offset, int count) - { - deflater_.SetInput(buffer, offset, count); - Deflate(); - } - #endregion - - #region Instance Fields - /// - /// This buffer is used temporarily to retrieve the bytes from the - /// deflater and write them to the underlying output stream. - /// - byte[] buffer_; - - /// - /// The deflater which is used to deflate the stream. - /// - protected Deflater deflater_; - - /// - /// Base stream the deflater depends on. - /// - protected Stream baseOutputStream_; - -#if true || !NETFX_CORE && !UWP - bool isClosed_; -#endif - - bool isStreamOwner_ = true; - #endregion - - #region Static Fields - -#if false//!NET_1_1 && !NETCF_2_0 - // Static to help ensure that multiple files within a zip will get different random salt - private static RNGCryptoServiceProvider _aesRnd; -#endif - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs deleted file mode 100644 index d96212a8..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs +++ /dev/null @@ -1,811 +0,0 @@ -// InflaterInputStream.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -// HISTORY -// 11-08-2009 GeoffHart T9121 Added Multi-member gzip support - -using System; -using System.IO; - -// ReSharper disable RedundantThisQualifier - -#if false//!NETCF_1_0 -using System.Security.Cryptography; -#endif - -namespace PdfSharpCore.SharpZipLib.Zip.Compression.Streams -{ - - /// - /// An input buffer customised for use by - /// - /// - /// The buffer supports decryption of incoming data. - /// - internal class InflaterInputBuffer - { - #region Constructors - /// - /// Initialise a new instance of with a default buffer size - /// - /// The stream to buffer. - public InflaterInputBuffer(Stream stream) - : this(stream, 4096) - { - } - - /// - /// Initialise a new instance of - /// - /// The stream to buffer. - /// The size to use for the buffer - /// A minimum buffer size of 1KB is permitted. Lower sizes are treated as 1KB. - public InflaterInputBuffer(Stream stream, int bufferSize) - { - inputStream = stream; - if (bufferSize < 1024) - { - bufferSize = 1024; - } - rawData = new byte[bufferSize]; - clearText = rawData; - } - #endregion - - /// - /// Get the length of bytes bytes in the - /// - public int RawLength - { - get - { - return rawLength; - } - } - - /// - /// Get the contents of the raw data buffer. - /// - /// This may contain encrypted data. - public byte[] RawData - { - get - { - return rawData; - } - } - - /// - /// Get the number of useable bytes in - /// - public int ClearTextLength - { - get - { - return clearTextLength; - } - } - - /// - /// Get the contents of the clear text buffer. - /// - public byte[] ClearText - { - get - { - return clearText; - } - } - - /// - /// Get/set the number of bytes available - /// - public int Available - { - get { return available; } - set { available = value; } - } - - /// - /// Call passing the current clear text buffer contents. - /// - /// The inflater to set input for. - public void SetInflaterInput(Inflater inflater) - { - if (available > 0) - { - inflater.SetInput(clearText, clearTextLength - available, available); - available = 0; - } - } - - /// - /// Fill the buffer from the underlying input stream. - /// - public void Fill() - { - rawLength = 0; - int toRead = rawData.Length; - - while (toRead > 0) - { - int count = inputStream.Read(rawData, rawLength, toRead); - if (count <= 0) - { - break; - } - rawLength += count; - toRead -= count; - } - -#if false//!NETCF_1_0 - if ( cryptoTransform != null ) { - clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0); - } - else -#endif - { - clearTextLength = rawLength; - } - - available = clearTextLength; - } - - /// - /// Read a buffer directly from the input stream - /// - /// The buffer to fill - /// Returns the number of bytes read. - public int ReadRawBuffer(byte[] buffer) - { - return ReadRawBuffer(buffer, 0, buffer.Length); - } - - /// - /// Read a buffer directly from the input stream - /// - /// The buffer to read into - /// The offset to start reading data into. - /// The number of bytes to read. - /// Returns the number of bytes read. - public int ReadRawBuffer(byte[] outBuffer, int offset, int length) - { - if (length < 0) - { - throw new ArgumentOutOfRangeException("length"); - } - - int currentOffset = offset; - int currentLength = length; - - while (currentLength > 0) - { - if (available <= 0) - { - Fill(); - if (available <= 0) - { - return 0; - } - } - int toCopy = Math.Min(currentLength, available); - System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy); - currentOffset += toCopy; - currentLength -= toCopy; - available -= toCopy; - } - return length; - } - - /// - /// Read clear text data from the input stream. - /// - /// The buffer to add data to. - /// The offset to start adding data at. - /// The number of bytes to read. - /// Returns the number of bytes actually read. - public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length) - { - if (length < 0) - { - throw new ArgumentOutOfRangeException("length"); - } - - int currentOffset = offset; - int currentLength = length; - - while (currentLength > 0) - { - if (available <= 0) - { - Fill(); - if (available <= 0) - { - return 0; - } - } - - int toCopy = Math.Min(currentLength, available); - Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy); - currentOffset += toCopy; - currentLength -= toCopy; - available -= toCopy; - } - return length; - } - - /// - /// Read a from the input stream. - /// - /// Returns the byte read. - public int ReadLeByte() - { - if (available <= 0) - { - Fill(); - if (available <= 0) - { - throw new ZipException("EOF in header"); - } - } - byte result = rawData[rawLength - available]; - available -= 1; - return result; - } - - /// - /// Read an in little endian byte order. - /// - /// The short value read case to an int. - public int ReadLeShort() - { - return ReadLeByte() | (ReadLeByte() << 8); - } - - /// - /// Read an in little endian byte order. - /// - /// The int value read. - public int ReadLeInt() - { - return ReadLeShort() | (ReadLeShort() << 16); - } - - /// - /// Read a in little endian byte order. - /// - /// The long value read. - public long ReadLeLong() - { - return (uint)ReadLeInt() | ((long)ReadLeInt() << 32); - } - -#if false//!NETCF_1_0 - /// - /// Get/set the to apply to any data. - /// - /// Set this value to null to have no transform applied. - public ICryptoTransform CryptoTransform - { - set { - cryptoTransform = value; - if ( cryptoTransform != null ) { - if ( rawData == clearText ) { - if ( internalClearText == null ) { - internalClearText = new byte[rawData.Length]; - } - clearText = internalClearText; - } - clearTextLength = rawLength; - if ( available > 0 ) { - cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available); - } - } else { - clearText = rawData; - clearTextLength = rawLength; - } - } - } -#endif - - #region Instance Fields - int rawLength; - byte[] rawData; - - int clearTextLength; - byte[] clearText; -#if false//!NETCF_1_0 - byte[] internalClearText; -#endif - - int available; - -#if false//!NETCF_1_0 - ICryptoTransform cryptoTransform; -#endif - Stream inputStream; - #endregion - } - - /// - /// This filter stream is used to decompress data compressed using the "deflate" - /// format. The "deflate" format is described in RFC 1951. - /// - /// This stream may form the basis for other decompression filters, such - /// as the GZipInputStream. - /// - /// Author of the original java version: John Leuner. - /// - internal class InflaterInputStream : Stream - { - #region Constructors - /// - /// Create an InflaterInputStream with the default decompressor - /// and a default buffer size of 4KB. - /// - /// - /// The InputStream to read bytes from - /// - public InflaterInputStream(Stream baseInputStream) - : this(baseInputStream, new Inflater(), 4096) - { - } - - /// - /// Create an InflaterInputStream with the specified decompressor - /// and a default buffer size of 4KB. - /// - /// - /// The source of input data - /// - /// - /// The decompressor used to decompress data read from baseInputStream - /// - public InflaterInputStream(Stream baseInputStream, Inflater inf) - : this(baseInputStream, inf, 4096) - { - } - - /// - /// Create an InflaterInputStream with the specified decompressor - /// and the specified buffer size. - /// - /// - /// The InputStream to read bytes from - /// - /// - /// The decompressor to use - /// - /// - /// Size of the buffer to use - /// - public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize) - { - if (baseInputStream == null) - { - throw new ArgumentNullException("baseInputStream"); - } - - if (inflater == null) - { - throw new ArgumentNullException("inflater"); - } - - if (bufferSize <= 0) - { - throw new ArgumentOutOfRangeException("bufferSize"); - } - - this.baseInputStream = baseInputStream; - this.inf = inflater; - - inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize); - } - - #endregion - - /// - /// Get/set flag indicating ownership of underlying stream. - /// When the flag is true will close the underlying stream also. - /// - /// - /// The default value is true. - /// - public bool IsStreamOwner - { - get { return isStreamOwner; } - set { isStreamOwner = value; } - } - - /// - /// Skip specified number of bytes of uncompressed data - /// - /// - /// Number of bytes to skip - /// - /// - /// The number of bytes skipped, zero if the end of - /// stream has been reached - /// - /// - /// The number of bytes to skip is less than or equal to zero. - /// - public long Skip(long count) - { - if (count <= 0) - { - throw new ArgumentOutOfRangeException("count"); - } - - // v0.80 Skip by seeking if underlying stream supports it... - if (baseInputStream.CanSeek) - { - baseInputStream.Seek(count, SeekOrigin.Current); - return count; - } - else - { - int length = 2048; - if (count < length) - { - length = (int)count; - } - - byte[] tmp = new byte[length]; - int readCount = 1; - long toSkip = count; - - while ((toSkip > 0) && (readCount > 0)) - { - if (toSkip < length) - { - length = (int)toSkip; - } - - readCount = baseInputStream.Read(tmp, 0, length); - toSkip -= readCount; - } - - return count - toSkip; - } - } - - /// - /// Clear any cryptographic state. - /// - protected void StopDecrypting() - { -#if false//!NETCF_1_0 - inputBuffer.CryptoTransform = null; -#endif - } - - /// - /// Returns 0 once the end of the stream (EOF) has been reached. - /// Otherwise returns 1. - /// - public virtual int Available - { - get - { - return inf.IsFinished ? 0 : 1; - } - } - - /// - /// Fills the buffer with more data to decompress. - /// - /// - /// Stream ends early - /// - protected void Fill() - { - // Protect against redundant calls - if (inputBuffer.Available <= 0) - { - inputBuffer.Fill(); - if (inputBuffer.Available <= 0) - { - throw new SharpZipBaseException("Unexpected EOF"); - } - } - inputBuffer.SetInflaterInput(inf); - } - - #region Stream Overrides - /// - /// Gets a value indicating whether the current stream supports reading - /// - public override bool CanRead - { - get - { - return baseInputStream.CanRead; - } - } - - /// - /// Gets a value of false indicating seeking is not supported for this stream. - /// - public override bool CanSeek - { - get - { - return false; - } - } - - /// - /// Gets a value of false indicating that this stream is not writeable. - /// - public override bool CanWrite - { - get - { - return false; - } - } - - /// - /// A value representing the length of the stream in bytes. - /// - public override long Length - { - get - { - return inputBuffer.RawLength; - } - } - - /// - /// The current position within the stream. - /// Throws a NotSupportedException when attempting to set the position - /// - /// Attempting to set the position - public override long Position - { - get - { - return baseInputStream.Position; - } - set - { - throw new NotSupportedException("InflaterInputStream Position not supported"); - } - } - - /// - /// Flushes the baseInputStream - /// - public override void Flush() - { - baseInputStream.Flush(); - } - - /// - /// Sets the position within the current stream - /// Always throws a NotSupportedException - /// - /// The relative offset to seek to. - /// The defining where to seek from. - /// The new position in the stream. - /// Any access - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException("Seek not supported"); - } - - /// - /// Set the length of the current stream - /// Always throws a NotSupportedException - /// - /// The new length value for the stream. - /// Any access - public override void SetLength(long value) - { - throw new NotSupportedException("InflaterInputStream SetLength not supported"); - } - - /// - /// Writes a sequence of bytes to stream and advances the current position - /// This method always throws a NotSupportedException - /// - /// Thew buffer containing data to write. - /// The offset of the first byte to write. - /// The number of bytes to write. - /// Any access - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException("InflaterInputStream Write not supported"); - } - - /// - /// Writes one byte to the current stream and advances the current position - /// Always throws a NotSupportedException - /// - /// The byte to write. - /// Any access - public override void WriteByte(byte value) - { - throw new NotSupportedException("InflaterInputStream WriteByte not supported"); - } - -#if !NETFX_CORE && !UWP && !PORTABLE - /// - /// Entry point to begin an asynchronous write. Always throws a NotSupportedException. - /// - /// The buffer to write data from - /// Offset of first byte to write - /// The maximum number of bytes to write - /// The method to be called when the asynchronous write operation is completed - /// A user-provided object that distinguishes this particular asynchronous write request from other requests - /// An IAsyncResult that references the asynchronous write - /// Any access - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - throw new NotSupportedException("InflaterInputStream BeginWrite not supported"); - } -#endif - -#if !NETFX_CORE && !UWP && !PORTABLE - /// - /// Closes the input stream. When - /// is true the underlying stream is also closed. - /// - public override void Close() - { - if (!isClosed) - { - isClosed = true; - if (isStreamOwner) - { - baseInputStream.Close(); - } - } - } -#else - public void Close() - { - if (!isClosed) - { - isClosed = true; - if (isStreamOwner) - { - //baseInputStream.Close(); - baseInputStream.Dispose(); - } - } - } -#endif - - /// - /// Reads decompressed data into the provided buffer byte array - /// - /// - /// The array to read and decompress data into - /// - /// - /// The offset indicating where the data should be placed - /// - /// - /// The number of bytes to decompress - /// - /// The number of bytes read. Zero signals the end of stream - /// - /// Inflater needs a dictionary - /// - public override int Read(byte[] buffer, int offset, int count) - { - if (inf.IsNeedingDictionary) - { - throw new SharpZipBaseException("Need a dictionary"); - } - - int remainingBytes = count; - while (true) - { - int bytesRead = inf.Inflate(buffer, offset, remainingBytes); - offset += bytesRead; - remainingBytes -= bytesRead; - - if (remainingBytes == 0 || inf.IsFinished) - { - break; - } - - if (inf.IsNeedingInput) - { - try - { - Fill(); - } - catch (SharpZipBaseException) - { - // WB! early EOF: apparantly not a big deal for some PDF pages: break out of the loop. - break; - } - - } - else if (bytesRead == 0) - { - throw new ZipException("Dont know what to do"); - } - } - return count - remainingBytes; - } - - - #endregion - - #region Instance Fields - /// - /// Decompressor for this stream - /// - protected Inflater inf; - - /// - /// Input buffer for this stream. - /// - protected InflaterInputBuffer inputBuffer; - - /// - /// Base stream the inflater reads from. - /// - private Stream baseInputStream; - - ///// - ///// The compressed size - ///// - ////protected long csize; - -#if true || !NETFX_CORE - /// - /// Flag indicating wether this instance has been closed or not. - /// - bool isClosed; -#endif - - /// - /// Flag indicating wether this instance is designated the stream owner. - /// When closing if this flag is true the underlying stream is closed. - /// - bool isStreamOwner = true; - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/OutputWindow.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/OutputWindow.cs deleted file mode 100644 index 2d106713..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/OutputWindow.cs +++ /dev/null @@ -1,256 +0,0 @@ -// OutputWindow.cs -// -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression.Streams -{ - - /// - /// Contains the output from the Inflation process. - /// We need to have a window so that we can refer backwards into the output stream - /// to repeat stuff.
- /// Author of the original java version: John Leuner - ///
- internal class OutputWindow - { - #region Constants - const int WindowSize = 1 << 15; - const int WindowMask = WindowSize - 1; - #endregion - - #region Instance Fields - byte[] window = new byte[WindowSize]; //The window is 2^15 bytes - int windowEnd; - int windowFilled; - #endregion - - /// - /// Write a byte to this output window - /// - /// value to write - /// - /// if window is full - /// - public void Write(int value) - { - if (windowFilled++ == WindowSize) - { - throw new InvalidOperationException("Window full"); - } - window[windowEnd++] = (byte)value; - windowEnd &= WindowMask; - } - - - private void SlowRepeat(int repStart, int length, int distance) - { - while (length-- > 0) - { - window[windowEnd++] = window[repStart++]; - windowEnd &= WindowMask; - repStart &= WindowMask; - } - } - - /// - /// Append a byte pattern already in the window itself - /// - /// length of pattern to copy - /// distance from end of window pattern occurs - /// - /// If the repeated data overflows the window - /// - public void Repeat(int length, int distance) - { - if ((windowFilled += length) > WindowSize) - { - throw new InvalidOperationException("Window full"); - } - - int repStart = (windowEnd - distance) & WindowMask; - int border = WindowSize - length; - if ((repStart <= border) && (windowEnd < border)) - { - if (length <= distance) - { - System.Array.Copy(window, repStart, window, windowEnd, length); - windowEnd += length; - } - else - { - // We have to copy manually, since the repeat pattern overlaps. - while (length-- > 0) - { - window[windowEnd++] = window[repStart++]; - } - } - } - else - { - SlowRepeat(repStart, length, distance); - } - } - - /// - /// Copy from input manipulator to internal window - /// - /// source of data - /// length of data to copy - /// the number of bytes copied - public int CopyStored(StreamManipulator input, int length) - { - length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes); - int copied; - - int tailLen = WindowSize - windowEnd; - if (length > tailLen) - { - copied = input.CopyBytes(window, windowEnd, tailLen); - if (copied == tailLen) - { - copied += input.CopyBytes(window, 0, length - tailLen); - } - } - else - { - copied = input.CopyBytes(window, windowEnd, length); - } - - windowEnd = (windowEnd + copied) & WindowMask; - windowFilled += copied; - return copied; - } - - /// - /// Copy dictionary to window - /// - /// source dictionary - /// offset of start in source dictionary - /// length of dictionary - /// - /// If window isnt empty - /// - public void CopyDict(byte[] dictionary, int offset, int length) - { - if (dictionary == null) - { - throw new ArgumentNullException("dictionary"); - } - - if (windowFilled > 0) - { - throw new InvalidOperationException(); - } - - if (length > WindowSize) - { - offset += length - WindowSize; - length = WindowSize; - } - System.Array.Copy(dictionary, offset, window, 0, length); - windowEnd = length & WindowMask; - } - - /// - /// Get remaining unfilled space in window - /// - /// Number of bytes left in window - public int GetFreeSpace() - { - return WindowSize - windowFilled; - } - - /// - /// Get bytes available for output in window - /// - /// Number of bytes filled - public int GetAvailable() - { - return windowFilled; - } - - /// - /// Copy contents of window to output - /// - /// buffer to copy to - /// offset to start at - /// number of bytes to count - /// The number of bytes copied - /// - /// If a window underflow occurs - /// - public int CopyOutput(byte[] output, int offset, int len) - { - int copyEnd = windowEnd; - if (len > windowFilled) - { - len = windowFilled; - } - else - { - copyEnd = (windowEnd - windowFilled + len) & WindowMask; - } - - int copied = len; - int tailLen = len - copyEnd; - - if (tailLen > 0) - { - System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen); - offset += tailLen; - len = copyEnd; - } - System.Array.Copy(window, copyEnd - len, output, offset, len); - windowFilled -= copied; - if (windowFilled < 0) - { - throw new InvalidOperationException(); - } - return copied; - } - - /// - /// Reset by clearing window so GetAvailable returns 0 - /// - public void Reset() - { - windowFilled = windowEnd = 0; - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs b/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs deleted file mode 100644 index 91daab87..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs +++ /dev/null @@ -1,318 +0,0 @@ -// StreamManipulator.cs -// -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -namespace PdfSharpCore.SharpZipLib.Zip.Compression.Streams -{ - - /// - /// This class allows us to retrieve a specified number of bits from - /// the input buffer, as well as copy big byte blocks. - /// - /// It uses an int buffer to store up to 31 bits for direct - /// manipulation. This guarantees that we can get at least 16 bits, - /// but we only need at most 15, so this is all safe. - /// - /// There are some optimizations in this class, for example, you must - /// never peek more than 8 bits more than needed, and you must first - /// peek bits before you may drop them. This is not a general purpose - /// class but optimized for the behaviour of the Inflater. - /// - /// Authors of the original java version: John Leuner, Jochen Hoenicke - /// - internal class StreamManipulator - { - #region Constructors - /// - /// Constructs a default StreamManipulator with all buffers empty - /// - public StreamManipulator() - { - } - #endregion - - /// - /// Get the next sequence of bits but don't increase input pointer. bitCount must be - /// less or equal 16 and if this call succeeds, you must drop - /// at least n - 8 bits in the next call. - /// - /// The number of bits to peek. - /// - /// the value of the bits, or -1 if not enough bits available. */ - /// - public int PeekBits(int bitCount) - { - if (bitsInBuffer_ < bitCount) - { - if (windowStart_ == windowEnd_) - { - return -1; // ok - } - buffer_ |= (uint)((window_[windowStart_++] & 0xff | - (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_); - bitsInBuffer_ += 16; - } - return (int)(buffer_ & ((1 << bitCount) - 1)); - } - - /// - /// Drops the next n bits from the input. You should have called PeekBits - /// with a bigger or equal n before, to make sure that enough bits are in - /// the bit buffer. - /// - /// The number of bits to drop. - public void DropBits(int bitCount) - { - buffer_ >>= bitCount; - bitsInBuffer_ -= bitCount; - } - - /// - /// Gets the next n bits and increases input pointer. This is equivalent - /// to followed by , except for correct error handling. - /// - /// The number of bits to retrieve. - /// - /// the value of the bits, or -1 if not enough bits available. - /// - public int GetBits(int bitCount) - { - int bits = PeekBits(bitCount); - if (bits >= 0) - { - DropBits(bitCount); - } - return bits; - } - - /// - /// Gets the number of bits available in the bit buffer. This must be - /// only called when a previous PeekBits() returned -1. - /// - /// - /// the number of bits available. - /// - public int AvailableBits - { - get - { - return bitsInBuffer_; - } - } - - /// - /// Gets the number of bytes available. - /// - /// - /// The number of bytes available. - /// - public int AvailableBytes - { - get - { - return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3); - } - } - - /// - /// Skips to the next byte boundary. - /// - public void SkipToByteBoundary() - { - buffer_ >>= (bitsInBuffer_ & 7); - bitsInBuffer_ &= ~7; - } - - /// - /// Returns true when SetInput can be called - /// - public bool IsNeedingInput - { - get - { - return windowStart_ == windowEnd_; - } - } - - /// - /// Copies bytes from input buffer to output buffer starting - /// at output[offset]. You have to make sure, that the buffer is - /// byte aligned. If not enough bytes are available, copies fewer - /// bytes. - /// - /// - /// The buffer to copy bytes to. - /// - /// - /// The offset in the buffer at which copying starts - /// - /// - /// The length to copy, 0 is allowed. - /// - /// - /// The number of bytes copied, 0 if no bytes were available. - /// - /// - /// Length is less than zero - /// - /// - /// Bit buffer isnt byte aligned - /// - public int CopyBytes(byte[] output, int offset, int length) - { - if (length < 0) - { - throw new ArgumentOutOfRangeException("length"); - } - - if ((bitsInBuffer_ & 7) != 0) - { - // bits_in_buffer may only be 0 or a multiple of 8 - throw new InvalidOperationException("Bit buffer is not byte aligned!"); - } - - int count = 0; - while ((bitsInBuffer_ > 0) && (length > 0)) - { - output[offset++] = (byte)buffer_; - buffer_ >>= 8; - bitsInBuffer_ -= 8; - length--; - count++; - } - - if (length == 0) - { - return count; - } - - int avail = windowEnd_ - windowStart_; - if (length > avail) - { - length = avail; - } - System.Array.Copy(window_, windowStart_, output, offset, length); - windowStart_ += length; - - if (((windowStart_ - windowEnd_) & 1) != 0) - { - // We always want an even number of bytes in input, see peekBits - buffer_ = (uint)(window_[windowStart_++] & 0xff); - bitsInBuffer_ = 8; - } - return count + length; - } - - /// - /// Resets state and empties internal buffers - /// - public void Reset() - { - buffer_ = 0; - windowStart_ = windowEnd_ = bitsInBuffer_ = 0; - } - - /// - /// Add more input for consumption. - /// Only call when IsNeedingInput returns true - /// - /// data to be input - /// offset of first byte of input - /// number of bytes of input to add. - public void SetInput(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException("buffer"); - } - - if (offset < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("offset"); -#else - throw new ArgumentOutOfRangeException("offset", "Cannot be negative"); -#endif - } - - if (count < 0) - { -#if NETCF_1_0 - throw new ArgumentOutOfRangeException("count"); -#else - throw new ArgumentOutOfRangeException("count", "Cannot be negative"); -#endif - } - - if (windowStart_ < windowEnd_) - { - throw new InvalidOperationException("Old input was not completely processed"); - } - - int end = offset + count; - - // We want to throw an ArrayIndexOutOfBoundsException early. - // Note the check also handles integer wrap around. - if ((offset > end) || (end > buffer.Length)) - { - throw new ArgumentOutOfRangeException("count"); - } - - if ((count & 1) != 0) - { - // We always want an even number of bytes in input, see PeekBits - buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_); - bitsInBuffer_ += 8; - } - - window_ = buffer; - windowStart_ = offset; - windowEnd_ = end; - } - - #region Instance Fields - private byte[] window_; - private int windowStart_; - private int windowEnd_; - - private uint buffer_; - private int bitsInBuffer_; - #endregion - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/ZipConstants.cs b/PdfSharpCore/SharpZipLib/Zip/ZipConstants.cs deleted file mode 100644 index 2d2ce9a3..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/ZipConstants.cs +++ /dev/null @@ -1,579 +0,0 @@ -// ZipConstants.cs -// -// Copyright (C) 2001 Mike Krueger -// Copyright (C) 2004 John Reilly -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -// HISTORY -// 22-12-2009 DavidPierson Added AES support - -using System; -using System.Globalization; -using System.Text; -using System.Threading; - -#if NETCF_1_0 || NETCF_2_0 -using System.Globalization; -#endif - -namespace PdfSharpCore.SharpZipLib.Zip -{ - - #region Enumerations - - /// - /// Determines how entries are tested to see if they should use Zip64 extensions or not. - /// - public enum UseZip64 - { - /// - /// Zip64 will not be forced on entries during processing. - /// - /// An entry can have this overridden if required ZipEntry.ForceZip64" - Off, - /// - /// Zip64 should always be used. - /// - On, - /// - /// #ZipLib will determine use based on entry values when added to archive. - /// - Dynamic, - } - - /// - /// The kind of compression used for an entry in an archive - /// - public enum CompressionMethod - { - /// - /// A direct copy of the file contents is held in the archive - /// - Stored = 0, - - /// - /// Common Zip compression method using a sliding dictionary - /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees - /// - Deflated = 8, - - /// - /// An extension to deflate with a 64KB window. Not supported by #Zip currently - /// - Deflate64 = 9, - - /// - /// BZip2 compression. Not supported by #Zip. - /// - BZip2 = 11, - - /// - /// WinZip special for AES encryption, Now supported by #Zip. - /// - WinZipAES = 99, - - } - - /// - /// Identifies the encryption algorithm used for an entry - /// - public enum EncryptionAlgorithm - { - /// - /// No encryption has been used. - /// - None = 0, - /// - /// Encrypted using PKZIP 2.0 or 'classic' encryption. - /// - PkzipClassic = 1, - /// - /// DES encryption has been used. - /// - Des = 0x6601, - /// - /// RC2 encryption has been used for encryption. - /// - RC2 = 0x6602, - /// - /// Triple DES encryption with 168 bit keys has been used for this entry. - /// - TripleDes168 = 0x6603, - /// - /// Triple DES with 112 bit keys has been used for this entry. - /// - TripleDes112 = 0x6609, - /// - /// AES 128 has been used for encryption. - /// - Aes128 = 0x660e, - /// - /// AES 192 has been used for encryption. - /// - Aes192 = 0x660f, - /// - /// AES 256 has been used for encryption. - /// - Aes256 = 0x6610, - /// - /// RC2 corrected has been used for encryption. - /// - RC2Corrected = 0x6702, - /// - /// Blowfish has been used for encryption. - /// - Blowfish = 0x6720, - /// - /// Twofish has been used for encryption. - /// - Twofish = 0x6721, - /// - /// RC4 has been used for encryption. - /// - RC4 = 0x6801, - /// - /// An unknown algorithm has been used for encryption. - /// - Unknown = 0xffff - } - - /// - /// Defines the contents of the general bit flags field for an archive entry. - /// - [Flags] - public enum GeneralBitFlags : int - { - /// - /// Bit 0 if set indicates that the file is encrypted - /// - Encrypted = 0x0001, - /// - /// Bits 1 and 2 - Two bits defining the compression method (only for Method 6 Imploding and 8,9 Deflating) - /// - Method = 0x0006, - /// - /// Bit 3 if set indicates a trailing data desciptor is appended to the entry data - /// - Descriptor = 0x0008, - /// - /// Bit 4 is reserved for use with method 8 for enhanced deflation - /// - ReservedPKware4 = 0x0010, - /// - /// Bit 5 if set indicates the file contains Pkzip compressed patched data. - /// Requires version 2.7 or greater. - /// - Patched = 0x0020, - /// - /// Bit 6 if set indicates strong encryption has been used for this entry. - /// - StrongEncryption = 0x0040, - /// - /// Bit 7 is currently unused - /// - Unused7 = 0x0080, - /// - /// Bit 8 is currently unused - /// - Unused8 = 0x0100, - /// - /// Bit 9 is currently unused - /// - Unused9 = 0x0200, - /// - /// Bit 10 is currently unused - /// - Unused10 = 0x0400, - /// - /// Bit 11 if set indicates the filename and - /// comment fields for this file must be encoded using UTF-8. - /// - UnicodeText = 0x0800, - /// - /// Bit 12 is documented as being reserved by PKware for enhanced compression. - /// - EnhancedCompress = 0x1000, - /// - /// Bit 13 if set indicates that values in the local header are masked to hide - /// their actual values, and the central directory is encrypted. - /// - /// - /// Used when encrypting the central directory contents. - /// - HeaderMasked = 0x2000, - /// - /// Bit 14 is documented as being reserved for use by PKware - /// - ReservedPkware14 = 0x4000, - /// - /// Bit 15 is documented as being reserved for use by PKware - /// - ReservedPkware15 = 0x8000 - } - - #endregion - - /// - /// This class contains constants used for Zip format files - /// - internal sealed class ZipConstants - { - #region Versions - /// - /// The version made by field for entries in the central header when created by this library - /// - /// - /// This is also the Zip version for the library when comparing against the version required to extract - /// for an entry. See ZipEntry.CanDecompress. - /// - public const int VersionMadeBy = 51; // was 45 before AES - - /// - /// The minimum version required to support strong encryption - /// - public const int VersionStrongEncryption = 50; - - /// - /// Version indicating AES encryption - /// - public const int VERSION_AES = 51; - - /// - /// The version required for Zip64 extensions (4.5 or higher) - /// - public const int VersionZip64 = 45; - #endregion - - #region Header Sizes - /// - /// Size of local entry header (excluding variable length fields at end) - /// - public const int LocalHeaderBaseSize = 30; - - /// - /// Size of Zip64 data descriptor - /// - public const int Zip64DataDescriptorSize = 24; - - /// - /// Size of data descriptor - /// - public const int DataDescriptorSize = 16; - - /// - /// Size of central header entry (excluding variable fields) - /// - public const int CentralHeaderBaseSize = 46; - - /// - /// Size of end of central record (excluding variable fields) - /// - public const int EndOfCentralRecordBaseSize = 22; - public const int ENDHDR = 22; - - /// - /// Size of 'classic' cryptographic header stored before any entry data - /// - public const int CryptoHeaderSize = 12; - #endregion - - #region Header Signatures - - /// - /// Signature for local entry header - /// - public const int LocalHeaderSignature = 'P' | ('K' << 8) | (3 << 16) | (4 << 24); - - /// - /// Signature for spanning entry - /// - public const int SpanningSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24); - - /// - /// Signature for temporary spanning entry - /// - public const int SpanningTempSignature = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24); - - /// - /// Signature for data descriptor - /// - /// - /// This is only used where the length, Crc, or compressed size isnt known when the - /// entry is created and the output stream doesnt support seeking. - /// The local entry cannot be 'patched' with the correct values in this case - /// so the values are recorded after the data prefixed by this header, as well as in the central directory. - /// - public const int DataDescriptorSignature = 'P' | ('K' << 8) | (7 << 16) | (8 << 24); - - /// - /// Signature for central header - /// - public const int CentralHeaderSignature = 'P' | ('K' << 8) | (1 << 16) | (2 << 24); - - /// - /// Signature for Zip64 central file header - /// - public const int Zip64CentralFileHeaderSignature = 'P' | ('K' << 8) | (6 << 16) | (6 << 24); - - /// - /// Signature for Zip64 central directory locator - /// - public const int Zip64CentralDirLocatorSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24); - - /// - /// Signature for archive extra data signature (were headers are encrypted). - /// - public const int ArchiveExtraDataSignature = 'P' | ('K' << 8) | (6 << 16) | (7 << 24); - - /// - /// Central header digitial signature - /// - public const int CentralHeaderDigitalSignature = 'P' | ('K' << 8) | (5 << 16) | (5 << 24); - - /// - /// End of central directory record signature - /// - public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24); - #endregion - -#if true//NETCF_1_0 || NETCF_2_0 - // This isnt so great but is better than nothing. - // Trying to work out an appropriate OEM code page would be good. - // 850 is a good default for english speakers particularly in Europe. -#if SILVERLIGHT || NETFX_CORE || UWP || PORTABLE - // TODO Do we need this for PDFsharp? If so, make it work. - static int defaultCodePage = 65001; -#else - static int defaultCodePage = CultureInfo.CurrentCulture.TextInfo.ANSICodePage; -#endif -#else - /// - /// Get OEM codepage from NetFX, which parses the NLP file with culture info table etc etc. - /// But sometimes it yields the special value of 1 which is nicknamed CodePageNoOEM in sources (might also mean CP_OEMCP, but Encoding puts it so). - /// This was observed on Ukranian and Hindu systems. - /// Given this value, throws an . - /// So replace it with some fallback, e.g. 437 which is the default cpcp in a console in a default Windows installation. - /// - static int defaultCodePage = - // these values cause ArgumentException in subsequent calls to Encoding::GetEncoding() - ((Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 1) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 2) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 3) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 42)) - ? 437 // The default OEM encoding in a console in a default Windows installation, as a fallback. - : Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage; -#endif - - /// - /// Default encoding used for string conversion. 0 gives the default system OEM code page. - /// Dont use unicode encodings if you want to be Zip compatible! - /// Using the default code page isnt the full solution neccessarily - /// there are many variable factors, codepage 850 is often a good choice for - /// European users, however be careful about compatability. - /// - public static int DefaultCodePage - { - get - { - return defaultCodePage; - } - set - { - if ((value < 0) || (value > 65535) || - (value == 1) || (value == 2) || (value == 3) || (value == 42)) - { - throw new ArgumentOutOfRangeException("value"); - } - - defaultCodePage = value; - } - } - - /// - /// Convert a portion of a byte array to a string. - /// - /// - /// Data to convert to string - /// - /// - /// Number of bytes to convert starting from index 0 - /// - /// - /// data[0]..data[count - 1] converted to a string - /// - public static string ConvertToString(byte[] data, int count) - { - if (data == null) - { - return string.Empty; - } - -#if SILVERLIGHT || NETFX_CORE || PORTABLE - return Encoding.GetEncoding("utf-8").GetString(data, 0, count); -#else - return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, count); -#endif - } - - /// - /// Convert a byte array to string - /// - /// - /// Byte array to convert - /// - /// - /// dataconverted to a string - /// - public static string ConvertToString(byte[] data) - { - if (data == null) - { - return string.Empty; - } - return ConvertToString(data, data.Length); - } - - /// - /// Convert a byte array to string - /// - /// The applicable general purpose bits flags - /// - /// Byte array to convert - /// - /// The number of bytes to convert. - /// - /// dataconverted to a string - /// - public static string ConvertToStringExt(int flags, byte[] data, int count) - { - if (data == null) - { - return string.Empty; - } - - if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) - { - return Encoding.UTF8.GetString(data, 0, count); - } - else - { - return ConvertToString(data, count); - } - } - - /// - /// Convert a byte array to string - /// - /// - /// Byte array to convert - /// - /// The applicable general purpose bits flags - /// - /// dataconverted to a string - /// - public static string ConvertToStringExt(int flags, byte[] data) - { - if (data == null) - { - return string.Empty; - } - - if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) - { - return Encoding.UTF8.GetString(data, 0, data.Length); - } - else - { - return ConvertToString(data, data.Length); - } - } - - /// - /// Convert a string to a byte array - /// - /// - /// String to convert to an array - /// - /// Converted array - public static byte[] ConvertToArray(string str) - { - if (str == null) - { - return new byte[0]; - } - -#if SILVERLIGHT || NETFX_CORE || PORTABLE - return Encoding.GetEncoding("utf-8").GetBytes(str); -#else - return Encoding.GetEncoding(DefaultCodePage).GetBytes(str); -#endif - } - - /// - /// Convert a string to a byte array - /// - /// The applicable general purpose bits flags - /// - /// String to convert to an array - /// - /// Converted array - public static byte[] ConvertToArray(int flags, string str) - { - if (str == null) - { - return new byte[0]; - } - - if ((flags & (int)GeneralBitFlags.UnicodeText) != 0) - { - return Encoding.UTF8.GetBytes(str); - } - else - { - return ConvertToArray(str); - } - } - - - /// - /// Initialise default instance of ZipConstants - /// - /// - /// Private to prevent instances being created. - /// - ZipConstants() - { - // Do nothing - } - } -} diff --git a/PdfSharpCore/SharpZipLib/Zip/ZipException.cs b/PdfSharpCore/SharpZipLib/Zip/ZipException.cs deleted file mode 100644 index 8c65ae07..00000000 --- a/PdfSharpCore/SharpZipLib/Zip/ZipException.cs +++ /dev/null @@ -1,93 +0,0 @@ -// ZipException.cs -// -// Copyright (C) 2001 Mike Krueger -// -// This file was translated from java, it was part of the GNU Classpath -// Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// Linking this library statically or dynamically with other modules is -// making a combined work based on this library. Thus, the terms and -// conditions of the GNU General Public License cover the whole -// combination. -// -// As a special exception, the copyright holders of this library give you -// permission to link this library with independent modules to produce an -// executable, regardless of the license terms of these independent -// modules, and to copy and distribute the resulting executable under -// terms of your choice, provided that you also meet, for each linked -// independent module, the terms and conditions of the license of that -// module. An independent module is a module which is not derived from -// or based on this library. If you modify this library, you may extend -// this exception to your version of the library, but you are not -// obligated to do so. If you do not wish to do so, delete this -// exception statement from your version. - -using System; - -#if false//!NETCF_1_0 && !NETCF_2_0 -using System.Runtime.Serialization; -#endif - -namespace PdfSharpCore.SharpZipLib.Zip -{ - /// - /// Represents exception conditions specific to Zip archive handling - /// -#if false//!NETCF_1_0 && !NETCF_2_0 - [Serializable] -#endif - internal class ZipException : SharpZipBaseException - { -#if false//!NETCF_1_0 && !NETCF_2_0 - /// - /// Deserialization constructor - /// - /// for this constructor - /// for this constructor - protected ZipException(SerializationInfo info, StreamingContext context ) - : base( info, context ) - { - } -#endif - - /// - /// Initializes a new instance of the ZipException class. - /// - public ZipException() - { - } - - /// - /// Initializes a new instance of the ZipException class with a specified error message. - /// - /// The error message that explains the reason for the exception. - public ZipException(string message) - : base(message) - { - } - - /// - /// Initialise a new instance of ZipException. - /// - /// A message describing the error. - /// The exception that is the cause of the current exception. - public ZipException(string message, Exception exception) - : base(message, exception) - { - } - } -} diff --git a/PdfSharpCore/Utils/FontResolver.cs b/PdfSharpCore/Utils/FontResolver.cs index 71405381..bfa2bac6 100644 --- a/PdfSharpCore/Utils/FontResolver.cs +++ b/PdfSharpCore/Utils/FontResolver.cs @@ -53,7 +53,19 @@ static FontResolver() if (isWindows) { fontDir = System.Environment.ExpandEnvironmentVariables(@"%SystemRoot%\Fonts"); - SSupportedFonts = System.IO.Directory.GetFiles(fontDir, "*.ttf", System.IO.SearchOption.AllDirectories); + var fontPaths = new List(); + + var systemFontPaths = System.IO.Directory.GetFiles(fontDir, "*.ttf", System.IO.SearchOption.AllDirectories); + fontPaths.AddRange(systemFontPaths); + + var appdataFontDir = System.Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Microsoft\Windows\Fonts"); + if(System.IO.Directory.Exists(appdataFontDir)) + { + var appdataFontPaths = System.IO.Directory.GetFiles(appdataFontDir, "*.ttf", System.IO.SearchOption.AllDirectories); + fontPaths.AddRange(appdataFontPaths); + } + + SSupportedFonts = fontPaths.ToArray(); SetupFontsFiles(SSupportedFonts); return; } @@ -113,7 +125,9 @@ public static void SetupFontsFiles(string[] sSupportedFonts) } catch (System.Exception e) { +#if DEBUG System.Console.Error.WriteLine(e); +#endif } } @@ -127,7 +141,9 @@ public static void SetupFontsFiles(string[] sSupportedFonts) } catch (System.Exception e) { +#if DEBUG System.Console.Error.WriteLine(e); +#endif } } @@ -153,7 +169,7 @@ private static FontFamilyModel DeserializeFontFamily(string fontFamilyName, IEnu return font; } - public byte[] GetFont(string faceFileName) + public virtual byte[] GetFont(string faceFileName) { using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { diff --git a/PdfSharpCore/Utils/ImageSharpImageSource.cs b/PdfSharpCore/Utils/ImageSharpImageSource.cs index 188c8578..383863f4 100644 --- a/PdfSharpCore/Utils/ImageSharpImageSource.cs +++ b/PdfSharpCore/Utils/ImageSharpImageSource.cs @@ -12,6 +12,13 @@ namespace PdfSharpCore.Utils { public class ImageSharpImageSource : ImageSource where TPixel : unmanaged, IPixel { + + public static IImageSource FromImageSharpImage(Image image, IImageFormat imgFormat, int? quality = 75) + { + var _path = "*" + Guid.NewGuid().ToString("B"); + return new ImageSharpImageSourceImpl(_path, image, (int)quality, imgFormat is PngFormat); + } + protected override IImageSource FromBinaryImpl(string name, Func imageSource, int? quality = 75) { var image = Image.Load(imageSource.Invoke(), out IImageFormat imgFormat); diff --git a/PdfSharpCore/Utils/LinuxSystemFontResolver.cs b/PdfSharpCore/Utils/LinuxSystemFontResolver.cs index f81a3c65..68cd4537 100644 --- a/PdfSharpCore/Utils/LinuxSystemFontResolver.cs +++ b/PdfSharpCore/Utils/LinuxSystemFontResolver.cs @@ -136,7 +136,9 @@ public static string[] Resolve() } catch(Exception ex) { +#if DEBUG Console.Error.WriteLine(ex.ToString()); +#endif return ResolveFallback().Where(x => x.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase)).ToArray(); } } @@ -194,8 +196,10 @@ static IEnumerable SearchPaths() } catch (Exception ex) { +#if DEBUG Console.Error.WriteLine(ex.Message); Console.Error.WriteLine(ex.StackTrace); +#endif } dirs.Add("/usr/share/fonts"); diff --git a/PdfSharpCore/root/PSSR.cs b/PdfSharpCore/root/PSSR.cs index d86e38d1..f047cbfd 100644 --- a/PdfSharpCore/root/PSSR.cs +++ b/PdfSharpCore/root/PSSR.cs @@ -378,16 +378,6 @@ public static ResourceManager ResMngr [Conditional("DEBUG")] public static void TestResourceMessages() { -#if !SILVERLIGHT && !__IOS__ && !__ANDROID__ && !PORTABLE - string[] names = Enum.GetNames(typeof(PSMsgID)); - foreach (string name in names) - { - string message = String.Format("{0}: '{1}'", name, ResMngr.GetString(name)); - Debug.Assert(message != null); - Debug.WriteLine(message); - } -#else -#endif } static PSSR() diff --git a/PdfSharpCore/root/PageSizeConverter.cs b/PdfSharpCore/root/PageSizeConverter.cs index 6c697b0d..395a4fc3 100644 --- a/PdfSharpCore/root/PageSizeConverter.cs +++ b/PdfSharpCore/root/PageSizeConverter.cs @@ -28,12 +28,6 @@ #endregion using System; -#if GDI -using System.Drawing; -#endif -#if WPF -using System.Windows; -#endif using PdfSharpCore.Drawing; namespace PdfSharpCore diff --git a/PdfSharpCore/root/ProductVersionInfo.cs b/PdfSharpCore/root/ProductVersionInfo.cs index 0248806d..090c94c4 100644 --- a/PdfSharpCore/root/ProductVersionInfo.cs +++ b/PdfSharpCore/root/ProductVersionInfo.cs @@ -234,46 +234,6 @@ public static class ProductVersionInfo /// -wp : Windows Phone /// -wrt : Windows RunTime ///
-#if GDI && !WPF - // GDI+ (System.Drawing) - public const string Technology = "-gdi"; -#endif -#if WPF && !GDI && !SILVERLIGHT - // Windows Presentation Foundation - public const string Technology = "-wpf"; -#endif -#if WPF && GDI - // Hybrid - for testing only - public const string Technology = "-h"; -#endif -#if SILVERLIGHT && !WINDOWS_PHONE - // Silverlight 5 - public const string Technology = "-sl"; -#endif -#if WINDOWS_PHONE - // Windows Phone - public const string Technology = "-wp"; -#endif -#if NETFX_CORE - // WinRT - public const string Technology = "-wrt"; -#endif -#if UWP - // Windows Universal App - public const string Technology = "-uwp"; -#endif -#if CORE - // .net without GDI+ and WPF - public const string Technology = ""; // no extension -#endif -#if __IOS__ - public const string Technology = "-ios"; -#endif -#if __ANDROID__ - public const string Technology = "-android"; -#endif -#if PORTABLE public const string Technology = "-netstandard"; -#endif } } diff --git a/README.md b/README.md index ad28d5dd..77449d95 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,60 @@ # PdfSharpCore -**PdfSharpCore** is a partial port of [PdfSharp.Xamarin](https://github.com/roceh/PdfSharp.Xamarin/) for .NET Standard +[![NuGet Version](https://img.shields.io/nuget/v/PdfSharpCore.svg)](https://www.nuget.org/packages/PdfSharpCore/) +[![CI](https://github.com/ststeiger/PdfSharpCore/actions/workflows/build.yml/badge.svg)](https://github.com/ststeiger/PdfSharpCore/actions/workflows/build.yml) +[![codecov.io](https://codecov.io/github/ststeiger/PdfSharpCore/coverage.svg?branch=master)](https://codecov.io/github/ststeiger/PdfSharpCore?branch=master) + +**PdfSharpCore** is a partial port of [PdfSharp.Xamarin](https://github.com/roceh/PdfSharp.Xamarin/) for .NET Standard. Additionally MigraDoc has been ported as well (from version 1.32). -Images have been implemented with [ImageSharp](https://github.com/JimBobSquarePants/ImageSharp/), which is still in Alpha. They State on their readme that it is still in Alpha status and shouldn't be used in productive environments. Since I didn't find any good alternatives it's still used. - -ImageSharp being Alpha isn't a big issue either since this code isn't by far done yet. So please chime in ;) - -**PdfSharp.Xamarin** is a partial port of [PdfSharp](http://www.pdfsharp.net/) for iOS and Android using Xamarin, it allows for creation and modification of PDF files. - - - -###### Example project - -There was an example project here.
-I've removed it from this project, and put it into a separate solution. -You can find it [here](https://github.com/ststeiger/Stammbaum).
-There's a default font-resolver in [FontResolver.cs](https://github.com/ststeiger/PdfSharpCore/blob/master/PdfSharpCore/Utils/FontResolver.cs).
-It should work on Windows, Linux, OSX and Azure.
-Some limitations apply.
-See open issues. - - -## Example usage - -```cs -//See the "Example" Project for a MigraDoc example -static void Main(string[] args) -{ - GlobalFontSettings.FontResolver = new FontResolver(); - - var document = new PdfDocument(); - var page = document.AddPage(); - var gfx = XGraphics.FromPdfPage(page); - var font = new XFont("OpenSans", 20, XFontStyle.Bold); - - gfx.DrawString("Hello World!", font, XBrushes.Black, new XRect(20, 20, page.Width, page.Height), XStringFormats.Center); - - document.Save("test.pdf"); -} - -//This implementation is obviously not very good --> Though it should be enough for everyone to implement their own. -public class FontResolver : IFontResolver -{ - public byte[] GetFont(string faceName) - { - using(var ms = new MemoryStream()) - { - using(var fs = File.Open(faceName, FileMode.Open)) - { - fs.CopyTo(ms); - ms.Position = 0; - return ms.ToArray(); - } - } - } - public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) - { - if (familyName.Equals("OpenSans", StringComparison.CurrentCultureIgnoreCase)) - { - if (isBold && isItalic) - { - return new FontResolverInfo("OpenSans-BoldItalic.ttf"); - } - else if (isBold) - { - return new FontResolverInfo("OpenSans-Bold.ttf"); - } - else if (isItalic) - { - return new FontResolverInfo("OpenSans-Italic.ttf"); - } - else - { - return new FontResolverInfo("OpenSans-Regular.ttf"); - } - } - return null; - } - } -} +Image support has been implemented with [SixLabors.ImageSharp](https://github.com/JimBobSquarePants/ImageSharp/) and Fonts support with [SixLabors.Fonts](https://github.com/SixLabors/Fonts). + + +## Table of Contents + +- [Documentation](docs/index.md) +- [Example](#example) +- [Contributing](#contributing) +- [License](#license) + + +## Example + +The following code snippet creates a simple PDF-file with the text 'Hello World!'. +The code is written for a .NET 6 console app with top level statements. + +```csharp +using PdfSharpCore.Drawing; +using PdfSharpCore.Fonts; +using PdfSharpCore.Pdf; +using PdfSharpCore.Utils; + +GlobalFontSettings.FontResolver = new FontResolver(); + +var document = new PdfDocument(); +var page = document.AddPage(); + +var gfx = XGraphics.FromPdfPage(page); +var font = new XFont("Arial", 20, XFontStyle.Bold); + +var textColor = XBrushes.Black; +var layout = new XRect(20, 20, page.Width, page.Height); +var format = XStringFormats.Center; + +gfx.DrawString("Hello World!", font, textColor, layout, format); + +document.Save("helloworld.pdf"); ``` -## License +## Contributing + +We appreciate feedback and contribution to this repo! -Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany) -Modified work Copyright (c) 2016 David Dunscombe -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: +## License + +This software is released under the MIT License. See the [LICENSE](LICENCE.md) file for more info. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +PdfSharpCore relies on the following projects, that are not under the MIT license: -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. +* *SixLabors.ImageSharp* and *SixLabors.Fonts* + * SixLabors.ImageSharp and SixLabors.Fonts, libraries which PdfSharpCore relies upon, are licensed under Apache 2.0 when distributed as part of PdfSharpCore. The SixLabors.ImageSharp license covers all other usage, see https://github.com/SixLabors/ImageSharp/blob/master/LICENSE \ No newline at end of file diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs new file mode 100644 index 00000000..2a049427 --- /dev/null +++ b/SampleApp/Program.cs @@ -0,0 +1,105 @@ +using PdfSharpCore.Drawing; +using PdfSharpCore.Drawing.Layout; +using PdfSharpCore.Drawing.Layout.enums; +using PdfSharpCore.Pdf; + +namespace SampleApp +{ + + + public class Program + { + + + private static string GetOutFilePath(string name) + { + string OutputDirName = @"."; + return System.IO.Path.Combine(OutputDirName, name); + } + + + private static void SaveDocument(PdfSharpCore.Pdf.PdfDocument document, string name) + { + string outFilePath = GetOutFilePath(name); + string? dir = System.IO.Path.GetDirectoryName(outFilePath); + if (dir != null && !System.IO.Directory.Exists(dir)) + { + System.IO.Directory.CreateDirectory(dir); + } + + document.Save(outFilePath); + } + + + public static void Main(string[] args) + { + System.Console.WriteLine("Starting..."); + + const string outName = "test1.pdf"; + + PdfDocument? document = new PdfDocument(); + + PdfPage? pageNewRenderer = document.AddPage(); + + XGraphics? renderer = XGraphics.FromPdfPage(pageNewRenderer); + + renderer.DrawString( + "Testy Test Test" + , new XFont("Arial", 12) + , XBrushes.Black + , new XPoint(12, 12) + ); + + XTextFormatter? formatter = new XTextFormatter(renderer); + + var font = new XFont("Arial", 12); + var brush = XBrushes.Black; + + formatter.AllowVerticalOverflow = true; + var originalLayout = new XRect(0, 30, 120, 120); + var text = "More and more text boxes to show alignment capabilities"; // " with addipional gline"; + var anotherText = + "Text to determine the size of the box I would like to place the text I'm goint to test"; + var rect = formatter.GetLayout( + anotherText, + font, + brush, + originalLayout); + rect.Location = new XPoint(50, 50); + formatter.AllowVerticalOverflow = false; + + // Prepare brush to draw the box that demostrates the text fits and aligns correctly + var translucentBrush = new XSolidBrush(XColor.FromArgb(20, 0, 0, 0)); + + // Draw the string with default alignments + formatter.DrawString( + text, + font, + brush, + rect + ); + // For checking purposes + renderer.DrawRectangle(translucentBrush, rect); + + rect.Location = new XPoint(300, 50); + + // Draw the string with custom alignments + formatter.DrawString(text, font, brush, rect, new TextFormatAlignment() + { + Horizontal = XParagraphAlignment.Center, + Vertical = XVerticalAlignment.Middle + }); + + // For checking purposes + renderer.DrawRectangle(translucentBrush, rect); + + SaveDocument(document, outName); + + System.Console.WriteLine("Done!"); + } // End Sub Main + + + } // End Class Program + + +} // End Namespace SampleApp diff --git a/SampleApp/Properties/PublishProfiles/FolderProfile.pubxml b/SampleApp/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 00000000..faa94c73 --- /dev/null +++ b/SampleApp/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,19 @@ + + + + + Release + Any CPU + bin\Release\net6.0\publish\win-x64\ + FileSystem + <_TargetId>Folder + net6.0 + win-x64 + true + false + true + true + + \ No newline at end of file diff --git a/SampleApp/SampleApp.csproj b/SampleApp/SampleApp.csproj new file mode 100644 index 00000000..464229b5 --- /dev/null +++ b/SampleApp/SampleApp.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp3.1;net5.0;net6.0 + false + enable + enable + true + true + disable + + + + + + + + diff --git a/ci-build.ps1 b/ci-build.ps1 index 5bc4663d..9579b73b 100644 --- a/ci-build.ps1 +++ b/ci-build.ps1 @@ -1,11 +1,6 @@ -param( - [Parameter(Mandatory = $true, Position = 0)] - [string]$targetFramework -) - dotnet clean -c Release $repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY" # Building for a specific framework. -dotnet build -c Release -f $targetFramework /p:RepositoryUrl=$repositoryUrl \ No newline at end of file +dotnet build -c Release /p:RepositoryUrl=$repositoryUrl \ No newline at end of file diff --git a/docs/MigraDocCore/faq.md b/docs/MigraDocCore/faq.md new file mode 100644 index 00000000..9d837e0f --- /dev/null +++ b/docs/MigraDocCore/faq.md @@ -0,0 +1,8 @@ +# MigraDocCore > FAQ + +FAQ for [MigraDocCore](index.md): + + +## What is MigraDocCore? + +MigraDocCore is the .NET library for modeling and rendering documents. diff --git a/docs/MigraDocCore/index.md b/docs/MigraDocCore/index.md new file mode 100644 index 00000000..e3a08fa0 --- /dev/null +++ b/docs/MigraDocCore/index.md @@ -0,0 +1,71 @@ +# MigraDocCore + +MigraDocCore is a document generator. +It supports almost anything you find in any good word processor. +You just add paragraphs, tables, charts, arrange all this in sections, use bookmarks to create links, tables of contents, indexes, etc. +MigraDocCore will do the layout creating page breaks as needed. +MigraDocCore will create PDF documents. + +* [Features](#features) +* [First steps](#first-steps) +* [Samples](samples/index.md) +* [FAQ](faq.md) + + +## Features + +* Create perfect documents “on the fly” +* Import data from various sources via XML files or direct interfaces (any data source that can be used with .NET) +* Integrates easily with existing applications and systems +* Various options for page layout, text formatting, and document design +* Dynamic tables and business charts +* Re-usable building blocks consisting of text and / or code +* Documents with navigation (hyperlinks and / or bookmarks) + + +## First steps + +Both PdfSharpCore and MigraDocCore provide a lot of `AddXxx` functions. +Typically these functions return the newly created objects. Once you’ve learned the basic principles it’s quite easy to work with. +Intellisense helps a lot then. + +We’ll discuss a few lines of the [Hello World](samples/HelloWorld.md) sample here. + +```cs +// We start with a new document: +Document document = new Document(); + +// With MigraDocCore, we don’t add pages, we add sections (at least one): +Section section = document.AddSection(); + +// Adding text is simple: +section.AddParagraph("Hello, World!"); + +// Adding empty paragraphs is even simpler: +section.AddParagraph(); + +// Store the newly created object for modification: +Paragraph paragraph = section.AddParagraph(); +paragraph.Format.Font.Color = Color.FromCmyk(100, 30, 20, 50); +paragraph.AddFormattedText("Hello, World!", TextFormat.Underline); + +// AddFormattedText also returns an object: +FormattedText ft = paragraph.AddFormattedText("Small text", TextFormat.Bold); +ft.Font.Size = 6; + +// And there’s much more that can be added: AddTable, AddImage, AddHyperlink, AddBookmark, AddPageField, AddPageBreak, ... + +// With MigraDocCore you can create PDF or RTF. Just select the appropriate renderer: +PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(false, +PdfFontEmbedding.Always); + +// Pass the document to the renderer: +pdfRenderer.Document = document; + +// Let the renderer do its job: +pdfRenderer.RenderDocument(); + +// Save the PDF to a file: +string filename = "HelloWorld.pdf"; +pdfRenderer.PdfDocument.Save(filename); +``` diff --git a/docs/MigraDocCore/samples/HelloMigraDocCore.md b/docs/MigraDocCore/samples/HelloMigraDocCore.md new file mode 100644 index 00000000..eea9eebe --- /dev/null +++ b/docs/MigraDocCore/samples/HelloMigraDocCore.md @@ -0,0 +1,512 @@ +# Hello MigraDocCore + +Shows various features of MigraDocCore including table of contents, tables, bookmarks, text formatting and font styles, charts, ... + +* [Styles](#define-styles) +* [Cover](#define-cover) +* [Table of Contents](#define-table-of-contents) +* [Content Section](#define-content-section) +* [Paragraphs](#define-paragraphs) +* [Tables](#define-tables) +* [Charts](#define-charts) + + +## The Main method: + +```cs +static void Main() +{ + // Create a MigraDocCore document + Document document = Documents.CreateDocument(); + + //string ddl = MigraDocCore.DocumentObjectModel.IO.DdlWriter.WriteToString(document); + MigraDocCore.DocumentObjectModel.IO.DdlWriter.WriteToFile(document, "MigraDocCore.mdddl"); + + PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always); + renderer.Document = document; + + renderer.RenderDocument(); + + // Save the document... + string filename = "HelloMigraDoc.pdf"; + renderer.PdfDocument.Save(filename); +} +``` + + +## CreateDocument is the method that creates the content: + +```cs +public static Document CreateDocument() +{ + // Create a new MigraDocCore document + Document document = new Document(); + document.Info.Title = "Hello, MigraDocCore"; + document.Info.Subject = "Demonstrates an excerpt of the capabilities of MigraDocCore."; + document.Info.Author = "Stefan Lange"; + + Styles.DefineStyles(document); + Cover.DefineCover(document); + TableOfContents.DefineTableOfContents(document); + DefineContentSection(document); + Paragraphs.DefineParagraphs(document); + Tables.DefineTables(document); + Charts.DefineCharts(document); + + return document; +} +``` + +### Define Styles + +```cs + /// + /// Defines the styles used in the document. + /// + public static void DefineStyles(Document document) + { + // Get the predefined style Normal. + Style style = document.Styles["Normal"]; + // Because all styles are derived from Normal, the next line changes the + // font of the whole document. Or, more exactly, it changes the font of + // all styles and paragraphs that do not redefine the font. + style.Font.Name = "Times New Roman"; + + // Heading1 to Heading9 are predefined styles with an outline level. An outline level + // other than OutlineLevel.BodyText automatically creates the outline (or bookmarks) + // in PDF. + + style = document.Styles["Heading1"]; + style.Font.Name = "Tahoma"; + style.Font.Size = 14; + style.Font.Bold = true; + style.Font.Color = Colors.DarkBlue; + style.ParagraphFormat.PageBreakBefore = true; + style.ParagraphFormat.SpaceAfter = 6; + + style = document.Styles["Heading2"]; + style.Font.Size = 12; + style.Font.Bold = true; + style.ParagraphFormat.PageBreakBefore = false; + style.ParagraphFormat.SpaceBefore = 6; + style.ParagraphFormat.SpaceAfter = 6; + + style = document.Styles["Heading3"]; + style.Font.Size = 10; + style.Font.Bold = true; + style.Font.Italic = true; + style.ParagraphFormat.SpaceBefore = 6; + style.ParagraphFormat.SpaceAfter = 3; + + style = document.Styles[StyleNames.Header]; + style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right); + + style = document.Styles[StyleNames.Footer]; + style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center); + + // Create a new style called TextBox based on style Normal + style = document.Styles.AddStyle("TextBox", "Normal"); + style.ParagraphFormat.Alignment = ParagraphAlignment.Justify; + style.ParagraphFormat.Borders.Width = 2.5; + style.ParagraphFormat.Borders.Distance = "3pt"; + style.ParagraphFormat.Shading.Color = Colors.SkyBlue; + + // Create a new style called TOC based on style Normal + style = document.Styles.AddStyle("TOC", "Normal"); + style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right, TabLeader.Dots); + style.ParagraphFormat.Font.Color = Colors.Blue; +} +``` + +### Define Cover + +```cs +/// +/// Defines the cover page. +/// +public static void DefineCover(Document document) +{ + Section section = document.AddSection(); + + Paragraph paragraph = section.AddParagraph(); + paragraph.Format.SpaceAfter = "3cm"; + + Image image = section.AddImage("../../images/Logo landscape.png"); + image.Width = "10cm"; + + paragraph = section.AddParagraph("A sample document that demonstrates the\ncapabilities of MigraDocCore"); + paragraph.Format.Font.Size = 16; + paragraph.Format.Font.Color = Colors.DarkRed; + paragraph.Format.SpaceBefore = "8cm"; + paragraph.Format.SpaceAfter = "3cm"; + + paragraph = section.AddParagraph("Rendering date: "); + paragraph.AddDateField(); +} +``` + +### Define Table of Contents + +```cs +/// +/// Defines the table of contents page. +/// +public static void DefineTableOfContents(Document document) +{ + Section section = document.LastSection; + + section.AddPageBreak(); + Paragraph paragraph = section.AddParagraph("Table of Contents"); + paragraph.Format.Font.Size = 14; + paragraph.Format.Font.Bold = true; + paragraph.Format.SpaceAfter = 24; + paragraph.Format.OutlineLevel = OutlineLevel.Level1; + + paragraph = section.AddParagraph(); + paragraph.Style = "TOC"; + Hyperlink hyperlink = paragraph.AddHyperlink("Paragraphs"); + hyperlink.AddText("Paragraphs\t"); + hyperlink.AddPageRefField("Paragraphs"); + + paragraph = section.AddParagraph(); + paragraph.Style = "TOC"; + hyperlink = paragraph.AddHyperlink("Tables"); + hyperlink.AddText("Tables\t"); + hyperlink.AddPageRefField("Tables"); + + paragraph = section.AddParagraph(); + paragraph.Style = "TOC"; + hyperlink = paragraph.AddHyperlink("Charts"); + hyperlink.AddText("Charts\t"); + hyperlink.AddPageRefField("Charts"); +} +``` + +### Define Content Section + +```cs +/// +/// Defines page setup, headers, and footers. +/// +static void DefineContentSection(Document document) +{ + Section section = document.AddSection(); + section.PageSetup.OddAndEvenPagesHeaderFooter = true; + section.PageSetup.StartingNumber = 1; + + HeaderFooter header = section.Headers.Primary; + header.AddParagraph("\tOdd Page Header"); + + header = section.Headers.EvenPage; + header.AddParagraph("Even Page Header"); + + // Create a paragraph with centered page number. See definition of style "Footer". + Paragraph paragraph = new Paragraph(); + paragraph.AddTab(); + paragraph.AddPageField(); + + // Add paragraph to footer for odd pages. + section.Footers.Primary.Add(paragraph); + // Add clone of paragraph to footer for odd pages. Cloning is necessary because an object must + // not belong to more than one other object. If you forget cloning an exception is thrown. + section.Footers.EvenPage.Add(paragraph.Clone()); +} +``` + +### Define Paragraphs + +```cs +public static void DefineParagraphs(Document document) +{ + Paragraph paragraph = document.LastSection.AddParagraph("Paragraph Layout Overview", "Heading1"); + paragraph.AddBookmark("Paragraphs"); + + DemonstrateAlignment(document); + DemonstrateIndent(document); + DemonstrateFormattedText(document); + DemonstrateBordersAndShading(document); +} + +static void DemonstrateAlignment(Document document) +{ + document.LastSection.AddParagraph("Alignment", "Heading2"); + + document.LastSection.AddParagraph("Left Aligned", "Heading3"); + + Paragraph paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Alignment = ParagraphAlignment.Left; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("Right Aligned", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Alignment = ParagraphAlignment.Right; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("Centered", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Alignment = ParagraphAlignment.Center; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("Justified", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Alignment = ParagraphAlignment.Justify; + paragraph.AddText(FillerText.MediumText); +} + +static void DemonstrateIndent(Document document) +{ + document.LastSection.AddParagraph("Indent", "Heading2"); + + document.LastSection.AddParagraph("Left Indent", "Heading3"); + + Paragraph paragraph = document.LastSection.AddParagraph(); + paragraph.Format.LeftIndent = "2cm"; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("Right Indent", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.RightIndent = "1in"; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("First Line Indent", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.FirstLineIndent = "12mm"; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("First Line Negative Indent", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.LeftIndent = "1.5cm"; + paragraph.Format.FirstLineIndent = "-1.5cm"; + paragraph.AddText(FillerText.Text); +} + +static void DemonstrateFormattedText(Document document) +{ + document.LastSection.AddParagraph("Formatted Text", "Heading2"); + + //document.LastSection.AddParagraph("Left Aligned", "Heading3"); + + Paragraph paragraph = document.LastSection.AddParagraph(); + paragraph.AddText("Text can be formatted "); + paragraph.AddFormattedText("bold", TextFormat.Bold); + paragraph.AddText(", "); + paragraph.AddFormattedText("italic", TextFormat.Italic); + paragraph.AddText(", or "); + paragraph.AddFormattedText("bold & italic", TextFormat.Bold | TextFormat.Italic); + paragraph.AddText("."); + paragraph.AddLineBreak(); + paragraph.AddText("You can set the "); + FormattedText formattedText = paragraph.AddFormattedText("size "); + formattedText.Size = 15; + paragraph.AddText("the "); + formattedText = paragraph.AddFormattedText("color "); + formattedText.Color = Colors.Firebrick; + paragraph.AddText("the "); + formattedText = paragraph.AddFormattedText("font", new Font("Verdana")); + paragraph.AddText("."); + paragraph.AddLineBreak(); + paragraph.AddText("You can set the "); + formattedText = paragraph.AddFormattedText("subscript"); + formattedText.Subscript = true; + paragraph.AddText(" or "); + formattedText = paragraph.AddFormattedText("superscript"); + formattedText.Superscript = true; + paragraph.AddText("."); +} + +static void DemonstrateBordersAndShading(Document document) +{ + document.LastSection.AddPageBreak(); + document.LastSection.AddParagraph("Borders and Shading", "Heading2"); + + document.LastSection.AddParagraph("Border around Paragraph", "Heading3"); + + Paragraph paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Borders.Width = 2.5; + paragraph.Format.Borders.Color = Colors.Navy; + paragraph.Format.Borders.Distance = 3; + paragraph.AddText(FillerText.MediumText); + + document.LastSection.AddParagraph("Shading", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Format.Shading.Color = Colors.LightCoral; + paragraph.AddText(FillerText.Text); + + document.LastSection.AddParagraph("Borders & Shading", "Heading3"); + + paragraph = document.LastSection.AddParagraph(); + paragraph.Style = "TextBox"; + paragraph.AddText(FillerText.MediumText); +} +``` + +### Define Tables + +```cs +public static void DefineTables(Document document) +{ + Paragraph paragraph = document.LastSection.AddParagraph("Table Overview", "Heading1"); + paragraph.AddBookmark("Tables"); + + DemonstrateSimpleTable(document); + DemonstrateAlignment(document); + DemonstrateCellMerge(document); +} + +public static void DemonstrateSimpleTable(Document document) +{ + document.LastSection.AddParagraph("Simple Tables", "Heading2"); + + Table table = new Table(); + table.Borders.Width = 0.75; + + Column column = table.AddColumn(Unit.FromCentimeter(2)); + column.Format.Alignment = ParagraphAlignment.Center; + + table.AddColumn(Unit.FromCentimeter(5)); + + Row row = table.AddRow(); + row.Shading.Color = Colors.PaleGoldenrod; + Cell cell = row.Cells[0]; + cell.AddParagraph("Itemus"); + cell = row.Cells[1]; + cell.AddParagraph("Descriptum"); + + row = table.AddRow(); + cell = row.Cells[0]; + cell.AddParagraph("1"); + cell = row.Cells[1]; + cell.AddParagraph(FillerText.ShortText); + + row = table.AddRow(); + cell = row.Cells[0]; + cell.AddParagraph("2"); + cell = row.Cells[1]; + cell.AddParagraph(FillerText.Text); + + table.SetEdge(0, 0, 2, 3, Edge.Box, BorderStyle.Single, 1.5, Colors.Black); + + document.LastSection.Add(table); +} + +public static void DemonstrateAlignment(Document document) +{ + document.LastSection.AddParagraph("Cell Alignment", "Heading2"); + + Table table = document.LastSection.AddTable(); + table.Borders.Visible = true; + table.Format.Shading.Color = Colors.LavenderBlush; + table.Shading.Color = Colors.Salmon; + table.TopPadding = 5; + table.BottomPadding = 5; + + Column column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Left; + + column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Center; + + column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Right; + + table.Rows.Height = 35; + + Row row = table.AddRow(); + row.VerticalAlignment = VerticalAlignment.Top; + row.Cells[0].AddParagraph("Text"); + row.Cells[1].AddParagraph("Text"); + row.Cells[2].AddParagraph("Text"); + + row = table.AddRow(); + row.VerticalAlignment = VerticalAlignment.Center; + row.Cells[0].AddParagraph("Text"); + row.Cells[1].AddParagraph("Text"); + row.Cells[2].AddParagraph("Text"); + + row = table.AddRow(); + row.VerticalAlignment = VerticalAlignment.Bottom; + row.Cells[0].AddParagraph("Text"); + row.Cells[1].AddParagraph("Text"); + row.Cells[2].AddParagraph("Text"); +} + +public static void DemonstrateCellMerge(Document document) +{ + document.LastSection.AddParagraph("Cell Merge", "Heading2"); + + Table table = document.LastSection.AddTable(); + table.Borders.Visible = true; + table.TopPadding = 5; + table.BottomPadding = 5; + + Column column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Left; + + column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Center; + + column = table.AddColumn(); + column.Format.Alignment = ParagraphAlignment.Right; + + table.Rows.Height = 35; + + Row row = table.AddRow(); + row.Cells[0].AddParagraph("Merge Right"); + row.Cells[0].MergeRight = 1; + + row = table.AddRow(); + row.VerticalAlignment = VerticalAlignment.Bottom; + row.Cells[0].MergeDown = 1; + row.Cells[0].VerticalAlignment = VerticalAlignment.Bottom; + row.Cells[0].AddParagraph("Merge Down"); + + table.AddRow(); +} +``` + +### Define Charts + +```cs +public static void DefineCharts(Document document) +{ + Paragraph paragraph = document.LastSection.AddParagraph("Chart Overview", "Heading1"); + paragraph.AddBookmark("Charts"); + + document.LastSection.AddParagraph("Sample Chart", "Heading2"); + + Chart chart = new Chart(); + chart.Left = 0; + + chart.Width = Unit.FromCentimeter(16); + chart.Height = Unit.FromCentimeter(12); + Series series = chart.SeriesCollection.AddSeries(); + series.ChartType = ChartType.Column2D; + series.Add(new double[]{1, 17, 45, 5, 3, 20, 11, 23, 8, 19}); + series.HasDataLabel = true; + + series = chart.SeriesCollection.AddSeries(); + series.ChartType = ChartType.Line; + series.Add(new double[]{41, 7, 5, 45, 13, 10, 21, 13, 18, 9}); + + XSeries xseries = chart.XValues.AddXSeries(); + xseries.Add("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"); + + chart.XAxis.MajorTickMark = TickMarkType.Outside; + chart.XAxis.Title.Caption = "X-Axis"; + + chart.YAxis.MajorTickMark = TickMarkType.Outside; + chart.YAxis.HasMajorGridlines = true; + + chart.PlotArea.LineFormat.Color = Colors.DarkGray; + chart.PlotArea.LineFormat.Width = 1; + + document.LastSection.Add(chart); +} +``` diff --git a/docs/MigraDocCore/samples/HelloWorld.md b/docs/MigraDocCore/samples/HelloWorld.md new file mode 100644 index 00000000..aaded13d --- /dev/null +++ b/docs/MigraDocCore/samples/HelloWorld.md @@ -0,0 +1,71 @@ +# Hello World + +Is the obligatory "Hello World" program for MigraDocCore documents. + + +## The Main method: + +```cs +static void Main(string[] args) +{ + // Create a MigraDocCore document + Document document = CreateDocument(); + document.UseCmykColor = true; + + // ===== Unicode encoding and font program embedding in MigraDocCore is demonstrated here ===== + + // A flag indicating whether to create a Unicode PDF or a WinAnsi PDF file. + // This setting applies to all fonts used in the PDF document. + // This setting has no effect on the RTF renderer. + const bool unicode = false; + + // An enum indicating whether to embed fonts or not. + // This setting applies to all font programs used in the document. + // This setting has no effect on the RTF renderer. + // (The term 'font program' is used by Adobe for a file containing a font. Technically a 'font file' + // is a collection of small programs and each program renders the glyph of a character when executed. + // Using a font in PdfSharpCore may lead to the embedding of one or more font programs, because each outline + // (regular, bold, italic, bold+italic, ...) has its own font program) + const PdfFontEmbedding embedding = PdfFontEmbedding.Always; + + // ======================================================================================== + + // Create a renderer for the MigraDocCore document. + PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(unicode, embedding); + + // Associate the MigraDocCore document with a renderer + pdfRenderer.Document = document; + + // Layout and render document to PDF + pdfRenderer.RenderDocument(); + + // Save the document... + const string filename = "HelloWorld.pdf"; + pdfRenderer.PdfDocument.Save(filename); +} +``` + +The CreateDocument method: + +```cs +/// +/// Creates an absolutely minimalistic document. +/// +static Document CreateDocument() +{ + // Create a new MigraDocCore document + Document document = new Document(); + + // Add a section to the document + Section section = document.AddSection(); + + // Add a paragraph to the section + Paragraph paragraph = section.AddParagraph(); + paragraph.Format.Font.Color = Color.FromCmyk(100, 30, 20, 50); + + // Add some text to the paragraph + paragraph.AddFormattedText("Hello, World!", TextFormat.Bold); + + return document; +} +``` diff --git a/docs/MigraDocCore/samples/Images.md b/docs/MigraDocCore/samples/Images.md new file mode 100644 index 00000000..d95b63b6 --- /dev/null +++ b/docs/MigraDocCore/samples/Images.md @@ -0,0 +1,29 @@ +# Images + +Shows how to use images in MigraDocCore documents. + + +## Code + +```cs +/// +/// Creates an absolutely minimalistic document. +/// +static Document CreateDocument() +{ + // Create a new MigraDocCore document + Document document = new Document(); + + // Add a section to the document + Section section = document.AddSection(); + + // Add a paragraph to the section + Paragraph paragraph = section.AddParagraph(); + + // Add some text to the paragraph + paragraph.AddFormattedText("Hello, World!", TextFormat.Italic); + section.AddImage("../../SomeImage.png"); + + return document; +} +``` diff --git a/docs/MigraDocCore/samples/Invoice.md b/docs/MigraDocCore/samples/Invoice.md new file mode 100644 index 00000000..a9820889 --- /dev/null +++ b/docs/MigraDocCore/samples/Invoice.md @@ -0,0 +1,289 @@ +# Invoice + +Shows how to create a simple invoice of a fictional book store. +The invoice document is created with the MigraDocCore document object model and then rendered to PDF with PdfSharpCore. + + +## Creating the Document + +```cs +public Document CreateDocument() +{ + // Create a new MigraDocCore document + this.document = new Document(); + this.document.Info.Title = "A sample invoice"; + this.document.Info.Subject = "Demonstrates how to create an invoice."; + this.document.Info.Author = "Stefan Lange"; + + DefineStyles(); + CreatePage(); + FillContent(); + + return this.document; +} +``` + + +## Defining the Styles + +Styles define how the text will look: + +```cs +void DefineStyles() +{ + // Get the predefined style Normal. + Style style = this.document.Styles["Normal"]; + // Because all styles are derived from Normal, the next line changes the + // font of the whole document. Or, more exactly, it changes the font of + // all styles and paragraphs that do not redefine the font. + style.Font.Name = "Verdana"; + + style = this.document.Styles[StyleNames.Header]; + style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right); + + style = this.document.Styles[StyleNames.Footer]; + style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center); + + // Create a new style called Table based on style Normal + style = this.document.Styles.AddStyle("Table", "Normal"); + style.Font.Name = "Verdana"; + style.Font.Name = "Times New Roman"; + style.Font.Size = 9; + + // Create a new style called Reference based on style Normal + style = this.document.Styles.AddStyle("Reference", "Normal"); + style.ParagraphFormat.SpaceBefore = "5mm"; + style.ParagraphFormat.SpaceAfter = "5mm"; + style.ParagraphFormat.TabStops.AddTabStop("16cm", TabAlignment.Right); +} +``` + + +## Create Page + +Create the page with invoice table, header, footer: + +```cs +void CreatePage() +{ + // Each MigraDocCore document needs at least one section. + Section section = this.document.AddSection(); + + // Put a logo in the header + Image image = section.Headers.Primary.AddImage("../../PowerBooks.png"); + image.Height = "2.5cm"; + image.LockAspectRatio = true; + image.RelativeVertical = RelativeVertical.Line; + image.RelativeHorizontal = RelativeHorizontal.Margin; + image.Top = ShapePosition.Top; + image.Left = ShapePosition.Right; + image.WrapFormat.Style = WrapStyle.Through; + + // Create footer + Paragraph paragraph = section.Footers.Primary.AddParagraph(); + paragraph.AddText("PowerBooks Inc · Sample Street 42 · 56789 Cologne · Germany"); + paragraph.Format.Font.Size = 9; + paragraph.Format.Alignment = ParagraphAlignment.Center; + + // Create the text frame for the address + this.addressFrame = section.AddTextFrame(); + this.addressFrame.Height = "3.0cm"; + this.addressFrame.Width = "7.0cm"; + this.addressFrame.Left = ShapePosition.Left; + this.addressFrame.RelativeHorizontal = RelativeHorizontal.Margin; + this.addressFrame.Top = "5.0cm"; + this.addressFrame.RelativeVertical = RelativeVertical.Page; + + // Put sender in address frame + paragraph = this.addressFrame.AddParagraph("PowerBooks Inc · Sample Street 42 · 56789 Cologne"); + paragraph.Format.Font.Name = "Times New Roman"; + paragraph.Format.Font.Size = 7; + paragraph.Format.SpaceAfter = 3; + + // Add the print date field + paragraph = section.AddParagraph(); + paragraph.Format.SpaceBefore = "8cm"; + paragraph.Style = "Reference"; + paragraph.AddFormattedText("INVOICE", TextFormat.Bold); + paragraph.AddTab(); + paragraph.AddText("Cologne, "); + paragraph.AddDateField("dd.MM.yyyy"); + + // Create the item table + this.table = section.AddTable(); + this.table.Style = "Table"; + this.table.Borders.Color = TableBorder; + this.table.Borders.Width = 0.25; + this.table.Borders.Left.Width = 0.5; + this.table.Borders.Right.Width = 0.5; + this.table.Rows.LeftIndent = 0; + + // Before you can add a row, you must define the columns + Column column = this.table.AddColumn("1cm"); + column.Format.Alignment = ParagraphAlignment.Center; + + column = this.table.AddColumn("2.5cm"); + column.Format.Alignment = ParagraphAlignment.Right; + + column = this.table.AddColumn("3cm"); + column.Format.Alignment = ParagraphAlignment.Right; + + column = this.table.AddColumn("3.5cm"); + column.Format.Alignment = ParagraphAlignment.Right; + + column = this.table.AddColumn("2cm"); + column.Format.Alignment = ParagraphAlignment.Center; + + column = this.table.AddColumn("4cm"); + column.Format.Alignment = ParagraphAlignment.Right; + + // Create the header of the table + Row row = table.AddRow(); + row.HeadingFormat = true; + row.Format.Alignment = ParagraphAlignment.Center; + row.Format.Font.Bold = true; + row.Shading.Color = TableBlue; + row.Cells[0].AddParagraph("Item"); + row.Cells[0].Format.Font.Bold = false; + row.Cells[0].Format.Alignment = ParagraphAlignment.Left; + row.Cells[0].VerticalAlignment = VerticalAlignment.Bottom; + row.Cells[0].MergeDown = 1; + row.Cells[1].AddParagraph("Title and Author"); + row.Cells[1].Format.Alignment = ParagraphAlignment.Left; + row.Cells[1].MergeRight = 3; + row.Cells[5].AddParagraph("Extended Price"); + row.Cells[5].Format.Alignment = ParagraphAlignment.Left; + row.Cells[5].VerticalAlignment = VerticalAlignment.Bottom; + row.Cells[5].MergeDown = 1; + + row = table.AddRow(); + row.HeadingFormat = true; + row.Format.Alignment = ParagraphAlignment.Center; + row.Format.Font.Bold = true; + row.Shading.Color = TableBlue; + row.Cells[1].AddParagraph("Quantity"); + row.Cells[1].Format.Alignment = ParagraphAlignment.Left; + row.Cells[2].AddParagraph("Unit Price"); + row.Cells[2].Format.Alignment = ParagraphAlignment.Left; + row.Cells[3].AddParagraph("Discount (%)"); + row.Cells[3].Format.Alignment = ParagraphAlignment.Left; + row.Cells[4].AddParagraph("Taxable"); + row.Cells[4].Format.Alignment = ParagraphAlignment.Left; + + this.table.SetEdge(0, 0, 6, 2, Edge.Box, BorderStyle.Single, 0.75, Color.Empty); +} +``` + + +## Fill in the Content + +This routine adds the dynamic data to the invoice: + +```cs +void FillContent() +{ + // Fill address in address text frame + XPathNavigator item = SelectItem("/invoice/to"); + Paragraph paragraph = this.addressFrame.AddParagraph(); + paragraph.AddText(GetValue(item, "name/singleName")); + paragraph.AddLineBreak(); + paragraph.AddText(GetValue(item, "address/line1")); + paragraph.AddLineBreak(); + paragraph.AddText(GetValue(item, "address/postalCode") + " " + GetValue(item, "address/city")); + + // Iterate the invoice items + double totalExtendedPrice = 0; + XPathNodeIterator iter = this.navigator.Select("/invoice/items/*"); + while (iter.MoveNext()) + { + item = iter.Current; + double quantity = GetValueAsDouble(item, "quantity"); + double price = GetValueAsDouble(item, "price"); + double discount = GetValueAsDouble(item, "discount"); + + // Each item fills two rows + Row row1 = this.table.AddRow(); + Row row2 = this.table.AddRow(); + row1.TopPadding = 1.5; + row1.Cells[0].Shading.Color = TableGray; + row1.Cells[0].VerticalAlignment = VerticalAlignment.Center; + row1.Cells[0].MergeDown = 1; + row1.Cells[1].Format.Alignment = ParagraphAlignment.Left; + row1.Cells[1].MergeRight = 3; + row1.Cells[5].Shading.Color = TableGray; + row1.Cells[5].MergeDown = 1; + + row1.Cells[0].AddParagraph(GetValue(item, "itemNumber")); + paragraph = row1.Cells[1].AddParagraph(); + paragraph.AddFormattedText(GetValue(item, "title"), TextFormat.Bold); + paragraph.AddFormattedText(" by ", TextFormat.Italic); + paragraph.AddText(GetValue(item, "author")); + row2.Cells[1].AddParagraph(GetValue(item, "quantity")); + row2.Cells[2].AddParagraph(price.ToString("0.00") + " €"); + row2.Cells[3].AddParagraph(discount.ToString("0.0")); + row2.Cells[4].AddParagraph(); + row2.Cells[5].AddParagraph(price.ToString("0.00")); + double extendedPrice = quantity * price; + extendedPrice = extendedPrice * (100 - discount) / 100; + row1.Cells[5].AddParagraph(extendedPrice.ToString("0.00") + " €"); + row1.Cells[5].VerticalAlignment = VerticalAlignment.Bottom; + totalExtendedPrice += extendedPrice; + + this.table.SetEdge(0, this.table.Rows.Count - 2, 6, 2, Edge.Box, BorderStyle.Single, 0.75); + } + + // Add an invisible row as a space line to the table + Row row = this.table.AddRow(); + row.Borders.Visible = false; + + // Add the total price row + row = this.table.AddRow(); + row.Cells[0].Borders.Visible = false; + row.Cells[0].AddParagraph("Total Price"); + row.Cells[0].Format.Font.Bold = true; + row.Cells[0].Format.Alignment = ParagraphAlignment.Right; + row.Cells[0].MergeRight = 4; + row.Cells[5].AddParagraph(totalExtendedPrice.ToString("0.00") + " €"); + + // Add the VAT row + row = this.table.AddRow(); + row.Cells[0].Borders.Visible = false; + row.Cells[0].AddParagraph("VAT (19%)"); + row.Cells[0].Format.Font.Bold = true; + row.Cells[0].Format.Alignment = ParagraphAlignment.Right; + row.Cells[0].MergeRight = 4; + row.Cells[5].AddParagraph((0.19 * totalExtendedPrice).ToString("0.00") + " €"); + + // Add the additional fee row + row = this.table.AddRow(); + row.Cells[0].Borders.Visible = false; + row.Cells[0].AddParagraph("Shipping and Handling"); + row.Cells[5].AddParagraph(0.ToString("0.00") + " €"); + row.Cells[0].Format.Font.Bold = true; + row.Cells[0].Format.Alignment = ParagraphAlignment.Right; + row.Cells[0].MergeRight = 4; + + // Add the total due row + row = this.table.AddRow(); + row.Cells[0].AddParagraph("Total Due"); + row.Cells[0].Borders.Visible = false; + row.Cells[0].Format.Font.Bold = true; + row.Cells[0].Format.Alignment = ParagraphAlignment.Right; + row.Cells[0].MergeRight = 4; + totalExtendedPrice += 0.19 * totalExtendedPrice; + row.Cells[5].AddParagraph(totalExtendedPrice.ToString("0.00") + " €"); + + // Set the borders of the specified cell range + this.table.SetEdge(5, this.table.Rows.Count - 4, 1, 4, Edge.Box, BorderStyle.Single, 0.75); + + // Add the notes paragraph + paragraph = this.document.LastSection.AddParagraph(); + paragraph.Format.SpaceBefore = "1cm"; + paragraph.Format.Borders.Width = 0.75; + paragraph.Format.Borders.Distance = 3; + paragraph.Format.Borders.Color = TableBorder; + paragraph.Format.Shading.Color = TableGray; + item = SelectItem("/invoice"); + paragraph.AddText(GetValue(item, "notes")); +} +``` diff --git a/docs/MigraDocCore/samples/MixMigraDocCoreAndPDFsharpCore.md b/docs/MigraDocCore/samples/MixMigraDocCoreAndPDFsharpCore.md new file mode 100644 index 00000000..625affeb --- /dev/null +++ b/docs/MigraDocCore/samples/MixMigraDocCoreAndPDFsharpCore.md @@ -0,0 +1,143 @@ +# Mix MigraDocCore and PdfSharpCore + +Demonstrates how to mix MigraDocCore and PdfSharpCore. + + +## Creating the Document + +We create a PdfDocument, not a (MigraDocCore) Document: + +```cs +static void Main() +{ + DateTime now = DateTime.Now; + string filename = "MixMigraDocCoreAndPdfSharpCore.pdf"; + filename = Guid.NewGuid().ToString("D").ToUpper() + ".pdf"; + PdfDocument document = new PdfDocument(); + document.Info.Title = "PdfSharpCore XGraphic Sample"; + document.Info.Author = "Stefan Lange"; + document.Info.Subject = "Created with code snippets that show the use of graphical functions"; + document.Info.Keywords = "PdfSharpCore, XGraphics"; + + SamplePage1(document); + SamplePage2(document); + + Debug.WriteLine("seconds=" + (DateTime.Now - now).TotalSeconds.ToString()); + + // Save the document... + document.Save(filename); +} +``` + + +## The First Page + +Here we create a MigraDocCore Document object to draw the content of this page: + +```cs +static void SamplePage1(PdfDocument document) +{ + PdfPage page = document.AddPage(); + XGraphics gfx = XGraphics.FromPdfPage(page); + // HACK + gfx.MUH = PdfFontEncoding.Unicode; + gfx.MFEH = PdfFontEmbedding.Default; + + XFont font = new XFont("Verdana", 13, XFontStyle.Bold); + + gfx.DrawString("The following paragraph was rendered using MigraDocCore:", font, XBrushes.Black, + new XRect(100, 100, page.Width - 200, 300), XStringFormats.Center); + + // You always need a MigraDocCore document for rendering. + Document doc = new Document(); + Section sec = doc.AddSection(); + // Add a single paragraph with some text and format information. + Paragraph para = sec.AddParagraph(); + para.Format.Alignment = ParagraphAlignment.Justify; + para.Format.Font.Name = "Times New Roman"; + para.Format.Font.Size = 12; + para.Format.Font.Color = MigraDocCore.DocumentObjectModel.Colors.DarkGray; + para.Format.Font.Color = MigraDocCore.DocumentObjectModel.Colors.DarkGray; + para.AddText("Duisism odigna acipsum delesenisl "); + para.AddFormattedText("ullum in velenit", TextFormat.Bold); + para.AddText(" ipit iurero dolum zzriliquisis nit wis dolore vel et nonsequipit, velendigna "+ + "auguercilit lor se dipisl duismod tatem zzrit at laore magna feummod oloborting ea con vel "+ + "essit augiati onsequat luptat nos diatum vel ullum illummy nonsent nit ipis et nonsequis "+ + "niation utpat. Odolobor augait et non etueril landre min ut ulla feugiam commodo lortie ex "+ + "essent augait el ing eumsan hendre feugait prat augiatem amconul laoreet. ≤≥≈≠"); + para.Format.Borders.Distance = "5pt"; + para.Format.Borders.Color = Colors.Gold; + + // Create a renderer and prepare (=layout) the document + MigraDocCore.Rendering.DocumentRenderer docRenderer = new DocumentRenderer(doc); + docRenderer.PrepareDocument(); + + // Render the paragraph. You can render tables or shapes the same way. + docRenderer.RenderObject(gfx, XUnit.FromCentimeter(5), XUnit.FromCentimeter(10), "12cm", para); +} +``` + + +## Creating Page Two + +This page contains six pages, created with MigraDocCore and scaled down to fit on one page: + +```cs +static void SamplePage2(PdfDocument document) +{ + PdfPage page = document.AddPage(); + XGraphics gfx = XGraphics.FromPdfPage(page); + // HACK + gfx.MUH = PdfFontEncoding.Unicode; + gfx.MFEH = PdfFontEmbedding.Default; + + // Create document from HalloMigraDoc sample + Document doc = HelloMigraDoc.Documents.CreateDocument(); + + // Create a renderer and prepare (=layout) the document + MigraDocCore.Rendering.DocumentRenderer docRenderer = new DocumentRenderer(doc); + docRenderer.PrepareDocument(); + + // For clarity we use point as unit of measure in this sample. + // A4 is the standard letter size in Germany (21cm x 29.7cm). + XRect A4Rect = new XRect(0, 0, A4Width, A4Height); + + int pageCount = docRenderer.FormattedDocument.PageCount; + for (int idx = 0; idx < pageCount; idx++) + { + XRect rect = GetRect(idx); + + // Use BeginContainer / EndContainer for simplicity only. You can naturally use you own transformations. + XGraphicsContainer container = gfx.BeginContainer(rect, A4Rect, XGraphicsUnit.Point); + + // Draw page border for better visual representation + gfx.DrawRectangle(XPens.LightGray, A4Rect); + + // Render the page. Note that page numbers start with 1. + docRenderer.RenderPage(gfx, idx + 1); + + // Note: The outline and the hyperlinks (table of content) does not work in the produced PDF document. + + // Pop the previous graphical state + gfx.EndContainer(container); + } +} +``` + + +## Helper Routine GetRect + +Calculates the area of a scaled down page: + +```cs +static XRect GetRect(int index) +{ + XRect rect = new XRect(0, 0, A4Width / 3 * 0.9, A4Height / 3 * 0.9); + rect.X = (index % 3) * A4Width / 3 + A4Width * 0.05 / 3; + rect.Y = (index / 3) * A4Height / 3 + A4Height * 0.05 / 3; + return rect; +} + +static double A4Width = XUnit.FromCentimeter(21).Point; +static double A4Height = XUnit.FromCentimeter(29.7).Point; +``` diff --git a/docs/MigraDocCore/samples/index.md b/docs/MigraDocCore/samples/index.md new file mode 100644 index 00000000..1423ecc5 --- /dev/null +++ b/docs/MigraDocCore/samples/index.md @@ -0,0 +1,9 @@ +# MigraDocCore > Samples + +Samples for [MigraDocCore](../index.md): + +* [Hello World](HelloWorld.md) +* [Hello MigraDocCore](HelloMigraDocCore.md) +* [Images](Images.md) +* [Invoice](Invoice.md) +* [Mix MigraDocCore and PdfSharpCore](MixMigraDocCoreAndPDFsharpCore.md) diff --git a/docs/PdfSharpCore/faq.md b/docs/PdfSharpCore/faq.md new file mode 100644 index 00000000..a231fad8 --- /dev/null +++ b/docs/PdfSharpCore/faq.md @@ -0,0 +1,107 @@ +# PdfSharpCore > FAQ + +FAQ for [PdfSharpCore](index.md): + + +## What is PdfSharpCore + +PdfSharpCore is a .NET library for creating and modifying Adobe PDF documents programmatically. It is written in C# and can be used from any .NET language. + + +## Is PdfSharpCore based on or does it require other libraries or tools? + +PdfSharpCore is newly designed and built from scratch in C#. Neither Adobe's PDF Library nor Acrobat are required. + + +## What is the license of PdfSharpCore? + +PdfSharpCore is Open Source. You can copy, modify and integrate the source code of PdfSharpCore in your application without restrictions at all. + +See also: PdfSharpCore [license](../../LICENCE.md) + + +## Can PdfSharpCore show PDF files? Print PDF files? Create images from PDF files? + +PdfSharpCore comes with a preview control designed to visualize drawing operations of the XGraphics object, but it cannot render PDF files. + +Further the DrawImage function can be used to draw so called form XObjects in PDF pages. If you try to render such an object in the preview, only the bounding box is drawn to show that it cannot be rendered. + +The PdfSharpCore [samples](samples/index.md) show how to invoke Adobe Reader or Acrobat to view or print PDF files and how to invoke GhostScript to create images from PDF pages. + + +## Can I use PostScript fonts with PdfSharpCore? + +PdfSharpCore cannot work with PostScript fonts. Only TrueType fonts and OpenType fonts with TrueType outlines can be used with PdfSharpCore. Read more... + + +## Can PdfSharpCore run on Web Servers under Medium Trust? + +You can run applications on web servers without full trust provided you only use fonts that are serviced by your own FontResolver. See the PdfSharpCore sample: [Font Resolver](samples/FontResolver.md) for further information. + + +## Does PdfSharpCore support for Arabic, Hebrew, CJK (Chinese, Japanese, Korean)? + +Not yet. Right-to-left languages are not yet supported. Only simple languages like English or German are supported, with an easy one-to-one relationship between characters and glyphs. + +"Not supported" needs some explanation. + +It seems that Hebrew works if you reverse the strings and set all paragraphs to left-aligned. + +Japanese characters will be displayed, but left to right and not top to bottom. We cannot read Japanese and cannot verify they are shown correctly. Make sure you select a font that contains Japanese characters. + +Arabic characters have different shapes (glyphs), depending on their position (beginning, end, middle, isolated). PdfSharpCore does not support the selection of the correct glyphs. Arabic text may work if you reverse the string and if you make sure to select the correct Unicode characters for beginning, end, middle, or isolated display. Make sure you select a font that contains Arabic characters. + + +## Which PDF versions are supported by PdfSharpCore? + +With PdfSharpCore you can create files with PDF versions from 1.2 (Adobe Acrobat Reader 3.0) through 1.7 (Adobe Reader 8.0). +PdfSharpCore fully supports PDF 1.4 (Adobe Reader 5.0) including the transparency features introduced with this version. +Some features of PDF 1.5 (Adobe Reader 6.0) are not yet implemented. Therefore PdfSharpCore cannot yet open all files marked for PDF 1.5 or higher. Since not all compression features of PDF 1.5 are implemented, with some files the file size may increase when they are processed with PdfSharpCore. + + +## Does PdfSharpCore support PDF/A? + +Not yet. + + +## Does PdfSharpCore support AcroForms? + +There is limited support for AcroForms included. + + +## Can I use PdfSharpCore to convert HTML or RTF to PDF? + +No, not "out of the box", and we do not plan to write such a converter in the near future. + +Yes, PdfSharpCore with some extra code can do it. But we do not supply that extra code. +On NuGet and other sources you can find a third party library "HTML Renderer for PDF using PdfSharpCore" that converts HTML to PDF. And there may be other libraries for the same or similar purposes, too. Maybe they work for you, maybe they get you started. + + +## Can I use PdfSharpCore to convert PDF to Word, RTF, HTML? + +No, and we do not plan to write such a converter in the near future. + + +## Can I use PDF files created with SQL Server 2008 Reporting Services? + +There is an issue with the PDFs created by SQL Server 2008 Reporting Services. We are working on it. +As a workaround, create reports with SQL Server 2005 Reporting Services. Workaround for SQL Server 2008 Reporting Services: For the DeviceSettings parameter for the Render method on the ReportExecutionService object, pass this value: +`theDeviceSettings = "True";`. +This disables PDF file compression for SSRS 2008. Then, PdfSharpCore is able to handle the resulting uncompressed PDF file. (Note: SSRS 2005 ignores this setting so it can be passed to both SSRS versions.) + + +## Can I use PdfSharpCore to extract text from PDF? + +This can be done at a low level. You can get at the characters in the order they are drawn - and most applications draw them from top-left to bottom-right. There are no high-level functions that return words, paragraphs, or whole pages. + + +## Can PdfSharpCore simulate Bold or Italics? + +Not yet. + + +## How many DPI are there in a PDF file? How can I set the DPI? + +PDF is a vector format, so there are no DPI. Raster images used in a PDF file do have DPI, but DPI is determined by the usage. +Consider an image with 300 DPI. This image can be embedded once in the PDF file, but can be drawn several times. There could be a thumbnail on page 1, a full size reproduction on page 2, and a double size reproduction on page 3. Thus the image is drawn with 600 DPI on page 1, 300 DPI on page 2, and 150 DPI on page 3. But when you watch the PDF file in Adobe Reader with a Zoom factor of 1000%, the DPI value will be much lower than that. +PDF is vector. There is no DPI. PdfSharpCore uses Points as the unit for coordinates. There are 72 Points per Inch. For ease of use, units can be converted from Inch, Centimeter, Millimeter and other units. diff --git a/docs/PdfSharpCore/index.md b/docs/PdfSharpCore/index.md new file mode 100644 index 00000000..b61ce06b --- /dev/null +++ b/docs/PdfSharpCore/index.md @@ -0,0 +1,63 @@ +# PdfSharpCore + +PdfSharpCore is a .NET library for processing PDF file. +You create PDF pages using drawing routines known from GDI+. +Almost anything that can be done with GDI+ will also work with PdfSharpCore. +Keep in mind it does no longer depend on GDI+, as it was ported to make use of [ImageSharp](https://github.com/SixLabors/ImageSharp). +Only basic text layout is supported by PdfSharpCore, and page breaks are not created automatically. +The same drawing routines can be used for screen, PDF, or meta files. + +* [Features](#features) +* [First steps](#first-steps) +* [Samples](samples/index.md) +* [FAQ](faq.md) + + +## Features + +* Creates PDF documents on the fly from any .NET language +* Easy to understand object model to compose documents +* One source code for drawing on a PDF page as well as in a window or on the printer +* Modify, merge, and split existing PDF files +* Images with transparency (color mask, monochrome mask, alpha mask) +* Newly designed from scratch and written entirely in C# +* The graphical classes go well with .NET + + +## First steps + +Both PdfSharpCore and MigraDocCore provide a lot of `AddXxx` functions. +Typically these functions return the newly created objects. Once you’ve learned the basic principles it’s quite easy to work with. +Intellisense helps a lot then. + +We’ll discuss a few lines of the [Hello World](samples/HelloWorld.md) sample here. + +```cs +// You’ll first need a PDF document: +PdfDocument document = new PdfDocument(); + +// And you need a page: +PdfPage page = document.AddPage(); + +// Drawing is done with an XGraphics object: +XGraphics gfx = XGraphics.FromPdfPage(page); + +// Then you'll create a font: +XFont font = new XFont("Verdana", 20, XFontStyle.Bold); + +// And you'll create an alignment to your text +XStringFormat stringFormat = new XStringFormat +{ + Alignment = XStringAlignment.Center +}; + +// And you use that font and alignment to draw a string: +gfx.DrawString( + "Hello, World!", font, XBrushes.Black, + new XRect(0, 0, page.Width, page.Height), + stringFormat); + +// When drawing is done, write the file: +string filename = "HelloWorld.pdf"; +document.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/Annotations.md b/docs/PdfSharpCore/samples/Annotations.md new file mode 100644 index 00000000..279a797d --- /dev/null +++ b/docs/PdfSharpCore/samples/Annotations.md @@ -0,0 +1,72 @@ +# Annotations + +This sample shows how to create PDF annotations. + +PdfSharpCore supports the creation of the following annotations: +* [Text annotations](#text-annotations) +* [Text annotations opened](#text-annotations-opened) +* [Rubber stamp annotations](#rubber-stamp-annotations) + + +## Text annotations + +```cs +// Create a PDF text annotation +PdfTextAnnotation textAnnot = new PdfTextAnnotation(); +textAnnot.Title = "This is the title"; +textAnnot.Subject = "This is the subject"; +textAnnot.Contents = "This is the contents of the annotation.\rThis is the 2nd line."; +textAnnot.Icon = PdfTextAnnotationIcon.Note; + +gfx.DrawString("The first text annotation", font, XBrushes.Black, 30, 50, XStringFormats.Default); + +// Convert rectangle from world space to page space. This is necessary because the annotation is +// placed relative to the bottom left corner of the page with units measured in point. +XRect rect = gfx.Transformer.WorldToDefaultPage(new XRect(new XPoint(30, 60), new XSize(30, 30))); +textAnnot.Rectangle = new PdfRectangle(rect); + +// Add the annotation to the page +page.Annotations.Add(textAnnot); +``` + + +## Text annotations opened +```cs +// Create another PDF text annotation which is open and transparent +textAnnot = new PdfTextAnnotation(); +textAnnot.Title = "Annotation 2 (title)"; +textAnnot.Subject = "Annotation 2 (subject)"; +textAnnot.Contents = "This is the contents of the 2nd annotation."; +textAnnot.Icon = PdfTextAnnotationIcon.Help; +textAnnot.Color = XColors.LimeGreen; +textAnnot.Opacity = 0.5; +textAnnot.Open = true; + +gfx.DrawString("The second text annotation (opened)", font, XBrushes.Black, 30, 140, XStringFormats.Default); + +rect = gfx.Transformer.WorldToDefaultPage(new XRect(new XPoint(30, 150), new XSize(30, 30))); +textAnnot.Rectangle = new PdfRectangle(rect); + +// Add the 2nd annotation to the page +page.Annotations.Add(textAnnot); +``` + + +## Rubber stamp annotations + +```cs +// Create a so called rubber stamp annotation. I'm not sure if it is useful, but at least +// it looks impressive... +PdfRubberStampAnnotation rsAnnot = new PdfRubberStampAnnotation(); +rsAnnot.Icon = PdfRubberStampAnnotationIcon.TopSecret; +rsAnnot.Flags = PdfAnnotationFlags.ReadOnly; + +rect = gfx.Transformer.WorldToDefaultPage(new XRect(new XPoint(100, 400), new XSize(350, 150))); +rsAnnot.Rectangle = new PdfRectangle(rect); + +// Add the rubber stamp annotation to the page +page.Annotations.Add(rsAnnot); +``` + +PDF supports some more pretty types of annotations like PdfLineAnnotation, PdfSquareAnnotation, PdfCircleAnnotation, PdfMarkupAnnotation (with the subtypes PdfHighlightAnnotation, PdfUnderlineAnnotation, PdfStrikeOutAnnotation, and PdfSquigglyAnnotation), PdfSoundAnnotation, or PdfMovieAnnotation. +If you need one of them, feel encouraged to implement it. It is quite easy. diff --git a/docs/PdfSharpCore/samples/Booklet.md b/docs/PdfSharpCore/samples/Booklet.md new file mode 100644 index 00000000..9625544a --- /dev/null +++ b/docs/PdfSharpCore/samples/Booklet.md @@ -0,0 +1,98 @@ +# Booklet + +Shows how to produce a booklet by placing two pages of an existing document on one landscape orientated page of a new document (for duplex printing). + + +## Code + +Here is the code that does the work: + +```cs +// Create the output document +PdfDocument outputDocument = new PdfDocument(); + +// Show single pages +// (Note: one page contains two pages from the source document. +// If the number of pages of the source document can not be +// divided by 4, the first pages of the output document will +// each contain only one page from the source document.) +outputDocument.PageLayout = PdfPageLayout.SinglePage; + +XGraphics gfx; + +// Open the external document as XPdfForm object +XPdfForm form = XPdfForm.FromFile(filename); +// Determine width and height +double extWidth = form.PixelWidth; +double extHeight = form.PixelHeight; + +int inputPages = form.PageCount; +int sheets = inputPages / 4; +if (sheets * 4 < inputPages) +sheets += 1; +int allpages = 4 * sheets; +int vacats = allpages - inputPages; + +for (int idx = 1; idx <= sheets; idx += 1) +{ + // Front page of a sheet: + // Add a new page to the output document + PdfPage page = outputDocument.AddPage(); + page.Orientation = PageOrientation.Landscape; + page.Width = 2 * extWidth; + page.Height = extHeight; + double width = page.Width; + double height = page.Height; + + gfx = XGraphics.FromPdfPage(page); + + // Skip if left side has to remain blank + XRect box; + if (vacats > 0) + vacats -= 1; + else + { + // Set page number (which is one-based) for left side + form.PageNumber = allpages + 2 * (1 - idx); + box = new XRect(0, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + } + + // Set page number (which is one-based) for right side + form.PageNumber = 2 * idx - 1; + box = new XRect(width / 2, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + + // Back page of a sheet + page = outputDocument.AddPage(); + page.Orientation = PageOrientation.Landscape; + page.Width = 2 * extWidth; + page.Height = extHeight; + + gfx = XGraphics.FromPdfPage(page); + + // Set page number (which is one-based) for left side + form.PageNumber = 2 * idx; + box = new XRect(0, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + + // Skip if right side has to remain blank + if (vacats > 0) + vacats -= 1; + else + { + // Set page number (which is one-based) for right side + form.PageNumber = allpages + 1 - 2 * idx; + box = new XRect(width / 2, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + } +} + +// Save the document... +filename = "Booklet.pdf"; +outputDocument.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/Bookmarks.md b/docs/PdfSharpCore/samples/Bookmarks.md new file mode 100644 index 00000000..8a60cb99 --- /dev/null +++ b/docs/PdfSharpCore/samples/Bookmarks.md @@ -0,0 +1,43 @@ +# Bookmarks + +This sample shows how to create bookmarks. Bookmarks are called outlines in the PDF reference manual, that's why you deal with the class PdfOutline. + +Acrobat uses the term "bookmark" in its English version and "Lesezeichen" in the German version. + + +## Code + +This is the source code that demonstrates the creation of bookmarks: + +```cs +// Create a new PDF document +PdfDocument document = new PdfDocument(); + +// Create a font +XFont font = new XFont("Verdana", 16); + +// Create first page +PdfPage page = document.AddPage(); +XGraphics gfx = XGraphics.FromPdfPage(page); +gfx.DrawString("Page 1", font, XBrushes.Black, 20, 50, XStringFormats.Default); + +// Create the root bookmark. You can set the style and the color. +PdfOutline outline = document.Outlines.Add("Root", page, true, PdfOutlineStyle.Bold, XColors.Red); + +// Create some more pages +for (int idx = 2; idx <= 5; idx++) +{ + page = document.AddPage(); + gfx = XGraphics.FromPdfPage(page); + + string text = "Page " + idx; + gfx.DrawString(text, font, XBrushes.Black, 20, 50, XStringFormats.Default); + + // Create a sub bookmark + outline.Outlines.Add(text, page, true); +} + +// Save the document... +const string filename = "Bookmarks_tempfile.pdf"; +document.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/Clock.md b/docs/PdfSharpCore/samples/Clock.md new file mode 100644 index 00000000..c2e60f70 --- /dev/null +++ b/docs/PdfSharpCore/samples/Clock.md @@ -0,0 +1,141 @@ +# Clock + +This sample shows how to create a PDF document on the fly in an ASP.NET application. For illustration the sample draws an analog clock that displays the current server time. + + +## Code +Here is the framework for an .aspx page that returns a PDF file: + +```cs +void Page_Load(object sender, EventArgs e) +{ + // Create new PDF document + PdfDocument document = new PdfDocument(); + this.time = document.Info.CreationDate; + document.Info.Title = "PdfSharpCore Clock Demo"; + document.Info.Author = "Stefan Lange"; + document.Info.Subject = "Server time: " + + this.time.ToString("F", CultureInfo.InvariantCulture); + + // Create new page + PdfPage page = document.AddPage(); + page.Width = XUnit.FromMillimeter(200); + page.Height = XUnit.FromMillimeter(200); + + // Create graphics object and draw clock + XGraphics gfx = XGraphics.FromPdfPage(page); + RenderClock(gfx); + + // Send PDF to browser + MemoryStream stream = new MemoryStream(); + document.Save(stream, false); + Response.Clear(); + Response.ContentType = "application/pdf"; + Response.AddHeader("content-length", stream.Length.ToString()); + Response.BinaryWrite(stream.ToArray()); + Response.Flush(); + stream.Close(); + Response.End(); +} +``` + +Here's the routine that draws a clock on a square page (Inspired by Charles Petzold's AnalogClock sample in 'Programming Microsoft Windows with C#'): + +```cs +void RenderClock(XGraphics gfx) +{ + // Clocks should always look happy on hardcopies... + //this.time = new DateTime(2005, 1, 1, 11, 6, 22, 500); + + XColor strokeColor = XColors.DarkBlue; + XColor fillColor = XColors.DarkOrange; + + XPen pen = new XPen(strokeColor, 5); + XBrush brush = new XSolidBrush(fillColor); + + strokeColor.A = 0.8; + fillColor.A = 0.8; + XPen handPen = new XPen(strokeColor, 5); + XBrush handBrush = new XSolidBrush(fillColor); + + DrawText(gfx, pen, brush); + + double width = gfx.PageSize.Width; + double height = gfx.PageSize.Height; + gfx.TranslateTransform(width / 2, height / 2); + double scale = Math.Min(width, height); + gfx.ScaleTransform(scale / 2000); + + DrawFace(gfx, pen, brush); + DrawHourHand(gfx, handPen, handBrush); + DrawMinuteHand(gfx, handPen, handBrush); + DrawSecondHand(gfx, new XPen(XColors.Red, 7)); +} +``` + +The helper that draws the text: + +```cs +static void DrawText(XGraphics gfx, XPen pen, XBrush brush) +{ + XSize size = gfx.PageSize; + XGraphicsPath path = new XGraphicsPath(); + path.AddString("PdfSharpCore", + new XFontFamily("Verdana"), XFontStyle.BoldItalic, 60, + new XRect(0, size.Height / 3.5, size.Width, 0), XStringFormats.Center); + gfx.DrawPath(new XPen(pen.Color, 3), brush, path); +} +``` + +The helper that draws the face: + +```cs +static void DrawFace(XGraphics gfx, XPen pen, XBrush brush) +{ + for (int i = 0; i < 60; i++) + { + int size = i % 5 == 0 ? 100 : 30; + gfx.DrawEllipse(pen, brush, 0 - size / 2, -900 - size / 2, size, size); + gfx.RotateTransform(6); + } +} +``` + +Three helpers draw the hands: + +```cs +void DrawHourHand(XGraphics gfx, XPen pen, XBrush brush) +{ + XGraphicsState gs = gfx.Save(); + gfx.RotateTransform(360 * Time.Hour / 12 + 30 * Time.Minute / 60); + gfx.DrawPolygon( + pen, brush, + new XPoint[]{new XPoint(0, 150), new XPoint(100, 0), + new XPoint(0, -600), new XPoint(-100, 0)}, + XFillMode.Winding); + gfx.Restore(gs); +} + +void DrawMinuteHand(XGraphics gfx, XPen pen, XBrush brush) +{ + XGraphicsState gs = gfx.Save(); + gfx.RotateTransform(360 * Time.Minute / 60 + 6 * Time.Second / 60); + + gfx.DrawPolygon(pen, brush, + new XPoint[]{new XPoint(0, 200), new XPoint(50, 0), + new XPoint(0, -800), new XPoint(-50, 0)}, + XFillMode.Winding); + gfx.Restore(gs); +} + +void DrawSecondHand(XGraphics gfx, XPen pen) +{ + XGraphicsState gs = gfx.Save(); + + gfx.RotateTransform(360 * Time.Second / 60 + 6 * Time.Millisecond / 1000); + + gfx.DrawEllipse(new XSolidBrush(pen.Color), -15, -15, 30, 30); + gfx.DrawLine(pen, 0, 40, 0, -800); + gfx.Restore(gs); +} +``` diff --git a/docs/PdfSharpCore/samples/ColorsCMYK.md b/docs/PdfSharpCore/samples/ColorsCMYK.md new file mode 100644 index 00000000..b694662b --- /dev/null +++ b/docs/PdfSharpCore/samples/ColorsCMYK.md @@ -0,0 +1,36 @@ +# Colors CMYK + +This sample shows how to use CMYK colors. + + +## Code + +This is the source code the shows how to set the color mode to CMYK: + +```cs +PdfDocument document = PdfReader.Open(filename); +document.Options.ColorMode = PdfColorMode.Cmyk; + +// Set version to PDF 1.4 (Acrobat 5) because we use transparency. +if (document.Version < 14) + document.Version = 14; + +PdfPage page = document.Pages[0]; + +// Get an XGraphics object for drawing beneath the existing content + +XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append); + +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(1, 0.68, 0, 0.12)), new XRect(30, 60, 50, 50)); +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0, 0.70, 1, 0)), new XRect(550, 60, 50, 50)); + +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0, 0, 0, 0)), new XRect(90, 100, 50, 50)); +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0, 0, 0, 0)), new XRect(150, 100, 50, 50)); + +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0.7, 0, 0.70, 1, 0)), new XRect(90, 100, 50, 50)); +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0.5, 0, 0.70, 1, 0)), new XRect(150, 100, 50, 50)); + +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0.35, 0.15, 0, 0.08)), new XRect(50, 360, 50, 50)); +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0.25, 0.10, 0, 0.05)), new XRect(150, 360, 50, 50)); +gfx.DrawRectangle(new XSolidBrush(XColor.FromCmyk(0.15, 0.05, 0, 0)), new XRect(250, 360, 50, 50)); +``` diff --git a/docs/PdfSharpCore/samples/CombineDocuments.md b/docs/PdfSharpCore/samples/CombineDocuments.md new file mode 100644 index 00000000..f4a14e07 --- /dev/null +++ b/docs/PdfSharpCore/samples/CombineDocuments.md @@ -0,0 +1,132 @@ +# Combine Documents + +This sample shows how to create a new document from two existing PDF files. The pages are inserted alternately from two external documents. This may be useful for visual comparison. + +Two different techniques are demonstrated: +* How to import a page from an external document. This technique includes all annotations of the imported page. +* How to import a page as a PDF form object. This technique treats the pages of external documents like images that can be transformed and placed everywhere. + +## Variant 1 + +Imports pages from an external document. Note that this technique imports the whole page including the hyperlinks. + +```cs +// Open the input files +PdfDocument inputDocument1 = PdfReader.Open(filename1, PdfDocumentOpenMode.Import); +PdfDocument inputDocument2 = PdfReader.Open(filename2, PdfDocumentOpenMode.Import); + +// Create the output document +PdfDocument outputDocument = new PdfDocument(); + +// Show consecutive pages facing. Requires Acrobat 5 or higher. +outputDocument.PageLayout = PdfPageLayout.TwoColumnLeft; + +XFont font = new XFont("Verdana", 10, XFontStyle.Bold); +XStringFormat format = new XStringFormat(); +format.Alignment = XStringAlignment.Center; +format.LineAlignment = XLineAlignment.Far; +XGraphics gfx; +XRect box; +int count = Math.Max(inputDocument1.PageCount, inputDocument2.PageCount); +for (int idx = 0; idx < count; idx++) +{ + // Get page from 1st document + PdfPage page1 = inputDocument1.PageCount > idx ? + inputDocument1.Pages[idx] : new PdfPage(); + + // Get page from 2nd document + PdfPage page2 = inputDocument2.PageCount > idx ? + inputDocument2.Pages[idx] : new PdfPage(); + + // Add both pages to the output document + page1 = outputDocument.AddPage(page1); + page2 = outputDocument.AddPage(page2); + + // Write document file name and page number on each page + gfx = XGraphics.FromPdfPage(page1); + box = page1.MediaBox.ToXRect(); + box.Inflate(0, -10); + gfx.DrawString(String.Format("{0} • {1}", filename1, idx + 1), + font, XBrushes.Red, box, format); + + gfx = XGraphics.FromPdfPage(page2); + box = page2.MediaBox.ToXRect(); + box.Inflate(0, -10); + gfx.DrawString(String.Format("{0} • {1}", filename2, idx + 1), + font, XBrushes.Red, box, format); +} + +// Save the document... +const string filename = "CompareDocument1_tempfile.pdf"; +outputDocument.Save(filename); +``` + + +## Variant 2 + +Imports the pages as form X objects. Note that this technique copies only the visual content and the hyperlinks do not work. + +```cs +// Create the output document +PdfDocument outputDocument = new PdfDocument(); + +// Show consecutive pages facing +outputDocument.PageLayout = PdfPageLayout.TwoPageLeft; + +XFont font = new XFont("Verdana", 10, XFontStyle.Bold); +XStringFormat format = new XStringFormat(); +format.Alignment = XStringAlignment.Center; +format.LineAlignment = XLineAlignment.Far; +XGraphics gfx; +XRect box; + +// Open the external documents as XPdfForm objects. Such objects are +// treated like images. By default the first page of the document is +// referenced by a new XPdfForm. +XPdfForm form1 = XPdfForm.FromFile(filename1); +XPdfForm form2 = XPdfForm.FromFile(filename2); + +int count = Math.Max(form1.PageCount, form2.PageCount); +for (int idx = 0; idx < count; idx++) +{ + // Add two new pages to the output document + PdfPage page1 = outputDocument.AddPage(); + PdfPage page2 = outputDocument.AddPage(); + + if (form1.PageCount > idx) + { + // Get a graphics object for page1 + gfx = XGraphics.FromPdfPage(page1); + + // Set page number (which is one-based) + form1.PageNumber = idx + 1; + + // Draw the page identified by the page number like an image + gfx.DrawImage(form1, new XRect(0, 0, form1.PointWidth, form1.PointHeight)); + + // Write document file name and page number on each page + box = page1.MediaBox.ToXRect(); + box.Inflate(0, -10); + gfx.DrawString(String.Format("{0} • {1}", filename1, idx + 1), + font, XBrushes.Red, box, format); + } + + // Same as above for second page + if (form2.PageCount > idx) + { + gfx = XGraphics.FromPdfPage(page2); + + form2.PageNumber = idx + 1; + gfx.DrawImage(form2, new XRect(0, 0, form2.PointWidth, form2.PointHeight)); + + box = page2.MediaBox.ToXRect(); + box.Inflate(0, -10); + gfx.DrawString(String.Format("{0} • {1}", filename2, idx + 1), + font, XBrushes.Red, box, format); + } +} + +// Save the document... +const string filename = "CompareDocument2_tempfile.pdf"; +outputDocument.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/ConcatenateDocuments.md b/docs/PdfSharpCore/samples/ConcatenateDocuments.md new file mode 100644 index 00000000..26242d6e --- /dev/null +++ b/docs/PdfSharpCore/samples/ConcatenateDocuments.md @@ -0,0 +1,196 @@ +# Concatenate Documents + +This sample shows how to concatenate the pages of several PDF documents to one single file. + +* When you add the same external page twice or more, the content of the pages is shared. +* Each imported page can be individually extended with graphics and text. + + +## Code + +Here are code snippets for the 4 variations implemented in Concatenate Documents: + +```cs +/// +/// Imports all pages from a list of documents. +/// +static void Variant1() +{ + // Get some file names + string[] files = GetFiles(); + + // Open the output document + PdfDocument outputDocument = new PdfDocument(); + + // Iterate files + foreach (string file in files) + { + // Open the document to import pages from it. + PdfDocument inputDocument = PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // Iterate pages + int count = inputDocument.PageCount; + for (int idx = 0; idx < count; idx++) + { + // Get the page from the external document... + PdfPage page = inputDocument.Pages[idx]; + // ...and add it to the output document. + outputDocument.AddPage(page); + } + } + + // Save the document... + const string filename = "ConcatenatedDocument1_tempfile.pdf"; + outputDocument.Save(filename); +} +``` + +```cs +/// +/// This sample adds each page twice to the output document. The output document +/// becomes only a little bit larger because the content of the pages is reused +/// and not duplicated. +/// +static void Variant2() +{ + // Get some file names + string[] files = GetFiles(); + + // Open the output document + PdfDocument outputDocument = new PdfDocument(); + + // Show consecutive pages facing. Requires Acrobat 5 or higher. + outputDocument.PageLayout = PdfPageLayout.TwoColumnLeft; + + // Iterate files + foreach (string file in files) + { + // Open the document to import pages from it. + PdfDocument inputDocument = PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // Iterate pages + int count = inputDocument.PageCount; + for (int idx = 0; idx < count; idx++) + { + // Get the page from the external document... + PdfPage page = inputDocument.Pages[idx]; + // ...and add them twice to the output document. + outputDocument.AddPage(page); + outputDocument.AddPage(page); + } + } + + // Save the document... + const string filename = "ConcatenatedDocument2_tempfile.pdf"; + outputDocument.Save(filename); +} +``` + +```cs +/// +/// This sample adds a consecutive number in the middle of each page. +/// It shows how you can add graphics to an imported page. +/// +static void Variant3() +{ + // Get some file names + string[] files = GetFiles(); + + // Open the output document + PdfDocument outputDocument = new PdfDocument(); + + // Note that the output document may look significant larger than in Variant1. + // This is because adding graphics to an imported page causes the + // uncompression of its content if it was compressed in the external document. + // To compare file sizes you should either run the sample as Release build + // or uncomment the following line. + //outputDocument.Options.CompressContentStreams = true; + + XFont font = new XFont("Verdana", 40, XFontStyle.Bold); + int number = 0; + + // Iterate files + foreach (string file in files) + { + // Open the document to import pages from it. + PdfDocument inputDocument = PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // Iterate pages + int count = inputDocument.PageCount; + for (int idx = 0; idx < count; idx++) + { + // Get the page from the external document... + PdfPage page = inputDocument.Pages[idx]; + // ...and add it to the output document. + // Note that the PdfPage instance returned by AddPage is a + // different object. + page = outputDocument.AddPage(page); + + // Create a graphics object for this page. To draw beneath the existing + // content set 'Append' to 'Prepend'. + XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append); + DrawNumber(gfx, font, ++number); + } + } + + // Save the document... + const string filename = "ConcatenatedDocument3_tempfile.pdf"; + outputDocument.Save(filename); +} +``` + +```cs +/// +/// This sample is the combination of Variant2 and Variant3. It shows that you +/// can add external pages more than once and still add individual graphics on +/// each page. The external content is shared among the pages, the new graphics +/// are unique to each page. You can check this by comparing the file size +/// of Variant3 and Variant4. +/// +static void Variant4() +{ + // Get some file names + string[] files = GetFiles(); + + // Open the output document + PdfDocument outputDocument = new PdfDocument(); + + // For checking the file size uncomment next line. + //outputDocument.Options.CompressContentStreams = true; + + XFont font = new XFont("Verdana", 40, XFontStyle.Bold); + int number = 0; + + // Iterate files + foreach (string file in files) + { + // Open the document to import pages from it. + PdfDocument inputDocument = PdfReader.Open(file, PdfDocumentOpenMode.Import); + + // Show consecutive pages facing. Requires Acrobat 5 or higher. + outputDocument.PageLayout = PdfPageLayout.TwoColumnLeft; + + // Iterate pages + int count = inputDocument.PageCount; + for (int idx = 0; idx < count; idx++) + { + // Get the page from the external document... + PdfPage page = inputDocument.Pages[idx]; + // ...and add it twice to the output document. + PdfPage page1 = outputDocument.AddPage(page); + PdfPage page2 = outputDocument.AddPage(page); + + XGraphics gfx = + XGraphics.FromPdfPage(page1, XGraphicsPdfPageOptions.Append); + DrawNumber(gfx, font, ++number); + + gfx = XGraphics.FromPdfPage(page2, XGraphicsPdfPageOptions.Append); + DrawNumber(gfx, font, ++number); + } + } + + // Save the document... + const string filename = "ConcatenatedDocument4_tempfile.pdf"; + outputDocument.Save(filename); +} +``` diff --git a/docs/PdfSharpCore/samples/ExportImages.md b/docs/PdfSharpCore/samples/ExportImages.md new file mode 100644 index 00000000..46673d8a --- /dev/null +++ b/docs/PdfSharpCore/samples/ExportImages.md @@ -0,0 +1,102 @@ +# Export Images + +This sample shows how to export JPEG images from a PDF file. + +Note: This snippet shows how to export JPEG images from a PDF file. PdfSharpCore cannot convert PDF pages to JPEG files. This sample does not handle non-JPEG images. It does not (yet) handle JPEG images that have been flate-encoded. + +There are several different formats for non-JPEG images in PDF. Those are not supported by this simple sample and require several hours of coding, but this is left as an exercise to the reader. + +PdfSharpCore cannot render PDF pages - not to printers, not to bitmaps, not to JPEG files. + + +## Code + +Here is the source code that does the work: + +```cs +const string filename = "../../../../../PDFs/SomeLayout.pdf"; +PdfDocument document = PdfReader.Open(filename); + +int imageCount = 0; +// Iterate pages +foreach (PdfPage page in document.Pages) +{ + // Get resources dictionary + PdfDictionary resources = page.Elements.GetDictionary("/Resources"); + if (resources != null) + { + // Get external objects dictionary + PdfDictionary xObjects = resources.Elements.GetDictionary("/XObject"); + if (xObjects != null) + { + ICollection items = xObjects.Elements.Values; + // Iterate references to external objects + foreach (PdfItem item in items) + { + PdfReference reference = item as PdfReference; + if (reference != null) + { + PdfDictionary xObject = reference.Value as PdfDictionary; + // Is external object an image? + if (xObject != null && xObject.Elements.GetString("/Subtype") == "/Image") + { + ExportImage(xObject, ref imageCount); + } + } + } + } + } +} +``` + +The image exporter: + +```cs +static void ExportImage(PdfDictionary image, ref int count) +{ + string filter = image.Elements.GetName("/Filter"); + switch (filter) + { + case "/DCTDecode": + ExportJpegImage(image, ref count); + break; + + case "/FlateDecode": + ExportAsPngImage(image, ref count); + break; + } +} +``` + +Here's the routine that exports JPEG images: + +```cs +static void ExportJpegImage(PdfDictionary image, ref int count) +{ + // Fortunately JPEG has native support in PDF and exporting an image is just writing the stream to a file. + byte[] stream = image.Stream.Value; + FileStream fs = new FileStream(String.Format("Image{0}.jpeg", count++), FileMode.Create, FileAccess.Write); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(stream); + bw.Close(); +} +``` + +Other image formats are not yet implemented, here is the stub: + +```cs +static void ExportAsPngImage(PdfDictionary image, ref int count) +{ + int width = image.Elements.GetInteger(PdfImage.Keys.Width); + int height = image.Elements.GetInteger(PdfImage.Keys.Height); + int bitsPerComponent = image.Elements.GetInteger(PdfImage.Keys.BitsPerComponent); + + // TODO: You can put the code here that converts vom PDF internal image format to a Windows bitmap + // and use GDI+ to save it in PNG format. + // It is the work of a day or two for the most important formats. Take a look at the file + // PdfSharpCore.Pdf.Advanced/PdfImage.cs to see how we create the PDF image formats. + // We don't need that feature at the moment and therefore will not implement it. + // If you write the code for exporting images I would be pleased to publish it in a future release + // of PdfSharpCore. +} +``` diff --git a/docs/PdfSharpCore/samples/FontResolver.md b/docs/PdfSharpCore/samples/FontResolver.md new file mode 100644 index 00000000..79321f20 --- /dev/null +++ b/docs/PdfSharpCore/samples/FontResolver.md @@ -0,0 +1,114 @@ +# Font Resolver + +This sample shows how to use fonts that are included with your application. This allows you to use fonts that are not installed on the computer. + + +## Default font resolver + +PdfSharpCore comes with a [default font resolver](../../../PdfSharpCore/Utils/FontResolver.cs). +This resolver uses the fonts from the operating system. +The font directories depend on the used operating system. + +**Windows** +1. `%SystemRoot%\Fonts` +1. `%LOCALAPPDATA%\Microsoft\Windows\Fonts` + +**Linux** +1. `/usr/share/fonts` +1. `/usr/local/share/fonts` +1. `~/.fonts` + +**iOS** +1. `/Library/Fonts/` + + +## Custom font resolver + +When running on web services or servers, the operating system might **not** have the fonts installed you need or you can **not** install the font you need. +In this scenario you must provide the fonts yourself and therefore implement your own font resolver. + +### IFontResolver interface + +In your application you create a class that implements the `IFontResolver` interface. + +There are only two methods you have to implement. The first method returns a `FontResolverInfo` for every supported font. + +```cs +public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) +``` + +The other method is called using the `FaceName` from the FontResolverInfo you previously returned. At this stage, return the font data as a byte array. + +```cs +public byte[] GetFont(string faceName) +``` + +Now you only need one more step: register your font resolver using the global font resolver property. +Here MyFontResolver is the class that implements `IFontResolver`. + +```cs +GlobalFontSettings.FontResolver = new MyFontResolver(); +``` + +Note: The `FontResolver` is a global object and applies to all consumers of the PdfSharpCore library. It is also used when the MigraDocCore library creates PDF files. + +### Code + +This implementation is obviously not complete. +But it should be enough for everyone to implement their own. +For more details have a look at the [default font resolver](../../../PdfSharpCore/Utils/FontResolver.cs). + +```cs +using System; +using System.IO; +using PdfSharpCore.Utils; + +public class MyFontResolver : IFontResolver +{ + public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) + { + if (familyName.Equals("OpenSans", StringComparison.CurrentCultureIgnoreCase)) + { + if (isBold && isItalic) + { + return new FontResolverInfo("OpenSans-BoldItalic.ttf"); + } + else if (isBold) + { + return new FontResolverInfo("OpenSans-Bold.ttf"); + } + else if (isItalic) + { + return new FontResolverInfo("OpenSans-Italic.ttf"); + } + else + { + return new FontResolverInfo("OpenSans-Regular.ttf"); + } + } + return null; + } + + public byte[] GetFont(string faceName) + { + var faceNamePath = Path.Join("my path", faceName); + using(var ms = new MemoryStream()) + { + try + { + using(var fs = File.OpenRead(faceNamePath)) + { + fs.CopyTo(ms); + ms.Position = 0; + return ms.ToArray(); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw new Exception($"No Font File Found - " + faceNamePath); + } + } + } +} +``` diff --git a/docs/PdfSharpCore/samples/Graphics.md b/docs/PdfSharpCore/samples/Graphics.md new file mode 100644 index 00000000..af0fbbb8 --- /dev/null +++ b/docs/PdfSharpCore/samples/Graphics.md @@ -0,0 +1,877 @@ +# Graphics + +Shows some of the capabilities of the XGraphics class. +You'll find code snippets for the following graphical primitives: + +* [Lines and curves](#lines-and-curves) +* [Shapes](#shapes) +* [Graphical paths](#paths-class) +* [Text and fonts](#text-class) +* [Images and external PDF forms](#images) + + +## Main program + +This is the main function. It creates a PDF document and adds some sample pages listed below. + +```cs +static void Main() +{ + // Create a temporary file + string filename = String.Format("{0}_tempfile.pdf", Guid.NewGuid().ToString("D").ToUpper()); + s_document = new PdfDocument(); + s_document.Info.Title = "PdfSharpCore XGraphic Sample"; + s_document.Info.Author = "Stefan Lange"; + s_document.Info.Subject = "Created with code snippets that show the use of graphical functions"; + s_document.Info.Keywords = "PdfSharpCore, XGraphics"; + + // Create demonstration pages + new LinesAndCurves().DrawPage(s_document.AddPage()); + new Shapes().DrawPage(s_document.AddPage()); + new Paths().DrawPage(s_document.AddPage()); + new Text().DrawPage(s_document.AddPage()); + new Images().DrawPage(s_document.AddPage()); + + // Save the s_document... + s_document.Save(filename); +} +``` + + +## Lines and Curves + +Shows how to draw lines and curves. + +```cs +public void DrawPage(PdfPage page) +{ + XGraphics gfx = XGraphics.FromPdfPage(page); + DrawTitle(page, gfx, "Lines & Curves"); + + DrawLine(gfx, 1); + DrawLines(gfx, 2); + DrawBezier(gfx, 3); + DrawBeziers(gfx, 4); + DrawCurve(gfx, 5); + DrawArc(gfx, 6); +} +``` + +### Draw simple lines + +```cs +void DrawLine(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawLine"); + + gfx.DrawLine(XPens.DarkGreen, 0, 0, 250, 0); + gfx.DrawLine(XPens.Gold, 15, 7, 230, 15); + + XPen pen = new XPen(XColors.Navy, 4); + gfx.DrawLine(pen, 0, 20, 250, 20); + + pen = new XPen(XColors.Firebrick, 6); + pen.DashStyle = XDashStyle.Dash; + gfx.DrawLine(pen, 0, 40, 250, 40); + + pen.Width = 7.3; + pen.DashStyle = XDashStyle.DashDotDot; + gfx.DrawLine(pen, 0, 60, 250, 60); + + pen = new XPen(XColors.Goldenrod, 10); + pen.LineCap = XLineCap.Flat; + gfx.DrawLine(pen, 10, 90, 240, 90); + gfx.DrawLine(XPens.Black, 10, 90, 240, 90); + + pen = new XPen(XColors.Goldenrod, 10); + pen.LineCap = XLineCap.Square; + gfx.DrawLine(pen, 10, 110, 240, 110); + gfx.DrawLine(XPens.Black, 10, 110, 240, 110); + + pen = new XPen(XColors.Goldenrod, 10); + pen.LineCap = XLineCap.Round; + gfx.DrawLine(pen, 10, 130, 240, 130); + gfx.DrawLine(XPens.Black, 10, 130, 240, 130); + + EndBox(gfx); +} +``` + +### Draw a polyline + +```cs +void DrawLines(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawLines"); + + XPen pen = new XPen(XColors.DarkSeaGreen, 6); + pen.LineCap = XLineCap.Round; + pen.LineJoin = XLineJoin.Bevel; + XPoint[] points = new XPoint[] + { + new XPoint(20, 30), new XPoint(60, 120), + new XPoint(90, 20), new XPoint(170, 90), + new XPoint(230, 40) + }; + gfx.DrawLines(pen, points); + + EndBox(gfx); +} +``` + +### Draw a single Bézier curve + +```cs +void DrawBezier(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawBezier"); + + gfx.DrawBezier(new XPen(XColors.DarkRed, 5), 20, 110, 40, 10, 170, 90, 230, 20); + + EndBox(gfx); +} +``` + +### Draw two Bézier curves + +```cs +void DrawBeziers(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawBeziers"); + + XPoint[] points = new XPoint[] + { + new XPoint(20, 30), new XPoint(40, 120), + new XPoint(80, 20), new XPoint(110, 90), + new XPoint(180, 40), new XPoint(210, 40), + new XPoint(220, 80) + }; + XPen pen = new XPen(XColors.Firebrick, 4); + gfx.DrawBeziers(pen, points); + + EndBox(gfx); +} +``` + +### Draw a cardinal spline + +```cs +void DrawCurve(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawCurve"); + + XPoint[] points = new XPoint[] + { + new XPoint(20, 30), new XPoint(60, 120), + new XPoint(90, 20), new XPoint(170, 90), + new XPoint(230, 40) + }; + XPen pen = new XPen(XColors.RoyalBlue, 3.5); + gfx.DrawCurve(pen, points, 1); + + EndBox(gfx); +} +``` + +### Draw an arc + +```cs +void DrawArc(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawArc"); + + XPen pen = new XPen(XColors.Plum, 4.7); + gfx.DrawArc(pen, 0, 0, 250, 140, 190, 200); + + EndBox(gfx); +} +``` + + +## Shapes + +Shows how to draw graphical shapes. + +```cs +public void DrawPage(PdfPage page) +{ + XGraphics gfx = XGraphics.FromPdfPage(page); + DrawTitle(page, gfx, "Shapes"); + + DrawRectangle(gfx, 1); + DrawRoundedRectangle(gfx, 2); + DrawEllipse(gfx, 3); + DrawPolygon(gfx, 4); + DrawPie(gfx, 5); + DrawClosedCurve(gfx, 6); +} +``` + +### Draw rectangles + +```cs +void DrawRectangle(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawRectangle"); + + XPen pen = new XPen(XColors.Navy, Math.PI); + + gfx.DrawRectangle(pen, 10, 0, 100, 60); + gfx.DrawRectangle(XBrushes.DarkOrange, 130, 0, 100, 60); + gfx.DrawRectangle(pen, XBrushes.DarkOrange, 10, 80, 100, 60); + gfx.DrawRectangle(pen, XBrushes.DarkOrange, 150, 80, 60, 60); + + EndBox(gfx); +} +``` + +### Draw rounded rectangles + +```cs +void DrawRoundedRectangle(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawRoundedRectangle"); + + XPen pen = new XPen(XColors.RoyalBlue, Math.PI); + + gfx.DrawRoundedRectangle(pen, 10, 0, 100, 60, 30, 20); + gfx.DrawRoundedRectangle(XBrushes.Orange, 130, 0, 100, 60, 30, 20); + gfx.DrawRoundedRectangle(pen, XBrushes.Orange, 10, 80, 100, 60, 30, 20); + gfx.DrawRoundedRectangle(pen, XBrushes.Orange, 150, 80, 60, 60, 20, 20); + + EndBox(gfx); +} +``` + +### Draw ellipses + +```cs +void DrawEllipse(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawEllipse"); + + XPen pen = new XPen(XColors.DarkBlue, 2.5); + + gfx.DrawEllipse(pen, 10, 0, 100, 60); + gfx.DrawEllipse(XBrushes.Goldenrod, 130, 0, 100, 60); + gfx.DrawEllipse(pen, XBrushes.Goldenrod, 10, 80, 100, 60); + gfx.DrawEllipse(pen, XBrushes.Goldenrod, 150, 80, 60, 60); + + EndBox(gfx); +} +``` + +### Draw polygons + +```cs +void DrawPolygon(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawPolygon"); + + XPen pen = new XPen(XColors.DarkBlue, 2.5); + + gfx.DrawPolygon(pen, XBrushes.LightCoral, GetPentagram(50, new XPoint(60, 70)), XFillMode.Winding); + gfx.DrawPolygon(pen, XBrushes.LightCoral, GetPentagram(50, new XPoint(180, 70)), XFillMode.Alternate); + + EndBox(gfx); +} +``` + +### Draw pies + +```cs +void DrawPie(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawPie"); + + XPen pen = new XPen(XColors.DarkBlue, 2.5); + + gfx.DrawPie(pen, 10, 0, 100, 90, -120, 75); + gfx.DrawPie(XBrushes.Gold, 130, 0, 100, 90, -160, 150); + gfx.DrawPie(pen, XBrushes.Gold, 10, 50, 100, 90, 80, 70); + gfx.DrawPie(pen, XBrushes.Gold, 150, 80, 60, 60, 35, 290); + + EndBox(gfx); +} +``` + +### Draw a closed cardinal spline + +```cs +void DrawClosedCurve(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawClosedCurve"); + + XPen pen = new XPen(XColors.DarkBlue, 2.5); + gfx.DrawClosedCurve( + pen, XBrushes.SkyBlue, + new XPoint[] + { + new XPoint(10, 120), new XPoint(80, 30), + new XPoint(220, 20), new XPoint(170, 110), + new XPoint(100, 90) + }, + XFillMode.Winding, 0.7); + + EndBox(gfx); +} +``` + +### Paths class + +Shows how to draw graphical paths. + +```cs +public void DrawPage(PdfPage page) +{ + XGraphics gfx = XGraphics.FromPdfPage(page); + + DrawTitle(page, gfx, "Paths"); + + DrawPathOpen(gfx, 1); + DrawPathClosed(gfx, 2); + DrawPathAlternateAndWinding(gfx, 3); + DrawGlyphs(gfx, 5); + DrawClipPath(gfx, 6); +} +``` + +### Stroke an open path + +```cs +void DrawPathOpen(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawPath (open)"); + + XPen pen = new XPen(XColors.Navy, Math.PI); + pen.DashStyle = XDashStyle.Dash; + + XGraphicsPath path = new XGraphicsPath(); + path.AddLine(10, 120, 50, 60); + path.AddArc(50, 20, 110, 80, 180, 180); + path.AddLine(160, 60, 220, 100); + gfx.DrawPath(pen, path); + + EndBox(gfx); +} +``` + +### Stroke a closed path + +```cs +void DrawPathClosed(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawPath (closed)"); + + XPen pen = new XPen(XColors.Navy, Math.PI); + pen.DashStyle = XDashStyle.Dash; + + XGraphicsPath path = new XGraphicsPath(); + path.AddLine(10, 120, 50, 60); + path.AddArc(50, 20, 110, 80, 180, 180); + path.AddLine(160, 60, 220, 100); + path.CloseFigure(); + gfx.DrawPath(pen, path); + + EndBox(gfx); +} +``` + +### Draw an alternating and a winding path + +```cs +void DrawPathAlternateAndWinding(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawPath (alternate / winding)"); + + XPen pen = new XPen(XColors.Navy, 2.5); + + // Alternate fill mode + XGraphicsPath path = new XGraphicsPath(); + path.FillMode = XFillMode.Alternate; + path.AddLine(10, 130, 10, 40); + path.AddBeziers( + new XPoint[] + { + new XPoint(10, 40), new XPoint(30, 0), + new XPoint(40, 20), new XPoint(60, 40), + new XPoint(80, 60), new XPoint(100, 60), + new XPoint(120, 40) + } + ); + path.AddLine(120, 40, 120, 130); + path.CloseFigure(); + path.AddEllipse(40, 80, 50, 40); + gfx.DrawPath(pen, XBrushes.DarkOrange, path); + + // Winding fill mode + path = new XGraphicsPath(); + path.FillMode = XFillMode.Winding; + path.AddLine(130, 130, 130, 40); + path.AddBeziers( + new XPoint[] + { + new XPoint(130, 40), new XPoint(150, 0), + new XPoint(160, 20), new XPoint(180, 40), + new XPoint(200, 60), new XPoint(220, 60), + new XPoint(240, 40) + } + ); + path.AddLine(240, 40, 240, 130); + path.CloseFigure(); + path.AddEllipse(160, 80, 50, 40); + gfx.DrawPath(pen, XBrushes.DarkOrange, path); + + EndBox(gfx); +} +``` + +### Convert text to path + +```cs +void DrawGlyphs(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "Draw Glyphs"); + + XGraphicsPath path = new XGraphicsPath(); + path.AddString( + "Hello!", new XFontFamily("Times New Roman"), + XFontStyle.BoldItalic, 100, + new XRect(0, 0, 250, 140), + XStringFormats.Center + ); + + gfx.DrawPath(new XPen(XColors.Purple, 2.3), XBrushes.DarkOrchid, path); + + EndBox(gfx); +} +``` + +### Clip through path + +```cs +void DrawClipPath(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "Clip through Path"); + + XGraphicsPath path = new XGraphicsPath(); + path.AddString( + "Clip!", new XFontFamily("Verdana"), + XFontStyle.Bold, 90, + new XRect(0, 0, 250, 140), + XStringFormats.Center + ); + + gfx.IntersectClip(path); + + // Draw a beam of dotted lines + XPen pen = XPens.DarkRed.Clone(); + pen.DashStyle = XDashStyle.Dot; + for (double r = 0; r <= 90; r += 0.5) + { + gfx.DrawLine( + pen, 0, 0, + 250 * Math.Cos(r / 90 * Math.PI), + 250 * Math.Sin(r / 90 * Math.PI) + ); + } + + EndBox(gfx); +} +``` + +## Text class + +Shows how to handle text. + +```cs +public void DrawPage(PdfPage page) +{ + XGraphics gfx = XGraphics.FromPdfPage(page); + DrawTitle(page, gfx, "Text"); + + DrawText(gfx, 1); + DrawTextAlignment(gfx, 2); + MeasureText(gfx, 3); +} +``` + +### Draw text in different styles + +```cs + void DrawText(XGraphics gfx, int number) + { + BeginBox(gfx, number, "Text Styles"); + + const string facename = "Times New Roman"; + + //XPdfFontOptions options = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always); + XPdfFontOptions options = new XPdfFontOptions(PdfFontEncoding.WinAnsi, PdfFontEmbedding.Default); + + XFont fontRegular = new XFont(facename, 20, XFontStyle.Regular, options); + XFont fontBold = new XFont(facename, 20, XFontStyle.Bold, options); + XFont fontItalic = new XFont(facename, 20, XFontStyle.Italic, options); + XFont fontBoldItalic = new XFont(facename, 20, XFontStyle.BoldItalic, options); + + // The default alignment is baseline left (that differs from GDI+) + gfx.DrawString("Times (regular)", fontRegular, XBrushes.DarkSlateGray, 0, 30); + gfx.DrawString("Times (bold)", fontBold, XBrushes.DarkSlateGray, 0, 65); + gfx.DrawString("Times (italic)", fontItalic, XBrushes.DarkSlateGray, 0, 100); + gfx.DrawString("Times (bold italic)", fontBoldItalic, XBrushes.DarkSlateGray, 0, 135); + + EndBox(gfx); + } +``` + +### Show how to align text in the layout rectangle + +```cs +void DrawTextAlignment(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "Text Alignment"); + XRect rect = new XRect(0, 0, 250, 140); + + XFont font = new XFont("Verdana", 10); + XBrush brush = XBrushes.Purple; + XStringFormat format = new XStringFormat(); + + gfx.DrawRectangle(XPens.YellowGreen, rect); + gfx.DrawLine(XPens.YellowGreen, rect.Width / 2, 0, rect.Width / 2, rect.Height); + gfx.DrawLine(XPens.YellowGreen, 0, rect.Height / 2, rect.Width, rect.Height / 2); + + gfx.DrawString("TopLeft", font, brush, rect, format); + + format.Alignment = XStringAlignment.Center; + gfx.DrawString("TopCenter", font, brush, rect, format); + + format.Alignment = XStringAlignment.Far; + gfx.DrawString("TopRight", font, brush, rect, format); + + format.LineAlignment = XLineAlignment.Center; + format.Alignment = XStringAlignment.Near; + gfx.DrawString("CenterLeft", font, brush, rect, format); + + format.Alignment = XStringAlignment.Center; + gfx.DrawString("Center", font, brush, rect, format); + + format.Alignment = XStringAlignment.Far; + gfx.DrawString("CenterRight", font, brush, rect, format); + + format.LineAlignment = XLineAlignment.Far; + format.Alignment = XStringAlignment.Near; + gfx.DrawString("BottomLeft", font, brush, rect, format); + + format.Alignment = XStringAlignment.Center; + gfx.DrawString("BottomCenter", font, brush, rect, format); + + format.Alignment = XStringAlignment.Far; + gfx.DrawString("BottomRight", font, brush, rect, format); + + EndBox(gfx); +} +``` + +### Show how to get text metric information + +```cs +void MeasureText(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "Measure Text"); + + const XFontStyle style = XFontStyle.Regular; + XFont font = new XFont("Times New Roman", 95, style); + + const string text = "Hallo"; + const double x = 20, y = 100; + XSize size = gfx.MeasureString(text, font); + + double lineSpace = font.GetHeight(gfx); + int cellSpace = font.FontFamily.GetLineSpacing(style); + int cellAscent = font.FontFamily.GetCellAscent(style); + int cellDescent = font.FontFamily.GetCellDescent(style); + int cellLeading = cellSpace - cellAscent - cellDescent; + + // Get effective ascent + double ascent = lineSpace * cellAscent / cellSpace; + gfx.DrawRectangle(XBrushes.Bisque, x, y - ascent, size.Width, ascent); + + // Get effective descent + double descent = lineSpace * cellDescent / cellSpace; + gfx.DrawRectangle(XBrushes.LightGreen, x, y, size.Width, descent); + + // Get effective leading + double leading = lineSpace * cellLeading / cellSpace; + gfx.DrawRectangle(XBrushes.Yellow, x, y + descent, size.Width, leading); + + // Draw text half transparent + XColor color = XColors.DarkSlateBlue; + color.A = 0.6; + gfx.DrawString(text, font, new XSolidBrush(color), x, y); + + EndBox(gfx); +} +``` + + +## Images + +Shows how to draw images. + +```cs +public void DrawPage(PdfPage page) +{ + XGraphics gfx = XGraphics.FromPdfPage(page); + DrawTitle(page, gfx, "Images"); + + DrawImage(gfx, 1); + DrawImageScaled(gfx, 2); + DrawImageRotated(gfx, 3); + DrawImageSheared(gfx, 4); + DrawGif(gfx, 5); + DrawPng(gfx, 6); + DrawTiff(gfx, 7); + DrawFormXObject(gfx, 8); +} +``` + +### Draw an image in original size + +```cs +void DrawImage(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawImage (original)"); + + XImage image = XImage.FromFile(jpegSamplePath); + + // Left position in point + double x = (250 - image.PixelWidth * 72 / image.HorizontalResolution) / 2; + gfx.DrawImage(image, x, 0); + + EndBox(gfx); +} +``` + +### Draw an image scaled + +```cs +void DrawImageScaled(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawImage (scaled)"); + + XImage image = XImage.FromFile(jpegSamplePath); + gfx.DrawImage(image, 0, 0, 250, 140); + + EndBox(gfx); +} +``` + +### Draw an image transformed + +```cs +void DrawImageRotated(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawImage (rotated)"); + + XImage image = XImage.FromFile(jpegSamplePath); + + const double dx = 250, dy = 140; + + gfx.TranslateTransform(dx / 2, dy / 2); + gfx.ScaleTransform(0.7); + gfx.RotateTransform(-25); + gfx.TranslateTransform(-dx / 2, -dy / 2); + + //XMatrix matrix = new XMatrix(); //XMatrix.Identity; + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, 0, width, height); + + EndBox(gfx); +} +``` + +### Draw an image transformed + +```cs +void DrawImageSheared(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawImage (sheared)"); + + XImage image = XImage.FromFile(jpegSamplePath); + + const double dx = 250, dy = 140; + + gfx.TranslateTransform(dx / 2, dy / 2); + gfx.ScaleTransform(-0.7, 0.7); + gfx.ShearTransform(-0.4, -0.3); + gfx.TranslateTransform(-dx / 2, -dy / 2); + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, 0, width, height); + + EndBox(gfx); +} +``` + +### Draw a GIF image with transparency + +```cs +void DrawGif(XGraphics gfx, int number) +{ + this.backColor = XColors.LightGoldenrodYellow; + this.borderPen = new XPen(XColor.FromArgb(202, 121, 74), this.borderWidth); + BeginBox(gfx, number, "DrawImage (GIF)"); + + XImage image = XImage.FromFile(gifSamplePath); + + const double dx = 250, dy = 140; + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, (dy - height) / 2, width, height); + + EndBox(gfx); +} +``` + +### Draw a PNG image with transparency + +```cs +void DrawPng(XGraphics gfx, int number) +{ + BeginBox(gfx, number, "DrawImage (PNG)"); + + XImage image = XImage.FromFile(pngSamplePath); + + const double dx = 250, dy = 140; + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, (dy - height) / 2, width, height); + + EndBox(gfx); +} +``` + +### Draw a TIFF image with transparency + +```cs +void DrawTiff(XGraphics gfx, int number) +{ + XColor oldBackColor = this.backColor; + this.backColor = XColors.LightGoldenrodYellow; + BeginBox(gfx, number, "DrawImage (TIFF)"); + + XImage image = XImage.FromFile(tiffSamplePath); + + const double dx = 250, dy = 140; + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, (dy - height) / 2, width, height); + + EndBox(gfx); + this.backColor = oldBackColor; +} +``` + +### Draw a form XObject (a page from an external PDF file) + +```cs +void DrawFormXObject(XGraphics gfx, int number) +{ + //this.backColor = XColors.LightSalmon; + BeginBox(gfx, number, "DrawImage (Form XObject)"); + + XImage image = XImage.FromFile(pdfSamplePath); + + const double dx = 250, dy = 140; + + gfx.TranslateTransform(dx / 2, dy / 2); + gfx.ScaleTransform(0.35); + gfx.TranslateTransform(-dx / 2, -dy / 2); + + double width = image.PixelWidth * 72 / image.HorizontalResolution; + double height = image.PixelHeight * 72 / image.HorizontalResolution; + + gfx.DrawImage(image, (dx - width) / 2, (dy - height) / 2, width, height); + + EndBox(gfx); +} +``` + +## Helper Functions + +Shows how to draw the page title and the rounded boxes. + +### Draw the page title and footer + +```cs +public void DrawTitle(PdfPage page, XGraphics gfx, string title) +{ + XRect rect = new XRect(new XPoint(), gfx.PageSize); + rect.Inflate(-10, -15); + XFont font = new XFont("Verdana", 14, XFontStyle.Bold); + gfx.DrawString(title, font, XBrushes.MidnightBlue, rect, XStringFormats.TopCenter); + + rect.Offset(0, 5); + font = new XFont("Verdana", 8, XFontStyle.Italic); + XStringFormat format = new XStringFormat(); + format.Alignment = XStringAlignment.Near; + format.LineAlignment = XLineAlignment.Far; + gfx.DrawString("Created with " + PdfSharp.ProductVersionInfo.Producer, font, XBrushes.DarkOrchid, rect, format); + + font = new XFont("Verdana", 8); + format.Alignment = XStringAlignment.Center; + gfx.DrawString(Program.s_document.PageCount.ToString(), font, XBrushes.DarkOrchid, rect, format); + + Program.s_document.Outlines.Add(title, page, true); +} +``` + +### Draw the box around the samples + +```cs +public void BeginBox(XGraphics gfx, int number, string title) +{ + const int dEllipse = 15; + XRect rect = new XRect(0, 20, 300, 200); + if (number % 2 == 0) + rect.X = 300 - 5; + rect.Y = 40 + ((number - 1) / 2) * (200 - 5); + rect.Inflate(-10, -10); + XRect rect2 = rect; + rect2.Offset(this.borderWidth, this.borderWidth); + gfx.DrawRoundedRectangle( + new XSolidBrush(this.shadowColor), + rect2, + new XSize(dEllipse + 8, dEllipse + 8) + ); + XLinearGradientBrush brush = new XLinearGradientBrush( + rect, this.backColor, this.backColor2, XLinearGradientMode.Vertical); + gfx.DrawRoundedRectangle(this.borderPen, brush, rect, new XSize(dEllipse, dEllipse)); + rect.Inflate(-5, -5); + + XFont font = new XFont("Verdana", 12, XFontStyle.Regular); + gfx.DrawString(title, font, XBrushes.Navy, rect, XStringFormats.TopCenter); + + rect.Inflate(-10, -5); + rect.Y += 20; + rect.Height -= 20; + + this.state = gfx.Save(); + gfx.TranslateTransform(rect.X, rect.Y); +} + +public void EndBox(XGraphics gfx) +{ + gfx.Restore(this.state); +} +``` diff --git a/docs/PdfSharpCore/samples/HelloWorld.md b/docs/PdfSharpCore/samples/HelloWorld.md new file mode 100644 index 00000000..8113ea60 --- /dev/null +++ b/docs/PdfSharpCore/samples/HelloWorld.md @@ -0,0 +1,51 @@ +# Hello World + +Is the obligatory "Hello World" program. + + +## Code + +```cs +using System; +using System.Diagnostics; +using System.IO; +using PdfSharp; +using PdfSharp.Drawing; +using PdfSharp.Pdf; +using PdfSharp.Pdf.IO; + +namespace HelloWorld +{ + /// + /// This sample is the obligatory Hello World program. + /// + class Program + { + static void Main(string[] args) + { + // Create a new PDF document + PdfDocument document = new PdfDocument(); + document.Info.Title = "Created with PdfSharpCore"; + + // Create an empty page + PdfPage page = document.AddPage(); + + // Get an XGraphics object for drawing + XGraphics gfx = XGraphics.FromPdfPage(page); + + // Create a font + XFont font = new XFont("Verdana", 20, XFontStyle.BoldItalic); + + // Draw the text + gfx.DrawString( + "Hello, World!", font, XBrushes.Black, + new XRect(0, 0, page.Width, page.Height), + XStringFormats.Center); + + // Save the document... + const string filename = "HelloWorld.pdf"; + document.Save(filename); + } + } +} +``` diff --git a/docs/PdfSharpCore/samples/MultiplePages.md b/docs/PdfSharpCore/samples/MultiplePages.md new file mode 100644 index 00000000..71a49a22 --- /dev/null +++ b/docs/PdfSharpCore/samples/MultiplePages.md @@ -0,0 +1,100 @@ +# Multiple Pages + +This sample shows one way to create a PDF document with multiple pages. + +When you program reaches the end of a page, you just have to create a new page by calling the `AddPage()` method of the PdfDocument class. Then you create a new XGraphics object for the new page and use it to draw on the second page, beginning at the top. + +Experience shows that users sometimes have difficulties to modify there code with support for a second page. They call `AddPage()`, but do not store the return value. They do not create a new XGraphics object and continue to draw on the first page. Or they try to create a new XGraphics object, but pass the first page as a parameter and receive an error message. + +If you know right from the start that you will or may need more than one page, then take this into account right from the start and your program will be readable and easy to maintain. + +Note: Consider using MigraDocCore instead of PdfSharpCore for large documents. You can use many attributes to format text and you get the line breaks and page breaks for free. + + +# Code + +The class LayoutHelper takes care of the line position and creates pages as needed: + +```cs +public class LayoutHelper +{ + private readonly PdfDocument _document; + private readonly XUnit _topPosition; + private readonly XUnit _bottomMargin; + private XUnit _currentPosition; + + public LayoutHelper(PdfDocument document, XUnit topPosition, XUnit bottomMargin) + { + _document = document; + _topPosition = topPosition; + _bottomMargin = bottomMargin; + // Set a value outside the page - a new page will be created on the first request. + _currentPosition = bottomMargin + 10000; + } + + public XUnit GetLinePosition(XUnit requestedHeight) + { + return GetLinePosition(requestedHeight, -1f); + } + + public XUnit GetLinePosition(XUnit requestedHeight, XUnit requiredHeight) + { + XUnit required = requiredHeight == -1f ? requestedHeight : requiredHeight; + if (_currentPosition + required > _bottomMargin) + CreatePage(); + XUnit result = _currentPosition; + _currentPosition += requestedHeight; + return result; + } + + public XGraphics Gfx { get; private set; } + public PdfPage Page { get; private set; } + + void CreatePage() + { + Page = _document.AddPage(); + Page.Size = PageSize.A4; + Gfx = XGraphics.FromPdfPage(Page); + _currentPosition = _topPosition; + } +} +``` + +And sample code that shows the LayoutHelper class at work. The sample uses short texts that will always fit into a single line. Adding line breaks to texts that do not fit into a single line is beyond the scope of this sample. + +I wrote it before: Consider using MigraDocCore instead of PdfSharpCore for large documents. You can use many attributes to format text and you get the line breaks and page breaks for free. + +```cs +PdfDocument document = new PdfDocument(); + +// Sample uses DIN A4, page height is 29.7 cm. We use margins of 2.5 cm. +LayoutHelper helper = new LayoutHelper(document, XUnit.FromCentimeter(2.5), XUnit.FromCentimeter(29.7 - 2.5)); +XUnit left = XUnit.FromCentimeter(2.5); + +// Random generator with seed value, so created document will always be the same. +Random rand = new Random(42); + +const int headerFontSize = 20; +const int normalFontSize = 10; + +XFont fontHeader = new XFont("Verdana", headerFontSize, XFontStyle.BoldItalic); +XFont fontNormal = new XFont("Verdana", normalFontSize, XFontStyle.Regular); + +const int totalLines = 666; +bool washeader = false; +for (int line = 0; line < totalLines; ++line) +{ + bool isHeader = line == 0 || !washeader && line < totalLines - 1 && rand.Next(15) == 0; + washeader = isHeader; + // We do not want a single header at the bottom of the page, + // so if we have a header we require space for header and a normal text line. + XUnit top = helper.GetLinePosition(isHeader ? headerFontSize + 5: normalFontSize + 2, isHeader ? headerFontSize + 5 + normalFontSize : normalFontSize); + + helper.Gfx.DrawString(isHeader ? "Sed massa libero, semper a nisi nec" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + isHeader ? fontHeader : fontNormal, XBrushes.Black, left, top, XStringFormats.TopLeft); +} + +// Save the document... +const string filename = "MultiplePages.pdf"; +document.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/PageSizes.md b/docs/PdfSharpCore/samples/PageSizes.md new file mode 100644 index 00000000..69b402db --- /dev/null +++ b/docs/PdfSharpCore/samples/PageSizes.md @@ -0,0 +1,46 @@ +# Page Sizes + +This sample shows a document with different page sizes. + +Note: You can set the size of a page to any size using the `Width` and `Height` properties. This sample just shows the predefined sizes. + + +## Code + +This is the whole source code needed to create the PDF file: + +```cs +// Create a new PDF document +PdfDocument document = new PdfDocument(); + +// Create a font +XFont font = new XFont("Times", 25, XFontStyle.Bold); + +PageSize[] pageSizes = (PageSize[])Enum.GetValues(typeof(PageSize)); +foreach (PageSize pageSize in pageSizes) +{ + if (pageSize == PageSize.Undefined) + continue; + + // One page in Portrait... + PdfPage page = document.AddPage(); + page.Size = pageSize; + XGraphics gfx = XGraphics.FromPdfPage(page); + gfx.DrawString(pageSize.ToString(), font, XBrushes.DarkRed, + new XRect(0, 0, page.Width, page.Height), + XStringFormats.Center); + + // ... and one in Landscape orientation. + page = document.AddPage(); + page.Size = pageSize; + page.Orientation = PageOrientation.Landscape; + gfx = XGraphics.FromPdfPage(page); + gfx.DrawString(pageSize + " (landscape)", font, + XBrushes.DarkRed, new XRect(0, 0, page.Width, page.Height), + XStringFormats.Center); +} + +// Save the document... +const string filename = "PageSizes_tempfile.pdf"; +document.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/Preview.md b/docs/PdfSharpCore/samples/Preview.md new file mode 100644 index 00000000..83ffaf22 --- /dev/null +++ b/docs/PdfSharpCore/samples/Preview.md @@ -0,0 +1,91 @@ +# Preview + +This sample shows how to render graphics in both a preview and a PDF document. + +## Code + +This is the source code of the Render method that is called for screen, PDF, and printer output: + +```cs +XRect rect; +XPen pen; +double x = 50, y = 100; +XFont fontH1 = new XFont("Times", 18, XFontStyle.Bold); +XFont font = new XFont("Times", 12); +XFont fontItalic = new XFont("Times", 12, XFontStyle.BoldItalic); +double ls = font.GetHeight(gfx); + +// Draw some text +gfx.DrawString("Create PDF on the fly with PdfSharpCore", +fontH1, XBrushes.Black, x, x); +gfx.DrawString("With PdfSharpCore you can use the same code to draw graphic, " + +"text and images on different targets.", font, XBrushes.Black, x, y); +y += ls; +gfx.DrawString("The object used for drawing is the XGraphics object.", +font, XBrushes.Black, x, y); +y += 2 * ls; + +// Draw an arc +pen = new XPen(XColors.Red, 4); +pen.DashStyle = XDashStyle.Dash; +gfx.DrawArc(pen, x + 20, y, 100, 60, 150, 120); + +// Draw a star +XGraphicsState gs = gfx.Save(); +gfx.TranslateTransform(x + 140, y + 30); +for (int idx = 0; idx < 360; idx += 10) +{ + gfx.RotateTransform(10); + gfx.DrawLine(XPens.DarkGreen, 0, 0, 30, 0); +} +gfx.Restore(gs); + +// Draw a rounded rectangle +rect = new XRect(x + 230, y, 100, 60); +pen = new XPen(XColors.DarkBlue, 2.5); +XColor color1 = XColor.FromKnownColor(KnownColor.DarkBlue); +XColor color2 = XColors.Red; +XLinearGradientBrush lbrush = new XLinearGradientBrush(rect, color1, color2, +XLinearGradientMode.Vertical); +gfx.DrawRoundedRectangle(pen, lbrush, rect, new XSize(10, 10)); + +// Draw a pie +pen = new XPen(XColors.DarkOrange, 1.5); +pen.DashStyle = XDashStyle.Dot; +gfx.DrawPie(pen, XBrushes.Blue, x + 360, y, 100, 60, -130, 135); + +// Draw some more text +y += 60 + 2 * ls; +gfx.DrawString("With XGraphics you can draw on a PDF page as well as " + +"on any System.Drawing.Graphics object.", font, XBrushes.Black, x, y); +y += ls * 1.1; +gfx.DrawString("Use the same code to", font, XBrushes.Black, x, y); +x += 10; +y += ls * 1.1; +gfx.DrawString("• draw on a newly created PDF page", font, XBrushes.Black, x, y); +y += ls; +gfx.DrawString("• draw above or beneath of the content of an existing PDF page", +font, XBrushes.Black, x, y); +y += ls; +gfx.DrawString("• draw in a window", font, XBrushes.Black, x, y); +y += ls; +gfx.DrawString("• draw on a printer", font, XBrushes.Black, x, y); +y += ls; +gfx.DrawString("• draw in a bitmap image", font, XBrushes.Black, x, y); +x -= 10; +y += ls * 1.1; +gfx.DrawString("You can also import an existing PDF page and use it like " + +"an image, e.g. draw it on another PDF page.", font, XBrushes.Black, x, y); +y += ls * 1.1 * 2; +gfx.DrawString("Imported PDF pages are neither drawn nor printed; create a " + +"PDF file to see or print them!", fontItalic, XBrushes.Firebrick, x, y); +y += ls * 1.1; +gfx.DrawString("Below this text is a PDF form that will be visible when " + +"viewed or printed with a PDF viewer.", fontItalic, XBrushes.Firebrick, x, y); +y += ls * 1.1; +XGraphicsState state = gfx.Save(); +XRect rcImage = new XRect(100, y, 100, 100 * Math.Sqrt(2)); +gfx.DrawRectangle(XBrushes.Snow, rcImage); +gfx.DrawImage(XPdfForm.FromFile("../../../../../PDFs/SomeLayout.pdf"), rcImage); +gfx.Restore(state); +``` diff --git a/docs/PdfSharpCore/samples/ProtectDocument.md b/docs/PdfSharpCore/samples/ProtectDocument.md new file mode 100644 index 00000000..6608486c --- /dev/null +++ b/docs/PdfSharpCore/samples/ProtectDocument.md @@ -0,0 +1,42 @@ +# Protect Document + +This sample shows how to protect a document with a password. + + +## Code + +This is the whole source code needed to create the PDF file: + +```cs +// Get a fresh copy of the sample PDF file +const string filenameSource = "HelloWorld.pdf"; +const string filenameDest = "HelloWorld_tempfile.pdf"; +File.Copy(Path.Combine("../../../../../PDFs/", filenameSource), +Path.Combine(Directory.GetCurrentDirectory(), filenameDest), true); + +// Open an existing document. Providing an unrequired password is ignored. +PdfDocument document = PdfReader.Open(filenameDest, "some text"); + +PdfSecuritySettings securitySettings = document.SecuritySettings; + +// Setting one of the passwords automatically sets the security level to +// PdfDocumentSecurityLevel.Encrypted128Bit. +securitySettings.UserPassword = "user"; +securitySettings.OwnerPassword = "owner"; + +// Don't use 40 bit encryption unless needed for compatibility +//securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted40Bit; + +// Restrict some rights. +securitySettings.PermitAccessibilityExtractContent = false; +securitySettings.PermitAnnotations = false; +securitySettings.PermitAssembleDocument = false; +securitySettings.PermitExtractContent = false; +securitySettings.PermitFormsFill = true; +securitySettings.PermitFullQualityPrint = false; +securitySettings.PermitModifyDocument = true; +securitySettings.PermitPrint = false; + +// Save the document... +document.Save(filenameDest); +``` diff --git a/docs/PdfSharpCore/samples/SplitDocument.md b/docs/PdfSharpCore/samples/SplitDocument.md new file mode 100644 index 00000000..25a91329 --- /dev/null +++ b/docs/PdfSharpCore/samples/SplitDocument.md @@ -0,0 +1,33 @@ +# Split Document + +This sample shows how to convert a PDF document with n pages into n documents with one page each. + + +## Code + +This is the whole source code needed to create the PDF file: + +````cs +// Get a fresh copy of the sample PDF file +const string filename = "Portable Document Format.pdf"; +File.Copy(Path.Combine("../../../../../PDFs/", filename), +Path.Combine(Directory.GetCurrentDirectory(), filename), true); + +// Open the file +PdfDocument inputDocument = PdfReader.Open(filename, PdfDocumentOpenMode.Import); + +string name = Path.GetFileNameWithoutExtension(filename); +for (int idx = 0; idx < inputDocument.PageCount; idx++) +{ + // Create new document + PdfDocument outputDocument = new PdfDocument(); + outputDocument.Version = inputDocument.Version; + outputDocument.Info.Title = + String.Format("Page {0} of {1}", idx + 1, inputDocument.Info.Title); + outputDocument.Info.Creator = inputDocument.Info.Creator; + + // Add the page and save it + outputDocument.AddPage(inputDocument.Pages[idx]); + outputDocument.Save(String.Format("{0} - Page {1}_tempfile.pdf", name, idx + 1)); +} +``` diff --git a/docs/PdfSharpCore/samples/TextLayout.md b/docs/PdfSharpCore/samples/TextLayout.md new file mode 100644 index 00000000..aa347fec --- /dev/null +++ b/docs/PdfSharpCore/samples/TextLayout.md @@ -0,0 +1,52 @@ +# Text Layout + +This sample shows how to layout text with the TextFormatter class. + +TextFormatter was provided because it was one of the "most wanted" features. But it is better and easier to use MigraDocCore to format paragraphs... + + +## Code + +This is the whole source code needed to create the PDF file: + +```cs +const string text =. + "Facin exeraessisit la consenim iureet dignibh eu facilluptat vercil dunt autpat. " + + "Ecte magna faccum dolor sequisc iliquat, quat, quipiss equipit accummy niate magna " + + "facil iure eraesequis am velit, quat atis dolore dolent luptat nulla adio odipissectet " + + "lan venis do essequatio conulla facillandrem zzriusci bla ad minim inis nim velit eugait " + + "aut aut lor at ilit ut nulla ate te eugait alit augiamet ad magnim iurem il eu feuissi.\n" + + "Guer sequis duis eu feugait luptat lum adiamet, si tate dolore mod eu facidunt adignisl in " + + "henim dolorem nulla faccum vel inis dolutpatum iusto od min ex euis adio exer sed del " + + "dolor ing enit veniamcon vullutat praestrud molenis ciduisim doloborem ipit nulla consequisi.\n" + + "Nos adit pratetu eriurem delestie del ut lumsandreet nis exerilisit wis nos alit venit praestrud " + + "dolor sum volore facidui blaor erillaortis ad ea augue corem dunt nis iustinciduis euisi.\n" + + "Ut ulputate volore min ut nulpute dolobor sequism olorperilit autatie modit wisl illuptat dolore " + + "min ut in ute doloboreet ip ex et am dunt at."; + +PdfDocument document = new PdfDocument(); + +PdfPage page = document.AddPage(); +XGraphics gfx = XGraphics.FromPdfPage(page); +XFont font = new XFont("Times New Roman", 10, XFontStyle.Bold); +XTextFormatter tf = new XTextFormatter(gfx); + +XRect rect = new XRect(40, 100, 250, 220); +gfx.DrawRectangle(XBrushes.SeaShell, rect); +//tf.Alignment = ParagraphAlignment.Left; +tf.DrawString(text, font, XBrushes.Black, rect, XStringFormats.TopLeft); + +rect = new XRect(310, 100, 250, 220); +gfx.DrawRectangle(XBrushes.SeaShell, rect); +tf.Alignment = XParagraphAlignment.Right; +tf.DrawString(text, font, XBrushes.Black, rect, XStringFormats.TopLeft); + +rect = new XRect(40, 400, 250, 220); +gfx.DrawRectangle(XBrushes.SeaShell, rect); +tf.Alignment = XParagraphAlignment.Center; +tf.DrawString(text, font, XBrushes.Black, rect, XStringFormats.TopLeft); + +rect = new XRect(310, 400, 250, 220); +gfx.DrawRectangle(XBrushes.SeaShell, rect); +tf.Alignment = XParagraphAlignment.Justify; +``` diff --git a/docs/PdfSharpCore/samples/TwoPagesOnOne.md b/docs/PdfSharpCore/samples/TwoPagesOnOne.md new file mode 100644 index 00000000..eb48ace6 --- /dev/null +++ b/docs/PdfSharpCore/samples/TwoPagesOnOne.md @@ -0,0 +1,75 @@ +# Two Pages on One + +This sample shows how to place two pages of an existing document on one landscape orientated page of a new document. + +## Code + +This is the whole source code needed to create the PDF file: + +```cs +// Get a fresh copy of the sample PDF file +string filename = "Portable Document Format.pdf"; +File.Copy(Path.Combine("../../../../../PDFs/", filename), +Path.Combine(Directory.GetCurrentDirectory(), filename), true); + +// Create the output document +PdfDocument outputDocument = new PdfDocument(); + +// Show single pages +// (Note: one page contains two pages from the source document) +outputDocument.PageLayout = PdfPageLayout.SinglePage; + +XFont font = new XFont("Verdana", 8, XFontStyle.Bold); +XStringFormat format = new XStringFormat(); +format.Alignment = XStringAlignment.Center; +format.LineAlignment = XLineAlignment.Far; +XGraphics gfx; +XRect box; + +// Open the external document as XPdfForm object +XPdfForm form = XPdfForm.FromFile(filename); + +for (int idx = 0; idx < form.PageCount; idx += 2) +{ + // Add a new page to the output document + PdfPage page = outputDocument.AddPage(); + page.Orientation = PageOrientation.Landscape; + double width = page.Width; + double height = page.Height; + + int rotate = page.Elements.GetInteger("/Rotate"); + + gfx = XGraphics.FromPdfPage(page); + + // Set page number (which is one-based) + form.PageNumber = idx + 1; + + box = new XRect(0, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + + // Write document file name and page number on each page + box.Inflate(0, -10); + gfx.DrawString(String.Format("- {1} -", filename, idx + 1), + font, XBrushes.Red, box, format); + + if (idx + 1 < form.PageCount) + { + // Set page number (which is one-based) + form.PageNumber = idx + 2; + + box = new XRect(width / 2, 0, width / 2, height); + // Draw the page identified by the page number like an image + gfx.DrawImage(form, box); + + // Write document file name and page number on each page + box.Inflate(0, -10); + gfx.DrawString(String.Format("- {1} -", filename, idx + 2), + font, XBrushes.Red, box, format); + } +} + +// Save the document... +filename = "TwoPagesOnOne_tempfile.pdf"; +outputDocument.Save(filename); +``` diff --git a/docs/PdfSharpCore/samples/Unicode.md b/docs/PdfSharpCore/samples/Unicode.md new file mode 100644 index 00000000..1c9dbd33 --- /dev/null +++ b/docs/PdfSharpCore/samples/Unicode.md @@ -0,0 +1,175 @@ +# Unicode + +This sample shows how to use Unicode text in PdfSharpCore. + +Languages based on Latin, Greek, or Cyrillic letters should all work with PdfSharpCore. + +You'll find code snippets for the following classes: +* XPdfFontOptions +* XTextFormatter + + +## Code + +Drawing the text is quite easy (just like the Text Layout sample): + +```cs +// Create new document +PdfDocument document = new PdfDocument(); + +// Set font encoding to unicode +XPdfFontOptions options = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always); + +XFont font = new XFont("Times New Roman", 12, XFontStyle.Regular, options); + +// Draw text in different languages +for (int idx = 0; idx < texts.Length; idx++) +{ + PdfPage page = document.AddPage(); + XGraphics gfx = XGraphics.FromPdfPage(page); + XTextFormatter tf = new XTextFormatter(gfx); + tf.Alignment = XParagraphAlignment.Left; + + tf.DrawString(texts[idx], font, XBrushes.Black, + new XRect(100, 100, page.Width - 200, 600), XStringFormats.TopLeft); +} + +const string filename = "Unicode_tempfile.pdf"; +// Save the document... +document.Save(filename); +``` + +Note: the XPdfFontOptions enable both Unicode support and font embedding. + +Here's the string array that contains the translations: + +```cs +static readonly string[] texts = new string[] +{ + // International version of the text in English. + "English\n" + + "PdfSharpCore is a .NET library for creating and processing PDF documents 'on the fly'. " + + "The library is completely written in C# and based exclusively on safe, managed code. " + + "PdfSharpCore offers two powerful abstraction levels to create and process PDF documents.\n" + + "For drawing text, graphics, and images there is a set of classes which are modeled similar to the classes " + + "of the name space System.Drawing of the .NET framework. With these classes it is not only possible to create " + + "the content of PDF pages in an easy way, but they can also be used to draw in a window or on a printer.\n" + + "Additionally PdfSharpCore completely models the structure elements PDF is based on. With them existing PDF documents " + + "can be modified, merged, or split with ease.\n" + + "The source code of PdfSharpCore is Open Source under the MIT license (http://en.wikipedia.org/wiki/MIT_License). " + + "Therefore it is possible to use PdfSharpCore without limitations in non open source or commercial projects/products.", + + // German version. + "German (deutsch)\n" + + "PdfSharpCore ist eine .NET-Bibliothek zum Erzeugen und Verarbeiten von PDF-Dokumenten 'On the Fly'. " + + "Die Bibliothek ist vollständig in C# geschrieben und basiert ausschließlich auf sicherem, verwaltetem Code. " + + "PdfSharpCore bietet zwei leistungsstarke Abstraktionsebenen zur Erstellung und Verarbeitung von PDF-Dokumenten.\n" + + "Zum Zeichnen von Text, Grafik und Bildern gibt es einen Satz von Klassen, die sehr stark an die Klassen " + + "des Namensraums System.Drawing des .NET Frameworks angelehnt sind. Mit diesen Klassen ist es nicht " + + "nur auf einfache Weise möglich, den Inhalt von PDF-Seiten zu gestalten, sondern sie können auch zum " + + "Zeichnen in einem Fenster oder auf einem Drucker verwendet werden.\n" + + "Zusätzlich modelliert PdfSharpCore vollständig die Stukturelemente, auf denen PDF basiert. Dadurch können existierende " + + "PDF-Dokumente mit Leichtigkeit zerlegt, ergänzt oder umgebaut werden.\n" + + "Der Quellcode von PdfSharpCore ist Open-Source unter der MIT-Lizenz (http://de.wikipedia.org/wiki/MIT-Lizenz). " + + "Damit kann PdfSharpCore auch uneingeschränkt in Nicht-Open-Source- oder kommerziellen Projekten/Produkten eingesetzt werden.", + + // Greek version. + // The text was translated by Babel Fish. We here in Germany have no idea what it means. + "Greek (Translated with Babel Fish)\n" + + "Το PdfSharpCore είναι βιβλιοθήκη δικτύου α. για τη δημιουργία και την επεξεργασία των εγγράφων PDF 'σχετικά με τη μύγα'. " + + "Η βιβλιοθήκη γράφεται εντελώς γ # και βασίζεται αποκλειστικά εκτός από, διοικούμενος κώδικας. " + + "Το PdfSharpCore προσφέρει δύο ισχυρά επίπεδα αφαίρεσης για να δημιουργήσει και να επεξεργαστεί τα έγγραφα PDF. " + + "Για το κείμενο, τη γραφική παράσταση, και τις εικόνες σχεδίων υπάρχει ένα σύνολο κατηγοριών που διαμορφώνονται " + + "παρόμοιος με τις κατηγορίες του διαστημικού σχεδίου συστημάτων ονόματος του. πλαισίου δικτύου. " + + "Με αυτές τις κατηγορίες που είναι όχι μόνο δυνατό να δημιουργηθεί το περιεχόμενο των σελίδων PDF με έναν εύκολο " + + "τρόπο, αλλά αυτοί μπορεί επίσης να χρησιμοποιηθεί για να επισύρει την προσοχή σε ένα παράθυρο ή σε έναν εκτυπωτή. " + + "Επιπλέον PdfSharpCore διαμορφώνει εντελώς τα στοιχεία PDF δομών είναι βασισμένο. Με τους τα υπάρχοντα έγγραφα PDF " + + "μπορούν να τροποποιηθούν, συγχωνευμένος, ή να χωρίσουν με την ευκολία. Ο κώδικας πηγής PdfSharpCore είναι ανοικτή πηγή " + + "με άδεια MIT (http://en.wikipedia.org/wiki/MIT_License). Επομένως είναι δυνατό να χρησιμοποιηθεί PdfSharpCore χωρίς " + + "προβλήματα στη μη ανοικτή πηγή ή τα εμπορικά προγράμματα/τα προϊόντα.", + + // Russian version (by courtesy of Alexey Kuznetsov). + "Russian\n" + + "PdfSharpCore это .NET библиотека для создания и обработки PDF документов 'налету'. " + + "Библиотека полностью написана на языке C# и базируется исключительно на безопасном, управляемом коде. " + + "PdfSharpCore использует два мощных абстрактных уровня для создания и обработки PDF документов.\n" + + "Для рисования текста, графики, и изображений в ней используется набор классов, которые разработаны аналогично с" + + "пакетом System.Drawing, библиотеки .NET framework. С помощью этих классов возможно не только создавать" + + "содержимое PDF страниц очень легко, но они так же позволяют рисовать напрямую в окне приложения или на принтере.\n" + + "Дополнительно PdfSharpCore имеет полноценные модели структурированных базовых элементов PDF. Они позволяют работать с существующим PDF документами " + + "для изменения их содержимого, склеивания документов, или разделения на части.\n" + + "Исходный код PdfSharpCore библиотеки это Open Source распространяемый под лицензией MIT (http://ru.wikipedia.org/wiki/MIT_License). " + + "Теоретически она позволяет использовать PdfSharpCore без ограничений в не open source проектах или коммерческих проектах/продуктах.", + + // French version (by courtesy of Olivier Dalet). + "French (Français)\n" + + "PdfSharpCore est une librairie .NET permettant de créer et de traiter des documents PDF 'à la volée'. " + + "La librairie est entièrement écrite en C# et exclusivement basée sur du code sûr et géré. " + + "PdfSharpCore fournit deux puissants niveaux d'abstraction pour la création et le traitement des documents PDF.\n" + + "Un jeu de classes, modélisées afin de ressembler aux classes du namespace System.Drawing du framework .NET, " + + "permet de dessiner du texte, des graphiques et des images. Non seulement ces classes permettent la création du " + + "contenu des pages PDF de manière aisée, mais elles peuvent aussi être utilisées pour dessiner dans une fenêtre ou pour l'imprimante.\n" + + "De plus, PdfSharpCore modélise complètement les éléments structurels de PDF. Ainsi, des documents PDF existants peuvent être " + + "facilement modifiés, fusionnés ou éclatés.\n" + + "Le code source de PdfSharpCore est Open Source sous licence MIT (http://fr.wikipedia.org/wiki/Licence_MIT). " + + "Il est donc possible d'utiliser PdfSharpCore sans limitation aucune dans des projets ou produits non Open Source ou commerciaux.", + + // Dutch version (by giCalle) + "Dutch\n" + + "PdfSharpCore is een .NET bibliotheek om PDF documenten te creëren en te verwerken. " + + "De bibliotheek is volledig geschreven in C# en gebruikt uitsluitend veilige, 'managed code'. " + + "PdfSharpCore biedt twee krachtige abstractie niveaus aan om PDF documenten te maken en te verwerken.\n" + + "Om tekst, beelden en foto's weer te geven zijn er een reeks klassen beschikbaar, gemodelleerd naar de klassen " + + "uit de 'System.Drawing' naamruimte van het .NET framework. Met behulp van deze klassen is het niet enkel mogelijk " + + "om de inhoud van PDF pagina's aan te maken op een eenvoudige manier, maar ze kunnen ook gebruikt worden om dingen " + + "weer te geven in een venster of naar een printer. Daarbovenop implementeert PdfSharpCore de volledige elementen structuur " + + "waarop PDF is gebaseerd. Hiermee kunnen bestaande PDF documenten eenvoudig aangepast, samengevoegd of opgesplitst worden.\n" + + "De broncode van PdfSharpCore is opensource onder een MIT licentie (http://nl.wikipedia.org/wiki/MIT-licentie). " + + "Daarom is het mogelijk om PdfSharpCore te gebruiken zonder beperkingen in niet open source of commerciële projecten/producten.", + + // Danish version (by courtesy of Mikael Lyngvig). + "Danish (Dansk)\n" + + "PdfSharpCore er et .NET bibliotek til at dynamisk lave og behandle PDF dokumenter. " + + "Biblioteket er skrevet rent i C# og indeholder kun sikker, managed kode. " + + "PdfSharpCore tilbyder to stærke abstraktionsniveauer til at lave og behandle PDF dokumenter. " + + "Til at tegne tekst, grafik og billeder findes der et sæt klasser som er modelleret ligesom klasserne i navnerummet " + + "System.Drawing i .NET biblioteket. Med disse klasser er det ikke kun muligt at udforme indholdet af PDF siderne på en " + + "nem måde – de kan også bruges til at tegne i et vindue eller på en printer. " + + "Derudover modellerer PdfSharpCore fuldstændigt strukturelementerne som PDF er baseret på. " + + "Med dem kan eksisterende PDF dokumenter nemt modificeres, sammenknyttes og adskilles. " + + "Kildekoden til PdfSharpCore er Open Source under MIT licensen (http://da.wikipedia.org/wiki/MIT-Licensen). " + + "Derfor er det muligt at bruge PdfSharpCore uden begrænsninger i både lukkede og kommercielle projekter og produkter.", + + // Portuguese version (by courtesy of Luís Rodrigues). + "Portuguese (Português)\n" + + "PdfSharpCore é uma biblioteca .NET para a criação e processamento de documentos PDF 'on the fly'." + + "A biblioteca é completamente escrita em C# e baseada exclusivamente em código gerenciado e seguro. " + + "O PdfSharpCore oferece dois níveis de abstração poderosa para criar e processar documentos PDF.\n" + + "Para desenhar texto, gráficos e imagens, há um conjunto de classes que são modeladas de forma semelhante às classes " + + "do espaço de nomes System.Drawing do framework .NET. Com essas classes não só é possível criar " + + "o conteúdo das páginas PDF de uma maneira fácil, mas podem também ser usadas para desenhar numa janela ou numa impressora.\n" + + "Adicionalmente, o PdfSharpCore modela completamente a estrutura dos elementos em que o PDF é baseado. Com eles, documentos PDF existentes " + + "podem ser modificados, unidos, ou divididos com facilidade.\n" + + "O código fonte do PdfSharpCore é Open Source sob a licença MIT (http://en.wikipedia.org/wiki/MIT_License). " + + "Por isso, é possível usar o PdfSharpCore sem limitações em projetos/produtos não open source ou comerciais.", + + // Polish version (by courtesy of Krzysztof Jędryka) + "Polish (polski)\n" + + "PdfSharpCore jest biblioteką .NET umożliwiającą tworzenie i przetwarzanie dokumentów PDF 'w locie'. " + + "Biblioteka ta została stworzona w całości w języku C# i jest oparta wyłącznie na bezpiecznym i zarządzanym kodzie. " + + "PdfSharpCore oferuje dwa rozbudowane poziomy abstrakcji do tworzenia i przetwarzania dokumentów PDF.\n" + + "Do rysowania tekstu, grafiki i obrazów stworzono zbiór klas projektowanych na wzór klas przestrzeni nazw System.Drawing" + + "platformy .NET. Z pomocą tych klas można tworzyć w wygodny sposób nie tylko zawartość stron dokumentu PDF, ale można również" + + "rysować w oknie programu lub generować wydruki.\n" + + "Ponadto PdfSharpCore w pełni odwzorowuje strukturę elementów na których opiera się format pliku PDF." + + "Używając tych elementów, dokumenty PDF można modyfikować, łączyć lub dzielić z łatwością.\n" + + "Kod źródłowy PdfSharpCore jest dostępny na licencji Open Source MIT (http://pl.wikipedia.org/wiki/Licencja_MIT). " + + "Zatem można korzystać z PdfSharpCore bez żadnych ograniczeń w projektach niedostępnych dla społeczności Open Source lub komercyjnych.", + + // Your language may come here. + "Invitation\n" + + "If you use PdfSharpCore and haven't found your native language in this document, we will be pleased to get your translation of the text above and include it here.\n" + +}; +``` + +The current implementation of PdfSharpCore is limited to left-to-right languages. Languages like Arabic cannot yet be created even with Unicode fonts. Also the so called CJK (Chinese, Japanese, Korean) support in PDF can also not be addressed with PDF sharp. However, we plan to support as many languages as possible with PdfSharpCore. If you are a programmer and a native speaker of one of these languages and you like to create PDF documents in your language, you can help us to implement it in PdfSharpCore. You don't have to do the programming, but just help us to verify our implementation. diff --git a/docs/PdfSharpCore/samples/UnprotectDocument.md b/docs/PdfSharpCore/samples/UnprotectDocument.md new file mode 100644 index 00000000..e3472b78 --- /dev/null +++ b/docs/PdfSharpCore/samples/UnprotectDocument.md @@ -0,0 +1,79 @@ +# Unprotect Document + +This sample shows how to unprotect a document (if you know the password). + +Note: that we will not explain nor give any tips how to crack a protected document with PdfSharpCore. + +## Code + +This code shows how to unprotect a document to allow modification: + +```cs +// Get a fresh copy of the sample PDF file. +// The passwords are 'user' and 'owner' in this sample. +const string filenameSource = "HelloWorld (protected).pdf"; +const string filenameDest = "HelloWorld_tempfile.pdf"; +File.Copy(Path.Combine("../../../../../PDFs/", filenameSource), +Path.Combine(Directory.GetCurrentDirectory(), filenameDest), true); + +PdfDocument document; + +// Opening a document will fail with an invalid password. +try +{ + document = PdfReader.Open(filenameDest, "invalid password"); +} +catch (Exception ex) +{ + Debug.WriteLine(ex.Message); +} + +// You can specify a delegate, which is called if the document needs a +// password. If you want to modify the document, you must provide the +// owner password. +document = PdfReader.Open(filenameDest, PdfDocumentOpenMode.Modify, PasswordProvider); + +// Open the document with the user password. +document = PdfReader.Open(filenameDest, "user", PdfDocumentOpenMode.ReadOnly); + +// Use the property HasOwnerPermissions to decide whether the used password +// was the user or the owner password. In both cases PdfSharpCore provides full +// access to the PDF document. It is up to the programmer who uses PdfSharpCore +// to honor the access rights. PdfSharpCore doesn't try to protect the document +// because this make little sense for an open source library. +bool hasOwnerAccess = document.SecuritySettings.HasOwnerPermissions; + +// Open the document with the owner password. +document = PdfReader.Open(filenameDest, "owner"); +hasOwnerAccess = document.SecuritySettings.HasOwnerPermissions; + +// A document opened with the owner password is completely unprotected +// and can be modified. +XGraphics gfx = XGraphics.FromPdfPage(document.Pages[0]); +gfx.DrawString("Some text...", +new XFont("Times New Roman", 12), XBrushes.Firebrick, 50, 100); + +// The modified document is saved without any protection applied. +PdfDocumentSecurityLevel level = document.SecuritySettings.DocumentSecurityLevel; + +// If you want to save it protected, you must set the DocumentSecurityLevel +// or apply new passwords. +// In the current implementation the old passwords are not automatically +// reused. See 'ProtectDocument' sample for further information. + +// Save the document... +document.Save(filenameDest); +``` + +Here's the source code for the password provider: + +```cs +/// +/// The 'get the password' call back function. +/// +static void PasswordProvider(PdfPasswordProviderArgs args) +{ + // Show a dialog here in a real application + args.Password = "owner"; +} +``` diff --git a/docs/PdfSharpCore/samples/Watermark.md b/docs/PdfSharpCore/samples/Watermark.md new file mode 100644 index 00000000..ceb5cf74 --- /dev/null +++ b/docs/PdfSharpCore/samples/Watermark.md @@ -0,0 +1,107 @@ +# Watermark + +This sample shows three variations how to add a watermark to an existing PDF file. + +Note: Technically the watermarks in this sample are simple graphical output. They have nothing to do with the Watermark Annotations introduced in PDF 1. + + +## Code + +Here's the code that creates the first kind of watermarks: + +```cs +// Variation 1: Draw a watermark as a text string. + +// Get an XGraphics object for drawing beneath the existing content. +var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend); + +// Get the size (in points) of the text. +var size = gfx.MeasureString(watermark, font); + +// Define a rotation transformation at the center of the page. +gfx.TranslateTransform(page.Width / 2, page.Height / 2); +gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); +gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); + +// Create a string format. +var format = new XStringFormat(); +format.Alignment = XStringAlignment.Near; +format.LineAlignment = XLineAlignment.Near; + +// Create a dimmed red brush. +XBrush brush = new XSolidBrush(XColor.FromArgb(128, 255, 0, 0)); + +// Draw the string. +gfx.DrawString(watermark, font, brush, +new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2), +format); +``` + +Here's the code that creates the second kind of watermarks: + +```cs +// Variation 2: Draw a watermark as an outlined graphical path. +// NYI: Does not work in Core build. + +// Get an XGraphics object for drawing beneath the existing content. +var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend); + +// Get the size (in points) of the text. +var size = gfx.MeasureString(watermark, font); + +// Define a rotation transformation at the center of the page. +gfx.TranslateTransform(page.Width / 2, page.Height / 2); +gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); +gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); + +// Create a graphical path. +var path = new XGraphicsPath(); + +// Create a string format. +var format = new XStringFormat(); +format.Alignment = XStringAlignment.Near; +format.LineAlignment = XLineAlignment.Near; + +// Add the text to the path. +// AddString is not implemented in PdfSharpCore Core. +path.AddString(watermark, font.FontFamily, XFontStyle.BoldItalic, 150, +new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2), +format); + +// Create a dimmed red pen. +var pen = new XPen(XColor.FromArgb(128, 255, 0, 0), 2); + +// Stroke the outline of the path. +gfx.DrawPath(pen, path); +``` + +Here's the code that creates the third kind of watermarks: + +```cs +// Variation 3: Draw a watermark as a transparent graphical path above text. +// NYI: Does not work in Core build. + +// Get an XGraphics object for drawing above the existing content. +var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append); + +// Get the size (in points) of the text. +var size = gfx.MeasureString(watermark, font); + +// Define a rotation transformation at the center of the page. +gfx.TranslateTransform(page.Width / 2, page.Height / 2); +gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); +gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); + +// Create a graphical path. +var path = new XGraphicsPath(); + +// Create a string format. +var format = new XStringFormat(); +format.Alignment = XStringAlignment.Near; +format.LineAlignment = XLineAlignment.Near; + +// Add the text to the path. +// AddString is not implemented in PdfSharpCore Core. +path.AddString(watermark, font.FontFamily, XFontStyle.BoldItalic, 150, +new XPoint((page.Width - si +``` diff --git a/docs/PdfSharpCore/samples/WorkOnPdfObjects.md b/docs/PdfSharpCore/samples/WorkOnPdfObjects.md new file mode 100644 index 00000000..038b1e57 --- /dev/null +++ b/docs/PdfSharpCore/samples/WorkOnPdfObjects.md @@ -0,0 +1,87 @@ +# Work on Pdf Objects + +This sample shows how to deal with PDF objects that are not (yet) covered by specialized PdfSharpCore classes (as an example it adds an OpenAction to an existing PDF file). + +PDF documents are based internally on objects like dictionaries, arrays, streams etc. This sample shows how to work directly on these underlying PDF objects. Use this functionality to achieve PDF features that are not yet implemented in PdfSharpCore. + + +## Code + +Here is the code that shows how to add an OpenAction: + +```cs +// Read document into memory for modification +PdfDocument document = PdfReader.Open(filename); + +// The current version of PdfSharpCore doesn't support the concept of +// 'actions'. Actions will come in a future version, but if you need them +// now, you can have them 'handmade'. +// +// This sample works on PDF objects directly, therefore some knowledge of +// the structure of PDF is required. +// If you are not familiar with the portable document format, first read +// at least chapter 3 in Adobe's PDF Reference +// (http://partners.adobe.com/public/developer/pdf/index_reference.html). +// If you can read German, I recommend chapter 12 of 'Die PostScript & +// PDF-Bibel', a much more interesting reading than the bone-dry Adobe +// books (http://www.pdflib.com/developer/technical-documentation/books/postscript-pdf-bibel/). +// +// The sample task is to add an 'open action' to the document so that it +// starts with the content of page 3 magnified just enough to fit the +// height of the page within the window. + +// First we have to create a new dictionary that defines the action. +PdfDictionary dict = new PdfDictionary(document); + +// According to the PDF Reference the dictionary requires two elements. +// A key /S that specifies the 'GoTo' action, +// and a key /D that describes the destination. + +// Adding a name as value of key /S is easy. +dict.Elements["/S"] = new PdfName("/GoTo"); + +// The destination is described by an array. +PdfArray array = new PdfArray(document); + +// Set the array as the value of key /D. +// This makes the array a direct object of the dictionary. +dict.Elements["/D"] = array; + +// Now add the elements to the array. According to the PDF Reference it +// must be three for a page as the target of a 'GoTo' action. +// The first element is an indirect reference to the destination page. +// To add an indirect reference to the page three, we first need the +// PdfReference object of that page. +// (The index in the Pages collection is zero based, therefore Pages[2]) +PdfReference iref = PdfInternals.GetReference(document.Pages[2]); + +// Add the reference to the third page as the first array element. +// Adding the iref (instead of the PdfPage object itself) makes it an +// indirect reference. +array.Elements.Add(iref); + +// The second element is the name /FitV to indicate 'fit vertically'. +array.Elements.Add(new PdfName("/FitV")); + +// /FitV requires the horizontal coordinate that will be positioned at the +// left edge of the window. We set -32768 because Acrobat uses this value +// to show the full page (it means 'left aligned' anyway if the window is +// so small that a horizontal scroll bar is required). +array.Elements.Add(new PdfInteger(-32768)); + +// Now that the action dictionary is complete, we can add it to the +// document's object table. +// Adding an object to the object table makes it an indirect object. +document.Internals.AddObject(dict); + +// Finally we must add the action dictionary to the /OpenAction key of +// the document's catalog as an indirect value. +document.Internals.Catalog.Elements["/OpenAction"] = PdfInternals.GetReference(dict); + +// Using PdfSharpCore we never deal with object numbers. We simply put the +// objects together and the PdfSharpCore framework does the rest. +``` + +Other objects not covered by PdfSharpCore can also be added this way. + +Using PdfSharpCore we never deal with object numbers. We simply put the objects together and the PdfSharpCore framework does the rest. diff --git a/docs/PdfSharpCore/samples/XForms.md b/docs/PdfSharpCore/samples/XForms.md new file mode 100644 index 00000000..711faf87 --- /dev/null +++ b/docs/PdfSharpCore/samples/XForms.md @@ -0,0 +1,66 @@ +# XForms + +This sample shows how to create an XForm object from scratch. You can think of such an object as a template, that, once created, can be drawn frequently anywhere in your PDF document. + +## Code + +Step 1: Create an XForm and draw some graphics on it: + +```cs +// Create an empty XForm object with the specified width and height +// A form is bound to its target document when it is created. The reason is that the form can +// share fonts and other objects with its target document. +XForm form = new XForm(document, XUnit.FromMillimeter(70), XUnit.FromMillimeter(55)); + +// Create an XGraphics object for drawing the contents of the form. +XGraphics formGfx = XGraphics.FromForm(form); + +// Draw a large transparent rectangle to visualize the area the form occupies +XColor back = XColors.Orange; +back.A = 0.2; +XSolidBrush brush = new XSolidBrush(back); +formGfx.DrawRectangle(brush, -10000, -10000, 20000, 20000); + +// On a form you can draw... + +// ... text +formGfx.DrawString("Text, Graphics, Images, and Forms", new XFont("Verdana", 10, XFontStyle.Regular), XBrushes.Navy, 3, 0, XStringFormats.TopLeft); +XPen pen = XPens.LightBlue.Clone(); +pen.Width = 2.5; + +// ... graphics like Bézier curves +formGfx.DrawBeziers(pen, XPoint.ParsePoints("30,120 80,20 100,140 175,33.3")); + +// ... raster images like GIF files +XGraphicsState state = formGfx.Save(); +formGfx.RotateAtTransform(17, new XPoint(30, 30)); +formGfx.DrawImage(XImage.FromFile("../../../../../../dev/XGraphicsLab/images/Test.gif"), 20, 20); +formGfx.Restore(state); + +// ... and forms like XPdfForm objects +state = formGfx.Save(); +formGfx.RotateAtTransform(-8, new XPoint(165, 115)); +formGfx.DrawImage(XPdfForm.FromFile("../../../../../PDFs/SomeLayout.pdf"), new XRect(140, 80, 50, 50 * Math.Sqrt(2))); +formGfx.Restore(state); + +// When you finished drawing on the form, dispose the XGraphic object. +formGfx.Dispose(); +``` + +Step 2: Draw the XPdfForm on your PDF page like an image: + +```cs +// Draw the form on the page of the document in its original size +gfx.DrawImage(form, 20, 50); + +// Draw it stretched +gfx.DrawImage(form, 300, 100, 250, 40); + +// Draw and rotate it +const int d = 25; +for (int idx = 0; idx < 360; idx += d) +{ + gfx.DrawImage(form, 300, 480, 200, 200); + gfx.RotateAtTransform(d, new XPoint(300, 480)); +} +``` diff --git a/docs/PdfSharpCore/samples/index.md b/docs/PdfSharpCore/samples/index.md new file mode 100644 index 00000000..ee50e028 --- /dev/null +++ b/docs/PdfSharpCore/samples/index.md @@ -0,0 +1,27 @@ +# PdfSharpCore > Samples + +Samples for [PdfSharpCore](../index.md): + +* [Hello World](HelloWorld.md) +* [Graphics](Graphics.md) +* [Annotations](Annotations.md) +* [Booklet](Booklet.md) +* [Bookmarks](Bookmarks.md) +* [Colors CMYK](ColorsCMYK.md) +* [Combine Documents](CombineDocuments.md) +* [Concatenate Documents](ConcatenateDocuments.md) +* [Export Images](ExportImages.md) +* [Font Resolver](FontResolver.md) +* [Multiple Pages](MultiplePages.md) +* [Page Sizes](PageSizes.md) +* [Preview](Preview.md) +* [Protect Document](ProtectDocument.md) +* [Unprotect Document](UnprotectDocument.md) +* [Split Document](SplitDocument.md) +* [Text Layout](TextLayout.md) +* [Two Pages on One](TwoPagesOnOne.md) +* [Unicode](Unicode.md) +* [Watermark](Watermark.md) +* [Work on Pdf Objects](WorkOnPdfObjects.md) +* [XForms](XForms.md) +* [Clock](Clock.md) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..9252c6e0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,32 @@ +# Welcome to PdfSharpCore & MigraDocCore! + +The libraries in this project are published Open Source and under the [MIT license](https://en.wikipedia.org/wiki/MIT_License) and are free to use. + + +## PdfSharpCore + +PdfSharpCore is the Open Source .NET library that easily creates and processes PDF documents on the fly. +The same drawing routines can be used to create PDF documents, draw on the screen, or send output to any printer. + +* [PdfSharpCore](PdfSharpCore/index.md) + + +## MigraDocCore + +MigraDocCore is the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF by using the PdfSharpCore library. + +* [MigraDocCore](MigraDocCore/index.md) + + +## Use PdfSharpCore or MigraDocCore? + +Use PdfSharpCore if you want to create PDF files only, but be able to control every pixel and every line that is drawn. +Use MigraDocCore if you need documents as PDF files and if you want to enjoy the comfort of a word processor. + + +## Mixing PdfSharpCore and MigraDocCore + +If MigraDocCore does almost anything you need, then you can use it to create PDF files and post-process them with PdfSharpCore to add some extra features. + +Or use PdfSharpCore to create the document but use MigraDocCore to create individual pages. +This could be the best choice if your application uses lots of graphics, but also needs some layout text.