Enable nullable annotations (#803)

* Enable nullable annotations

* Remove unused Jetbrain annotations

* Ensure system using statements are first

* Improve nullability annotations

* Annotate encryptionDictionary is non-null when IsEncrypted is true

* Disable nullable for PdfTokenScanner.Get

* Improve nullability annotations for ObjectLocationProvider.TryGetCached

* Revert changes to RGBWorkingSpace

* Update UglyToad.PdfPig.Package with new framework targets (fixes nightly builds)
This commit is contained in:
Jason Nelson 2024-03-17 11:51:40 -07:00 committed by GitHub
parent bf6c519483
commit a412a239be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
189 changed files with 1391 additions and 2383 deletions

View File

@ -6,7 +6,6 @@
using Core;
using Fields;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// A collection of interactive fields for gathering data from a user through dropdowns, textboxes, checkboxes, etc.
@ -22,7 +21,6 @@
/// <summary>
/// The raw PDF dictionary which is the root form object.
/// </summary>
[NotNull]
public DictionaryToken Dictionary { get; }
/// <summary>

View File

@ -42,12 +42,12 @@ namespace UglyToad.PdfPig.AcroForms
/// <summary>
/// Get string values of field.
/// </summary>
public static KeyValuePair<string, string> GetFieldValue(this AcroFieldBase fieldBase)
public static KeyValuePair<string?, string?> GetFieldValue(this AcroFieldBase fieldBase)
{
return fieldBase switch
{
AcroTextField textField => new(textField.Information.PartialName, textField.Value),
AcroCheckboxField checkboxField => new(checkboxField.Information.PartialName, checkboxField.IsChecked.ToString()),
AcroCheckboxField checkboxField => new(checkboxField.Information.PartialName, checkboxField.IsChecked.ToString())!,
_ => new(fieldBase.Information.PartialName, ""),
};
}

View File

@ -1,18 +1,17 @@
namespace UglyToad.PdfPig.AcroForms
{
using System;
using System.Collections.Generic;
using System.Linq;
using Content;
using Core;
using CrossReference;
using Fields;
using Filters;
using Parser.Parts;
using System;
using System.Collections.Generic;
using System.Linq;
using Tokenization.Scanner;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
/// <summary>
/// Extracts the <see cref="AcroForm"/> from the document, if available.
@ -43,15 +42,14 @@
/// Retrieve the <see cref="AcroForm"/> from the document, if applicable.
/// </summary>
/// <returns>The <see cref="AcroForm"/> if the document contains one.</returns>
[CanBeNull]
public AcroForm GetAcroForm(Catalog catalog)
public AcroForm? GetAcroForm(Catalog catalog)
{
if (!catalog.CatalogDictionary.TryGet(NameToken.AcroForm, out var acroRawToken) )
{
return null;
}
if (!DirectObjectFinder.TryGet(acroRawToken, tokenScanner, out DictionaryToken acroDictionary))
if (!DirectObjectFinder.TryGet(acroRawToken, tokenScanner, out DictionaryToken? acroDictionary))
{
var fieldsRefs = new List<IndirectReferenceToken>();
@ -59,12 +57,12 @@
foreach (var reference in crossReferenceTable.ObjectOffsets.Keys)
{
var referenceToken = new IndirectReferenceToken(reference);
if (!DirectObjectFinder.TryGet(referenceToken, tokenScanner, out DictionaryToken dict))
if (!DirectObjectFinder.TryGet(referenceToken, tokenScanner, out DictionaryToken? dict))
{
continue;
}
if (dict.TryGet(NameToken.Kids, tokenScanner, out ArrayToken _) && dict.TryGet(NameToken.T, tokenScanner, out StringToken _))
if (dict.TryGet(NameToken.Kids, tokenScanner, out ArrayToken? _) && dict.TryGet(NameToken.T, tokenScanner, out StringToken? _))
{
fieldsRefs.Add(referenceToken);
}
@ -82,40 +80,40 @@
}
var signatureFlags = (SignatureFlags)0;
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.SigFlags, tokenScanner, out NumericToken signatureToken))
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.SigFlags, tokenScanner, out NumericToken? signatureToken))
{
signatureFlags = (SignatureFlags)signatureToken.Int;
}
var needAppearances = false;
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.NeedAppearances, tokenScanner, out BooleanToken appearancesToken))
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.NeedAppearances, tokenScanner, out BooleanToken? appearancesToken))
{
needAppearances = appearancesToken.Data;
}
var calculationOrder = default(ArrayToken);
ArrayToken? calculationOrder;
acroDictionary.TryGetOptionalTokenDirect(NameToken.Co, tokenScanner, out calculationOrder);
var formResources = default(DictionaryToken);
DictionaryToken? formResources = default;
acroDictionary.TryGetOptionalTokenDirect(NameToken.Dr, tokenScanner, out formResources);
var da = default(string);
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Da, tokenScanner, out StringToken daToken))
string? da = default;
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Da, tokenScanner, out StringToken? daToken))
{
da = daToken.Data;
}
else if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Da, tokenScanner, out HexToken daHexToken))
else if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Da, tokenScanner, out HexToken? daHexToken))
{
da = daHexToken.Data;
}
var q = default(int?);
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Q, tokenScanner, out NumericToken qToken))
if (acroDictionary.TryGetOptionalTokenDirect(NameToken.Q, tokenScanner, out NumericToken? qToken))
{
q = qToken.Int;
}
if (!acroDictionary.TryGet(NameToken.Fields, tokenScanner, out ArrayToken fieldsArray))
if (!acroDictionary.TryGet(NameToken.Fields, tokenScanner, out ArrayToken? fieldsArray))
{
return null;
}
@ -146,12 +144,12 @@
fieldDictionary = combinedFieldDictionary;
fieldDictionary.TryGet(NameToken.Ft, tokenScanner, out NameToken fieldType);
fieldDictionary.TryGet(NameToken.Ff, tokenScanner, out NumericToken fieldFlagsToken);
fieldDictionary.TryGet(NameToken.Ft, tokenScanner, out NameToken? fieldType);
fieldDictionary.TryGet(NameToken.Ff, tokenScanner, out NumericToken? fieldFlagsToken);
var kids = new List<(bool hasParent, DictionaryToken dictionary)>();
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Kids, tokenScanner, out ArrayToken kidsToken))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Kids, tokenScanner, out ArrayToken? kidsToken))
{
foreach (var kid in kidsToken.Data)
{
@ -185,13 +183,13 @@
var information = new AcroFieldCommonInformation(parentReferenceToken?.Data, partialFieldName, alternateFieldName, mappingName);
int? pageNumber = null;
if (fieldDictionary.TryGet(NameToken.P, tokenScanner, out IndirectReferenceToken pageReference))
if (fieldDictionary.TryGet(NameToken.P, tokenScanner, out IndirectReferenceToken? pageReference))
{
pageNumber = catalog.Pages.GetPageByReference(pageReference.Data)?.PageNumber;
}
PdfRectangle? bounds = null;
if (fieldDictionary.TryGet(NameToken.Rect, tokenScanner, out ArrayToken rectArray) && rectArray.Length == 4)
if (fieldDictionary.TryGet(NameToken.Rect, tokenScanner, out ArrayToken? rectArray) && rectArray.Length == 4)
{
bounds = rectArray.ToRectangle(tokenScanner);
}
@ -303,22 +301,22 @@
var textValue = default(string);
if (fieldDictionary.TryGet(NameToken.V, out var textValueToken))
{
if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StringToken valueStringToken))
if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StringToken? valueStringToken))
{
textValue = valueStringToken.Data;
}
else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out HexToken valueHexToken))
else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out HexToken? valueHexToken))
{
textValue = valueHexToken.Data;
}
else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StreamToken valueStreamToken))
else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StreamToken? valueStreamToken))
{
textValue = OtherEncodings.BytesAsLatin1String(valueStreamToken.Decode(filterProvider, tokenScanner).ToArray());
}
}
var maxLength = default(int?);
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.MaxLen, tokenScanner, out NumericToken maxLenToken))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.MaxLen, tokenScanner, out NumericToken? maxLenToken))
{
maxLength = maxLenToken.Int;
}
@ -341,27 +339,27 @@
var selectedOptions = Array.Empty<string>();
if (fieldDictionary.TryGet(NameToken.V, out var valueToken))
{
if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out StringToken valueString))
if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out StringToken? valueString))
{
selectedOptions = [valueString.Data];
}
else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out HexToken valueHex))
else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out HexToken? valueHex))
{
selectedOptions = [valueHex.Data];
}
else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out ArrayToken valueArray))
else if (DirectObjectFinder.TryGet(valueToken, tokenScanner, out ArrayToken? valueArray))
{
selectedOptions = new string[valueArray.Length];
for (var i = 0; i < valueArray.Length; i++)
{
var valueOptToken = valueArray.Data[i];
if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out StringToken valueOptString))
if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out StringToken? valueOptString))
{
selectedOptions[i] = valueOptString.Data;
}
else if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out HexToken valueOptHex))
else if (DirectObjectFinder.TryGet(valueOptToken, tokenScanner, out HexToken? valueOptHex))
{
selectedOptions[i] = valueOptHex.Data;
}
@ -370,7 +368,7 @@
}
var selectedIndices = default(int[]);
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.I, tokenScanner, out ArrayToken indicesArray))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.I, tokenScanner, out ArrayToken? indicesArray))
{
selectedIndices = new int[indicesArray.Length];
for (var i = 0; i < indicesArray.Data.Count; i++)
@ -382,24 +380,24 @@
}
var options = new List<AcroChoiceOption>();
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Opt, tokenScanner, out ArrayToken optionsArrayToken))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Opt, tokenScanner, out ArrayToken? optionsArrayToken))
{
for (var i = 0; i < optionsArrayToken.Data.Count; i++)
{
var optionToken = optionsArrayToken.Data[i];
if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out StringToken optionStringToken))
if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out StringToken? optionStringToken))
{
var name = optionStringToken.Data;
var isSelected = IsChoiceSelected(selectedOptions, selectedIndices, i, name);
options.Add(new AcroChoiceOption(i, isSelected, optionStringToken.Data));
}
else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out HexToken optionHexToken))
else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out HexToken? optionHexToken))
{
var name = optionHexToken.Data;
var isSelected = IsChoiceSelected(selectedOptions, selectedIndices, i, name);
options.Add(new AcroChoiceOption(i, isSelected, optionHexToken.Data));
}
else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out ArrayToken optionArrayToken))
else if (DirectObjectFinder.TryGet(optionToken, tokenScanner, out ArrayToken? optionArrayToken))
{
if (optionArrayToken.Length != 2)
{
@ -407,11 +405,11 @@
}
string exportValue;
if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out StringToken exportValueStringToken))
if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out StringToken? exportValueStringToken))
{
exportValue = exportValueStringToken.Data;
}
else if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out HexToken exportValueHexToken))
else if (DirectObjectFinder.TryGet(optionArrayToken.Data[0], tokenScanner, out HexToken? exportValueHexToken))
{
exportValue = exportValueHexToken.Data;
}
@ -421,11 +419,11 @@
}
string name;
if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out StringToken nameStringToken))
if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out StringToken? nameStringToken))
{
name = nameStringToken.Data;
}
else if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out HexToken nameHexToken))
else if (DirectObjectFinder.TryGet(optionArrayToken.Data[1], tokenScanner, out HexToken? nameHexToken))
{
name = nameHexToken.Data;
}
@ -458,7 +456,7 @@
}
var topIndex = default(int?);
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ti, tokenScanner, out NumericToken topIndexToken))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ti, tokenScanner, out NumericToken? topIndexToken))
{
topIndex = topIndexToken.Int;
}
@ -475,10 +473,10 @@
private (bool isChecked, NameToken stateName) GetCheckedState(DictionaryToken fieldDictionary, bool inheritsValue)
{
var isChecked = false;
if (!fieldDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NameToken valueToken))
if (!fieldDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NameToken? valueToken))
{
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.As, tokenScanner, out NameToken appearanceStateName)
&& fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ap, tokenScanner, out DictionaryToken _))
if (fieldDictionary.TryGetOptionalTokenDirect(NameToken.As, tokenScanner, out NameToken? appearanceStateName)
&& fieldDictionary.TryGetOptionalTokenDirect(NameToken.Ap, tokenScanner, out DictionaryToken? _))
{
// Issue #267 - Use the set appearance instead, this might not work for 3 state checkboxes.
isChecked = !string.Equals(
@ -490,7 +488,7 @@
}
valueToken = NameToken.Off;
}
else if (inheritsValue && fieldDictionary.TryGet(NameToken.As, tokenScanner, out NameToken appearanceStateName))
else if (inheritsValue && fieldDictionary.TryGet(NameToken.As, tokenScanner, out NameToken? appearanceStateName))
{
// The parent field's V entry holds a name object corresponding to the
// appearance state of whichever child field is currently in the on state.
@ -546,7 +544,7 @@
return (new DictionaryToken(inheritedDictionary), inheritsValue);
}
private static bool IsChoiceSelected(IReadOnlyList<string> selectedOptionNames, IReadOnlyList<int> selectedOptionIndices, int index, string name)
private static bool IsChoiceSelected(IReadOnlyList<string> selectedOptionNames, IReadOnlyList<int>? selectedOptionIndices, int index, string name)
{
if (selectedOptionNames.Count == 0)
{

View File

@ -23,7 +23,7 @@
/// <summary>
/// The value of the option when the form is exported.
/// </summary>
public string ExportValue { get; }
public string? ExportValue { get; }
/// <summary>
/// Whether the field defined an export value for this option.
@ -33,7 +33,7 @@
/// <summary>
/// Create a new <see cref="AcroChoiceOption"/>.
/// </summary>
public AcroChoiceOption(int index, bool isSelected, string name, string exportValue = null)
public AcroChoiceOption(int index, bool isSelected, string name, string? exportValue = null)
{
Index = index;
IsSelected = isSelected;

View File

@ -4,7 +4,6 @@
using System.Collections.Generic;
using Core;
using Tokens;
using Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -21,20 +20,17 @@
/// <summary>
/// The options to be presented to the user.
/// </summary>
[NotNull]
public IReadOnlyList<AcroChoiceOption> Options { get; }
/// <summary>
/// The names of any currently selected options.
/// </summary>
[NotNull]
public IReadOnlyList<string> SelectedOptions { get; }
/// <summary>
/// For multiple select lists with duplicate names gives the indices of the selected options.
/// </summary>
[CanBeNull]
public IReadOnlyList<int> SelectedOptionIndices { get; }
public IReadOnlyList<int>? SelectedOptionIndices { get; }
/// <inheritdoc />
/// <summary>
@ -49,10 +45,13 @@
/// <param name="selectedOptions">The names of the selected options.</param>
/// <param name="pageNumber">The number of the page this field appears on.</param>
/// <param name="bounds">The location of this field on the page.</param>
public AcroComboBoxField(DictionaryToken dictionary, string fieldType, AcroChoiceFieldFlags fieldFlags,
public AcroComboBoxField(
DictionaryToken dictionary,
string fieldType,
AcroChoiceFieldFlags fieldFlags,
AcroFieldCommonInformation information, IReadOnlyList<AcroChoiceOption> options,
IReadOnlyList<string> selectedOptions,
IReadOnlyList<int> selectedOptionIndices,
IReadOnlyList<int>? selectedOptionIndices,
int? pageNumber,
PdfRectangle? bounds) :
base(dictionary, fieldType, (uint)fieldFlags, AcroFieldType.ComboBox, information,

View File

@ -1,9 +1,8 @@
namespace UglyToad.PdfPig.AcroForms.Fields
{
using System;
using Core;
using System;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// A field in an interactive <see cref="AcroForm"/>.
@ -13,13 +12,11 @@
/// <summary>
/// The raw PDF dictionary for this field.
/// </summary>
[NotNull]
public DictionaryToken Dictionary { get; }
/// <summary>
/// The <see cref="string"/> representing the type of this field in PDF format.
/// </summary>
[NotNull]
public string RawFieldType { get; }
/// <summary>
@ -35,7 +32,6 @@
/// <summary>
/// The optional information common to all types of field.
/// </summary>
[NotNull]
public AcroFieldCommonInformation Information { get; }
/// <summary>

View File

@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.AcroForms.Fields
{
using Core;
using Util.JetBrains.Annotations;
/// <summary>
/// Information from the field dictionary which is common across all field types.
@ -18,26 +17,23 @@
/// The partial field name for this field. The fully qualified field name is the
/// period '.' joined name of all parents' partial names and this field's partial name.
/// </summary>
[CanBeNull]
public string PartialName { get; }
public string? PartialName { get; }
/// <summary>
/// The alternate field name to be used instead of the fully qualified field name where
/// the field is being identified on the user interface or by screen readers.
/// </summary>
[CanBeNull]
public string AlternateName { get; }
public string? AlternateName { get; }
/// <summary>
/// The mapping name used when exporting form field data from the document.
/// </summary>
[CanBeNull]
public string MappingName { get; }
public string? MappingName { get; }
/// <summary>
/// Create a new <see cref="AcroFieldCommonInformation"/>.
/// </summary>
public AcroFieldCommonInformation(IndirectReference? parent, string partialName, string alternateName, string mappingName)
public AcroFieldCommonInformation(IndirectReference? parent, string? partialName, string? alternateName, string? mappingName)
{
Parent = parent;
PartialName = partialName;
@ -48,7 +44,7 @@
/// <inheritdoc />
public override string ToString()
{
string AppendIfNotNull(string val, string label, string result)
string AppendIfNotNull(string? val, string label, string result)
{
if (val is null)
{

View File

@ -4,7 +4,6 @@
using System.Collections.Generic;
using Core;
using Tokens;
using Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -20,20 +19,17 @@
/// <summary>
/// The options to be presented to the user.
/// </summary>
[NotNull]
public IReadOnlyList<AcroChoiceOption> Options { get; }
/// <summary>
/// The names of any currently selected options.
/// </summary>
[NotNull]
public IReadOnlyList<string> SelectedOptions { get; }
/// <summary>
/// For multiple select lists with duplicate names gives the indices of the selected options.
/// </summary>
[CanBeNull]
public IReadOnlyList<int> SelectedOptionIndices { get; }
public IReadOnlyList<int>? SelectedOptionIndices { get; }
/// <summary>
/// For scrollable list boxes gives the index of the first visible option.
@ -62,7 +58,7 @@
public AcroListBoxField(DictionaryToken dictionary, string fieldType, AcroChoiceFieldFlags fieldFlags,
AcroFieldCommonInformation information, IReadOnlyList<AcroChoiceOption> options,
IReadOnlyList<string> selectedOptions,
IReadOnlyList<int> selectedOptionIndices,
IReadOnlyList<int>? selectedOptionIndices,
int? topIndex,
int? pageNumber,
PdfRectangle? bounds) :

View File

@ -19,7 +19,7 @@
/// The value of the text in this text field.
/// This can be <see langword="null"/> if no value has been set.
/// </summary>
public string Value { get; }
public string? Value { get; }
/// <summary>
/// The optional maximum length of the text field.
@ -50,7 +50,7 @@
/// <param name="bounds">The location of this field on the page.</param>
public AcroTextField(DictionaryToken dictionary, string fieldType, AcroTextFieldFlags fieldFlags,
AcroFieldCommonInformation information,
string value,
string? value,
int? maxLength,
int? pageNumber,
PdfRectangle? bounds) :

View File

@ -1,11 +1,11 @@
namespace UglyToad.PdfPig.Actions
{
using System.Diagnostics.CodeAnalysis;
using Core;
using Logging;
using Outline;
using Outline.Destinations;
using Tokenization.Scanner;
using Tokens;
using Outline.Destinations;
using Util;
internal static class ActionProvider
@ -13,20 +13,21 @@
/// <summary>
/// Get an action (A) from dictionary. If GoTo, GoToR or GoToE, also fetches the action destination.
/// </summary>
internal static bool TryGetAction(DictionaryToken dictionary,
internal static bool TryGetAction(
DictionaryToken dictionary,
NamedDestinations namedDestinations,
IPdfTokenScanner pdfScanner,
ILog log,
out PdfAction result)
[NotNullWhen(true)] out PdfAction? result)
{
result = null;
if (!dictionary.TryGet(NameToken.A, pdfScanner, out DictionaryToken actionDictionary))
if (!dictionary.TryGet(NameToken.A, pdfScanner, out DictionaryToken? actionDictionary))
{
return false;
}
if (!actionDictionary.TryGet(NameToken.S, pdfScanner, out NameToken actionType))
if (!actionDictionary.TryGet(NameToken.S, pdfScanner, out NameToken? actionType))
{
throw new PdfDocumentFormatException($"No action type (/S) specified for action: {actionDictionary}.");
}
@ -81,7 +82,7 @@
fileSpecification = null;
}
result = new GoToEAction(destination, fileSpecification);
result = new GoToEAction(destination, fileSpecification!);
return true;
}
}

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Actions
#nullable disable
namespace UglyToad.PdfPig.Actions
{
/// <summary>
/// Action to open a URI

View File

@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content;
using Core;
using Filters;
@ -37,14 +38,14 @@
/// </summary>
/// <param name="embeddedFiles">The set of embedded files in this document.</param>
/// <returns><see langword="true"/> if this document contains more than zero embedded files, otherwise <see langword="false"/>.</returns>
public bool TryGetEmbeddedFiles(out IReadOnlyList<EmbeddedFile> embeddedFiles)
public bool TryGetEmbeddedFiles([NotNullWhen(true)] out IReadOnlyList<EmbeddedFile>? embeddedFiles)
{
GuardDisposed();
embeddedFiles = null;
if (!catalog.CatalogDictionary.TryGet(NameToken.Names, pdfScanner, out DictionaryToken namesDictionary)
|| !namesDictionary.TryGet(NameToken.EmbeddedFiles, pdfScanner, out DictionaryToken embeddedFileNamesDictionary))
if (!catalog.CatalogDictionary.TryGet(NameToken.Names, pdfScanner, out DictionaryToken? namesDictionary)
|| !namesDictionary.TryGet(NameToken.EmbeddedFiles, pdfScanner, out DictionaryToken? embeddedFileNamesDictionary))
{
return false;
}
@ -60,15 +61,15 @@
foreach (var keyValuePair in embeddedFileNames)
{
if (!DirectObjectFinder.TryGet(keyValuePair.Value, pdfScanner, out DictionaryToken fileDescriptorDictionaryToken)
|| !fileDescriptorDictionaryToken.TryGet(NameToken.Ef, pdfScanner, out DictionaryToken efDictionary)
|| !efDictionary.TryGet(NameToken.F, pdfScanner, out StreamToken fileStreamToken))
if (!DirectObjectFinder.TryGet(keyValuePair.Value, pdfScanner, out DictionaryToken? fileDescriptorDictionaryToken)
|| !fileDescriptorDictionaryToken.TryGet(NameToken.Ef, pdfScanner, out DictionaryToken? efDictionary)
|| !efDictionary.TryGet(NameToken.F, pdfScanner, out StreamToken? fileStreamToken))
{
continue;
}
var fileSpecification = string.Empty;
if (fileDescriptorDictionaryToken.TryGet(NameToken.F, pdfScanner, out IDataToken<string> fileSpecificationToken))
if (fileDescriptorDictionaryToken.TryGet(NameToken.F, pdfScanner, out IDataToken<string>? fileSpecificationToken))
{
fileSpecification = fileSpecificationToken.Data;
}

View File

@ -5,22 +5,20 @@
using Core;
using Actions;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// An annotation on a page in a PDF document.
/// </summary>
public class Annotation
{
internal readonly AppearanceStream normalAppearanceStream;
internal readonly AppearanceStream rollOverAppearanceStream;
internal readonly AppearanceStream downAppearanceStream;
internal readonly string appearanceState;
internal readonly AppearanceStream? normalAppearanceStream;
internal readonly AppearanceStream? rollOverAppearanceStream;
internal readonly AppearanceStream? downAppearanceStream;
internal readonly string? appearanceState;
/// <summary>
/// The underlying PDF dictionary which this annotation was created from.
/// </summary>
[NotNull]
public DictionaryToken AnnotationDictionary { get; }
/// <summary>
@ -36,20 +34,17 @@
/// <summary>
/// The annotation text, or if the annotation does not display text, a description of the annotation's contents. Optional.
/// </summary>
[CanBeNull]
public string Content { get; }
public string? Content { get; }
/// <summary>
/// The name of this annotation which should be unique per page. Optional.
/// </summary>
[CanBeNull]
public string Name { get; }
public string? Name { get; }
/// <summary>
/// The date and time the annotation was last modified, can be in any format. Optional.
/// </summary>
[CanBeNull]
public string ModifiedDate { get; }
public string? ModifiedDate { get; }
/// <summary>
/// Flags defining the appearance and behaviour of this annotation.
@ -71,7 +66,7 @@
/// <summary>
/// Action for this annotation, if any (can be null)
/// </summary>
public PdfAction Action { get; }
public PdfAction? Action { get; }
/// <summary>
/// Indicates if a normal appearance is present for this annotation
@ -91,7 +86,7 @@
/// <summary>
/// The <see cref="Annotation"/> this annotation was in reply to. Can be <see langword="null" />
/// </summary>
public Annotation InReplyTo { get; }
public Annotation? InReplyTo { get; }
/// <summary>
/// Create a new <see cref="Annotation"/>.
@ -100,18 +95,18 @@
DictionaryToken annotationDictionary,
AnnotationType type,
PdfRectangle rectangle,
string content,
string name,
string modifiedDate,
string? content,
string? name,
string? modifiedDate,
AnnotationFlags flags,
AnnotationBorder border,
IReadOnlyList<QuadPointsQuadrilateral> quadPoints,
PdfAction action,
AppearanceStream normalAppearanceStream,
AppearanceStream rollOverAppearanceStream,
AppearanceStream downAppearanceStream,
string appearanceState,
Annotation inReplyTo)
PdfAction? action,
AppearanceStream? normalAppearanceStream,
AppearanceStream? rollOverAppearanceStream,
AppearanceStream? downAppearanceStream,
string? appearanceState,
Annotation? inReplyTo)
{
AnnotationDictionary = annotationDictionary ?? throw new ArgumentNullException(nameof(annotationDictionary));
Type = type;

View File

@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.Annotations
{
using System.Collections.Generic;
using Util.JetBrains.Annotations;
/// <summary>
/// A border for a PDF <see cref="Annotation"/> object.
@ -31,13 +30,12 @@
/// <summary>
/// The dash pattern for the border lines if provided. Optional.
/// </summary>
[CanBeNull]
public IReadOnlyList<double> LineDashPattern { get; }
public IReadOnlyList<double>? LineDashPattern { get; }
/// <summary>
/// Create a new <see cref="AnnotationBorder"/>.
/// </summary>
public AnnotationBorder(double horizontalCornerRadius, double verticalCornerRadius, double borderWidth, IReadOnlyList<double> lineDashPattern)
public AnnotationBorder(double horizontalCornerRadius, double verticalCornerRadius, double borderWidth, IReadOnlyList<double>? lineDashPattern)
{
HorizontalCornerRadius = horizontalCornerRadius;
VerticalCornerRadius = verticalCornerRadius;

View File

@ -1,9 +1,9 @@
namespace UglyToad.PdfPig.Annotations
{
using Actions;
using System;
using System.Collections.Generic;
using System.Linq;
using Actions;
using Core;
using Logging;
using Outline.Destinations;
@ -46,21 +46,21 @@
{
var lookupAnnotations = new Dictionary<IndirectReference, Annotation>();
if (!pageDictionary.TryGet(NameToken.Annots, tokenScanner, out ArrayToken annotationsArray))
if (!pageDictionary.TryGet(NameToken.Annots, tokenScanner, out ArrayToken? annotationsArray))
{
yield break;
}
foreach (var token in annotationsArray.Data)
{
if (!DirectObjectFinder.TryGet(token, tokenScanner, out DictionaryToken annotationDictionary))
if (!DirectObjectFinder.TryGet(token, tokenScanner, out DictionaryToken? annotationDictionary))
{
continue;
}
Annotation replyTo = null;
if (annotationDictionary.TryGet(NameToken.Irt, out IndirectReferenceToken referencedAnnotation)
&& lookupAnnotations.TryGetValue(referencedAnnotation.Data, out var linkedAnnotation))
Annotation? replyTo = null;
if (annotationDictionary.TryGet(NameToken.Irt, out IndirectReferenceToken? referencedAnnotation)
&& lookupAnnotations.TryGetValue(referencedAnnotation!.Data, out var linkedAnnotation))
{
replyTo = linkedAnnotation;
}
@ -77,14 +77,14 @@
var flags = (AnnotationFlags)0;
if (annotationDictionary.TryGet(NameToken.F, out var flagsToken) &&
DirectObjectFinder.TryGet(flagsToken, tokenScanner, out NumericToken flagsNumericToken))
DirectObjectFinder.TryGet(flagsToken, tokenScanner, out NumericToken? flagsNumericToken))
{
flags = (AnnotationFlags)flagsNumericToken.Int;
}
var border = AnnotationBorder.Default;
if (annotationDictionary.TryGet(NameToken.Border, out var borderToken) &&
DirectObjectFinder.TryGet(borderToken, tokenScanner, out ArrayToken borderArray)
DirectObjectFinder.TryGet(borderToken, tokenScanner, out ArrayToken? borderArray)
&& borderArray.Length >= 3)
{
var horizontal = borderArray.GetNumeric(0).Data;
@ -101,7 +101,7 @@
}
var quadPointRectangles = new List<QuadPointsQuadrilateral>();
if (annotationDictionary.TryGet(NameToken.Quadpoints, tokenScanner, out ArrayToken quadPointsArray))
if (annotationDictionary.TryGet(NameToken.Quadpoints, tokenScanner, out ArrayToken? quadPointsArray))
{
var values = new List<double>();
for (var i = 0; i < quadPointsArray.Length; i++)
@ -128,14 +128,14 @@
}
}
AppearanceStream normalAppearanceStream = null;
AppearanceStream downAppearanceStream = null;
AppearanceStream rollOverAppearanceStream = null;
AppearanceStream? normalAppearanceStream = null;
AppearanceStream? downAppearanceStream = null;
AppearanceStream? rollOverAppearanceStream = null;
if (annotationDictionary.TryGet(NameToken.Ap, out DictionaryToken appearanceDictionary))
{
// The normal appearance of this annotation
if (AppearanceStreamFactory.TryCreate(appearanceDictionary, NameToken.N, tokenScanner, out AppearanceStream stream))
if (AppearanceStreamFactory.TryCreate(appearanceDictionary, NameToken.N, tokenScanner, out AppearanceStream? stream))
{
normalAppearanceStream = stream;
}
@ -153,7 +153,7 @@
}
}
string appearanceState = null;
string? appearanceState = null;
if (annotationDictionary.TryGet(NameToken.As, out NameToken appearanceStateToken))
{
appearanceState = appearanceStateToken.Data;
@ -185,7 +185,7 @@
}
}
internal PdfAction GetAction(DictionaryToken annotationDictionary)
internal PdfAction? GetAction(DictionaryToken annotationDictionary)
{
// If this annotation returns a direct destination, turn it into a GoTo action.
if (DestinationProvider.TryGetDestination(annotationDictionary,
@ -209,9 +209,9 @@
return null;
}
private string GetNamedString(NameToken name, DictionaryToken dictionary)
private string? GetNamedString(NameToken name, DictionaryToken dictionary)
{
string content = null;
string? content = null;
if (dictionary.TryGet(name, out var contentToken))
{
if (contentToken is StringToken contentString)
@ -222,7 +222,7 @@
{
content = contentHex.Data;
}
else if (DirectObjectFinder.TryGet(contentToken, tokenScanner, out StringToken indirectContentString))
else if (DirectObjectFinder.TryGet(contentToken, tokenScanner, out StringToken? indirectContentString))
{
content = indirectContentString.Data;
}

View File

@ -12,9 +12,9 @@
/// </summary>
public class AppearanceStream
{
private readonly IDictionary<string, StreamToken> appearanceStreamsByState;
private readonly IDictionary<string, StreamToken>? appearanceStreamsByState;
private readonly StreamToken statelessAppearanceStream;
private readonly StreamToken? statelessAppearanceStream;
/// <summary>
/// Indicates if this appearance stream is stateless, or whether you can get appearances by state.
@ -30,7 +30,7 @@
/// Constructor for stateless appearance stream
/// </summary>
/// <param name="streamToken"></param>
internal AppearanceStream(StreamToken streamToken)
internal AppearanceStream(StreamToken? streamToken)
{
statelessAppearanceStream = streamToken;
}

View File

@ -1,12 +1,13 @@
namespace UglyToad.PdfPig.Annotations
{
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Tokenization.Scanner;
using Tokens;
internal static class AppearanceStreamFactory
{
public static bool TryCreate(DictionaryToken appearanceDictionary, NameToken name, IPdfTokenScanner tokenScanner, out AppearanceStream appearanceStream)
public static bool TryCreate(DictionaryToken appearanceDictionary, NameToken name, IPdfTokenScanner tokenScanner, [NotNullWhen(true)] out AppearanceStream? appearanceStream)
{
if (appearanceDictionary.TryGet(name, out IndirectReferenceToken appearanceReference))
{
@ -24,7 +25,7 @@
stateRef is IndirectReferenceToken appearanceRef)
{
var streamToken = tokenScanner.Get(appearanceRef.Data)?.Data as StreamToken;
dict[state] = streamToken;
dict[state] = streamToken!;
}
}

View File

@ -25,15 +25,15 @@
}
// Must be a link annotation with an action of type /URI.
if (!annotation.AnnotationDictionary.TryGet(NameToken.A, pdfScanner, out DictionaryToken actionDictionary)
|| !actionDictionary.TryGet(NameToken.S, pdfScanner, out NameToken actionType)
if (!annotation.AnnotationDictionary.TryGet(NameToken.A, pdfScanner, out DictionaryToken? actionDictionary)
|| !actionDictionary.TryGet(NameToken.S, pdfScanner, out NameToken? actionType)
|| actionType != NameToken.Uri)
{
continue;
}
// (Required) The uniform resource identifier to resolve, encoded in 7-bit ASCII.
if (!actionDictionary.TryGet(NameToken.Uri, pdfScanner, out IDataToken<string> uriStringToken))
if (!actionDictionary.TryGet(NameToken.Uri, pdfScanner, out IDataToken<string>? uriStringToken))
{
continue;
}

View File

@ -1,8 +1,8 @@
namespace UglyToad.PdfPig.Content
{
using Core;
using System;
using System.Collections.Generic;
using Core;
using Tokens;
using UglyToad.PdfPig.Graphics;
@ -26,12 +26,12 @@
/// The artifact's subtype. Standard values are Header, Footer, and Watermark.
/// Additional values may be specified for this entry, provided they comply with the naming conventions.
/// </summary>
public string SubType { get; }
public string? SubType { get; }
/// <summary>
/// The artifact's attribute owners.
/// </summary>
public string AttributeOwners { get; }
public string? AttributeOwners { get; }
/// <summary>
/// The artifact's bounding box.
@ -64,13 +64,13 @@
public bool IsRightAttached => IsAttached(NameToken.Right);
internal ArtifactMarkedContentElement(int markedContentIdentifier, NameToken tag, DictionaryToken properties,
string language,
string actualText,
string alternateDescription,
string expandedForm,
string? language,
string? actualText,
string? alternateDescription,
string? expandedForm,
ArtifactType artifactType,
string subType,
string attributeOwners,
string? subType,
string? attributeOwners,
PdfRectangle? boundingBox,
IReadOnlyList<NameToken> attached,
IReadOnlyList<MarkedContentElement> children,

View File

@ -79,7 +79,7 @@
}
var rotation = new PageRotationDegrees(pageTreeMembers.Rotation);
if (dictionary.TryGet(NameToken.Rotate, PdfScanner, out NumericToken rotateToken))
if (dictionary.TryGet(NameToken.Rotate, PdfScanner, out NumericToken? rotateToken))
{
rotation = new PageRotationDegrees(rotateToken.Int);
}
@ -94,7 +94,7 @@
stackDepth++;
}
if (dictionary.TryGet(NameToken.Resources, PdfScanner, out DictionaryToken resources))
if (dictionary.TryGet(NameToken.Resources, PdfScanner, out DictionaryToken? resources))
{
ResourceStore.LoadResourceDictionary(resources);
stackDepth++;
@ -177,7 +177,7 @@
UserSpaceUnit userSpaceUnit,
PageRotationDegrees rotation,
TransformationMatrix initialMatrix,
IReadOnlyList<byte> contentBytes)
IReadOnlyList<byte>? contentBytes)
{
IReadOnlyList<IGraphicsStateOperation> operations;
@ -192,7 +192,8 @@
ParsingOptions.Logger);
}
return ProcessPage(pageNumber,
return ProcessPage(
pageNumber,
dictionary,
namedDestinations,
mediaBox,
@ -246,7 +247,7 @@
{
CropBox cropBox;
if (dictionary.TryGet(NameToken.CropBox, out var cropBoxObject) &&
DirectObjectFinder.TryGet(cropBoxObject, PdfScanner, out ArrayToken cropBoxArray))
DirectObjectFinder.TryGet(cropBoxObject, PdfScanner, out ArrayToken? cropBoxArray))
{
if (cropBoxArray.Length != 4)
{
@ -275,7 +276,7 @@
{
MediaBox mediaBox;
if (dictionary.TryGet(NameToken.MediaBox, out var mediaBoxObject)
&& DirectObjectFinder.TryGet(mediaBoxObject, PdfScanner, out ArrayToken mediaBoxArray))
&& DirectObjectFinder.TryGet(mediaBoxObject, PdfScanner, out ArrayToken? mediaBoxArray))
{
if (mediaBoxArray.Length != 4)
{

View File

@ -3,7 +3,6 @@
using System;
using Outline.Destinations;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// The root of the document's object hierarchy. Contains references to objects defining the contents,
@ -14,7 +13,6 @@
/// <summary>
/// The catalog dictionary containing assorted information.
/// </summary>
[NotNull]
public DictionaryToken CatalogDictionary { get; }
internal NamedDestinations NamedDestinations { get; }

View File

@ -5,7 +5,6 @@
using System.Text;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
/// <summary>
/// Metadata for the PDF document.
@ -20,59 +19,58 @@
/// <summary>
/// The underlying document information PDF dictionary from the document.
/// </summary>
public DictionaryToken DocumentInformationDictionary { get; }
public DictionaryToken? DocumentInformationDictionary { get; }
/// <summary>
/// The title of this document if applicable.
/// </summary>
[CanBeNull]
public string Title { get; }
public string? Title { get; }
/// <summary>
/// The name of the person who created this document if applicable.
/// </summary>
[CanBeNull]
public string Author { get; }
public string? Author { get; }
/// <summary>
/// The subject of this document if applicable.
/// </summary>
[CanBeNull]
public string Subject { get; }
public string? Subject { get; }
/// <summary>
/// Any keywords associated with this document if applicable.
/// </summary>
[CanBeNull]
public string Keywords { get; }
public string? Keywords { get; }
/// <summary>
/// The name of the application which created the original document before it was converted to PDF if applicable.
/// </summary>
[CanBeNull]
public string Creator { get; }
public string? Creator { get; }
/// <summary>
/// The name of the application used to convert the original document to PDF if applicable.
/// </summary>
[CanBeNull]
public string Producer { get; }
public string? Producer { get; }
/// <summary>
/// The date and time the document was created.
/// </summary>
[CanBeNull]
public string CreationDate { get; }
public string? CreationDate { get; }
/// <summary>
/// The date and time the document was most recently modified.
/// </summary>
[CanBeNull]
public string ModifiedDate { get; }
public string? ModifiedDate { get; }
internal DocumentInformation(DictionaryToken documentInformationDictionary, string title, string author, string subject, string keywords, string creator, string producer,
string creationDate,
string modifiedDate)
internal DocumentInformation(
DictionaryToken? documentInformationDictionary,
string? title,
string? author,
string? subject,
string? keywords,
string? creator,
string? producer,
string? creationDate,
string? modifiedDate)
{
DocumentInformationDictionary = documentInformationDictionary ?? new DictionaryToken(new Dictionary<NameToken, IToken>());
Title = title;
@ -103,6 +101,11 @@
/// </summary>
public DateTimeOffset? GetCreatedDateTimeOffset()
{
if (CreationDate is null)
{
return null;
}
return DateFormatHelper.TryParseDateTimeOffset(CreationDate, out var result) ? result : default(DateTimeOffset?);
}
@ -111,6 +114,11 @@
/// </summary>
public DateTimeOffset? GetModifiedDateTimeOffset()
{
if (ModifiedDate is null)
{
return null;
}
return DateFormatHelper.TryParseDateTimeOffset(ModifiedDate, out var result) ? result : default(DateTimeOffset?);
}
@ -122,7 +130,7 @@
return representation;
}
private static void AppendPart(string name, string value, StringBuilder builder)
private static void AppendPart(string name, string? value, StringBuilder builder)
{
if (value is null)
{

View File

@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Content
{
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Core;
using Graphics.Colors;
using Graphics.Core;
@ -85,17 +86,17 @@
/// This is not defined where <see cref="IsImageMask"/> is <see langword="true"/> and is optional where the image is JPXEncoded for <see cref="XObjectImage"/>.
/// </para>
/// </summary>
ColorSpaceDetails ColorSpaceDetails { get; }
ColorSpaceDetails? ColorSpaceDetails { get; }
/// <summary>
/// Get the decoded bytes of the image if applicable. For JPEG images and some other types the
/// <see cref="RawBytes"/> should be used directly.
/// </summary>
bool TryGetBytes(out IReadOnlyList<byte> bytes);
bool TryGetBytes([NotNullWhen(true)] out IReadOnlyList<byte>? bytes);
/// <summary>
/// Try to convert the image to PNG. Doesn't support conversion of JPG to PNG.
/// </summary>
bool TryGetPng(out byte[] bytes);
bool TryGetPng([NotNullWhen(true)] out byte[]? bytes);
}
}

View File

@ -1,8 +1,9 @@
namespace UglyToad.PdfPig.Content
{
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Graphics.Colors;
using PdfFonts;
using System.Collections.Generic;
using Tokens;
/// <summary>
@ -24,12 +25,12 @@
/// <summary>
/// Get the font corresponding to the name.
/// </summary>
IFont GetFont(NameToken name);
IFont? GetFont(NameToken name);
/// <summary>
/// Try getting the XObject corresponding to the name.
/// </summary>
bool TryGetXObject(NameToken name, out StreamToken stream);
bool TryGetXObject(NameToken name, [NotNullWhen(true)] out StreamToken? stream);
/// <summary>
/// Get the extended graphics state dictionary corresponding to the name.
@ -49,12 +50,12 @@
/// <summary>
/// Get the color space details corresponding to the name.
/// </summary>
ColorSpaceDetails GetColorSpaceDetails(NameToken name, DictionaryToken dictionary);
ColorSpaceDetails GetColorSpaceDetails(NameToken? name, DictionaryToken? dictionary);
/// <summary>
/// Get the marked content properties dictionary corresponding to the name.
/// </summary>
DictionaryToken GetMarkedContentPropertiesDictionary(NameToken name);
DictionaryToken? GetMarkedContentPropertiesDictionary(NameToken name);
/// <summary>
/// Get all <see cref="PatternColor"/> as a dictionary. Keys are the <see cref="PatternColor"/> names.

View File

@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Core;
using Filters;
@ -9,7 +10,6 @@
using Graphics.Core;
using Tokens;
using Images.Png;
using UglyToad.PdfPig.Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -17,7 +17,7 @@
/// </summary>
public class InlineImage : IPdfImage
{
private readonly Lazy<IReadOnlyList<byte>> bytesFactory;
private readonly Lazy<IReadOnlyList<byte>>? bytesFactory;
/// <inheritdoc />
public PdfRectangle Bounds { get; }
@ -41,7 +41,6 @@
public bool IsInlineImage { get; } = true;
/// <inheritdoc />
[NotNull]
public DictionaryToken ImageDictionary { get; }
/// <inheritdoc />
@ -105,7 +104,7 @@
}
/// <inheritdoc />
public bool TryGetBytes(out IReadOnlyList<byte> bytes)
public bool TryGetBytes([NotNullWhen(true)] out IReadOnlyList<byte>? bytes)
{
bytes = null;
if (bytesFactory is null)
@ -119,7 +118,7 @@
}
/// <inheritdoc />
public bool TryGetPng(out byte[] bytes) => PngFromPdfImageFactory.TryGenerate(this, out bytes);
public bool TryGetPng([NotNullWhen(true)] out byte[]? bytes) => PngFromPdfImageFactory.TryGenerate(this, out bytes);
/// <inheritdoc />
public override string ToString()

View File

@ -3,7 +3,6 @@
using Core;
using Graphics.Colors;
using PdfFonts;
using System.Diagnostics;
/// <summary>
/// A glyph or combination of glyphs (characters) drawn by a PDF content stream.
@ -55,7 +54,7 @@
/// <summary>
/// The name of the font.
/// </summary>
public string FontName => Font?.Name;
public string? FontName => Font?.Name;
/// <summary>
/// Details about the font for this letter.

View File

@ -60,31 +60,32 @@
/// <summary>
/// The natural language specification.
/// </summary>
public string Language { get; }
public string? Language { get; }
/// <summary>
/// The replacement text.
/// </summary>
public string ActualText { get; }
public string? ActualText { get; }
/// <summary>
/// The alternate description.
/// </summary>
public string AlternateDescription { get; }
public string? AlternateDescription { get; }
/// <summary>
/// The abbreviation expansion text.
/// </summary>
public string ExpandedForm { get; }
public string? ExpandedForm { get; }
/// <summary>
/// Create a new <see cref="MarkedContentElement"/>.
/// </summary>
public MarkedContentElement(int markedContentIdentifier, NameToken tag, DictionaryToken properties,
string language,
string actualText,
string alternateDescription,
string expandedForm,
public MarkedContentElement(int markedContentIdentifier, NameToken tag,
DictionaryToken properties,
string? language,
string? actualText,
string? alternateDescription,
string? expandedForm,
bool isArtifact,
IReadOnlyList<MarkedContentElement> children,
IReadOnlyList<Letter> letters,

View File

@ -20,18 +20,18 @@ namespace UglyToad.PdfPig.Content
/// <summary>
/// The name of the optional content group, suitable for presentation in a viewer application's user interface.
/// </summary>
public string Name { get; }
public string? Name { get; }
/// <summary>
/// A single name or an array containing any combination of names.
/// <para>Default value is 'View'.</para>
/// </summary>
public IReadOnlyList<string> Intent { get; }
public IReadOnlyList<string>? Intent { get; }
/// <summary>
/// A usage dictionary describing the nature of the content controlled by the group.
/// </summary>
public IReadOnlyDictionary<string, IToken> Usage { get; }
public IReadOnlyDictionary<string, IToken>? Usage { get; }
/// <summary>
/// Underlying <see cref="MarkedContentElement"/>.
@ -43,11 +43,11 @@ namespace UglyToad.PdfPig.Content
MarkedContent = markedContentElement;
// Type - Required
if (markedContentElement.Properties.TryGet(NameToken.Type, pdfTokenScanner, out NameToken type))
if (markedContentElement.Properties.TryGet(NameToken.Type, pdfTokenScanner, out NameToken? type))
{
Type = type.Data;
}
else if (markedContentElement.Properties.TryGet(NameToken.Type, pdfTokenScanner, out StringToken typeStr))
else if (markedContentElement.Properties.TryGet(NameToken.Type, pdfTokenScanner, out StringToken? typeStr))
{
Type = typeStr.Data;
}
@ -60,11 +60,11 @@ namespace UglyToad.PdfPig.Content
{
case "OCG": // Optional content group dictionary
// Name - Required
if (markedContentElement.Properties.TryGet(NameToken.Name, pdfTokenScanner, out NameToken name))
if (markedContentElement.Properties.TryGet(NameToken.Name, pdfTokenScanner, out NameToken? name))
{
Name = name.Data;
}
else if (markedContentElement.Properties.TryGet(NameToken.Name, pdfTokenScanner, out StringToken nameStr))
else if (markedContentElement.Properties.TryGet(NameToken.Name, pdfTokenScanner, out StringToken? nameStr))
{
Name = nameStr.Data;
}
@ -74,15 +74,15 @@ namespace UglyToad.PdfPig.Content
}
// Intent - Optional
if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out NameToken intentName))
if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out NameToken? intentName))
{
Intent = new string[] { intentName.Data };
Intent = [intentName.Data];
}
else if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out StringToken intentStr))
else if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out StringToken? intentStr))
{
Intent = new string[] { intentStr.Data };
Intent = [intentStr.Data];
}
else if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out ArrayToken intentArray))
else if (markedContentElement.Properties.TryGet(NameToken.Intent, pdfTokenScanner, out ArrayToken? intentArray))
{
List<string> intentList = new List<string>();
foreach (var token in intentArray.Data)
@ -105,11 +105,11 @@ namespace UglyToad.PdfPig.Content
else
{
// Default value is 'View'.
Intent = new string[] { "View" };
Intent = ["View"];
}
// Usage - Optional
if (markedContentElement.Properties.TryGet(NameToken.Usage, pdfTokenScanner, out DictionaryToken usage))
if (markedContentElement.Properties.TryGet(NameToken.Usage, pdfTokenScanner, out DictionaryToken? usage))
{
this.Usage = usage.Data;
}
@ -117,25 +117,25 @@ namespace UglyToad.PdfPig.Content
case "OCMD":
// OCGs - Optional
if (markedContentElement.Properties.TryGet(NameToken.Ocgs, pdfTokenScanner, out DictionaryToken ocgsD))
if (markedContentElement.Properties.TryGet(NameToken.Ocgs, pdfTokenScanner, out DictionaryToken? ocgsD))
{
// dictionary or array
throw new NotImplementedException($"{NameToken.Ocgs}");
}
else if (markedContentElement.Properties.TryGet(NameToken.Ocgs, pdfTokenScanner, out ArrayToken ocgsA))
else if (markedContentElement.Properties.TryGet(NameToken.Ocgs, pdfTokenScanner, out ArrayToken? ocgsA))
{
// dictionary or array
throw new NotImplementedException($"{NameToken.Ocgs}");
}
// P - Optional
if (markedContentElement.Properties.TryGet(NameToken.P, pdfTokenScanner, out NameToken p))
if (markedContentElement.Properties.TryGet(NameToken.P, pdfTokenScanner, out NameToken? p))
{
throw new NotImplementedException($"{NameToken.P}");
}
// VE - Optional
if (markedContentElement.Properties.TryGet(NameToken.VE, pdfTokenScanner, out ArrayToken ve))
if (markedContentElement.Properties.TryGet(NameToken.VE, pdfTokenScanner, out ArrayToken? ve))
{
throw new NotImplementedException($"{NameToken.VE}");
}

View File

@ -3,15 +3,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Annotations;
using Geometry;
using Graphics.Operations;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
using Tokenization.Scanner;
using Graphics;
using System.Linq;
/// <summary>
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
@ -87,7 +86,6 @@
/// <summary>
/// Access to members whose future locations within the API will change without warning.
/// </summary>
[NotNull]
public Experimental ExperimentalAccess { get; }
internal Page(int number, DictionaryToken dictionary, MediaBox mediaBox, CropBox cropBox, PageRotationDegrees rotation, PageContent content,
@ -215,12 +213,12 @@
// TO DO
//var annots = GetAnnotations().ToList();
return mcesOptional.GroupBy(oc => oc.Name).ToDictionary(g => g.Key, g => g.ToList() as IReadOnlyList<OptionalContentGroupElement>);
return mcesOptional.GroupBy(oc => oc.Name).ToDictionary(g => g.Key!, g => (IReadOnlyList<OptionalContentGroupElement>)g.ToList());
}
private void GetOptionalContentsRecursively(IReadOnlyList<MarkedContentElement> markedContentElements, ref List<OptionalContentGroupElement> mcesOptional)
private void GetOptionalContentsRecursively(IReadOnlyList<MarkedContentElement>? markedContentElements, ref List<OptionalContentGroupElement> mcesOptional)
{
if (markedContentElements.Count == 0)
if (markedContentElements is null || markedContentElements.Count == 0)
{
return;
}

View File

@ -72,7 +72,7 @@
}
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is PageRotationDegrees degrees && Equals(degrees);
}

View File

@ -147,11 +147,11 @@
Height = height;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is WidthHeight height &&
Math.Round(Width) == Math.Round(height.Width) &&
Math.Round(Height) == Math.Round(height.Height);
return obj is WidthHeight other &&
Math.Round(Width) == Math.Round(other.Width) &&
Math.Round(Height) == Math.Round(other.Height);
}
public override int GetHashCode()

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Content
#nullable disable
namespace UglyToad.PdfPig.Content
{
using System.Collections.Generic;
using Tokens;

View File

@ -4,7 +4,6 @@
using System.Collections.Generic;
using Core;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// A node in the PDF document's page tree.
@ -16,7 +15,6 @@
/// <summary>
/// The dictionary for this node in the page tree.
/// </summary>
[NotNull]
public DictionaryToken NodeDictionary { get; }
/// <summary>
@ -37,14 +35,12 @@
/// <summary>
/// The child nodes of this node if <see cref="IsPage"/> is <see langword="false" />
/// </summary>
[NotNull]
public IReadOnlyList<PageTreeNode> Children { get; private set; }
public IReadOnlyList<PageTreeNode>? Children { get; private set; }
/// <summary>
/// The parent node of this node, unless it is the root node.
/// </summary>
[CanBeNull]
public PageTreeNode Parent { get; private set; }
public PageTreeNode? Parent { get; private set; }
/// <summary>
/// Whether this node is the root node.
@ -93,7 +89,7 @@
return $"Page #{PageNumber}: {NodeDictionary}.";
}
return $"Pages ({Children.Count} children): {NodeDictionary}";
return $"Pages ({Children?.Count ?? 0} children): {NodeDictionary}";
}
}
}

View File

@ -81,17 +81,17 @@
{
currentNode = pageStack.Pop();
if (currentNode.NodeDictionary.TryGet(NameToken.Resources, pdfScanner, out DictionaryToken resourcesDictionary))
if (currentNode.NodeDictionary.TryGet(NameToken.Resources, pdfScanner, out DictionaryToken? resourcesDictionary))
{
pageTreeMembers.ParentResources.Enqueue(resourcesDictionary);
}
if (currentNode.NodeDictionary.TryGet(NameToken.MediaBox, pdfScanner, out ArrayToken mediaBox))
if (currentNode.NodeDictionary.TryGet(NameToken.MediaBox, pdfScanner, out ArrayToken? mediaBox))
{
pageTreeMembers.MediaBox = new MediaBox(mediaBox.ToRectangle(pdfScanner));
}
if (currentNode.NodeDictionary.TryGet(NameToken.Rotate, pdfScanner, out NumericToken rotateToken))
if (currentNode.NodeDictionary.TryGet(NameToken.Rotate, pdfScanner, out NumericToken? rotateToken))
{
pageTreeMembers.Rotation = rotateToken.Int;
}
@ -167,7 +167,7 @@
return node;
}
internal PageTreeNode GetPageByReference(IndirectReference reference)
internal PageTreeNode? GetPageByReference(IndirectReference reference)
{
foreach (var page in pagesByNumber)
{

View File

@ -131,7 +131,7 @@
}
}
#endregion
if (!current.nodeDictionary.TryGet(NameToken.Kids, pdfTokenScanner, out ArrayToken kids))
if (!current.nodeDictionary.TryGet(NameToken.Kids, pdfTokenScanner, out ArrayToken? kids))
{
if (!isLenientParsing)
{
@ -148,7 +148,7 @@
throw new PdfDocumentFormatException($"Kids array contained invalid entry (must be indirect reference): {kid}.");
}
if (!DirectObjectFinder.TryGet(kidRef, pdfTokenScanner, out DictionaryToken kidDictionaryToken))
if (!DirectObjectFinder.TryGet(kidRef, pdfTokenScanner, out DictionaryToken? kidDictionaryToken))
{
throw new PdfDocumentFormatException($"Could not find dictionary associated with reference in pages kids array: {kidRef}.");
}
@ -181,7 +181,7 @@
action();
}
foreach (var child in firstPage.Children.ToRecursiveOrderList(x => x.Children).Where(child => child.IsPage))
foreach (var child in firstPage.Children!.ToRecursiveOrderList(x => x.Children!).Where(child => child.IsPage))
{
pageNumber.Increment();
child.PageNumber = pageNumber.PageCount;
@ -194,22 +194,28 @@
{
var isPage = false;
if (!nodeDictionary.TryGet(NameToken.Type, pdfTokenScanner, out NameToken type))
if (!nodeDictionary.TryGet(NameToken.Type, pdfTokenScanner, out NameToken? type))
{
if (!isLenientParsing) { throw new PdfDocumentFormatException($"Node in the document pages tree did not define a type: {nodeDictionary}."); }
if (!nodeDictionary.TryGet(NameToken.Kids, pdfTokenScanner, out ArrayToken _)) { isPage = true; }
if (!nodeDictionary.TryGet(NameToken.Kids, pdfTokenScanner, out ArrayToken? _)) { isPage = true; }
}
else
{
isPage = type.Equals(NameToken.Page);
if (!isPage && !type.Equals(NameToken.Pages) && !isLenientParsing) { throw new PdfDocumentFormatException($"Node in the document pages tree defined invalid type: {nodeDictionary}."); }
if (!isPage && !type.Equals(NameToken.Pages) && !isLenientParsing)
{
throw new PdfDocumentFormatException($"Node in the document pages tree defined invalid type: {nodeDictionary}.");
}
}
if (!isLenientParsing && !isRoot)
{
if (!nodeDictionary.TryGet(NameToken.Parent, pdfTokenScanner, out IndirectReferenceToken parentReferenceToken)) { throw new PdfDocumentFormatException($"Could not find parent indirect reference token on pages tree node: {nodeDictionary}."); }
if (!nodeDictionary.TryGet(NameToken.Parent, pdfTokenScanner, out IndirectReferenceToken? parentReferenceToken))
{
throw new PdfDocumentFormatException($"Could not find parent indirect reference token on pages tree node: {nodeDictionary}.");
}
if (!parentReferenceToken.Data.Equals(parentReference)) { throw new PdfDocumentFormatException($"Pages tree node parent reference {parentReferenceToken.Data} did not match actual parent {parentReference}."); }
}
@ -230,7 +236,7 @@
return;
}
foreach (var child in node.Children)
foreach (var child in node.Children!)
{
PopulatePageByNumberDictionary(child, result);
}

View File

@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Core;
using Graphics.Colors;
using Parser.Parts;
@ -33,7 +34,7 @@
private readonly Dictionary<NameToken, PatternColor> patternsProperties = new Dictionary<NameToken, PatternColor>();
private (NameToken name, IFont font) lastLoadedFont;
private (NameToken? name, IFont? font) lastLoadedFont;
public ResourceStore(IPdfTokenScanner scanner,
IFontFactory fontFactory,
@ -81,7 +82,7 @@
}
}
if (resourceDictionary.TryGet(NameToken.ExtGState, scanner, out DictionaryToken extGStateDictionaryToken))
if (resourceDictionary.TryGet(NameToken.ExtGState, scanner, out DictionaryToken? extGStateDictionaryToken))
{
foreach (var pair in extGStateDictionaryToken.Data)
{
@ -92,17 +93,17 @@
}
}
if (resourceDictionary.TryGet(NameToken.ColorSpace, scanner, out DictionaryToken colorSpaceDictionary))
if (resourceDictionary.TryGet(NameToken.ColorSpace, scanner, out DictionaryToken? colorSpaceDictionary))
{
foreach (var nameColorSpacePair in colorSpaceDictionary.Data)
{
var name = NameToken.Create(nameColorSpacePair.Key);
if (DirectObjectFinder.TryGet(nameColorSpacePair.Value, scanner, out NameToken colorSpaceName))
if (DirectObjectFinder.TryGet(nameColorSpacePair.Value, scanner, out NameToken? colorSpaceName))
{
namedColorSpaces[name] = new ResourceColorSpace(colorSpaceName);
}
else if (DirectObjectFinder.TryGet(nameColorSpacePair.Value, scanner, out ArrayToken colorSpaceArray))
else if (DirectObjectFinder.TryGet(nameColorSpacePair.Value, scanner, out ArrayToken? colorSpaceArray))
{
if (colorSpaceArray.Length == 0)
{
@ -125,7 +126,7 @@
}
}
if (resourceDictionary.TryGet(NameToken.Pattern, scanner, out DictionaryToken patternDictionary))
if (resourceDictionary.TryGet(NameToken.Pattern, scanner, out DictionaryToken? patternDictionary))
{
// NB: in PDF, all patterns shall be local to the context in which they are defined.
foreach (var namePatternPair in patternDictionary.Data)
@ -135,13 +136,13 @@
}
}
if (resourceDictionary.TryGet(NameToken.Properties, scanner, out DictionaryToken markedContentPropertiesList))
if (resourceDictionary.TryGet(NameToken.Properties, scanner, out DictionaryToken? markedContentPropertiesList))
{
foreach (var pair in markedContentPropertiesList.Data)
{
var key = NameToken.Create(pair.Key);
if (!DirectObjectFinder.TryGet(pair.Value, scanner, out DictionaryToken namedProperties))
if (!DirectObjectFinder.TryGet(pair.Value, scanner, out DictionaryToken? namedProperties))
{
continue;
}
@ -150,16 +151,16 @@
}
}
if (resourceDictionary.TryGet(NameToken.Shading, scanner, out DictionaryToken shadingList))
if (resourceDictionary.TryGet(NameToken.Shading, scanner, out DictionaryToken? shadingList))
{
foreach (var pair in shadingList.Data)
{
var key = NameToken.Create(pair.Key);
if (DirectObjectFinder.TryGet(pair.Value, scanner, out DictionaryToken namedPropertiesDictionary))
if (DirectObjectFinder.TryGet(pair.Value, scanner, out DictionaryToken? namedPropertiesDictionary))
{
shadingsProperties[key] = ShadingParser.Create(namedPropertiesDictionary, scanner, this, filterProvider);
}
else if (DirectObjectFinder.TryGet(pair.Value, scanner, out StreamToken namedPropertiesStream))
else if (DirectObjectFinder.TryGet(pair.Value, scanner, out StreamToken? namedPropertiesStream))
{
// Shading types 4 to 7 shall be defined by a stream containing descriptive data characterizing
// the shading's gradient fill.
@ -229,14 +230,14 @@
}
}
public IFont GetFont(NameToken name)
public IFont? GetFont(NameToken name)
{
if (lastLoadedFont.name == name)
{
return lastLoadedFont.font;
}
IFont font;
IFont? font;
if (currentResourceState.TryGetValue(name, out var reference))
{
loadedFonts.TryGetValue(reference, out font);
@ -255,7 +256,7 @@
{
lastLoadedFont = (null, null);
if (!DirectObjectFinder.TryGet(fontReferenceToken, scanner, out DictionaryToken fontDictionaryToken))
if (!DirectObjectFinder.TryGet(fontReferenceToken, scanner, out DictionaryToken? fontDictionaryToken))
{
throw new PdfDocumentFormatException($"The requested font reference token {fontReferenceToken} wasn't a font.");
}
@ -265,7 +266,7 @@
return font;
}
public bool TryGetNamedColorSpace(NameToken name, out ResourceColorSpace namedToken)
public bool TryGetNamedColorSpace(NameToken? name, out ResourceColorSpace namedToken)
{
namedToken = default(ResourceColorSpace);
@ -284,13 +285,10 @@
return true;
}
public ColorSpaceDetails GetColorSpaceDetails(NameToken name, DictionaryToken dictionary)
{
if (dictionary is null)
{
dictionary = new DictionaryToken(new Dictionary<NameToken, IToken>());
}
public ColorSpaceDetails GetColorSpaceDetails(NameToken? name, DictionaryToken? dictionary)
{
dictionary ??= new DictionaryToken(new Dictionary<NameToken, IToken>());
// Null color space for images
if (name is null)
{
@ -299,12 +297,12 @@
if (name.TryMapToColorSpace(out ColorSpace colorspaceActual))
{
// TODO - We need to find a way to store profile that have an actual dictionnary, e.g. ICC profiles - without parsing them again
// TODO - We need to find a way to store profile that have an actual dictionary, e.g. ICC profiles - without parsing them again
return ColorSpaceDetailsParser.GetColorSpaceDetails(colorspaceActual, dictionary, scanner, this, filterProvider);
}
// Named color spaces
if (loadedNamedColorSpaceDetails.TryGetValue(name, out ColorSpaceDetails csdLoaded))
if (loadedNamedColorSpaceDetails.TryGetValue(name, out ColorSpaceDetails? csdLoaded))
{
return csdLoaded;
}
@ -327,7 +325,7 @@
throw new InvalidOperationException($"Could not find color space for token '{name}'.");
}
public bool TryGetXObject(NameToken name, out StreamToken stream)
public bool TryGetXObject(NameToken name, [NotNullWhen(true)] out StreamToken? stream)
{
stream = null;
if (!currentResourceState.TryGetValue(name, out var indirectReference))
@ -343,7 +341,7 @@
return extendedGraphicsStates[name];
}
public DictionaryToken GetMarkedContentPropertiesDictionary(NameToken name)
public DictionaryToken? GetMarkedContentPropertiesDictionary(NameToken name)
{
return markedContentProperties.TryGetValue(name, out var result) ? result : null;
}

View File

@ -29,7 +29,7 @@
/// <summary>
/// The name of the font for the word.
/// </summary>
public string FontName { get; }
public string? FontName { get; }
/// <summary>
/// The letters contained in the word.

View File

@ -8,7 +8,6 @@
using Filters;
using Tokenization.Scanner;
using Tokens;
using Util.JetBrains.Annotations;
/// <summary>
/// Wraps an XML based Extensible Metadata Platform (XMP) document. These XML documents are embedded in PDFs to provide metadata
@ -22,7 +21,6 @@
/// <summary>
/// The underlying <see cref="StreamToken"/> for this metadata.
/// </summary>
[NotNull]
public StreamToken MetadataStreamToken { get; }
internal XmpMetadata(StreamToken stream, ILookupFilterProvider filterProvider, IPdfTokenScanner pdfTokenScanner)

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using Core;
using Util.JetBrains.Annotations;
/// <summary>
/// The cross-reference table contains information that enables random access to PDF objects within the file by object number
@ -19,7 +18,6 @@
/// <summary>
/// The corresponding byte offset for each keyed object in this document.
/// </summary>
[NotNull]
public IReadOnlyDictionary<IndirectReference, long> ObjectOffsets => objectOffsets;
/// <summary>
@ -30,14 +28,12 @@
/// <summary>
/// The trailer dictionary.
/// </summary>
[NotNull]
public TrailerDictionary Trailer { get; }
/// <summary>
/// The byte offsets of each cross-reference table or stream in this document and the previous
/// table or stream they link to if applicable.
/// </summary>
[NotNull]
public IReadOnlyList<CrossReferenceOffset> CrossReferenceOffsets { get; }
internal CrossReferenceTable(CrossReferenceType type, IReadOnlyDictionary<IndirectReference, long> objectOffsets,

View File

@ -12,7 +12,7 @@
public long Previous { get; set; }
public DictionaryToken Dictionary { get; set; }
public DictionaryToken? Dictionary { get; set; }
public CrossReferenceType XRefType { get; set; }
@ -30,7 +30,7 @@
public CrossReferenceTablePart Build()
{
return new CrossReferenceTablePart(objects, Offset, Previous, Dictionary, XRefType, TiedToPreviousAtOffset);
return new CrossReferenceTablePart(objects, Offset, Previous, Dictionary!, XRefType, TiedToPreviousAtOffset);
}
}
}

View File

@ -3,10 +3,8 @@
using System;
using System.Collections.Generic;
using Core;
using Exceptions;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
/// <summary>
/// Contains information for interpreting the cross-reference table.
@ -47,8 +45,7 @@
/// <summary>
/// The document's encryption dictionary.
/// </summary>
[CanBeNull]
public IToken EncryptionToken { get; }
public IToken? EncryptionToken { get; }
/// <summary>
/// Create a new <see cref="TrailerDictionary"/>.

View File

@ -1,9 +1,9 @@
namespace UglyToad.PdfPig.Encryption
{
using System;
using System.Diagnostics.CodeAnalysis;
using Exceptions;
using Tokens;
using Util.JetBrains.Annotations;
internal class EncryptionDictionary
{
@ -15,21 +15,19 @@
public int Revision { get; }
public byte[] OwnerBytes { get; }
public byte[]? OwnerBytes { get; }
public byte[] UserBytes { get; }
public byte[]? UserBytes { get; }
/// <summary>
/// Required if <see cref="Revision"/> is 5 or above. A 32-byte string, based on the owner and user passwords that is used in computing the encryption key.
/// </summary>
[CanBeNull]
public byte[] OwnerEncryptionBytes { get; }
public byte[]? OwnerEncryptionBytes { get; }
/// <summary>
/// Required if <see cref="Revision"/> is 5 or above. A 32-byte string, based on the user password that is used in computing the encryption key.
/// </summary>
[CanBeNull]
public byte[] UserEncryptionBytes { get; }
public byte[]? UserEncryptionBytes { get; }
public UserAccessPermissions UserAccessPermissions { get; }
@ -42,10 +40,10 @@
public EncryptionDictionary(string filter, EncryptionAlgorithmCode encryptionAlgorithmCode,
int? keyLength,
int revision,
byte[] ownerBytes,
byte[] userBytes,
byte[] ownerEncryptionBytes,
byte[] userEncryptionBytes,
byte[]? ownerBytes,
byte[]? userBytes,
byte[]? ownerEncryptionBytes,
byte[]? userEncryptionBytes,
UserAccessPermissions userAccessPermissions,
DictionaryToken dictionary,
bool encryptMetadata)
@ -63,7 +61,7 @@
EncryptMetadata = encryptMetadata;
}
public bool TryGetCryptHandler(out CryptHandler cryptHandler)
public bool TryGetCryptHandler([NotNullWhen(true)] out CryptHandler? cryptHandler)
{
cryptHandler = null;

View File

@ -20,25 +20,25 @@
var code = EncryptionAlgorithmCode.Unrecognized;
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NumericToken vNum))
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.V, tokenScanner, out NumericToken? vNum))
{
code = (EncryptionAlgorithmCode) vNum.Int;
}
var length = default(int?);
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.Length, tokenScanner, out NumericToken lengthToken))
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.Length, tokenScanner, out NumericToken? lengthToken))
{
length = lengthToken.Int;
}
var revision = default(int);
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.R, tokenScanner, out NumericToken revisionToken))
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.R, tokenScanner, out NumericToken? revisionToken))
{
revision = revisionToken.Int;
}
byte[] ownerBytes = null;
byte[]? ownerBytes = null;
if (encryptionDictionary.TryGet(NameToken.O, out IToken ownerToken))
{
if (ownerToken is StringToken ownerString)
@ -51,7 +51,7 @@
}
}
byte[] userBytes = null;
byte[]? userBytes = null;
if (encryptionDictionary.TryGet(NameToken.U, out IToken userToken))
{
if (userToken is StringToken userString)
@ -66,22 +66,25 @@
var access = default(UserAccessPermissions);
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.P, tokenScanner, out NumericToken accessToken))
if (encryptionDictionary.TryGetOptionalTokenDirect(NameToken.P, tokenScanner, out NumericToken? accessToken))
{
// This can be bigger than an integer.
access = (UserAccessPermissions) accessToken.Long;
}
byte[] userEncryptionBytes = null, ownerEncryptionBytes = null;
byte[]? userEncryptionBytes = null;
byte[]? ownerEncryptionBytes = null;
if (revision >= 5)
{
ownerEncryptionBytes = GetEncryptionBytesOrDefault(encryptionDictionary, tokenScanner, false);
userEncryptionBytes = GetEncryptionBytesOrDefault(encryptionDictionary, tokenScanner, true);
}
encryptionDictionary.TryGetOptionalTokenDirect(NameToken.EncryptMetaData, tokenScanner, out BooleanToken encryptMetadata);
encryptionDictionary.TryGetOptionalTokenDirect(NameToken.EncryptMetaData, tokenScanner, out BooleanToken? encryptMetadata);
return new EncryptionDictionary(filter.Data, code, length, revision, ownerBytes, userBytes,
return new EncryptionDictionary(filter.Data, code, length, revision,
ownerBytes,
userBytes,
ownerEncryptionBytes,
userEncryptionBytes,
access,
@ -89,15 +92,15 @@
encryptMetadata?.Data ?? true);
}
private static byte[] GetEncryptionBytesOrDefault(DictionaryToken encryptionDictionary, IPdfTokenScanner tokenScanner, bool isUser)
private static byte[]? GetEncryptionBytesOrDefault(DictionaryToken encryptionDictionary, IPdfTokenScanner tokenScanner, bool isUser)
{
var name = isUser ? NameToken.Ue : NameToken.Oe;
if (encryptionDictionary.TryGet(name, tokenScanner, out StringToken stringToken))
if (encryptionDictionary.TryGet(name, tokenScanner, out StringToken? stringToken))
{
return OtherEncodings.StringAsLatin1Bytes(stringToken.Data);
}
if (encryptionDictionary.TryGet(name, tokenScanner, out HexToken hexToken))
if (encryptionDictionary.TryGet(name, tokenScanner, out HexToken? hexToken))
{
return hexToken.Bytes.ToArray();
}

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Encryption
#nullable disable
namespace UglyToad.PdfPig.Encryption
{
using System;
using System.Collections.Generic;
@ -11,7 +13,6 @@
using Exceptions;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
internal sealed class EncryptionHandler : IEncryptionHandler
{
@ -28,22 +29,16 @@
];
private readonly HashSet<IndirectReference> previouslyDecrypted = new HashSet<IndirectReference>();
[CanBeNull]
private readonly EncryptionDictionary encryptionDictionary;
[CanBeNull]
private readonly CryptHandler cryptHandler;
private readonly byte[] encryptionKey;
private readonly bool useAes;
public EncryptionHandler(EncryptionDictionary encryptionDictionary, TrailerDictionary trailerDictionary, IReadOnlyList<string> passwords)
{
this.encryptionDictionary = encryptionDictionary;
passwords ??= new[] { string.Empty };
passwords ??= [string.Empty];
if (!passwords.Contains(string.Empty))
{
@ -268,7 +263,7 @@
{
// 5. (Revision 2 only) Decrypt the value of the encryption dictionary's owner entry,
// using an RC4 encryption function with the encryption key computed in step 1 - 4.
userPassword = RC4.Encrypt(key, encryptionDictionary.OwnerBytes);
userPassword = RC4.Encrypt(key, encryptionDictionary.OwnerBytes!);
}
else
{
@ -282,12 +277,12 @@
if (i == 0)
{
output = encryptionDictionary.OwnerBytes;
output = encryptionDictionary.OwnerBytes!;
}
// Decrypt the value of the encryption dictionary's owner entry (first iteration)
// or the output from the previous iteration using an RC4 encryption function.
output = RC4.Encrypt(keyIter, output);
output = RC4.Encrypt(keyIter, output!);
}
userPassword = output;
@ -648,14 +643,14 @@
if (encryptionDictionary.Revision == 6)
{
intermediateKey = ComputeStupidIsoHash(password, ownerKeySalt, encryptionDictionary.UserBytes);
intermediateKey = ComputeStupidIsoHash(password, ownerKeySalt, encryptionDictionary.UserBytes!);
}
else
{
intermediateKey = ComputeSha256Hash(password, ownerKeySalt, encryptionDictionary.UserBytes);
intermediateKey = ComputeSha256Hash(password, ownerKeySalt, encryptionDictionary.UserBytes!);
}
encryptedFileKey = encryptionDictionary.OwnerEncryptionBytes;
encryptedFileKey = encryptionDictionary.OwnerEncryptionBytes!;
}
else
{

View File

@ -11,7 +11,7 @@
[Serializable]
public class PdfDocumentEncryptedException : Exception
{
internal EncryptionDictionary Dictionary { get; }
internal EncryptionDictionary? Dictionary { get; }
/// <inheritdoc />
public PdfDocumentEncryptedException()

View File

@ -10,7 +10,7 @@
///
/// Ported from https://github.com/apache/pdfbox/blob/e644c29279e276bde14ce7a33bdeef0cb1001b3e/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java
/// </summary>
internal class CcittFaxDecoderStream : StreamWrapper
internal sealed class CcittFaxDecoderStream : StreamWrapper
{
// See TIFF 6.0 Specification, Section 10: "Modified Huffman Compression", page 43.
@ -450,8 +450,8 @@
private class Node
{
public Node Left { get; set; }
public Node Right { get; set; }
public Node? Left { get; set; }
public Node? Right { get; set; }
public int Value { get; set; }
@ -472,7 +472,7 @@
public Node Walk(bool next)
{
return next ? Right : Left;
return next ? Right! : Left!;
}
public override string ToString()

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Filters
#nullable disable
namespace UglyToad.PdfPig.Filters
{
using System;
using System.Collections.Generic;
@ -10,7 +12,7 @@
/// The LZW (Lempel-Ziv-Welch) filter is a variable-length, adaptive compression method
/// that has been adopted as one of the standard compression methods in the Tag Image File Format (TIFF) standard.
/// </summary>
internal class LzwFilter : IFilter
internal sealed class LzwFilter : IFilter
{
private const int DefaultColors = 1;
private const int DefaultBitsPerComponent = 8;
@ -146,7 +148,7 @@
for (var i = 0; i < 256; i++)
{
table[i] = new[] { (byte)i };
table[i] = [(byte)i];
}
table[ClearTable] = null;

View File

@ -12,12 +12,12 @@
/// <summary>
/// The function dictionary.
/// </summary>
public DictionaryToken FunctionDictionary { get; }
public DictionaryToken? FunctionDictionary { get; }
/// <summary>
/// The function stream.
/// </summary>
public StreamToken FunctionStream { get; }
public StreamToken? FunctionStream { get; }
private int numberOfInputValues = -1;
private int numberOfOutputValues = -1;
@ -25,7 +25,7 @@
/// <summary>
/// This class represents a function in a PDF document.
/// </summary>
public PdfFunction(DictionaryToken function, ArrayToken domain, ArrayToken range)
public PdfFunction(DictionaryToken function, ArrayToken domain, ArrayToken? range)
{
FunctionDictionary = function;
DomainValues = domain;
@ -35,7 +35,7 @@
/// <summary>
/// This class represents a function in a PDF document.
/// </summary>
public PdfFunction(StreamToken function, ArrayToken domain, ArrayToken range)
public PdfFunction(StreamToken function, ArrayToken domain, ArrayToken? range)
{
FunctionStream = function;
DomainValues = domain;
@ -58,7 +58,7 @@
/// Returns the function's dictionary. If <see cref="FunctionDictionary"/> is defined, it will be returned.
/// If not, the <see cref="FunctionStream"/>'s StreamDictionary will be returned.
/// </summary>
public DictionaryToken GetDictionary()
public DictionaryToken? GetDictionary()
{
if (FunctionStream != null)
{
@ -106,7 +106,7 @@
/// <returns>The range for this component.</returns>
public PdfRange GetRangeForOutput(int n)
{
return new PdfRange(RangeValues.Data.OfType<NumericToken>().Select(t => t.Double), n);
return new PdfRange(RangeValues!.Data.OfType<NumericToken>().Select(t => t.Double), n);
}
/// <summary>
@ -154,7 +154,7 @@
/// Returns all ranges for the output values as <see cref="ArrayToken"/>. Required for type 0 and type 4 functions.
/// </summary>
/// <returns>the ranges array.</returns>
protected ArrayToken RangeValues { get; }
protected ArrayToken? RangeValues { get; }
/// <summary>
/// Returns all domains for the input values as <see cref="ArrayToken"/>. Required for all function types.
@ -169,7 +169,7 @@
/// <returns>the clipped values</returns>
protected double[] ClipToRange(double[] inputValues)
{
ArrayToken rangesArray = RangeValues;
ArrayToken rangesArray = RangeValues!;
double[] result;
if (rangesArray != null && rangesArray.Length > 0)
{

View File

@ -12,7 +12,7 @@
/// <summary>
/// The samples of the function.
/// </summary>
private int[][] samples;
private int[][]? samples;
/// <summary>
/// Stitching function
@ -262,7 +262,7 @@
ArrayToken sizes = Size;
for (int i = 0; i < nIn; i++)
{
arraySize *= (sizes[i] as NumericToken).Int;
arraySize *= ((NumericToken)sizes[i]).Int;
}
samples = new int[arraySize][];
int bitsPerSample = BitsPerSample;
@ -270,7 +270,7 @@
// PDF spec 1.7 p.171:
// Each sample value is represented as a sequence of BitsPerSample bits.
// Successive values are adjacent in the bit stream; there is no padding at byte boundaries.
var bits = new BitArray(FunctionStream.Data.ToArray());
var bits = new BitArray(FunctionStream!.Data.ToArray());
for (int i = 0; i < arraySize; i++)
{
@ -311,10 +311,9 @@
for (int i = 0; i < numberOfInputValues; i++)
{
PdfRange domain = GetDomainForInput(i);
PdfRange? encodeValues = GetEncodeForParameter(i);
PdfRange encodeValues = GetEncodeForParameter(i)!.Value;
input[i] = ClipToRange(input[i], domain.Min, domain.Max);
input[i] = Interpolate(input[i], domain.Min, domain.Max,
encodeValues.Value.Min, encodeValues.Value.Max);
input[i] = Interpolate(input[i], domain.Min, domain.Max, encodeValues.Min, encodeValues.Max);
input[i] = ClipToRange(input[i], 0, sizeValues[i] - 1);
inputPrev[i] = (int)Math.Floor(input[i]);
inputNext[i] = (int)Math.Ceiling(input[i]);

View File

@ -11,7 +11,7 @@
/// <summary>
/// Exponential interpolation function
/// </summary>
internal PdfFunctionType2(DictionaryToken function, ArrayToken domain, ArrayToken range, ArrayToken c0, ArrayToken c1, double n)
internal PdfFunctionType2(DictionaryToken function, ArrayToken domain, ArrayToken? range, ArrayToken c0, ArrayToken c1, double n)
: base(function, domain, range)
{
C0 = c0;
@ -19,7 +19,7 @@
N = n;
}
internal PdfFunctionType2(StreamToken function, ArrayToken domain, ArrayToken range, ArrayToken c0, ArrayToken c1, double n)
internal PdfFunctionType2(StreamToken function, ArrayToken domain, ArrayToken? range, ArrayToken c0, ArrayToken c1, double n)
: base(function, domain, range)
{
C0 = c0;

View File

@ -17,7 +17,7 @@
/// <summary>
/// Stitching function
/// </summary>
internal PdfFunctionType3(DictionaryToken function, ArrayToken domain, ArrayToken range, IReadOnlyList<PdfFunction> functionsArray, ArrayToken bounds, ArrayToken encode)
internal PdfFunctionType3(DictionaryToken function, ArrayToken domain, ArrayToken? range, IReadOnlyList<PdfFunction> functionsArray, ArrayToken bounds, ArrayToken encode)
: base(function, domain, range)
{
if (functionsArray is null || functionsArray.Count == 0)
@ -59,7 +59,7 @@
// This function is known as a "stitching" function. Based on the input, it decides which child function to call.
// All functions in the array are 1-value-input functions
// See PDF Reference section 3.9.3.
PdfFunction function = null;
PdfFunction? function = null;
double x = input[0];
PdfRange domain = GetDomainForInput(0);
// clip input value to domain

View File

@ -20,7 +20,7 @@
internal PdfFunctionType4(StreamToken function, ArrayToken domain, ArrayToken range)
: base(function, domain, range)
{
byte[] bytes = FunctionStream.Data.ToArray();
byte[] bytes = FunctionStream!.Data.ToArray();
string str = OtherEncodings.Iso88591.GetString(bytes);
this.instructions = InstructionSequenceBuilder.Parse(str);
}

View File

@ -70,6 +70,8 @@
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System;

View File

@ -73,6 +73,7 @@
//use_lines: Enables open path clipping. Adds a very minor cost to performance.
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{

View File

@ -123,7 +123,7 @@ namespace UglyToad.PdfPig.Geometry.ClipperLibrary
return !(val1 == val2);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (!(obj is ClipperInt128 i128))
{

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System.Collections.Generic;

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperJoin

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperLocalMinima

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperMaxima

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperOutPt

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
/// <summary>

View File

@ -117,7 +117,7 @@ namespace UglyToad.PdfPig.Geometry.ClipperLibrary
public static bool operator !=(ClipperIntPoint a, ClipperIntPoint b) => a.X != b.X || a.Y != b.Y;
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj == null)
{

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System.Collections.Generic;

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperScanbeam

View File

@ -69,6 +69,9 @@
* Code modified for PdfPig *
* *
*******************************************************************************/
#nullable disable
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperTEdge

View File

@ -24,7 +24,7 @@
/// <summary>
/// Generates the result of applying a clipping path to another path.
/// </summary>
public static PdfPath Clip(this PdfPath clipping, PdfPath subject, ILog? log = null)
public static PdfPath? Clip(this PdfPath clipping, PdfPath subject, ILog? log = null)
{
if (clipping is null)
{

View File

@ -741,12 +741,12 @@
/// The intersection of the line formed by <paramref name="pl1"/> and <paramref name="pl2"/>
/// intersects the rectangle.
/// </summary>
private static PdfPoint[] Intersect(PdfRectangle rectangle, PdfPoint pl1, PdfPoint pl2)
private static PdfPoint[]? Intersect(PdfRectangle rectangle, PdfPoint pl1, PdfPoint pl2)
{
var clipper = new Clipper();
clipper.AddPath(rectangle.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true);
clipper.AddPath(new List<ClipperIntPoint>() { pl1.ToClipperIntPoint(), pl2.ToClipperIntPoint() }, ClipperPolyType.Subject, false);
clipper.AddPath([pl1.ToClipperIntPoint(), pl2.ToClipperIntPoint()], ClipperPolyType.Subject, false);
var solutions = new ClipperPolyTree();
if (clipper.Execute(ClipperClipType.Intersection, solutions))
@ -759,11 +759,11 @@
{
var solution = solutions.Children[0];
return new[]
{
return
[
new PdfPoint(solution.Contour[0].X / ClippingExtensions.Factor, solution.Contour[0].Y / ClippingExtensions.Factor),
new PdfPoint(solution.Contour[1].X / ClippingExtensions.Factor, solution.Contour[1].Y / ClippingExtensions.Factor)
};
];
}
else
{
@ -906,7 +906,7 @@
/// Get the t values that are the intersections of the line and the curve.
/// </summary>
/// <returns>List of t values where the <see cref="BezierCurve"/> and the <see cref="PdfLine"/> intersect.</returns>
public static double[] IntersectT(this BezierCurve bezierCurve, PdfLine line)
public static double[]? IntersectT(this BezierCurve bezierCurve, PdfLine line)
{
return IntersectT(bezierCurve, line.Point1, line.Point2);
}
@ -915,12 +915,12 @@
/// Get the t values that are the intersections of the line and the curve.
/// </summary>
/// <returns>List of t values where the <see cref="BezierCurve"/> and the <see cref="Line"/> intersect.</returns>
public static double[] IntersectT(this BezierCurve bezierCurve, Line line)
public static double[]? IntersectT(this BezierCurve bezierCurve, Line line)
{
return IntersectT(bezierCurve, line.From, line.To);
}
private static double[] IntersectT(BezierCurve bezierCurve, PdfPoint p1, PdfPoint p2)
private static double[]? IntersectT(BezierCurve bezierCurve, PdfPoint p1, PdfPoint p2)
{
// if the bounding boxes do not intersect, they cannot intersect
var bezierBbox = bezierCurve.GetBoundingRectangle();

View File

@ -1,5 +1,10 @@
namespace UglyToad.PdfPig.Graphics
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Colors;
using Content;
using Core;
@ -10,10 +15,6 @@
using Parser;
using PdfFonts;
using PdfPig.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Tokenization.Scanner;
using Tokens;
using XObjects;
@ -67,12 +68,12 @@
/// <summary>
/// The active ExtendedGraphicsState font.
/// </summary>
protected IFont ActiveExtendedGraphicsStateFont;
protected IFont? ActiveExtendedGraphicsStateFont;
/// <summary>
/// Inline image builder.
/// </summary>
protected InlineImageBuilder InlineImageBuilder;
protected InlineImageBuilder? InlineImageBuilder;
/// <summary>
/// The page number.
@ -281,8 +282,8 @@
var boundingBox = font.GetBoundingBox(code);
RenderGlyph(font,
currentState.CurrentStrokingColor,
currentState.CurrentNonStrokingColor,
currentState.CurrentStrokingColor!,
currentState.CurrentNonStrokingColor!,
currentState.FontState.TextRenderingMode,
fontSize,
pointSize,
@ -336,7 +337,7 @@
var currentState = GetCurrentState();
var textState = currentState.FontState;
var textState = currentState.FontState!;
var fontSize = textState.FontSize;
var horizontalScaling = textState.HorizontalScaling / 100.0;
@ -346,7 +347,7 @@
{
if (ParsingOptions.SkipMissingFonts)
{
ParsingOptions.Logger.Warn($"Skipping a missing font with name {currentState.FontState.FontName} " +
ParsingOptions.Logger.Warn($"Skipping a missing font with name {currentState.FontState!.FontName} " +
$"since it is not present in the document and {nameof(PdfPig.ParsingOptions.SkipMissingFonts)} " +
"is set to true. This may result in some text being skipped and not included in the output.");
@ -469,11 +470,9 @@
* 5. Restore the saved graphics state, as if by invoking the Q operator.
*/
var hasResources =
formStream.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources,
if (formStream.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources,
PdfScanner,
out var formResources);
if (hasResources)
out var formResources))
{
ResourceStore.LoadResourceDictionary(formResources);
}
@ -484,7 +483,7 @@
var startState = GetCurrentState();
// Transparency Group XObjects
if (formStream.StreamDictionary.TryGet(NameToken.Group, PdfScanner, out DictionaryToken formGroupToken))
if (formStream.StreamDictionary.TryGet(NameToken.Group, PdfScanner, out DictionaryToken? formGroupToken))
{
if (!formGroupToken.TryGet<NameToken>(NameToken.S, PdfScanner, out var sToken) ||
sToken != NameToken.Transparency)
@ -512,16 +511,16 @@
startState.AlphaConstantNonStroking = 1.0;
startState.AlphaConstantStroking = 1.0;
if (formGroupToken.TryGet(NameToken.Cs, PdfScanner, out NameToken csNameToken))
if (formGroupToken.TryGet(NameToken.Cs, PdfScanner, out NameToken? csNameToken))
{
startState.ColorSpaceContext.SetNonStrokingColorspace(csNameToken);
startState.ColorSpaceContext!.SetNonStrokingColorspace(csNameToken);
}
else if (formGroupToken.TryGet(NameToken.Cs, PdfScanner, out ArrayToken csArrayToken)
else if (formGroupToken.TryGet(NameToken.Cs, PdfScanner, out ArrayToken? csArrayToken)
&& csArrayToken.Length > 0)
{
if (csArrayToken.Data[0] is NameToken firstColorSpaceName)
{
startState.ColorSpaceContext.SetNonStrokingColorspace(firstColorSpaceName, formGroupToken);
startState.ColorSpaceContext!.SetNonStrokingColorspace(firstColorSpaceName, formGroupToken);
}
else
{
@ -530,7 +529,7 @@
}
bool isolated = false;
if (formGroupToken.TryGet(NameToken.I, PdfScanner, out BooleanToken isolatedToken))
if (formGroupToken.TryGet(NameToken.I, PdfScanner, out BooleanToken? isolatedToken))
{
/*
* (Optional) A flag specifying whether the transparency group is isolated (see Isolated Groups).
@ -542,7 +541,7 @@
}
bool knockout = false;
if (formGroupToken.TryGet(NameToken.K, PdfScanner, out BooleanToken knockoutToken))
if (formGroupToken.TryGet(NameToken.K, PdfScanner, out BooleanToken? knockoutToken))
{
/*
* (Optional) A flag specifying whether the transparency group is a knockout group (see Knockout Groups).
@ -597,7 +596,7 @@
// 5. Restore saved state.
PopState();
if (hasResources)
if (formResources != null) // has resources
{
ResourceStore.UnloadResourceDictionary();
}
@ -667,22 +666,22 @@
var state = ResourceStore.GetExtendedGraphicsStateDictionary(stateName);
if (state.TryGet(NameToken.Lw, PdfScanner, out NumericToken lwToken))
if (state.TryGet(NameToken.Lw, PdfScanner, out NumericToken? lwToken))
{
currentGraphicsState.LineWidth = lwToken.Data;
}
if (state.TryGet(NameToken.Lc, PdfScanner, out NumericToken lcToken))
if (state.TryGet(NameToken.Lc, PdfScanner, out NumericToken? lcToken))
{
currentGraphicsState.CapStyle = (LineCapStyle)lcToken.Int;
}
if (state.TryGet(NameToken.Lj, PdfScanner, out NumericToken ljToken))
if (state.TryGet(NameToken.Lj, PdfScanner, out NumericToken? ljToken))
{
currentGraphicsState.JoinStyle = (LineJoinStyle)ljToken.Int;
}
if (state.TryGet(NameToken.Font, PdfScanner, out ArrayToken fontArray) && fontArray.Length == 2
if (state.TryGet(NameToken.Font, PdfScanner, out ArrayToken? fontArray) && fontArray.Length == 2
&& fontArray.Data[0] is IndirectReferenceToken fontReference &&
fontArray.Data[1] is NumericToken sizeToken)
{
@ -691,7 +690,7 @@
ActiveExtendedGraphicsStateFont = ResourceStore.GetFontDirectly(fontReference);
}
if (state.TryGet(NameToken.Ais, PdfScanner, out BooleanToken aisToken))
if (state.TryGet(NameToken.Ais, PdfScanner, out BooleanToken? aisToken))
{
// The alpha source flag (“alpha is shape”), specifying
// whether the current soft mask and alpha constant are to be interpreted as
@ -699,7 +698,7 @@
currentGraphicsState.AlphaSource = aisToken.Data;
}
if (state.TryGet(NameToken.Ca, PdfScanner, out NumericToken caToken))
if (state.TryGet(NameToken.Ca, PdfScanner, out NumericToken? caToken))
{
// (Optional; PDF 1.4) The current stroking alpha constant, specifying the constant
// shape or constant opacity value to be used for stroking operations in the
@ -708,7 +707,7 @@
currentGraphicsState.AlphaConstantStroking = caToken.Data;
}
if (state.TryGet(NameToken.CaNs, PdfScanner, out NumericToken cansToken))
if (state.TryGet(NameToken.CaNs, PdfScanner, out NumericToken? cansToken))
{
// (Optional; PDF 1.4) The current stroking alpha constant, specifying the constant
// shape or constant opacity value to be used for NON-stroking operations in the
@ -717,7 +716,7 @@
currentGraphicsState.AlphaConstantNonStroking = cansToken.Data;
}
if (state.TryGet(NameToken.Op, PdfScanner, out BooleanToken OPToken))
if (state.TryGet(NameToken.Op, PdfScanner, out BooleanToken? OPToken))
{
// (Optional) A flag specifying whether to apply overprint (see Section 4.5.6,
// “Overprint Control”). In PDF 1.2 and earlier, there is a single overprint
@ -729,7 +728,7 @@
currentGraphicsState.Overprint = OPToken.Data;
}
if (state.TryGet(NameToken.OpNs, PdfScanner, out BooleanToken opToken))
if (state.TryGet(NameToken.OpNs, PdfScanner, out BooleanToken? opToken))
{
// (Optional; PDF 1.3) A flag specifying whether to apply overprint (see Section
// 4.5.6, “Overprint Control”) for painting operations other than stroking. If
@ -737,13 +736,13 @@
currentGraphicsState.NonStrokingOverprint = opToken.Data;
}
if (state.TryGet(NameToken.Opm, PdfScanner, out NumericToken opmToken))
if (state.TryGet(NameToken.Opm, PdfScanner, out NumericToken? opmToken))
{
// (Optional; PDF 1.3) The overprint mode (see Section 4.5.6, “Overprint Control”).
currentGraphicsState.OverprintMode = opmToken.Data;
}
if (state.TryGet(NameToken.Sa, PdfScanner, out BooleanToken saToken))
if (state.TryGet(NameToken.Sa, PdfScanner, out BooleanToken? saToken))
{
// (Optional) A flag specifying whether to apply automatic stroke adjustment
// (see Section 6.5.4, “Automatic Stroke Adjustment”).
@ -805,9 +804,10 @@
protected abstract void RenderInlineImage(InlineImage inlineImage);
/// <inheritdoc/>
public abstract void BeginMarkedContent(NameToken name,
NameToken propertyDictionaryName,
DictionaryToken properties);
public abstract void BeginMarkedContent(
NameToken name,
NameToken? propertyDictionaryName,
DictionaryToken? properties);
/// <inheritdoc/>
public abstract void EndMarkedContent();

View File

@ -22,7 +22,7 @@
this.resourceStore = resourceStore ?? throw new ArgumentNullException(nameof(resourceStore));
}
public void SetStrokingColorspace(NameToken colorspace, DictionaryToken dictionary = null)
public void SetStrokingColorspace(NameToken colorspace, DictionaryToken? dictionary = null)
{
CurrentStrokingColorSpace = resourceStore.GetColorSpaceDetails(colorspace, dictionary);
if (CurrentStrokingColorSpace is UnsupportedColorSpaceDetails)
@ -33,7 +33,7 @@
currentStateFunc().CurrentStrokingColor = CurrentStrokingColorSpace.GetInitializeColor();
}
public void SetStrokingColor(IReadOnlyList<double> operands, NameToken patternName)
public void SetStrokingColor(IReadOnlyList<double> operands, NameToken? patternName)
{
if (CurrentStrokingColorSpace is UnsupportedColorSpaceDetails)
{
@ -69,7 +69,7 @@
currentStateFunc().CurrentStrokingColor = CurrentStrokingColorSpace.GetColor(c, m, y, k);
}
public void SetNonStrokingColorspace(NameToken colorspace, DictionaryToken dictionary = null)
public void SetNonStrokingColorspace(NameToken colorspace, DictionaryToken? dictionary = null)
{
CurrentNonStrokingColorSpace = resourceStore.GetColorSpaceDetails(colorspace, dictionary);
if (CurrentNonStrokingColorSpace is UnsupportedColorSpaceDetails)
@ -80,7 +80,7 @@
currentStateFunc().CurrentNonStrokingColor = CurrentNonStrokingColorSpace.GetInitializeColor();
}
public void SetNonStrokingColor(IReadOnlyList<double> operands, NameToken patternName)
public void SetNonStrokingColor(IReadOnlyList<double> operands, NameToken? patternName)
{
if (CurrentNonStrokingColorSpace is UnsupportedColorSpaceDetails)
{

View File

@ -56,7 +56,7 @@
var mXYZ = new Matrix3x3(
Xr, Xg, Xb,
Yr, Yg, Yb,
Zr, Zg, Zb).Inverse();
Zr, Zg, Zb).Inverse()!;
var S = mXYZ.Multiply(destinationWorkingSpace.ReferenceWhite);
@ -69,7 +69,7 @@
Sr * Yr, Sg * Yg, Sb * Yb,
Sr * Zr, Sg * Zg, Sb * Zb);
transformationMatrix = M.Inverse();
transformationMatrix = M.Inverse()!;
}
/// <summary>

View File

@ -61,16 +61,20 @@ namespace UglyToad.PdfPig.Graphics.Colors
}
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return Equals(obj as CMYKColor);
return obj is CMYKColor other && Equals(other);
}
/// <inheritdoc />
public bool Equals(CMYKColor other)
public bool Equals(CMYKColor? other)
{
return other != null &&
C == other.C &&
if (other is null)
{
return this is null;
}
return C == other.C &&
M == other.M &&
Y == other.Y &&
K == other.K;
@ -79,12 +83,7 @@ namespace UglyToad.PdfPig.Graphics.Colors
/// <inheritdoc />
public override int GetHashCode()
{
var hashCode = -492570696;
hashCode = hashCode * -1521134295 + C.GetHashCode();
hashCode = hashCode * -1521134295 + M.GetHashCode();
hashCode = hashCode * -1521134295 + Y.GetHashCode();
hashCode = hashCode * -1521134295 + K.GetHashCode();
return hashCode;
return HashCode.Combine(C, M, Y, K);
}
/// <summary>

View File

@ -17,8 +17,8 @@
(double Xwd, double Ywd, double Zwd) destinationReferenceWhite,
Method method = Method.Bradford)
{
var coneReponseDomain = GetConeResponseDomain(method);
var inverseConeResponseDomain = coneReponseDomain.Inverse();
var coneReponseDomain = GetConeResponseDomain(method)!;
var inverseConeResponseDomain = coneReponseDomain.Inverse()!;
var (ρS, γS, βS) = coneReponseDomain.Multiply(sourceReferenceWhite);
var (ρD, γD, βD) = coneReponseDomain.Multiply(destinationReferenceWhite);

View File

@ -8,7 +8,6 @@
using UglyToad.PdfPig.Content;
using UglyToad.PdfPig.Functions;
using UglyToad.PdfPig.Util;
using UglyToad.PdfPig.Util.JetBrains.Annotations;
/// <summary>
/// Contains more document-specific information about the <see cref="ColorSpace"/>.
@ -58,7 +57,7 @@
/// <summary>
/// Get the color that initialize the current stroking or nonstroking colour.
/// </summary>
public abstract IColor GetInitializeColor();
public abstract IColor? GetInitializeColor();
/// <summary>
/// Transform image bytes.
@ -106,7 +105,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
double gray = values[0];
@ -168,7 +167,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
double r = values[0];
@ -230,7 +229,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
double c = values[0];
@ -332,7 +331,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
return cache.GetOrAdd(values[0], v =>
@ -345,7 +344,7 @@
internal byte[] UnwrapIndexedColorSpaceBytes(IReadOnlyList<byte> input)
{
var multiplier = 1;
Func<byte, IEnumerable<byte>> transformer = null;
Func<byte, IEnumerable<byte>>? transformer = null;
switch (BaseType)
{
case ColorSpace.DeviceRGB:
@ -520,7 +519,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
// TODO - use attributes
@ -546,7 +545,7 @@
comps[n] = b / 255.0;
}
if (!cache.TryGetValue(key, out double[] colors))
if (!cache.TryGetValue(key, out double[]? colors))
{
colors = Process(comps);
cache[key] = colors;
@ -582,17 +581,17 @@
/// <summary>
/// Colorants - dictionary - Required if Subtype is NChannel and the colour space includes spot colorants; otherwise optional.
/// </summary>
public DictionaryToken Colorants { get; }
public DictionaryToken? Colorants { get; }
/// <summary>
/// Process - dictionary - Required if Subtype is NChannel and the colour space includes components of a process colour space, otherwise optional.
/// </summary>
public DictionaryToken Process { get; }
public DictionaryToken? Process { get; }
/// <summary>
/// MixingHints - dictionary - Optional
/// </summary>
public DictionaryToken MixingHints { get; }
public DictionaryToken? MixingHints { get; }
/// <summary>
/// Create a new <see cref="DeviceNColorSpaceAttributes"/>.
@ -608,7 +607,7 @@
/// <summary>
/// Create a new <see cref="DeviceNColorSpaceAttributes"/>.
/// </summary>
public DeviceNColorSpaceAttributes(NameToken subtype, DictionaryToken colorants, DictionaryToken process, DictionaryToken mixingHints)
public DeviceNColorSpaceAttributes(NameToken subtype, DictionaryToken? colorants, DictionaryToken? process, DictionaryToken? mixingHints)
{
Subtype = subtype;
Colorants = colorants;
@ -690,7 +689,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
// TODO - we ignore the name for now
@ -710,7 +709,7 @@
for (var i = 0; i < values.Count; i += 3)
{
byte b = values[i++];
if (!cache.TryGetValue(b, out double[] colors))
if (!cache.TryGetValue(b, out double[]? colors))
{
colors = Process(b / 255.0);
cache[b] = colors;
@ -770,7 +769,7 @@
/// <summary>
/// Create a new <see cref="CalGrayColorSpaceDetails"/>.
/// </summary>
public CalGrayColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, double? gamma)
public CalGrayColorSpaceDetails(IReadOnlyList<double> whitePoint, IReadOnlyList<double>? blackPoint, double? gamma)
: base(ColorSpace.CalGray)
{
WhitePoint = whitePoint ?? throw new ArgumentNullException(nameof(whitePoint));
@ -782,7 +781,7 @@
BlackPoint = blackPoint ?? new[] { 0.0, 0, 0 }.ToArray();
if (BlackPoint.Count != 3)
{
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint.Count}.");
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint?.Count ?? 0}.");
}
Gamma = gamma ?? 1.0;
@ -840,7 +839,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
return TransformToRGB(values[0]);
@ -901,7 +900,7 @@
/// <summary>
/// Create a new <see cref="CalRGBColorSpaceDetails"/>.
/// </summary>
public CalRGBColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, [CanBeNull] IReadOnlyList<double> gamma, [CanBeNull] IReadOnlyList<double> matrix)
public CalRGBColorSpaceDetails(IReadOnlyList<double> whitePoint, IReadOnlyList<double>? blackPoint, IReadOnlyList<double>? gamma, IReadOnlyList<double>? matrix)
: base(ColorSpace.CalRGB)
{
WhitePoint = whitePoint ?? throw new ArgumentNullException(nameof(whitePoint));
@ -910,22 +909,22 @@
throw new ArgumentOutOfRangeException(nameof(whitePoint), whitePoint, $"Must consist of exactly three numbers, but was passed {whitePoint.Count}.");
}
BlackPoint = blackPoint ?? new[] { 0.0, 0, 0 }.ToArray();
BlackPoint = blackPoint ?? new[] { 0.0, 0, 0 };
if (BlackPoint.Count != 3)
{
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint.Count}.");
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint!.Count}.");
}
Gamma = gamma ?? new[] { 1.0, 1, 1 }.ToArray();
Gamma = gamma ?? new[] { 1.0, 1, 1 };
if (Gamma.Count != 3)
{
throw new ArgumentOutOfRangeException(nameof(gamma), gamma, $"Must consist of exactly three numbers, but was passed {gamma.Count}.");
throw new ArgumentOutOfRangeException(nameof(gamma), gamma, $"Must consist of exactly three numbers, but was passed {gamma!.Count}.");
}
Matrix = matrix ?? new[] { 1.0, 0, 0, 0, 1, 0, 0, 0, 1 }.ToArray();
Matrix = matrix ?? new[] { 1.0, 0, 0, 0, 1, 0, 0, 0, 1 };
if (Matrix.Count != 9)
{
throw new ArgumentOutOfRangeException(nameof(matrix), matrix, $"Must consist of exactly nine numbers, but was passed {matrix.Count}.");
throw new ArgumentOutOfRangeException(nameof(matrix), matrix, $"Must consist of exactly nine numbers, but was passed {matrix!.Count}.");
}
colorSpaceTransformer =
@ -981,7 +980,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
return TransformToRGB((values[0], values[1], values[2]));
@ -1037,7 +1036,7 @@
/// <summary>
/// Create a new <see cref="LabColorSpaceDetails"/>.
/// </summary>
public LabColorSpaceDetails([NotNull] IReadOnlyList<double> whitePoint, [CanBeNull] IReadOnlyList<double> blackPoint, [CanBeNull] IReadOnlyList<double> matrix)
public LabColorSpaceDetails(IReadOnlyList<double> whitePoint, IReadOnlyList<double>? blackPoint, IReadOnlyList<double>? matrix)
: base(ColorSpace.Lab)
{
WhitePoint = whitePoint?.Select(v => v).ToArray() ?? throw new ArgumentNullException(nameof(whitePoint));
@ -1049,13 +1048,13 @@
BlackPoint = blackPoint?.Select(v => v).ToArray() ?? new[] { 0.0, 0.0, 0.0 };
if (BlackPoint.Count != 3)
{
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint.Count}.");
throw new ArgumentOutOfRangeException(nameof(blackPoint), blackPoint, $"Must consist of exactly three numbers, but was passed {blackPoint!.Count}.");
}
Matrix = matrix?.Select(v => v).ToArray() ?? new[] { -100.0, 100.0, -100.0, 100.0 };
if (Matrix.Count != 4)
{
throw new ArgumentOutOfRangeException(nameof(matrix), matrix, $"Must consist of exactly four numbers, but was passed {matrix.Count}.");
throw new ArgumentOutOfRangeException(nameof(matrix), matrix, $"Must consist of exactly four numbers, but was passed {matrix!.Count}.");
}
colorSpaceTransformer = new CIEBasedColorSpaceTransformer((WhitePoint[0], WhitePoint[1], WhitePoint[2]), RGBWorkingSpace.sRGB);
@ -1122,7 +1121,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
return TransformToRGB((values[0], values[1], values[2]));
@ -1176,7 +1175,6 @@
/// must be substituted.
/// </para>
/// </summary>
[NotNull]
public ColorSpaceDetails AlternateColorSpace { get; }
/// <summary>
@ -1184,20 +1182,20 @@
/// specifies the minimum and maximum valid values of the corresponding color components. These
/// values must match the information in the ICC profile. Default value: [0.0 1.0 0.0 1.0 ...].
/// </summary>
[NotNull]
public IReadOnlyList<double> Range { get; }
/// <summary>
/// An optional metadata stream that contains metadata for the color space.
/// </summary>
[CanBeNull]
public XmpMetadata Metadata { get; }
public XmpMetadata? Metadata { get; }
/// <summary>
/// Create a new <see cref="ICCBasedColorSpaceDetails"/>.
/// </summary>
internal ICCBasedColorSpaceDetails(int numberOfColorComponents, [CanBeNull] ColorSpaceDetails alternateColorSpaceDetails,
[CanBeNull] IReadOnlyList<double> range, [CanBeNull] XmpMetadata metadata)
internal ICCBasedColorSpaceDetails(int numberOfColorComponents,
ColorSpaceDetails? alternateColorSpaceDetails,
IReadOnlyList<double>? range,
XmpMetadata? metadata)
: base(ColorSpace.ICCBased)
{
if (numberOfColorComponents != 1 && numberOfColorComponents != 3 && numberOfColorComponents != 4)
@ -1207,8 +1205,8 @@
NumberOfColorComponents = numberOfColorComponents;
AlternateColorSpace = alternateColorSpaceDetails ??
(NumberOfColorComponents == 1 ? (ColorSpaceDetails)DeviceGrayColorSpaceDetails.Instance :
NumberOfColorComponents == 3 ? (ColorSpaceDetails)DeviceRgbColorSpaceDetails.Instance : (ColorSpaceDetails)DeviceCmykColorSpaceDetails.Instance);
(NumberOfColorComponents == 1 ? DeviceGrayColorSpaceDetails.Instance :
NumberOfColorComponents == 3 ? DeviceRgbColorSpaceDetails.Instance : DeviceCmykColorSpaceDetails.Instance);
BaseType = AlternateColorSpace.BaseType;
Range = range ??
@ -1216,7 +1214,7 @@
if (Range.Count != 2 * numberOfColorComponents)
{
throw new ArgumentOutOfRangeException(nameof(range), range,
$"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range.Count}");
$"Must consist of exactly {2 * numberOfColorComponents} (2 x NumberOfColorComponents), but was passed {range?.Count ?? 0}");
}
Metadata = metadata;
}
@ -1234,7 +1232,7 @@
{
if (values is null || values.Length != NumberOfColorComponents)
{
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values.Length}", nameof(values));
throw new ArgumentException($"Invalid number of inputs, expecting {NumberOfColorComponents} but got {values?.Length ?? 0}", nameof(values));
}
// TODO - use ICC profile
@ -1293,13 +1291,12 @@
/// Valid for Uncoloured Tiling Patterns. Wwill throw a <see cref="InvalidOperationException"/> otherwise.
/// </para>
/// </summary>
internal override int BaseNumberOfColorComponents => UnderlyingColourSpace.NumberOfColorComponents;
internal override int BaseNumberOfColorComponents => UnderlyingColourSpace!.NumberOfColorComponents;
/// <summary>
/// The underlying color space for Uncoloured Tiling Patterns.
/// </summary>
[CanBeNull]
public ColorSpaceDetails UnderlyingColourSpace { get; }
public ColorSpaceDetails? UnderlyingColourSpace { get; }
/// <summary>
/// Create a new <see cref="PatternColorSpaceDetails"/>.
@ -1349,7 +1346,7 @@
/// <inheritdoc/>
/// </summary>
/// <returns>Always returns <c>null</c>.</returns>
public override IColor GetInitializeColor()
public override IColor? GetInitializeColor()
{
return null;
}
@ -1409,7 +1406,7 @@
}
/// <inheritdoc/>
public override IColor GetInitializeColor()
public override IColor? GetInitializeColor()
{
throw new InvalidOperationException("UnsupportedColorSpaceDetails");
}

View File

@ -41,16 +41,20 @@ namespace UglyToad.PdfPig.Graphics.Colors
}
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return Equals(obj as GrayColor);
return obj is GrayColor other && Equals(other);
}
/// <inheritdoc />
public bool Equals(GrayColor other)
public bool Equals(GrayColor? other)
{
return other != null &&
Gray == other.Gray;
if (other is null)
{
return this is null;
}
return Gray == other.Gray;
}
/// <inheritdoc />

View File

@ -143,19 +143,19 @@
}
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is TilingPatternColor color)
{
return Equals(color);
}
return false;
return obj is TilingPatternColor other && Equals(other);
}
/// <inheritdoc/>
public bool Equals(TilingPatternColor other)
public bool Equals(TilingPatternColor? other)
{
if (other is null)
{
return this is null;
}
return PatternType.Equals(other.PatternType) &&
Matrix.Equals(other.Matrix) &&
ExtGState.Equals(other.ExtGState) &&
@ -210,19 +210,19 @@
}
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is ShadingPatternColor color)
{
return Equals(color);
}
return false;
return obj is ShadingPatternColor other && Equals(other);
}
/// <inheritdoc/>
public bool Equals(ShadingPatternColor other)
public bool Equals(ShadingPatternColor? other)
{
if (other is null)
{
return this is null;
}
return PatternType.Equals(other.PatternType) &&
Matrix.Equals(other.Matrix) &&
ExtGState.Equals(other.ExtGState) &&

View File

@ -53,26 +53,25 @@
public (double r, double g, double b) ToRGBValues() => (R, G, B);
/// <inheritdoc />
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is RGBColor color)
{
return Equals(color);
}
return false;
return obj is RGBColor other && Equals(other);
}
/// <inheritdoc />
/// <summary>
/// Whether 2 RGB colors are equal across all channels.
/// </summary>
public bool Equals(RGBColor other)
public bool Equals(RGBColor? other)
{
return other != null &&
R == other.R &&
G == other.G &&
B == other.B;
if (other is null)
{
return this is null;
}
return R == other.R
&& G == other.G
&& B == other.B;
}
/// <inheritdoc />

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Colors
#nullable disable
namespace UglyToad.PdfPig.Graphics.Colors
{
using System;
@ -7,8 +9,7 @@
{
public static readonly XYZReferenceWhite ReferenceWhites = new XYZReferenceWhite();
public static readonly RGBWorkingSpace AdobeRGB1998 = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace AdobeRGB1998 = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D65,
RedPrimary = (0.6400, 0.3300, 0.297361),
@ -16,8 +17,7 @@
BluePrimary = (0.1500, 0.0600, 0.075285),
};
public static readonly RGBWorkingSpace AppleRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace AppleRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(1.8),
ReferenceWhite = ReferenceWhites.D65,
RedPrimary = (0.6250, 0.3400, 0.244634),
@ -25,8 +25,7 @@
BluePrimary = (0.1550, 0.0700, 0.083332)
};
public static readonly RGBWorkingSpace BestRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace BestRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.7347, 0.2653, 0.228457),
@ -34,8 +33,7 @@
BluePrimary = (0.1300, 0.0350, 0.034191)
};
public static readonly RGBWorkingSpace BetaRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace BetaRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.6888, 0.3112, 0.303273),
@ -43,8 +41,7 @@
BluePrimary = (0.1265, 0.0352, 0.032941)
};
public static readonly RGBWorkingSpace BruceRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace BruceRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D65,
RedPrimary = (0.6400, 0.3300, 0.240995),
@ -52,8 +49,7 @@
BluePrimary = (0.1500, 0.0600, 0.075452)
};
public static readonly RGBWorkingSpace CIE_RGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace CIE_RGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.E,
RedPrimary = (0.7350, 0.2650, 0.176204),
@ -61,8 +57,7 @@
BluePrimary = (0.1670, 0.0090, 0.010811)
};
public static readonly RGBWorkingSpace ColorMatchRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace ColorMatchRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(1.8),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.6300, 0.3400, 0.274884),
@ -70,8 +65,7 @@
BluePrimary = (0.1500, 0.0750, 0.066985)
};
public static readonly RGBWorkingSpace DonRGB4 = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace DonRGB4 = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.6960, 0.3000, 0.278350),
@ -79,8 +73,7 @@
BluePrimary = (0.1300, 0.0350, 0.033680)
};
public static readonly RGBWorkingSpace EktaSpacePS5 = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace EktaSpacePS5 = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.6950, 0.3050, 0.260629),
@ -88,8 +81,7 @@
BluePrimary = (0.1100, 0.0050, 0.004425)
};
public static readonly RGBWorkingSpace NTSC_RGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace NTSC_RGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.C,
RedPrimary = (0.6700, 0.3300, 0.298839),
@ -97,8 +89,7 @@
BluePrimary = (0.1400, 0.0800, 0.114350)
};
public static readonly RGBWorkingSpace PAL_SECAM_RGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace PAL_SECAM_RGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D65,
RedPrimary = (0.6400, 0.3300, 0.222021),
@ -106,8 +97,7 @@
BluePrimary = (0.1500, 0.0600, 0.071334)
};
public static readonly RGBWorkingSpace ProPhotoRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace ProPhotoRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(1.8),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.7347, 0.2653, 0.288040),
@ -115,8 +105,7 @@
BluePrimary = (0.0366, 0.0001, 0.000086)
};
public static readonly RGBWorkingSpace SMPTE_C_RGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace SMPTE_C_RGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D65,
RedPrimary = (0.6300, 0.3400, 0.212395),
@ -124,8 +113,7 @@
BluePrimary = (0.1550, 0.0700, 0.086556)
};
public static readonly RGBWorkingSpace sRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace sRGB = new RGBWorkingSpace {
// sRGB gamma correction obtained from: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
GammaCorrection = val => val <= 0.0031308 ? 12.92 * val : (1.055 * Math.Pow(val, (1 / 2.4)) - 0.055),
ReferenceWhite = ReferenceWhites.D65,
@ -134,8 +122,7 @@
BluePrimary = (0.1500, 0.0600, 0.072186),
};
public static readonly RGBWorkingSpace WideGamutRGB = new RGBWorkingSpace
{
public static readonly RGBWorkingSpace WideGamutRGB = new RGBWorkingSpace {
GammaCorrection = CreateGammaFunc(2.2),
ReferenceWhite = ReferenceWhites.D50,
RedPrimary = (0.7350, 0.2650, 0.258187),
@ -151,8 +138,7 @@
private static Func<double, double> CreateGammaFunc(double gamma)
{
return val =>
{
return val => {
var result = Math.Pow(val, 1 / gamma);
return double.IsNaN(result) ? 0 : result;
};
@ -175,4 +161,4 @@
public readonly (double X, double Y, double Z) F11 = (1.00962, 1.00000, 0.64350);
}
}
}
}

View File

@ -15,9 +15,9 @@
/// <summary>
/// The color space data.
/// </summary>
public IToken Data { get; }
public IToken? Data { get; }
internal ResourceColorSpace(NameToken name, IToken data)
internal ResourceColorSpace(NameToken name, IToken? data)
{
Name = name;
Data = data;

View File

@ -35,7 +35,7 @@
/// the shading, to fill those portions of the area to be painted
/// that lie outside the bounds of the shading object.
/// </summary>
public double[] Background { get; }
public double[]? Background { get; }
/// <summary>
/// The shading's bounding box. The coordinates shall be interpreted
@ -62,7 +62,7 @@
/// Create a new <see cref="Shading"/>.
/// </summary>
protected internal Shading(ShadingType shadingType, bool antiAlias, DictionaryToken shadingDictionary,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background)
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background)
{
ShadingType = shadingType;
AntiAlias = antiAlias;
@ -75,7 +75,7 @@
/// <summary>
/// The shading's function(s), if any.
/// </summary>
public abstract PdfFunction[] Functions { get; }
public abstract PdfFunction[]? Functions { get; }
/// <summary>
/// Convert the input values using the functions of the shading.
@ -157,7 +157,7 @@
/// Create a new <see cref="FunctionBasedShading"/>.
/// </summary>
public FunctionBasedShading(bool antiAlias, DictionaryToken shadingDictionary,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background, double[] domain,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background, double[] domain,
TransformationMatrix matrix, PdfFunction[] functions)
: base(ShadingType.FunctionBased, antiAlias, shadingDictionary, colorSpace, bbox, background)
{
@ -207,7 +207,7 @@
/// Create a new <see cref="AxialShading"/>.
/// </summary>
public AxialShading(bool antiAlias, DictionaryToken shadingDictionary,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
double[] coords, double[] domain, PdfFunction[] functions, bool[] extend)
: base(ShadingType.Axial, antiAlias, shadingDictionary, colorSpace, bbox, background)
{
@ -267,7 +267,7 @@
/// Create a new <see cref="RadialShading"/>.
/// </summary>
public RadialShading(bool antiAlias, DictionaryToken shadingDictionary,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
double[] coords, double[] domain, PdfFunction[] functions, bool[] extend)
: base(ShadingType.Radial, antiAlias, shadingDictionary, colorSpace, bbox, background)
{
@ -327,14 +327,14 @@
/// to the nearest valid value.
/// This entry shall not be used with an Indexed colour space.
/// </summary>
public override PdfFunction[] Functions { get; }
public override PdfFunction[]? Functions { get; }
/// <summary>
/// Create a new <see cref="FreeFormGouraudShading"/>.
/// </summary>
public FreeFormGouraudShading(bool antiAlias, StreamToken shadingStream,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[] functions)
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[]? functions)
: base(ShadingType.FreeFormGouraud, antiAlias, shadingStream.StreamDictionary, colorSpace, bbox, background)
{
BitsPerCoordinate = bitsPerCoordinate;
@ -390,14 +390,14 @@
/// component is out of range, it shall be adjusted to the nearest valid value.
/// This entry shall not be used with an Indexed colour space.
/// </summary>
public override PdfFunction[] Functions { get; }
public override PdfFunction[]? Functions { get; }
/// <summary>
/// Create a new <see cref="LatticeFormGouraudShading"/>.
/// </summary>
public LatticeFormGouraudShading(bool antiAlias, StreamToken shadingStream,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
int bitsPerCoordinate, int bitsPerComponent, int verticesPerRow, double[] decode, PdfFunction[] functions)
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
int bitsPerCoordinate, int bitsPerComponent, int verticesPerRow, double[] decode, PdfFunction[]? functions)
: base(ShadingType.LatticeFormGouraud, antiAlias, shadingStream.StreamDictionary, colorSpace, bbox, background)
{
BitsPerCoordinate = bitsPerCoordinate;
@ -455,14 +455,14 @@
/// shall be adjusted to the nearest valid value.
/// This entry shall not be used with an Indexed colour space.
/// </summary>
public override PdfFunction[] Functions { get; }
public override PdfFunction[]? Functions { get; }
/// <summary>
/// Create a new <see cref="CoonsPatchMeshesShading"/>.
/// </summary>
public CoonsPatchMeshesShading(bool antiAlias, StreamToken shadingStream,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[] functions)
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[]? functions)
: base(ShadingType.CoonsPatch, antiAlias, shadingStream.StreamDictionary, colorSpace, bbox, background)
{
BitsPerCoordinate = bitsPerCoordinate;
@ -520,14 +520,14 @@
/// shall be adjusted to the nearest valid value.
/// This entry shall not be used with an Indexed colour space.
/// </summary>
public override PdfFunction[] Functions { get; }
public override PdfFunction[]? Functions { get; }
/// <summary>
/// Create a new <see cref="TensorProductPatchMeshesShading"/>.
/// </summary>
public TensorProductPatchMeshesShading(bool antiAlias, StreamToken shadingStream,
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[] background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[] functions)
ColorSpaceDetails colorSpace, PdfRectangle? bbox, double[]? background,
int bitsPerCoordinate, int bitsPerComponent, int bitsPerFlag, double[] decode, PdfFunction[]? functions)
: base(ShadingType.TensorProductPatch, antiAlias, shadingStream.StreamDictionary, colorSpace, bbox, background)
{
BitsPerCoordinate = bitsPerCoordinate;

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.Graphics
#nullable disable
namespace UglyToad.PdfPig.Graphics
{
using System;
using System.Collections.Generic;
@ -30,8 +32,7 @@
/// <summary>
/// Stores a link to each image (either inline or XObject) as it is encountered in the content stream.
/// </summary>
private readonly List<Union<XObjectContentRecord, InlineImage>> images =
new List<Union<XObjectContentRecord, InlineImage>>();
private readonly List<Union<XObjectContentRecord, InlineImage>> images = new();
/// <summary>
/// Stores each marked content as it is encountered in the content stream.
@ -362,7 +363,7 @@
{
AddCurrentSubpath();
if (CurrentPath.IsClipping)
if (CurrentPath!.IsClipping)
{
EndPath();
return;
@ -413,7 +414,7 @@
if (ParsingOptions.ClipPaths)
{
var currentClipping = GetCurrentState().CurrentClippingPath;
var currentClipping = GetCurrentState().CurrentClippingPath!;
currentClipping.SetClipping(clippingRule);
var newClippings = CurrentPath.Clip(currentClipping, ParsingOptions.Logger);

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Util.JetBrains.Annotations;
/// <summary>
/// The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
@ -19,7 +18,6 @@
/// <summary>
/// The numbers that specify the lengths of alternating dashes and gaps.
/// </summary>
[NotNull]
public IReadOnlyList<double> Array { get; }
/// <summary>
@ -27,7 +25,7 @@
/// </summary>
/// <param name="phase">The phase. <see cref="Phase"/>.</param>
/// <param name="array">The array. <see cref="Array"/>.</param>
public LineDashPattern(int phase, [NotNull]IReadOnlyList<double> array)
public LineDashPattern(int phase, IReadOnlyList<double> array)
{
Phase = phase;
Array = array ?? throw new ArgumentNullException(nameof(array));

View File

@ -1,7 +1,9 @@
// ReSharper disable RedundantDefaultMemberInitializer
#nullable disable
// ReSharper disable RedundantDefaultMemberInitializer
namespace UglyToad.PdfPig.Graphics
{
using Core;
using Operations.SpecialGraphicsState;
using PdfPig.Core;
using Tokens;

View File

@ -1,4 +1,6 @@
// ReSharper disable RedundantDefaultMemberInitializer
#nullable disable
// ReSharper disable RedundantDefaultMemberInitializer
namespace UglyToad.PdfPig.Graphics
{
using Colors;

View File

@ -1,7 +1,7 @@
namespace UglyToad.PdfPig.Graphics
{
using Colors;
using System.Collections.Generic;
using Colors;
using Tokens;
using UglyToad.PdfPig.Core;
@ -25,19 +25,19 @@
/// </summary>
/// <param name="colorspace">The color space name.</param>
/// <param name="dictionary">The color space dictionary. Default value is null.</param>
void SetStrokingColorspace(NameToken colorspace, DictionaryToken dictionary = null);
void SetStrokingColorspace(NameToken colorspace, DictionaryToken? dictionary = null);
/// <summary>
/// Set the current color space to use for nonstroking operations and initialize the nonstroking color.
/// </summary>
/// <param name="colorspace">The color space name.</param>
/// <param name="dictionary">The color space dictionary. Default value is null.</param>
void SetNonStrokingColorspace(NameToken colorspace, DictionaryToken dictionary = null);
void SetNonStrokingColorspace(NameToken colorspace, DictionaryToken? dictionary = null);
/// <summary>
/// Set the color to use for stroking operations using the current color space.
/// </summary>
void SetStrokingColor(IReadOnlyList<double> operands, NameToken patternName = null);
void SetStrokingColor(IReadOnlyList<double> operands, NameToken? patternName = null);
/// <summary>
/// Set the stroking color space to DeviceGray and set the gray level to use for stroking operations.
@ -65,7 +65,7 @@
/// <summary>
/// Set the color to use for nonstroking operations using the current color space.
/// </summary>
void SetNonStrokingColor(IReadOnlyList<double> operands, NameToken patternName = null);
void SetNonStrokingColor(IReadOnlyList<double> operands, NameToken? patternName = null);
/// <summary>
/// Set the nonstroking color space to DeviceGray and set the gray level to use for nonstroking operations.

View File

@ -3,11 +3,9 @@
using System.Collections.Generic;
using Operations;
using Tokens;
using Util.JetBrains.Annotations;
internal interface IGraphicsStateOperationFactory
{
[CanBeNull]
IGraphicsStateOperation Create(OperatorToken op, IReadOnlyList<IToken> operands);
IGraphicsStateOperation? Create(OperatorToken op, IReadOnlyList<IToken> operands);
}
}

View File

@ -132,7 +132,7 @@
/// <summary>
/// Indicate that a marked content region is started.
/// </summary>
void BeginMarkedContent(NameToken name, NameToken propertyDictionaryName, DictionaryToken properties);
void BeginMarkedContent(NameToken name, NameToken? propertyDictionaryName, DictionaryToken? properties);
/// <summary>
/// Indicates that the current marked content region is complete.

View File

@ -18,14 +18,15 @@
/// <summary>
/// Inline image properties.
/// </summary>
public IReadOnlyDictionary<NameToken, IToken> Properties { get; internal set; }
public IReadOnlyDictionary<NameToken, IToken>? Properties { get; internal set; }
/// <summary>
/// Inline image bytes.
/// </summary>
public IReadOnlyList<byte> Bytes { get; internal set; }
public IReadOnlyList<byte>? Bytes { get; internal set; }
internal InlineImage CreateInlineImage(TransformationMatrix transformationMatrix, ILookupFilterProvider filterProvider,
internal InlineImage CreateInlineImage(TransformationMatrix transformationMatrix,
ILookupFilterProvider filterProvider,
IPdfTokenScanner tokenScanner,
RenderingIntent defaultRenderingIntent,
IResourceStore resourceStore)
@ -48,7 +49,7 @@
var bitsPerComponent = GetByKeys<NumericToken>(NameToken.BitsPerComponent, NameToken.Bpc, !isMask)?.Int ?? 1;
NameToken colorSpaceName = null;
NameToken? colorSpaceName = null;
if (!isMask)
{
@ -110,8 +111,11 @@
details);
}
#nullable disable
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
private T GetByKeys<T>(NameToken name1, NameToken name2, bool required) where T : IToken
private T GetByKeys<T>(NameToken name1, NameToken name2, bool required)
where T : class, IToken
{
if (Properties.TryGetValue(name1, out var val) && val is T result)
{
@ -131,7 +135,7 @@
throw new PdfDocumentFormatException($"Inline image dictionary missing required entry {name1}/{name2}.");
}
return default(T);
return null;
}
}
}

View File

@ -17,7 +17,7 @@
private readonly Stack<MarkedContentElementActiveBuilder> builderStack = new Stack<MarkedContentElementActiveBuilder>();
private int number = -1;
private MarkedContentElementActiveBuilder top;
private MarkedContentElementActiveBuilder? top;
public bool CanPop => top != null;
@ -32,7 +32,7 @@
builderStack.Push(top);
}
public MarkedContentElement Pop(IPdfTokenScanner pdfScanner)
public MarkedContentElement? Pop(IPdfTokenScanner pdfScanner)
{
var builder = builderStack.Pop();
@ -116,7 +116,7 @@
public MarkedContentElement Build(IPdfTokenScanner pdfScanner)
{
var mcid = -1;
if (properties.TryGet(NameToken.Mcid, pdfScanner, out NumericToken mcidToken))
if (properties.TryGet(NameToken.Mcid, pdfScanner, out NumericToken? mcidToken))
{
mcid = mcidToken.Int;
}
@ -142,7 +142,7 @@
}
var artifactType = ArtifactMarkedContentElement.ArtifactType.Unknown;
if (properties.TryGet(NameToken.Type, pdfScanner, out IDataToken<string> typeToken)
if (properties.TryGet(NameToken.Type, pdfScanner, out IDataToken<string>? typeToken)
&& Enum.TryParse(typeToken.Data, true, out ArtifactMarkedContentElement.ArtifactType parsedType))
{
artifactType = parsedType;
@ -152,12 +152,12 @@
var attributeOwners = GetOptional(NameToken.O, pdfScanner);
var boundingBox = default(PdfRectangle?);
if (properties.TryGet(NameToken.Bbox, pdfScanner, out ArrayToken arrayToken))
if (properties.TryGet(NameToken.Bbox, pdfScanner, out ArrayToken? arrayToken))
{
NumericToken left = null;
NumericToken bottom = null;
NumericToken right = null;
NumericToken top = null;
NumericToken? left = null;
NumericToken? bottom = null;
NumericToken? right = null;
NumericToken? top = null;
if (arrayToken.Length == 4)
{
@ -192,7 +192,8 @@
}
}
return new ArtifactMarkedContentElement(mcid, name, properties, language,
return new ArtifactMarkedContentElement(mcid, name,properties,
language,
actualText,
alternateDescription,
expandedForm,
@ -208,10 +209,10 @@
number);
}
private string GetOptional(NameToken optionName, IPdfTokenScanner pdfScanner)
private string? GetOptional(NameToken optionName, IPdfTokenScanner pdfScanner)
{
var result = default(string);
if (properties.TryGet(optionName, pdfScanner, out IDataToken<string> token))
if (properties.TryGet(optionName, pdfScanner, out IDataToken<string>? token))
{
result = token.Data;
}

View File

@ -2,7 +2,6 @@
{
using System.IO;
using Tokens;
using Util.JetBrains.Annotations;
using Writer;
/// <inheritdoc />
@ -30,15 +29,13 @@
/// The name of the property dictionary in the Properties subdictionary of the current resource dictionary.
/// Can be <see langword="null"/> if the property dictionary is provided inline.
/// </summary>
[CanBeNull]
public NameToken PropertyDictionaryName { get; }
public NameToken? PropertyDictionaryName { get; }
/// <summary>
/// The marked-content sequence properties.
/// Can be <see langword="null"/> if a name of the property dictionary is provided instead.
/// </summary>
[CanBeNull]
public DictionaryToken Properties { get; }
public DictionaryToken? Properties { get; }
/// <summary>
/// Create a new <see cref="BeginMarkedContentWithProperties"/>.
@ -65,7 +62,7 @@
/// <inheritdoc />
public void Run(IOperationContext operationContext)
{
operationContext.BeginMarkedContent(Name, PropertyDictionaryName, Properties);
operationContext.BeginMarkedContent(Name, PropertyDictionaryName, Properties!);
}
/// <inheritdoc />
@ -80,7 +77,7 @@
}
else
{
TokenWriter.WriteToken(Properties, stream);
TokenWriter.WriteToken(Properties!, stream);
}
stream.WriteWhiteSpace();

View File

@ -2,7 +2,6 @@
{
using System.IO;
using Tokens;
using Util.JetBrains.Annotations;
using Writer;
/// <inheritdoc />
@ -30,15 +29,13 @@
/// The name of the property dictionary in the Properties subdictionary of the current resource dictionary.
/// Can be <see langword="null"/> if the property dictionary is provided inline.
/// </summary>
[CanBeNull]
public NameToken PropertyDictionaryName { get; }
public NameToken? PropertyDictionaryName { get; }
/// <summary>
/// The marked-content point properties.
/// Can be <see langword="null"/> if a name of the property dictionary is provided instead.
/// </summary>
[CanBeNull]
public DictionaryToken Properties { get; }
public DictionaryToken? Properties { get; }
/// <summary>
/// Create a new <see cref="DesignateMarkedContentPointWithProperties"/>.
@ -80,7 +77,7 @@
}
else
{
TokenWriter.WriteToken(Properties, stream);
TokenWriter.WriteToken(Properties!, stream);
}
stream.WriteWhiteSpace();

View File

@ -29,7 +29,7 @@
/// <summary>
/// The name of an entry in the Pattern subdictionary of the current resource dictionary.
/// </summary>
public NameToken PatternName { get; }
public NameToken? PatternName { get; }
/// <summary>
/// Create a new <see cref="SetNonStrokeColorAdvanced"/>.

View File

@ -29,7 +29,7 @@
/// <summary>
/// The name of an entry in the Pattern subdictionary of the current resource dictionary.
/// </summary>
public NameToken PatternName { get; }
public NameToken? PatternName { get; }
/// <summary>
/// Create a new <see cref="SetStrokeColor"/>.

View File

@ -2,7 +2,6 @@
{
using System.IO;
using TextPositioning;
using Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -21,14 +20,12 @@
/// <summary>
/// The text to show as a <see cref="string"/>.
/// </summary>
[CanBeNull]
public string Text { get; }
public string? Text { get; }
/// <summary>
/// The text to show as hex bytes.
/// </summary>
[CanBeNull]
public byte[] Bytes { get; }
public byte[]? Bytes { get; }
/// <summary>
/// Create a new <see cref="MoveToNextLineShowText"/>.
@ -53,7 +50,7 @@
{
var move = MoveToNextLine.Value;
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes);
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes!);
move.Run(operationContext);
showText.Run(operationContext);

View File

@ -3,7 +3,6 @@
using System.IO;
using TextPositioning;
using TextState;
using Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -32,14 +31,12 @@
/// <summary>
/// The bytes of the text.
/// </summary>
[CanBeNull]
public byte[] Bytes { get; }
public byte[]? Bytes { get; }
/// <summary>
/// The text to show.
/// </summary>
[CanBeNull]
public string Text { get; }
public string? Text { get; }
/// <summary>
/// Create a new <see cref="MoveToNextLineShowTextWithSpacing"/>.
@ -73,7 +70,7 @@
var setWordSpacing = new SetWordSpacing(WordSpacing);
var setCharacterSpacing = new SetCharacterSpacing(CharacterSpacing);
var moveToNextLine = MoveToNextLine.Value;
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes);
var showText = Text != null ? new ShowText(Text) : new ShowText(Bytes!);
setWordSpacing.Run(operationContext);
setCharacterSpacing.Run(operationContext);

View File

@ -1,8 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextShowing
{
using System.IO;
using PdfPig.Core;
using Util.JetBrains.Annotations;
using System.IO;
/// <inheritdoc />
/// <summary>
@ -34,14 +33,12 @@
/// <summary>
/// The text string to show.
/// </summary>
[CanBeNull]
public string Text { get; }
public string? Text { get; }
/// <summary>
/// The bytes of the string to show.
/// </summary>
[CanBeNull]
public byte[] Bytes { get; }
public byte[]? Bytes { get; }
/// <summary>
/// Create a new <see cref="ShowText"/>.
@ -67,7 +64,7 @@
operationContext.ShowText(input);
}
string EscapeText(string text)
string? EscapeText(string? text)
{
if (text is null) return null;
// Fix Issue 350 from PDF Spec 1.7 (page 408) on handling 'special characters' of '(', ')' and '\'.

View File

@ -4,7 +4,6 @@
using System.Globalization;
using System.IO;
using Tokens;
using Util.JetBrains.Annotations;
/// <inheritdoc />
/// <summary>
@ -25,7 +24,6 @@
/// <summary>
/// The name of the font as defined in the resource dictionary.
/// </summary>
[NotNull]
public NameToken Font { get; }
/// <summary>

View File

@ -29,7 +29,7 @@
/// <summary>
/// The fill color.
/// </summary>
public IColor FillColor { get; internal set; }
public IColor? FillColor { get; internal set; }
/// <summary>
/// Returns true if the path is stroked.
@ -39,7 +39,7 @@
/// <summary>
/// The stroke color.
/// </summary>
public IColor StrokeColor { get; internal set; }
public IColor? StrokeColor { get; internal set; }
/// <summary>
/// Thickness in user space units of path to be stroked.

View File

@ -30,7 +30,7 @@ namespace UglyToad.PdfPig.Graphics
public ReflectionGraphicsStateOperationFactory()
{
var assemblyTypes = Assembly.GetAssembly(typeof(ReflectionGraphicsStateOperationFactory)).GetTypes();
var assemblyTypes = Assembly.GetAssembly(typeof(ReflectionGraphicsStateOperationFactory))!.GetTypes();
var result = new Dictionary<string, Type>();
@ -45,7 +45,7 @@ namespace UglyToad.PdfPig.Graphics
throw new InvalidOperationException("An operation type was defined without the public const Symbol being declared. Type was: " + assemblyType.FullName);
}
var value = symbol.GetValue(null).ToString();
var value = symbol.GetValue(null)!.ToString()!;
result[value] = assemblyType;
}
@ -114,7 +114,7 @@ namespace UglyToad.PdfPig.Graphics
return numeric.Data;
}
public IGraphicsStateOperation Create(OperatorToken op, IReadOnlyList<IToken> operands)
public IGraphicsStateOperation? Create(OperatorToken op, IReadOnlyList<IToken> operands)
{
switch (op.Data)
{
@ -388,7 +388,7 @@ namespace UglyToad.PdfPig.Graphics
return new ShowTextsWithPositioning(array);
}
if (!operations.TryGetValue(op.Data, out Type operationType))
if (!operations.TryGetValue(op.Data, out Type? operationType))
{
return null;
}
@ -405,7 +405,7 @@ namespace UglyToad.PdfPig.Graphics
if (constructor.IsPrivate)
{
return (IGraphicsStateOperation)operationType.GetField("Value").GetValue(null);
return (IGraphicsStateOperation)operationType.GetField("Value")?.GetValue(null)!;
}
var parameters = constructor.GetParameters();

View File

@ -5,7 +5,6 @@
using Core;
using PdfPig.Core;
using Tokens;
using Util.JetBrains.Annotations;
using XObjects;
/// <summary>
@ -21,7 +20,6 @@
/// <summary>
/// The XObject stream.
/// </summary>
[NotNull]
public StreamToken Stream { get; }
/// <summary>

View File

@ -1,4 +1,6 @@
namespace UglyToad.PdfPig.IO
#nullable disable
namespace UglyToad.PdfPig.IO
{
using System;
using System.Collections.Generic;

Some files were not shown because too many files have changed in this diff Show More